• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt/router/netatalk-3.0.5/libatalk/dsi/
1/*
2 * Copyright (c) 1998 Adrian Sun (asun@zoology.washington.edu)
3 * Copyright (c) 2010,2011,2012 Frank Lahm <franklahm@googlemail.com>
4 * All rights reserved. See COPYRIGHT.
5 *
6 * this file provides the following functions:
7 * dsi_stream_write:    just write a bunch of bytes.
8 * dsi_stream_read:     just read a bunch of bytes.
9 * dsi_stream_send:     send a DSI header + data.
10 * dsi_stream_receive:  read a DSI header + data.
11 */
12
13#ifdef HAVE_CONFIG_H
14#include "config.h"
15#endif /* HAVE_CONFIG_H */
16
17#include <stdio.h>
18#include <stdlib.h>
19#include <unistd.h>
20#include <string.h>
21#include <errno.h>
22#include <sys/types.h>
23#include <sys/socket.h>
24#include <sys/uio.h>
25
26#ifdef HAVE_SENDFILEV
27#include <sys/sendfile.h>
28#endif
29
30#include <atalk/logger.h>
31#include <atalk/dsi.h>
32#include <atalk/util.h>
33
34#ifndef MSG_MORE
35#define MSG_MORE 0x8000
36#endif
37
38#ifndef MSG_DONTWAIT
39#define MSG_DONTWAIT 0x40
40#endif
41
42/* Pack a DSI header in wire format */
43static void dsi_header_pack_reply(const DSI *dsi, char *buf)
44{
45    buf[0] = dsi->header.dsi_flags;
46    buf[1] = dsi->header.dsi_command;
47    memcpy(buf + 2, &dsi->header.dsi_requestID, sizeof(dsi->header.dsi_requestID));
48    memcpy(buf + 4, &dsi->header.dsi_data.dsi_code, sizeof(dsi->header.dsi_data.dsi_code));
49    memcpy(buf + 8, &dsi->header.dsi_len, sizeof(dsi->header.dsi_len));
50    memcpy(buf + 12, &dsi->header.dsi_reserved, sizeof(dsi->header.dsi_reserved));
51}
52
53/*
54 * afpd is sleeping too much while trying to send something.
55 * May be there's no reader or the reader is also sleeping in write,
56 * look if there's some data for us to read, hopefully it will wake up
57 * the reader so we can write again.
58 *
59 * @returns 0 when is possible to send again, -1 on error
60 */
61static int dsi_peek(DSI *dsi)
62{
63    static int warned = 0;
64    fd_set readfds, writefds;
65    int    len;
66    int    maxfd;
67    int    ret;
68
69    LOG(log_debug, logtype_dsi, "dsi_peek");
70
71    maxfd = dsi->socket + 1;
72
73    while (1) {
74        if (dsi->socket == -1)
75            /* eg dsi_disconnect() might have disconnected us */
76            return -1;
77        FD_ZERO(&readfds);
78        FD_ZERO(&writefds);
79
80        if (dsi->eof < dsi->end) {
81            /* space in read buffer */
82            FD_SET( dsi->socket, &readfds);
83        } else {
84            if (!warned) {
85                warned = 1;
86                LOG(log_note, logtype_dsi, "dsi_peek: readahead buffer is full, possibly increase -dsireadbuf option");
87                LOG(log_note, logtype_dsi, "dsi_peek: dsireadbuf: %d, DSI quantum: %d, effective buffer size: %d",
88                    dsi->dsireadbuf,
89                    dsi->server_quantum ? dsi->server_quantum : DSI_SERVQUANT_DEF,
90                    dsi->end - dsi->buffer);
91            }
92        }
93
94        FD_SET( dsi->socket, &writefds);
95
96        /* No timeout: if there's nothing to read nor nothing to write,
97         * we've got nothing to do at all */
98        if ((ret = select( maxfd, &readfds, &writefds, NULL, NULL)) <= 0) {
99            if (ret == -1 && errno == EINTR)
100                /* we might have been interrupted by out timer, so restart select */
101                continue;
102            /* give up */
103            LOG(log_error, logtype_dsi, "dsi_peek: unexpected select return: %d %s",
104                ret, ret < 0 ? strerror(errno) : "");
105            return -1;
106        }
107
108        if (FD_ISSET(dsi->socket, &writefds)) {
109            /* we can write again */
110            LOG(log_debug, logtype_dsi, "dsi_peek: can write again");
111            break;
112        }
113
114        /* Check if there's sth to read, hopefully reading that will unblock the client */
115        if (FD_ISSET(dsi->socket, &readfds)) {
116            len = dsi->end - dsi->eof; /* it's ensured above that there's space */
117
118            if ((len = recv(dsi->socket, dsi->eof, len, 0)) <= 0) {
119                if (len == 0) {
120                    LOG(log_error, logtype_dsi, "dsi_peek: EOF");
121                    return -1;
122                }
123                LOG(log_error, logtype_dsi, "dsi_peek: read: %s", strerror(errno));
124                if (errno == EAGAIN)
125                    continue;
126                return -1;
127            }
128            LOG(log_debug, logtype_dsi, "dsi_peek: read %d bytes", len);
129
130            dsi->eof += len;
131        }
132    }
133
134    return 0;
135}
136
137/*
138 * Return all bytes up to count from dsi->buffer if there are any buffered there
139 */
140static size_t from_buf(DSI *dsi, uint8_t *buf, size_t count)
141{
142    size_t nbe = 0;
143
144    if (dsi->buffer == NULL)
145        /* afpd master has no DSI buffering */
146        return 0;
147
148    LOG(log_maxdebug, logtype_dsi, "from_buf: %u bytes", count);
149
150    nbe = dsi->eof - dsi->start;
151
152    if (nbe > 0) {
153        nbe = MIN((size_t)nbe, count);
154        memcpy(buf, dsi->start, nbe);
155        dsi->start += nbe;
156
157        if (dsi->eof == dsi->start)
158            dsi->start = dsi->eof = dsi->buffer;
159    }
160
161    LOG(log_debug, logtype_dsi, "from_buf(read: %u, unread:%u , space left: %u): returning %u",
162        dsi->start - dsi->buffer, dsi->eof - dsi->start, dsi->end - dsi->eof, nbe);
163
164    return nbe;
165}
166
167/*
168 * Get bytes from buffer dsi->buffer or read from socket
169 *
170 * 1. Check if there are bytes in the the dsi->buffer buffer.
171 * 2. Return bytes from (1) if yes.
172 *    Note: this may return fewer bytes then requested in count !!
173 * 3. If the buffer was empty, read from the socket.
174 */
175static ssize_t buf_read(DSI *dsi, uint8_t *buf, size_t count)
176{
177    ssize_t len;
178
179    LOG(log_maxdebug, logtype_dsi, "buf_read(%u bytes)", count);
180
181    if (!count)
182        return 0;
183
184    len = from_buf(dsi, buf, count); /* 1. */
185    if (len)
186        return len;             /* 2. */
187
188    len = readt(dsi->socket, buf, count, 0, 0); /* 3. */
189
190    LOG(log_maxdebug, logtype_dsi, "buf_read(%u bytes): got: %d", count, len);
191
192    return len;
193}
194
195/*
196 * Get "length" bytes from buffer and/or socket. In order to avoid frequent small reads
197 * this tries to read larger chunks (8192 bytes) into a buffer.
198 */
199static size_t dsi_buffered_stream_read(DSI *dsi, uint8_t *data, const size_t length)
200{
201  size_t len;
202  size_t buflen;
203
204  LOG(log_maxdebug, logtype_dsi, "dsi_buffered_stream_read: %u bytes", length);
205
206  len = from_buf(dsi, data, length); /* read from buffer dsi->buffer */
207  dsi->read_count += len;
208  if (len == length) {          /* got enough bytes from there ? */
209      return len;               /* yes */
210  }
211
212  /* fill the buffer with 8192 bytes or until buffer is full */
213  buflen = MIN(8192, dsi->end - dsi->eof);
214  if (buflen > 0) {
215      ssize_t ret;
216      ret = recv(dsi->socket, dsi->eof, buflen, 0);
217      if (ret > 0)
218          dsi->eof += ret;
219  }
220
221  /* now get the remaining data */
222  if ((buflen = dsi_stream_read(dsi, data + len, length - len)) != length - len)
223      return 0;
224  len += buflen;
225
226  return len;
227}
228
229/* ---------------------------------------
230*/
231static void block_sig(DSI *dsi)
232{
233  dsi->in_write++;
234}
235
236/* ---------------------------------------
237*/
238static void unblock_sig(DSI *dsi)
239{
240  dsi->in_write--;
241}
242
243/*********************************************************************************
244 * Public functions
245 *********************************************************************************/
246
247/*!
248 * Communication error with the client, enter disconnected state
249 *
250 * 1. close the socket
251 * 2. set the DSI_DISCONNECTED flag, remove possible sleep flags
252 *
253 * @returns  0 if successfully entered disconnected state
254 *          -1 if ppid is 1 which means afpd master died
255 *             or euid == 0 ie where still running as root (unauthenticated session)
256 */
257int dsi_disconnect(DSI *dsi)
258{
259    LOG(log_note, logtype_dsi, "dsi_disconnect: entering disconnected state");
260    dsi->proto_close(dsi);          /* 1 */
261    dsi->flags &= ~(DSI_SLEEPING | DSI_EXTSLEEP); /* 2 */
262    dsi->flags |= DSI_DISCONNECTED;
263    if (geteuid() == 0)
264        return -1;
265    return 0;
266}
267
268/* ------------------------------
269 * write raw data. return actual bytes read. checks against EINTR
270 * aren't necessary if all of the signals have SA_RESTART
271 * specified. */
272ssize_t dsi_stream_write(DSI *dsi, void *data, const size_t length, int mode)
273{
274  size_t written;
275  ssize_t len;
276  unsigned int flags;
277
278  dsi->in_write++;
279  written = 0;
280
281  LOG(log_maxdebug, logtype_dsi, "dsi_stream_write(send: %zd bytes): START", length);
282
283  if (dsi->flags & DSI_DISCONNECTED)
284      return -1;
285
286  if (mode & DSI_MSG_MORE)
287      flags = MSG_MORE;
288  else
289      flags = 0;
290
291  while (written < length) {
292      len = send(dsi->socket, (uint8_t *) data + written, length - written, flags);
293      if (len >= 0) {
294          written += len;
295          continue;
296      }
297
298      if (errno == EINTR)
299          continue;
300
301      if (errno == EAGAIN || errno == EWOULDBLOCK) {
302          LOG(log_debug, logtype_dsi, "dsi_stream_write: send: %s", strerror(errno));
303
304          if (mode == DSI_NOWAIT && written == 0) {
305              /* DSI_NOWAIT is used by attention give up in this case. */
306              written = -1;
307              goto exit;
308          }
309
310          /* Try to read sth. in order to break up possible deadlock */
311          if (dsi_peek(dsi) != 0) {
312              written = -1;
313              goto exit;
314          }
315          /* Now try writing again */
316          continue;
317      }
318
319      LOG(log_error, logtype_dsi, "dsi_stream_write: %s", strerror(errno));
320      written = -1;
321      goto exit;
322  }
323
324  dsi->write_count += written;
325  LOG(log_maxdebug, logtype_dsi, "dsi_stream_write(send: %zd bytes): END", length);
326
327exit:
328  dsi->in_write--;
329  return written;
330}
331
332/* ---------------------------------
333*/
334#ifdef WITH_SENDFILE
335ssize_t dsi_stream_read_file(DSI *dsi, const int fromfd, off_t offset, const size_t length, const int err)
336{
337    int ret = 0;
338    size_t written = 0;
339    size_t total = length;
340    ssize_t len;
341    off_t pos = offset;
342    char block[DSI_BLOCKSIZ];
343#ifdef HAVE_SENDFILEV
344    int sfvcnt;
345    struct sendfilevec vec[2];
346    ssize_t nwritten;
347#elif defined(FREEBSD)
348    ssize_t nwritten;
349    void *hdrp;
350    struct sf_hdtr hdr;
351    struct iovec iovec;
352    hdr.headers = &iovec;
353    hdr.hdr_cnt = 1;
354    hdr.trailers = NULL;
355    hdr.trl_cnt = 0;
356    hdrp = &hdr;
357#endif
358
359    LOG(log_maxdebug, logtype_dsi, "dsi_stream_read_file(off: %jd, len: %zu)", (intmax_t)offset, length);
360
361    if (dsi->flags & DSI_DISCONNECTED)
362        return -1;
363
364    dsi->in_write++;
365
366    dsi->flags |= DSI_NOREPLY;
367    dsi->header.dsi_flags = DSIFL_REPLY;
368    dsi->header.dsi_len = htonl(length);
369    dsi->header.dsi_data.dsi_code = htonl(err);
370    dsi_header_pack_reply(dsi, block);
371
372#ifdef HAVE_SENDFILEV
373    total += DSI_BLOCKSIZ;
374    sfvcnt = 2;
375    vec[0].sfv_fd = SFV_FD_SELF;
376    vec[0].sfv_flag = 0;
377    /* Cast to unsigned long to prevent sign extension of the
378     * pointer value for the LFS case; see Apache PR 39463. */
379    vec[0].sfv_off = (unsigned long)block;
380    vec[0].sfv_len = DSI_BLOCKSIZ;
381    vec[1].sfv_fd = fromfd;
382    vec[1].sfv_flag = 0;
383    vec[1].sfv_off = offset;
384    vec[1].sfv_len = length;
385#elif defined(FREEBSD)
386    iovec.iov_base = block;
387    iovec.iov_len = DSI_BLOCKSIZ;
388#else
389    dsi_stream_write(dsi, block, sizeof(block), DSI_MSG_MORE);
390#endif
391
392    while (written < total) {
393#ifdef HAVE_SENDFILEV
394        nwritten = 0;
395        len = sendfilev(dsi->socket, vec, sfvcnt, &nwritten);
396#elif defined(FREEBSD)
397        len = sendfile(fromfd, dsi->socket, pos, total - written, hdrp, &nwritten, 0);
398        if (len == 0)
399            len = nwritten;
400#else
401        len = sys_sendfile(dsi->socket, fromfd, &pos, total - written);
402#endif
403        if (len < 0) {
404            switch (errno) {
405            case EINTR:
406            case EAGAIN:
407                len = 0;
408#if defined(HAVE_SENDFILEV) || defined(FREEBSD)
409                len = (size_t)nwritten;
410#elif defined(SOLARIS)
411                if (pos > offset) {
412                    /* we actually have sent sth., adjust counters and keep trying */
413                    len = pos - offset;
414                    offset = pos;
415                }
416#endif /* HAVE_SENDFILEV */
417
418                if (dsi_peek(dsi) != 0) {
419                    ret = -1;
420                    goto exit;
421                }
422                break;
423            default:
424                LOG(log_error, logtype_dsi, "dsi_stream_read_file: %s", strerror(errno));
425                ret = -1;
426                goto exit;
427            }
428        } else if (len == 0) {
429            /* afpd is going to exit */
430            ret = -1;
431            goto exit;
432        }
433#ifdef HAVE_SENDFILEV
434        if (sfvcnt == 2 && len >= vec[0].sfv_len) {
435            vec[1].sfv_off += len - vec[0].sfv_len;
436            vec[1].sfv_len -= len - vec[0].sfv_len;
437
438            vec[0] = vec[1];
439            sfvcnt = 1;
440        } else {
441            vec[0].sfv_off += len;
442            vec[0].sfv_len -= len;
443        }
444#elif defined(FREEBSD)
445        if (hdrp) {
446            if (len >= iovec.iov_len) {
447                hdrp = NULL;
448                len -= iovec.iov_len;   /* len now contains how much sendfile() actually sent from the file */
449            } else {
450                iovec.iov_len -= len;
451                iovec.iov_base += len;
452                len = 0;
453            }
454        }
455        pos += len;
456#endif  /* HAVE_SENDFILEV */
457        LOG(log_maxdebug, logtype_dsi, "dsi_stream_read_file: wrote: %zd", len);
458        written += len;
459    }
460#ifdef HAVE_SENDFILEV
461    written -= DSI_BLOCKSIZ;
462#endif
463    dsi->write_count += written;
464
465exit:
466    dsi->in_write--;
467    LOG(log_maxdebug, logtype_dsi, "dsi_stream_read_file: written: %zd", written);
468    if (ret != 0)
469        return -1;
470    return written;
471}
472#endif
473
474
475/*
476 * Essentially a loop around buf_read() to ensure "length" bytes are read
477 * from dsi->buffer and/or the socket.
478 *
479 * @returns length on success, some value smaller then length indicates an error
480 */
481size_t dsi_stream_read(DSI *dsi, void *data, const size_t length)
482{
483  size_t stored;
484  ssize_t len;
485
486  if (dsi->flags & DSI_DISCONNECTED)
487      return 0;
488
489  LOG(log_maxdebug, logtype_dsi, "dsi_stream_read(%u bytes)", length);
490
491  stored = 0;
492  while (stored < length) {
493      len = buf_read(dsi, (uint8_t *) data + stored, length - stored);
494      if (len == -1 && (errno == EINTR || errno == EAGAIN)) {
495          LOG(log_maxdebug, logtype_dsi, "dsi_stream_read: select read loop");
496          continue;
497      } else if (len > 0) {
498          stored += len;
499      } else { /* eof or error */
500          /* don't log EOF error if it's just after connect (OSX 10.3 probe) */
501          if (len || stored || dsi->read_count) {
502              if (! (dsi->flags & DSI_DISCONNECTED)) {
503                  LOG(log_error, logtype_dsi, "dsi_stream_read: len:%d, %s",
504                      len, (len < 0) ? strerror(errno) : "unexpected EOF");
505              }
506              return 0;
507          }
508          break;
509      }
510  }
511
512  dsi->read_count += stored;
513
514  LOG(log_maxdebug, logtype_dsi, "dsi_stream_read(%u bytes): got: %u", length, stored);
515  return stored;
516}
517
518/* ---------------------------------------
519 * write data. 0 on failure. this assumes that dsi_len will never
520 * cause an overflow in the data buffer.
521 */
522int dsi_stream_send(DSI *dsi, void *buf, size_t length)
523{
524  char block[DSI_BLOCKSIZ];
525  struct iovec iov[2];
526  int iovecs = 2;
527  size_t towrite;
528  ssize_t len;
529
530  LOG(log_maxdebug, logtype_dsi, "dsi_stream_send(%u bytes): START", length);
531
532  if (dsi->flags & DSI_DISCONNECTED)
533      return 0;
534
535  dsi_header_pack_reply(dsi, block);
536
537  if (!length) { /* just write the header */
538      LOG(log_maxdebug, logtype_dsi, "dsi_stream_send(%u bytes): DSI header, no data", sizeof(block));
539    length = (dsi_stream_write(dsi, block, sizeof(block), 0) == sizeof(block));
540    return length; /* really 0 on failure, 1 on success */
541  }
542
543  /* block signals */
544  block_sig(dsi);
545  iov[0].iov_base = block;
546  iov[0].iov_len = sizeof(block);
547  iov[1].iov_base = buf;
548  iov[1].iov_len = length;
549
550  towrite = sizeof(block) + length;
551  dsi->write_count += towrite;
552  while (towrite > 0) {
553      if (((len = writev(dsi->socket, iov, iovecs)) == -1 && errno == EINTR) || (len == 0))
554          continue;
555
556      if ((size_t)len == towrite) /* wrote everything out */
557          break;
558      else if (len < 0) { /* error */
559          if (errno == EAGAIN || errno == EWOULDBLOCK) {
560              if (dsi_peek(dsi) == 0) {
561                  continue;
562              }
563          }
564          LOG(log_error, logtype_dsi, "dsi_stream_send: %s", strerror(errno));
565          unblock_sig(dsi);
566          return 0;
567      }
568
569      towrite -= len;
570      if (towrite > length) { /* skip part of header */
571          iov[0].iov_base = (char *) iov[0].iov_base + len;
572          iov[0].iov_len -= len;
573      } else { /* skip to data */
574          if (iovecs == 2) {
575              iovecs = 1;
576              len -= iov[0].iov_len;
577              iov[0] = iov[1];
578          }
579          iov[0].iov_base = (char *) iov[0].iov_base + len;
580          iov[0].iov_len -= len;
581      }
582  }
583
584  LOG(log_maxdebug, logtype_dsi, "dsi_stream_send(%u bytes): END", length);
585
586  unblock_sig(dsi);
587  return 1;
588}
589
590
591/*!
592 * Read DSI command and data
593 *
594 * @param  dsi   (rw) DSI handle
595 *
596 * @return    DSI function on success, 0 on failure
597 */
598int dsi_stream_receive(DSI *dsi)
599{
600  char block[DSI_BLOCKSIZ];
601
602  LOG(log_maxdebug, logtype_dsi, "dsi_stream_receive: START");
603
604  if (dsi->flags & DSI_DISCONNECTED)
605      return 0;
606
607  /* read in the header */
608  if (dsi_buffered_stream_read(dsi, (uint8_t *)block, sizeof(block)) != sizeof(block))
609    return 0;
610
611  dsi->header.dsi_flags = block[0];
612  dsi->header.dsi_command = block[1];
613
614  if (dsi->header.dsi_command == 0)
615      return 0;
616
617  memcpy(&dsi->header.dsi_requestID, block + 2, sizeof(dsi->header.dsi_requestID));
618  memcpy(&dsi->header.dsi_data.dsi_code, block + 4, sizeof(dsi->header.dsi_data.dsi_code));
619  memcpy(&dsi->header.dsi_len, block + 8, sizeof(dsi->header.dsi_len));
620  memcpy(&dsi->header.dsi_reserved, block + 12, sizeof(dsi->header.dsi_reserved));
621  dsi->clientID = ntohs(dsi->header.dsi_requestID);
622
623  /* make sure we don't over-write our buffers. */
624  dsi->cmdlen = MIN(ntohl(dsi->header.dsi_len), dsi->server_quantum);
625  if (dsi_stream_read(dsi, dsi->commands, dsi->cmdlen) != dsi->cmdlen)
626    return 0;
627
628  LOG(log_debug, logtype_dsi, "dsi_stream_receive: DSI cmdlen: %zd", dsi->cmdlen);
629
630  return block[1];
631}
632