• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-WNDR4500v2-V1.0.0.60_1.0.38/ap/gpl/timemachine/netatalk-2.2.0/libatalk/dsi/
1/*
2 * Copyright (c) 1998 Adrian Sun (asun@zoology.washington.edu)
3 * All rights reserved. See COPYRIGHT.
4 *
5 * this file provides the following functions:
6 * dsi_stream_write:    just write a bunch of bytes.
7 * dsi_stream_read:     just read a bunch of bytes.
8 * dsi_stream_send:     send a DSI header + data.
9 * dsi_stream_receive:  read a DSI header + data.
10 */
11
12#ifdef HAVE_CONFIG_H
13#include "config.h"
14#endif /* HAVE_CONFIG_H */
15
16#include <stdio.h>
17#include <stdlib.h>
18
19#ifdef HAVE_UNISTD_H
20#include <unistd.h>
21#endif
22
23#include <string.h>
24#include <errno.h>
25#include <sys/types.h>
26#include <sys/socket.h>
27#include <sys/uio.h>
28
29#include <atalk/logger.h>
30#include <atalk/dsi.h>
31#include <netatalk/endian.h>
32#include <atalk/util.h>
33
34#define min(a,b)  ((a) < (b) ? (a) : (b))
35
36#ifndef MSG_MORE
37#define MSG_MORE 0x8000
38#endif
39
40#ifndef MSG_DONTWAIT
41#define MSG_DONTWAIT 0x40
42#endif
43
44/*
45 * afpd is sleeping too much while trying to send something.
46 * May be there's no reader or the reader is also sleeping in write,
47 * look if there's some data for us to read, hopefully it will wake up
48 * the reader so we can write again.
49 *
50 * @returns 0 when is possible to send again, -1 on error
51 */
52static int dsi_peek(DSI *dsi)
53{
54    static int warned = 0;
55    fd_set readfds, writefds;
56    int    len;
57    int    maxfd;
58    int    ret;
59
60    LOG(log_debug, logtype_dsi, "dsi_peek");
61
62    maxfd = dsi->socket + 1;
63
64    while (1) {
65        FD_ZERO(&readfds);
66        FD_ZERO(&writefds);
67
68        if (dsi->eof < dsi->end) {
69            /* space in read buffer */
70            FD_SET( dsi->socket, &readfds);
71        } else {
72            if (!warned) {
73                warned = 1;
74                LOG(log_note, logtype_dsi, "dsi_peek: readahead buffer is full, possibly increase -dsireadbuf option");
75                LOG(log_note, logtype_dsi, "dsi_peek: dsireadbuf: %d, DSI quantum: %d, effective buffer size: %d",
76                    dsi->dsireadbuf,
77                    dsi->server_quantum ? dsi->server_quantum : DSI_SERVQUANT_DEF,
78                    dsi->end - dsi->buffer);
79            }
80        }
81
82        FD_SET( dsi->socket, &writefds);
83
84        /* No timeout: if there's nothing to read nor nothing to write,
85         * we've got nothing to do at all */
86        if ((ret = select( maxfd, &readfds, &writefds, NULL, NULL)) <= 0) {
87            if (ret == -1 && errno == EINTR)
88                /* we might have been interrupted by out timer, so restart select */
89                continue;
90            /* give up */
91            LOG(log_error, logtype_dsi, "dsi_peek: unexpected select return: %d %s",
92                ret, ret < 0 ? strerror(errno) : "");
93            return -1;
94        }
95
96        if (FD_ISSET(dsi->socket, &writefds)) {
97            /* we can write again */
98            LOG(log_debug, logtype_dsi, "dsi_peek: can write again");
99            break;
100        }
101
102        /* Check if there's sth to read, hopefully reading that will unblock the client */
103        if (FD_ISSET(dsi->socket, &readfds)) {
104            len = dsi->end - dsi->eof; /* it's ensured above that there's space */
105
106            if ((len = read(dsi->socket, dsi->eof, len)) <= 0) {
107                if (len == 0) {
108                    LOG(log_error, logtype_dsi, "dsi_peek: EOF");
109                    return -1;
110                }
111                LOG(log_error, logtype_dsi, "dsi_peek: read: %s", strerror(errno));
112                if (errno == EAGAIN)
113                    continue;
114                return -1;
115            }
116            LOG(log_debug, logtype_dsi, "dsi_peek: read %d bytes", len);
117
118            dsi->eof += len;
119        }
120    }
121
122    return 0;
123}
124
125/*
126 * Return all bytes up to count from dsi->buffer if there are any buffered there
127 */
128static size_t from_buf(DSI *dsi, u_int8_t *buf, size_t count)
129{
130    size_t nbe = 0;
131
132    if (dsi->buffer == NULL)
133        /* afpd master has no DSI buffering */
134        return 0;
135
136    LOG(log_maxdebug, logtype_dsi, "from_buf: %u bytes", count);
137
138    nbe = dsi->eof - dsi->start;
139
140    if (nbe > 0) {
141        nbe = min((size_t)nbe, count);
142        memcpy(buf, dsi->start, nbe);
143        dsi->start += nbe;
144
145        if (dsi->eof == dsi->start)
146            dsi->start = dsi->eof = dsi->buffer;
147    }
148
149    LOG(log_debug, logtype_dsi, "from_buf(read: %u, unread:%u , space left: %u): returning %u",
150        dsi->start - dsi->buffer, dsi->eof - dsi->start, dsi->end - dsi->eof, nbe);
151
152    return nbe;
153}
154
155/*
156 * Get bytes from buffer dsi->buffer or read from socket
157 *
158 * 1. Check if there are bytes in the the dsi->buffer buffer.
159 * 2. Return bytes from (1) if yes.
160 *    Note: this may return fewer bytes then requested in count !!
161 * 3. If the buffer was empty, read from the socket.
162 */
163static ssize_t buf_read(DSI *dsi, u_int8_t *buf, size_t count)
164{
165    ssize_t len;
166
167    LOG(log_maxdebug, logtype_dsi, "buf_read(%u bytes)", count);
168
169    if (!count)
170        return 0;
171
172    len = from_buf(dsi, buf, count); /* 1. */
173    if (len)
174        return len;             /* 2. */
175
176    len = readt(dsi->socket, buf, count, 0, 1); /* 3. */
177
178    LOG(log_maxdebug, logtype_dsi, "buf_read(%u bytes): got: %d", count, len);
179
180    return len;
181}
182
183/*
184 * Get "length" bytes from buffer and/or socket. In order to avoid frequent small reads
185 * this tries to read larger chunks (8192 bytes) into a buffer.
186 */
187static size_t dsi_buffered_stream_read(DSI *dsi, u_int8_t *data, const size_t length)
188{
189  size_t len;
190  size_t buflen;
191
192  LOG(log_maxdebug, logtype_dsi, "dsi_buffered_stream_read: %u bytes", length);
193
194  len = from_buf(dsi, data, length); /* read from buffer dsi->buffer */
195  dsi->read_count += len;
196  if (len == length) {          /* got enough bytes from there ? */
197      return len;               /* yes */
198  }
199
200  /* fill the buffer with 8192 bytes or until buffer is full */
201  buflen = min(8192, dsi->end - dsi->eof);
202  if (buflen > 0) {
203      ssize_t ret;
204      ret = read(dsi->socket, dsi->eof, buflen);
205      if (ret > 0)
206          dsi->eof += ret;
207  }
208
209  /* now get the remaining data */
210  if ((buflen = dsi_stream_read(dsi, data + len, length - len)) != length - len)
211      return 0;
212  len += buflen;
213
214  return len;
215}
216
217/* ---------------------------------------
218*/
219static void block_sig(DSI *dsi)
220{
221  dsi->in_write++;
222}
223
224/* ---------------------------------------
225*/
226static void unblock_sig(DSI *dsi)
227{
228  dsi->in_write--;
229}
230
231/*********************************************************************************
232 * Public functions
233 *********************************************************************************/
234
235/*!
236 * Communication error with the client, enter disconnected state
237 *
238 * 1. close the socket
239 * 2. set the DSI_DISCONNECTED flag
240 *
241 * @returns  0 if successfully entered disconnected state
242 *          -1 if ppid is 1 which means afpd master died
243 *             or euid == 0 ie where still running as root (unauthenticated session)
244 */
245int dsi_disconnect(DSI *dsi)
246{
247    dsi->proto_close(dsi);          /* 1 */
248    dsi->flags |= DSI_DISCONNECTED; /* 2 */
249    if (geteuid() == 0)
250        return -1;
251    return 0;
252}
253
254/* ------------------------------
255 * write raw data. return actual bytes read. checks against EINTR
256 * aren't necessary if all of the signals have SA_RESTART
257 * specified. */
258ssize_t dsi_stream_write(DSI *dsi, void *data, const size_t length, int mode)
259{
260  size_t written;
261  ssize_t len;
262  unsigned int flags = 0;
263
264  dsi->in_write++;
265  written = 0;
266
267  LOG(log_maxdebug, logtype_dsi, "dsi_stream_write: sending %u bytes", length);
268
269  if (dsi->flags & DSI_DISCONNECTED)
270      return -1;
271
272  while (written < length) {
273      len = send(dsi->socket, (u_int8_t *) data + written, length - written, flags);
274      if (len >= 0) {
275          written += len;
276          continue;
277      }
278
279      if (errno == EINTR)
280          continue;
281
282      if (errno == EAGAIN || errno == EWOULDBLOCK) {
283          LOG(log_debug, logtype_dsi, "dsi_stream_write: send: %s", strerror(errno));
284
285          if (mode == DSI_NOWAIT && written == 0) {
286              /* DSI_NOWAIT is used by attention give up in this case. */
287              written = -1;
288              goto exit;
289          }
290
291          /* Try to read sth. in order to break up possible deadlock */
292          if (dsi_peek(dsi) != 0) {
293              written = -1;
294              goto exit;
295          }
296          /* Now try writing again */
297          continue;
298      }
299
300      LOG(log_error, logtype_dsi, "dsi_stream_write: %s", strerror(errno));
301      written = -1;
302      goto exit;
303  }
304
305  dsi->write_count += written;
306
307exit:
308  dsi->in_write--;
309  return written;
310}
311
312
313/* ---------------------------------
314*/
315#ifdef WITH_SENDFILE
316ssize_t dsi_stream_read_file(DSI *dsi, int fromfd, off_t offset, const size_t length)
317{
318  size_t written;
319  ssize_t len;
320
321  LOG(log_maxdebug, logtype_dsi, "dsi_stream_read_file: sending %u bytes", length);
322
323  if (dsi->flags & DSI_DISCONNECTED)
324      return -1;
325
326  dsi->in_write++;
327  written = 0;
328
329  while (written < length) {
330    len = sys_sendfile(dsi->socket, fromfd, &offset, length - written);
331
332    if (len < 0) {
333      if (errno == EINTR)
334          continue;
335      if (errno == EINVAL || errno == ENOSYS)
336          return -1;
337
338      if (errno == EAGAIN || errno == EWOULDBLOCK) {
339          if (dsi_peek(dsi)) {
340              /* can't go back to blocking mode, exit, the next read
341                 will return with an error and afpd will die.
342              */
343              break;
344          }
345          continue;
346      }
347      LOG(log_error, logtype_dsi, "dsi_stream_read_file: %s", strerror(errno));
348      break;
349    }
350    else if (!len) {
351        /* afpd is going to exit */
352        errno = EIO;
353        return -1; /* I think we're at EOF here... */
354    }
355    else
356        written += len;
357  }
358
359  dsi->write_count += written;
360  dsi->in_write--;
361  return written;
362}
363#endif
364
365
366/*
367 * Essentially a loop around buf_read() to ensure "length" bytes are read
368 * from dsi->buffer and/or the socket.
369 *
370 * @returns length on success, some value smaller then length indicates an error
371 */
372size_t dsi_stream_read(DSI *dsi, void *data, const size_t length)
373{
374  size_t stored;
375  ssize_t len;
376
377  if (dsi->flags & DSI_DISCONNECTED)
378      return 0;
379
380  LOG(log_maxdebug, logtype_dsi, "dsi_stream_read(%u bytes)", length);
381
382  stored = 0;
383  while (stored < length) {
384      len = buf_read(dsi, (u_int8_t *) data + stored, length - stored);
385      if (len == -1 && (errno == EINTR || errno == EAGAIN)) {
386          LOG(log_maxdebug, logtype_dsi, "dsi_stream_read: select read loop");
387          continue;
388      } else if (len > 0) {
389          stored += len;
390      } else { /* eof or error */
391          /* don't log EOF error if it's just after connect (OSX 10.3 probe) */
392          if (errno == ECONNRESET)
393              dsi->flags |= DSI_GOT_ECONNRESET;
394          if (len || stored || dsi->read_count) {
395              if (! (dsi->flags & DSI_DISCONNECTED)) {
396                  LOG(log_error, logtype_dsi, "dsi_stream_read: len:%d, %s",
397                      len, (len < 0) ? strerror(errno) : "unexpected EOF");
398              }
399              return 0;
400          }
401          break;
402      }
403  }
404
405  dsi->read_count += stored;
406
407  LOG(log_maxdebug, logtype_dsi, "dsi_stream_read(%u bytes): got: %u", length, stored);
408  return stored;
409}
410
411/* ---------------------------------------
412 * write data. 0 on failure. this assumes that dsi_len will never
413 * cause an overflow in the data buffer.
414 */
415int dsi_stream_send(DSI *dsi, void *buf, size_t length)
416{
417  char block[DSI_BLOCKSIZ];
418  struct iovec iov[2];
419  size_t towrite;
420  ssize_t len;
421
422  LOG(log_maxdebug, logtype_dsi, "dsi_stream_send: %u bytes",
423      length ? length : sizeof(block));
424
425  if (dsi->flags & DSI_DISCONNECTED)
426      return 0;
427
428  block[0] = dsi->header.dsi_flags;
429  block[1] = dsi->header.dsi_command;
430  memcpy(block + 2, &dsi->header.dsi_requestID,
431	 sizeof(dsi->header.dsi_requestID));
432  memcpy(block + 4, &dsi->header.dsi_code, sizeof(dsi->header.dsi_code));
433  memcpy(block + 8, &dsi->header.dsi_len, sizeof(dsi->header.dsi_len));
434  memcpy(block + 12, &dsi->header.dsi_reserved,
435	 sizeof(dsi->header.dsi_reserved));
436
437  if (!length) { /* just write the header */
438    length = (dsi_stream_write(dsi, block, sizeof(block), 0) == sizeof(block));
439    return length; /* really 0 on failure, 1 on success */
440  }
441
442  /* block signals */
443  block_sig(dsi);
444  iov[0].iov_base = block;
445  iov[0].iov_len = sizeof(block);
446  iov[1].iov_base = buf;
447  iov[1].iov_len = length;
448
449  towrite = sizeof(block) + length;
450  dsi->write_count += towrite;
451  while (towrite > 0) {
452      if (((len = writev(dsi->socket, iov, 2)) == -1 && errno == EINTR) || (len == 0))
453          continue;
454
455      if ((size_t)len == towrite) /* wrote everything out */
456          break;
457      else if (len < 0) { /* error */
458          if (errno == EAGAIN || errno == EWOULDBLOCK) {
459              if (!dsi_peek(dsi)) {
460                  continue;
461              }
462          }
463          LOG(log_error, logtype_dsi, "dsi_stream_send: %s", strerror(errno));
464          unblock_sig(dsi);
465          return 0;
466      }
467
468      towrite -= len;
469      if (towrite > length) { /* skip part of header */
470          iov[0].iov_base = (char *) iov[0].iov_base + len;
471          iov[0].iov_len -= len;
472      } else { /* skip to data */
473          if (iov[0].iov_len) {
474              len -= iov[0].iov_len;
475              iov[0].iov_len = 0;
476          }
477          iov[1].iov_base = (char *) iov[1].iov_base + len;
478          iov[1].iov_len -= len;
479      }
480  }
481
482  unblock_sig(dsi);
483  return 1;
484}
485
486
487/* ---------------------------------------
488 * read data. function on success. 0 on failure. data length gets
489 * stored in length variable. this should really use size_t's, but
490 * that would require changes elsewhere. */
491int dsi_stream_receive(DSI *dsi, void *buf, const size_t ilength,
492		       size_t *rlength)
493{
494  char block[DSI_BLOCKSIZ];
495
496  LOG(log_maxdebug, logtype_dsi, "dsi_stream_receive: %u bytes", ilength);
497
498  if (dsi->flags & DSI_DISCONNECTED)
499      return 0;
500
501  /* read in the header */
502  if (dsi_buffered_stream_read(dsi, (u_int8_t *)block, sizeof(block)) != sizeof(block))
503    return 0;
504
505  dsi->header.dsi_flags = block[0];
506  dsi->header.dsi_command = block[1];
507  /* FIXME, not the right place,
508     but we get a server disconnect without reason in the log
509  */
510  if (!block[1]) {
511      LOG(log_error, logtype_dsi, "dsi_stream_receive: invalid packet, fatal");
512      return 0;
513  }
514
515  memcpy(&dsi->header.dsi_requestID, block + 2,
516	 sizeof(dsi->header.dsi_requestID));
517  memcpy(&dsi->header.dsi_code, block + 4, sizeof(dsi->header.dsi_code));
518  memcpy(&dsi->header.dsi_len, block + 8, sizeof(dsi->header.dsi_len));
519  memcpy(&dsi->header.dsi_reserved, block + 12,
520	 sizeof(dsi->header.dsi_reserved));
521  dsi->clientID = ntohs(dsi->header.dsi_requestID);
522
523  /* make sure we don't over-write our buffers. */
524  *rlength = min(ntohl(dsi->header.dsi_len), ilength);
525  if (dsi_stream_read(dsi, buf, *rlength) != *rlength)
526    return 0;
527
528  return block[1];
529}
530