1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
|
/*
* This file is part of the Green End SFTP Server.
* Copyright (C) 2007, 2011 Richard Kettlewell
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
/** @file send.c @brief Message sending implementation */
#include "sftpserver.h"
#include "debug.h"
#include "utils.h"
#include "handle.h"
#include "send.h"
#include "thread.h"
#include "types.h"
#include "globals.h"
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include "putword.h"
#if NTHREADS > 1
/** @brief Mutex to serialize IO */
static pthread_mutex_t output_lock = PTHREAD_MUTEX_INITIALIZER;
#endif
int sftpout = 1; /* default is stdout */
/** @brief Store a 16-bit value */
#define sftp_send_raw16(u) do { \
put16(&w->buffer[w->bufused], u); \
w->bufused += 2; \
} while(0)
/** @brief Store a 32-bit value */
#define sftp_send_raw32(u) do { \
put32(&w->buffer[w->bufused], u); \
w->bufused += 4; \
} while(0)
/** @brief Store a 64-bit value */
#define sftp_send_raw64(u) do { \
put64(&w->buffer[w->bufused], u); \
w->bufused += 8; \
} while(0)
void sftp_send_need(struct worker *w, size_t n) {
assert(w->bufused < 0x80000000);
if(n > w->bufsize - w->bufused) {
size_t newsize = w->bufsize ? w->bufsize : 64;
while(newsize && newsize < w->bufsize + n)
newsize <<= 1;
if(!newsize)
fatal("sftp_send_need: out of memory (%zu)", n);
w->buffer = xrealloc(w->buffer, w->bufsize = newsize);
}
}
void sftp_send_begin(struct worker *w) {
w->bufused = 0;
sftp_send_uint32(w, 0); /* placeholder for length */
}
void sftp_send_end(struct worker *w) {
ssize_t n, written;
assert(w->bufused < 0x80000000);
/* Fill in length word. The malloc'd area is assumed to be aligned
* suitably. */
*(uint32_t *)w->buffer = htonl(w->bufused - 4);
/* Write the complete output, protecting stdout with a lock to avoid
* interleaving different responses. */
ferrcheck(pthread_mutex_lock(&output_lock));
if(sftp_debugging) {
D(("%s:", sendtype));
sftp_debug_hexdump(w->buffer + 4, w->bufused - 4);
}
/* Write the whole buffer, coping with short writes */
written = 0;
while((size_t)written < w->bufused)
if((n = write(sftpout, w->buffer + written, w->bufused - written)) > 0)
written += n;
else if(n < 0)
fatal("error sending response: %s", strerror(errno));
ferrcheck(pthread_mutex_unlock(&output_lock));
w->bufused = 0x80000000;
}
void sftp_send_uint8(struct worker *w, int n) {
sftp_send_need(w, 1);
w->buffer[w->bufused++] = (uint8_t)n;
}
void sftp_send_uint16(struct worker *w, uint16_t u) {
sftp_send_need(w, 2);
sftp_send_raw16(u);
}
void sftp_send_uint32(struct worker *w, uint32_t u) {
sftp_send_need(w, 4);
sftp_send_raw32(u);
}
void sftp_send_uint64(struct worker *w, uint64_t u) {
sftp_send_need(w, 8);
sftp_send_raw64(u);
}
void sftp_send_bytes(struct worker *w, const void *bytes, size_t n) {
sftp_send_need(w, n + 4);
sftp_send_raw32(n);
memcpy(w->buffer + w->bufused, bytes, n);
w->bufused += n;
}
void sftp_send_string(struct worker *w, const char *s) {
sftp_send_bytes(w, s, strlen(s));
}
void sftp_send_path(struct sftpjob *job, struct worker *w, const char *path) {
if(protocol->encode(job, (char **)&path))
fatal("cannot encode local path name '%s'", path);
sftp_send_string(w, path);
}
void sftp_send_handle(struct worker *w, const struct handleid *id) {
sftp_send_need(w, 12);
sftp_send_raw32(8);
sftp_send_raw32(id->id);
sftp_send_raw32(id->tag);
}
size_t sftp_send_sub_begin(struct worker *w) {
sftp_send_need(w, 4);
w->bufused += 4;
return w->bufused;
}
void sftp_send_sub_end(struct worker *w, size_t offset) {
const size_t latest = w->bufused;
w->bufused = offset - 4;
sftp_send_raw32(latest - offset);
w->bufused = latest;
}
/*
Local Variables:
c-basic-offset:2
comment-column:40
fill-column:79
indent-tabs-mode:nil
End:
*/
|