root/source3/lib/packet.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. packet_context_destructor
  2. packet_init
  3. packet_fd_read
  4. packet_fd_read_sync
  5. packet_handler
  6. packet_outgoing_bytes
  7. packet_fd_write
  8. packet_flush
  9. packet_send
  10. packet_get_fd

   1 /* 
   2    Unix SMB/CIFS implementation.
   3    Packet handling
   4    Copyright (C) Volker Lendecke 2007
   5    
   6    This program is free software; you can redistribute it and/or modify
   7    it under the terms of the GNU General Public License as published by
   8    the Free Software Foundation; either version 3 of the License, or
   9    (at your option) any later version.
  10    
  11    This program is distributed in the hope that it will be useful,
  12    but WITHOUT ANY WARRANTY; without even the implied warranty of
  13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14    GNU General Public License for more details.
  15    
  16    You should have received a copy of the GNU General Public License
  17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  18 */
  19 
  20 #include "includes.h"
  21 
  22 struct packet_context {
  23         int fd;
  24         DATA_BLOB in, out;
  25 };
  26 
  27 /*
  28  * Close the underlying fd
  29  */
  30 static int packet_context_destructor(struct packet_context *ctx)
     /* [<][>][^][v][top][bottom][index][help] */
  31 {
  32         return close(ctx->fd);
  33 }
  34 
  35 /*
  36  * Initialize a packet context. The fd is given to the packet context, meaning
  37  * that it is automatically closed when the packet context is freed.
  38  */
  39 struct packet_context *packet_init(TALLOC_CTX *mem_ctx, int fd)
     /* [<][>][^][v][top][bottom][index][help] */
  40 {
  41         struct packet_context *result;
  42 
  43         if (!(result = TALLOC_ZERO_P(mem_ctx, struct packet_context))) {
  44                 return NULL;
  45         }
  46 
  47         result->fd = fd;
  48         talloc_set_destructor(result, packet_context_destructor);
  49         return result;
  50 }
  51 
  52 /*
  53  * Pull data from the fd
  54  */
  55 NTSTATUS packet_fd_read(struct packet_context *ctx)
     /* [<][>][^][v][top][bottom][index][help] */
  56 {
  57         int res, available;
  58         size_t new_size;
  59         uint8 *in;
  60 
  61         res = ioctl(ctx->fd, FIONREAD, &available);
  62 
  63         if (res == -1) {
  64                 DEBUG(10, ("ioctl(FIONREAD) failed: %s\n", strerror(errno)));
  65                 return map_nt_error_from_unix(errno);
  66         }
  67 
  68         SMB_ASSERT(available >= 0);
  69 
  70         if (available == 0) {
  71                 return NT_STATUS_END_OF_FILE;
  72         }
  73 
  74         new_size = ctx->in.length + available;
  75 
  76         if (new_size < ctx->in.length) {
  77                 DEBUG(0, ("integer wrap\n"));
  78                 return NT_STATUS_NO_MEMORY;
  79         }
  80 
  81         if (!(in = TALLOC_REALLOC_ARRAY(ctx, ctx->in.data, uint8, new_size))) {
  82                 DEBUG(10, ("talloc failed\n"));
  83                 return NT_STATUS_NO_MEMORY;
  84         }
  85 
  86         ctx->in.data = in;
  87 
  88         res = recv(ctx->fd, in + ctx->in.length, available, 0);
  89 
  90         if (res < 0) {
  91                 DEBUG(10, ("recv failed: %s\n", strerror(errno)));
  92                 return map_nt_error_from_unix(errno);
  93         }
  94 
  95         if (res == 0) {
  96                 return NT_STATUS_END_OF_FILE;
  97         }
  98 
  99         ctx->in.length += res;
 100 
 101         return NT_STATUS_OK;
 102 }
 103 
 104 NTSTATUS packet_fd_read_sync(struct packet_context *ctx)
     /* [<][>][^][v][top][bottom][index][help] */
 105 {
 106         int res;
 107         fd_set r_fds;
 108 
 109         FD_ZERO(&r_fds);
 110         FD_SET(ctx->fd, &r_fds);
 111 
 112         res = sys_select(ctx->fd+1, &r_fds, NULL, NULL, NULL);
 113 
 114         if (res == -1) {
 115                 DEBUG(10, ("select returned %s\n", strerror(errno)));
 116                 return map_nt_error_from_unix(errno);
 117         }
 118 
 119         return packet_fd_read(ctx);
 120 }
 121 
 122 bool packet_handler(struct packet_context *ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 123                     bool (*full_req)(const uint8_t *buf,
 124                                      size_t available,
 125                                      size_t *length,
 126                                      void *priv),
 127                     NTSTATUS (*callback)(uint8_t *buf, size_t length,
 128                                          void *priv),
 129                     void *priv, NTSTATUS *status)
 130 {
 131         size_t length;
 132         uint8_t *buf;
 133 
 134         if (!full_req(ctx->in.data, ctx->in.length, &length, priv)) {
 135                 return False;
 136         }
 137 
 138         if (length > ctx->in.length) {
 139                 *status = NT_STATUS_INTERNAL_ERROR;
 140                 return true;
 141         }
 142 
 143         if (length == ctx->in.length) {
 144                 buf = ctx->in.data;
 145                 ctx->in.data = NULL;
 146                 ctx->in.length = 0;
 147         } else {
 148                 buf = (uint8_t *)TALLOC_MEMDUP(ctx, ctx->in.data, length);
 149                 if (buf == NULL) {
 150                         *status = NT_STATUS_NO_MEMORY;
 151                         return true;
 152                 }
 153 
 154                 memmove(ctx->in.data, ctx->in.data + length,
 155                         ctx->in.length - length);
 156                 ctx->in.length -= length;
 157         }
 158 
 159         *status = callback(buf, length, priv);
 160         return True;
 161 }
 162 
 163 /*
 164  * How many bytes of outgoing data do we have pending?
 165  */
 166 size_t packet_outgoing_bytes(struct packet_context *ctx)
     /* [<][>][^][v][top][bottom][index][help] */
 167 {
 168         return ctx->out.length;
 169 }
 170 
 171 /*
 172  * Push data to the fd
 173  */
 174 NTSTATUS packet_fd_write(struct packet_context *ctx)
     /* [<][>][^][v][top][bottom][index][help] */
 175 {
 176         ssize_t sent;
 177 
 178         sent = send(ctx->fd, ctx->out.data, ctx->out.length, 0);
 179 
 180         if (sent == -1) {
 181                 DEBUG(0, ("send failed: %s\n", strerror(errno)));
 182                 return map_nt_error_from_unix(errno);
 183         }
 184 
 185         memmove(ctx->out.data, ctx->out.data + sent,
 186                 ctx->out.length - sent);
 187         ctx->out.length -= sent;
 188 
 189         return NT_STATUS_OK;
 190 }
 191 
 192 /*
 193  * Sync flush all outgoing bytes
 194  */
 195 NTSTATUS packet_flush(struct packet_context *ctx)
     /* [<][>][^][v][top][bottom][index][help] */
 196 {
 197         while (ctx->out.length != 0) {
 198                 NTSTATUS status = packet_fd_write(ctx);
 199                 if (!NT_STATUS_IS_OK(status)) {
 200                         return status;
 201                 }
 202         }
 203         return NT_STATUS_OK;
 204 }
 205 
 206 /*
 207  * Send a list of DATA_BLOBs
 208  *
 209  * Example:  packet_send(ctx, 2, data_blob_const(&size, sizeof(size)),
 210  *                       data_blob_const(buf, size));
 211  */
 212 NTSTATUS packet_send(struct packet_context *ctx, int num_blobs, ...)
     /* [<][>][^][v][top][bottom][index][help] */
 213 {
 214         va_list ap;
 215         int i;
 216         size_t len;
 217         uint8 *out;
 218 
 219         len = ctx->out.length;
 220 
 221         va_start(ap, num_blobs);
 222         for (i=0; i<num_blobs; i++) {
 223                 size_t tmp;
 224                 DATA_BLOB blob = va_arg(ap, DATA_BLOB);
 225 
 226                 tmp = len + blob.length;
 227                 if (tmp < len) {
 228                         DEBUG(0, ("integer overflow\n"));
 229                         va_end(ap);
 230                         return NT_STATUS_NO_MEMORY;
 231                 }
 232                 len = tmp;
 233         }
 234         va_end(ap);
 235 
 236         if (len == 0) {
 237                 return NT_STATUS_OK;
 238         }
 239 
 240         if (!(out = TALLOC_REALLOC_ARRAY(ctx, ctx->out.data, uint8, len))) {
 241                 DEBUG(0, ("talloc failed\n"));
 242                 return NT_STATUS_NO_MEMORY;
 243         }
 244 
 245         ctx->out.data = out;
 246 
 247         va_start(ap, num_blobs);
 248         for (i=0; i<num_blobs; i++) {
 249                 DATA_BLOB blob = va_arg(ap, DATA_BLOB);
 250 
 251                 memcpy(ctx->out.data+ctx->out.length, blob.data, blob.length);
 252                 ctx->out.length += blob.length;
 253         }
 254         va_end(ap);
 255 
 256         SMB_ASSERT(ctx->out.length == len);
 257         return NT_STATUS_OK;
 258 }
 259 
 260 /*
 261  * Get the packet context's file descriptor
 262  */
 263 int packet_get_fd(struct packet_context *ctx)
     /* [<][>][^][v][top][bottom][index][help] */
 264 {
 265         return ctx->fd;
 266 }
 267 

/* [<][>][^][v][top][bottom][index][help] */