• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-WNDR4500v2-V1.0.0.60_1.0.38/ap/gpl/timemachine/netatalk-2.2.5/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        if (dsi->socket == -1)
66            /* eg dsi_disconnect() might have disconnected us */
67            return -1;
68        FD_ZERO(&readfds);
69        FD_ZERO(&writefds);
70
71        if (dsi->eof < dsi->end) {
72            /* space in read buffer */
73            FD_SET( dsi->socket, &readfds);
74        } else {
75            if (!warned) {
76                warned = 1;
77                LOG(log_note, logtype_dsi, "dsi_peek: readahead buffer is full, possibly increase -dsireadbuf option");
78                LOG(log_note, logtype_dsi, "dsi_peek: dsireadbuf: %d, DSI quantum: %d, effective buffer size: %d",
79                    dsi->dsireadbuf,
80                    dsi->server_quantum ? dsi->server_quantum : DSI_SERVQUANT_DEF,
81                    dsi->end - dsi->buffer);
82            }
83        }
84
85        FD_SET( dsi->socket, &writefds);
86
87        /* No timeout: if there's nothing to read nor nothing to write,
88         * we've got nothing to do at all */
89        if ((ret = select( maxfd, &readfds, &writefds, NULL, NULL)) <= 0) {
90            if (ret == -1 && errno == EINTR)
91                /* we might have been interrupted by out timer, so restart select */
92                continue;
93            /* give up */
94            LOG(log_error, logtype_dsi, "dsi_peek: unexpected select return: %d %s",
95                ret, ret < 0 ? strerror(errno) : "");
96            return -1;
97        }
98
99        if (FD_ISSET(dsi->socket, &writefds)) {
100            /* we can write again */
101            LOG(log_debug, logtype_dsi, "dsi_peek: can write again");
102            break;
103        }
104
105        /* Check if there's sth to read, hopefully reading that will unblock the client */
106        if (FD_ISSET(dsi->socket, &readfds)) {
107            len = dsi->end - dsi->eof; /* it's ensured above that there's space */
108
109            if ((len = read(dsi->socket, dsi->eof, len)) <= 0) {
110                if (len == 0) {
111                    LOG(log_error, logtype_dsi, "dsi_peek: EOF");
112                    return -1;
113                }
114                LOG(log_error, logtype_dsi, "dsi_peek: read: %s", strerror(errno));
115                if (errno == EAGAIN)
116                    continue;
117                return -1;
118            }
119            LOG(log_debug, logtype_dsi, "dsi_peek: read %d bytes", len);
120
121            dsi->eof += len;
122        }
123    }
124
125    return 0;
126}
127
128/*
129 * Return all bytes up to count from dsi->buffer if there are any buffered there
130 */
131static size_t from_buf(DSI *dsi, u_int8_t *buf, size_t count)
132{
133    size_t nbe = 0;
134
135    if (dsi->buffer == NULL)
136        /* afpd master has no DSI buffering */
137        return 0;
138
139    LOG(log_maxdebug, logtype_dsi, "from_buf: %u bytes", count);
140
141    nbe = dsi->eof - dsi->start;
142
143    if (nbe > 0) {
144        nbe = min((size_t)nbe, count);
145        memcpy(buf, dsi->start, nbe);
146        dsi->start += nbe;
147
148        if (dsi->eof == dsi->start)
149            dsi->start = dsi->eof = dsi->buffer;
150    }
151
152    LOG(log_debug, logtype_dsi, "from_buf(read: %u, unread:%u , space left: %u): returning %u",
153        dsi->start - dsi->buffer, dsi->eof - dsi->start, dsi->end - dsi->eof, nbe);
154
155    return nbe;
156}
157
158/*
159 * Get bytes from buffer dsi->buffer or read from socket
160 *
161 * 1. Check if there are bytes in the the dsi->buffer buffer.
162 * 2. Return bytes from (1) if yes.
163 *    Note: this may return fewer bytes then requested in count !!
164 * 3. If the buffer was empty, read from the socket.
165 */
166static ssize_t buf_read(DSI *dsi, u_int8_t *buf, size_t count)
167{
168    ssize_t len;
169
170    LOG(log_maxdebug, logtype_dsi, "buf_read(%u bytes)", count);
171
172    if (!count)
173        return 0;
174
175    len = from_buf(dsi, buf, count); /* 1. */
176    if (len)
177        return len;             /* 2. */
178
179    len = readt(dsi->socket, buf, count, 0, 1); /* 3. */
180
181    LOG(log_maxdebug, logtype_dsi, "buf_read(%u bytes): got: %d", count, len);
182
183    return len;
184}
185
186/*
187 * Get "length" bytes from buffer and/or socket. In order to avoid frequent small reads
188 * this tries to read larger chunks (8192 bytes) into a buffer.
189 */
190static size_t dsi_buffered_stream_read(DSI *dsi, u_int8_t *data, const size_t length)
191{
192  size_t len;
193  size_t buflen;
194
195  LOG(log_maxdebug, logtype_dsi, "dsi_buffered_stream_read: %u bytes", length);
196
197  len = from_buf(dsi, data, length); /* read from buffer dsi->buffer */
198  dsi->read_count += len;
199  if (len == length) {          /* got enough bytes from there ? */
200      return len;               /* yes */
201  }
202
203  /* fill the buffer with 8192 bytes or until buffer is full */
204  buflen = min(8192, dsi->end - dsi->eof);
205  if (buflen > 0) {
206      ssize_t ret;
207      ret = read(dsi->socket, dsi->eof, buflen);
208      if (ret > 0)
209          dsi->eof += ret;
210  }
211
212  /* now get the remaining data */
213  if ((buflen = dsi_stream_read(dsi, data + len, length - len)) != length - len)
214      return 0;
215  len += buflen;
216
217  return len;
218}
219
220/* ---------------------------------------
221*/
222static void block_sig(DSI *dsi)
223{
224  dsi->in_write++;
225}
226
227/* ---------------------------------------
228*/
229static void unblock_sig(DSI *dsi)
230{
231  dsi->in_write--;
232}
233
234/*********************************************************************************
235 * Public functions
236 *********************************************************************************/
237
238/*!
239 * Communication error with the client, enter disconnected state
240 *
241 * 1. close the socket
242 * 2. set the DSI_DISCONNECTED flag, remove possible sleep flags
243 *
244 * @returns  0 if successfully entered disconnected state
245 *          -1 if ppid is 1 which means afpd master died
246 *             or euid == 0 ie where still running as root (unauthenticated session)
247 */
248int dsi_disconnect(DSI *dsi)
249{
250    LOG(log_note, logtype_dsi, "dsi_disconnect: entering disconnected state");
251    dsi->proto_close(dsi);          /* 1 */
252    dsi->flags &= ~(DSI_SLEEPING | DSI_EXTSLEEP); /* 2 */
253    dsi->flags |= DSI_DISCONNECTED;
254    if (geteuid() == 0)
255        return -1;
256    return 0;
257}
258
259/* ------------------------------
260 * write raw data. return actual bytes read. checks against EINTR
261 * aren't necessary if all of the signals have SA_RESTART
262 * specified. */
263ssize_t dsi_stream_write(DSI *dsi, void *data, const size_t length, int mode)
264{
265  size_t written;
266  ssize_t len;
267  unsigned int flags = 0;
268
269  dsi->in_write++;
270  written = 0;
271
272  LOG(log_maxdebug, logtype_dsi, "dsi_stream_write(send: %zd bytes): START", length);
273
274  if (dsi->flags & DSI_DISCONNECTED)
275      return -1;
276
277  while (written < length) {
278      len = send(dsi->socket, (u_int8_t *) data + written, length - written, flags);
279      if (len >= 0) {
280          written += len;
281          continue;
282      }
283
284      if (errno == EINTR)
285          continue;
286
287      if (errno == EAGAIN || errno == EWOULDBLOCK) {
288          LOG(log_debug, logtype_dsi, "dsi_stream_write: send: %s", strerror(errno));
289
290          if (mode == DSI_NOWAIT && written == 0) {
291              /* DSI_NOWAIT is used by attention give up in this case. */
292              written = -1;
293              goto exit;
294          }
295
296          /* Try to read sth. in order to break up possible deadlock */
297          if (dsi_peek(dsi) != 0) {
298              written = -1;
299              goto exit;
300          }
301          /* Now try writing again */
302          continue;
303      }
304
305      LOG(log_error, logtype_dsi, "dsi_stream_write: %s", strerror(errno));
306      written = -1;
307      goto exit;
308  }
309
310  dsi->write_count += written;
311  LOG(log_maxdebug, logtype_dsi, "dsi_stream_write(send: %zd bytes): END", length);
312
313exit:
314  dsi->in_write--;
315  return written;
316}
317
318
319/* ---------------------------------
320*/
321#ifdef WITH_SENDFILE
322ssize_t dsi_stream_read_file(DSI *dsi, int fromfd, off_t offset, const size_t length)
323{
324  int ret = 0;
325  size_t written;
326  ssize_t len;
327  off_t pos = offset;
328
329  LOG(log_maxdebug, logtype_dsi, "dsi_stream_read_file(send %zd bytes): START", length);
330
331  if (dsi->flags & DSI_DISCONNECTED)
332      return -1;
333
334  dsi->in_write++;
335  written = 0;
336
337  while (written < length) {
338    len = sys_sendfile(dsi->socket, fromfd, &pos, length - written);
339
340    if (len < 0) {
341      if (errno == EINVAL || errno == ENOSYS) {
342          ret = -1;
343          goto exit;
344      }
345      if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
346          /*
347           * May return EINTR too, see:
348           * http://wesunsolve.net/bugid/id/6408517
349           * https://issues.apache.org/bugzilla/show_bug.cgi?id=44550
350           */
351#if defined(SOLARIS) || defined(FREEBSD)
352          if (pos > offset) {
353              /* we actually have sent sth., adjust counters and keep trying */
354              len = pos - offset;
355              written += len;
356              offset = pos;
357          }
358#endif
359          if (dsi_peek(dsi)) {
360              /* can't go back to blocking mode, exit, the next read
361                 will return with an error and afpd will die.
362              */
363              break;
364          }
365          continue;
366      }
367      LOG(log_error, logtype_dsi, "dsi_stream_read_file: %s", strerror(errno));
368      break;
369    }
370    else if (!len) {
371        /* afpd is going to exit */
372          ret = -1;
373          goto exit;
374    }
375    else
376        written += len;
377  }
378
379  dsi->write_count += written;
380
381exit:
382  dsi->in_write--;
383  LOG(log_maxdebug, logtype_dsi, "dsi_stream_read_file: sent: %zd", written);
384  if (ret != 0)
385      return -1;
386  return written;
387}
388#endif
389
390
391/*
392 * Essentially a loop around buf_read() to ensure "length" bytes are read
393 * from dsi->buffer and/or the socket.
394 *
395 * @returns length on success, some value smaller then length indicates an error
396 */
397size_t dsi_stream_read(DSI *dsi, void *data, const size_t length)
398{
399  size_t stored;
400  ssize_t len;
401
402  if (dsi->flags & DSI_DISCONNECTED)
403      return 0;
404
405  LOG(log_maxdebug, logtype_dsi, "dsi_stream_read(%u bytes)", length);
406
407  stored = 0;
408  while (stored < length) {
409      len = buf_read(dsi, (u_int8_t *) data + stored, length - stored);
410      if (len == -1 && (errno == EINTR || errno == EAGAIN)) {
411          LOG(log_maxdebug, logtype_dsi, "dsi_stream_read: select read loop");
412          continue;
413      } else if (len > 0) {
414          stored += len;
415      } else { /* eof or error */
416          /* don't log EOF error if it's just after connect (OSX 10.3 probe) */
417#if 0
418          if (errno == ECONNRESET)
419              dsi->flags |= DSI_GOT_ECONNRESET;
420#endif
421          if (len || stored || dsi->read_count) {
422              if (! (dsi->flags & DSI_DISCONNECTED)) {
423                  LOG(log_error, logtype_dsi, "dsi_stream_read: len:%d, %s",
424                      len, (len < 0) ? strerror(errno) : "unexpected EOF");
425              }
426              return 0;
427          }
428          break;
429      }
430  }
431
432  dsi->read_count += stored;
433
434  LOG(log_maxdebug, logtype_dsi, "dsi_stream_read(%u bytes): got: %u", length, stored);
435  return stored;
436}
437
438/* ---------------------------------------
439 * write data. 0 on failure. this assumes that dsi_len will never
440 * cause an overflow in the data buffer.
441 */
442int dsi_stream_send(DSI *dsi, void *buf, size_t length)
443{
444  char block[DSI_BLOCKSIZ];
445  struct iovec iov[2];
446  size_t towrite;
447  ssize_t len;
448
449  LOG(log_maxdebug, logtype_dsi, "dsi_stream_send(%u bytes): START", length);
450
451  if (dsi->flags & DSI_DISCONNECTED)
452      return 0;
453
454  block[0] = dsi->header.dsi_flags;
455  block[1] = dsi->header.dsi_command;
456  memcpy(block + 2, &dsi->header.dsi_requestID,
457	 sizeof(dsi->header.dsi_requestID));
458  memcpy(block + 4, &dsi->header.dsi_code, sizeof(dsi->header.dsi_code));
459  memcpy(block + 8, &dsi->header.dsi_len, sizeof(dsi->header.dsi_len));
460  memcpy(block + 12, &dsi->header.dsi_reserved,
461	 sizeof(dsi->header.dsi_reserved));
462
463  if (!length) { /* just write the header */
464      LOG(log_maxdebug, logtype_dsi, "dsi_stream_send(%u bytes): DSI header, no data", sizeof(block));
465    length = (dsi_stream_write(dsi, block, sizeof(block), 0) == sizeof(block));
466    return length; /* really 0 on failure, 1 on success */
467  }
468
469  /* block signals */
470  block_sig(dsi);
471  iov[0].iov_base = block;
472  iov[0].iov_len = sizeof(block);
473  iov[1].iov_base = buf;
474  iov[1].iov_len = length;
475
476  towrite = sizeof(block) + length;
477  dsi->write_count += towrite;
478  while (towrite > 0) {
479      if (((len = writev(dsi->socket, iov, 2)) == -1 && errno == EINTR) || (len == 0))
480          continue;
481
482      if ((size_t)len == towrite) /* wrote everything out */
483          break;
484      else if (len < 0) { /* error */
485          if (errno == EAGAIN || errno == EWOULDBLOCK) {
486              if (!dsi_peek(dsi)) {
487                  continue;
488              }
489          }
490          LOG(log_error, logtype_dsi, "dsi_stream_send: %s", strerror(errno));
491          unblock_sig(dsi);
492          return 0;
493      }
494
495      towrite -= len;
496      if (towrite > length) { /* skip part of header */
497          iov[0].iov_base = (char *) iov[0].iov_base + len;
498          iov[0].iov_len -= len;
499      } else { /* skip to data */
500          if (iov[0].iov_len) {
501              len -= iov[0].iov_len;
502              iov[0].iov_len = 0;
503          }
504          iov[1].iov_base = (char *) iov[1].iov_base + len;
505          iov[1].iov_len -= len;
506      }
507  }
508
509  LOG(log_maxdebug, logtype_dsi, "dsi_stream_send(%u bytes): END", length);
510
511  unblock_sig(dsi);
512  return 1;
513}
514
515
516/*!
517 * Read DSI command and data
518 *
519 * @param  dsi   (rw) DSI handle
520 *
521 * @return    DSI function on success, 0 on failure
522 */
523int dsi_stream_receive(DSI *dsi)
524{
525  char block[DSI_BLOCKSIZ];
526
527  LOG(log_maxdebug, logtype_dsi, "dsi_stream_receive: START");
528
529  if (dsi->flags & DSI_DISCONNECTED)
530      return 0;
531
532  /* read in the header */
533  if (dsi_buffered_stream_read(dsi, (u_int8_t *)block, sizeof(block)) != sizeof(block))
534    return 0;
535
536  dsi->header.dsi_flags = block[0];
537  dsi->header.dsi_command = block[1];
538
539  if (dsi->header.dsi_command == 0)
540      return 0;
541
542  memcpy(&dsi->header.dsi_requestID, block + 2, sizeof(dsi->header.dsi_requestID));
543  memcpy(&dsi->header.dsi_code, block + 4, sizeof(dsi->header.dsi_code));
544  memcpy(&dsi->header.dsi_len, block + 8, sizeof(dsi->header.dsi_len));
545  memcpy(&dsi->header.dsi_reserved, block + 12, sizeof(dsi->header.dsi_reserved));
546  dsi->clientID = ntohs(dsi->header.dsi_requestID);
547
548  /* make sure we don't over-write our buffers. */
549  dsi->cmdlen = min(ntohl(dsi->header.dsi_len), DSI_CMDSIZ);
550  if (dsi_stream_read(dsi, dsi->commands, dsi->cmdlen) != dsi->cmdlen)
551    return 0;
552
553  LOG(log_debug, logtype_dsi, "dsi_stream_receive: DSI cmdlen: %zd", dsi->cmdlen);
554
555  return block[1];
556}
557