2 * $Id: dsi_stream.c,v 1.20 2009-10-26 12:35:56 franklahm Exp $
4 * Copyright (c) 1998 Adrian Sun (asun@zoology.washington.edu)
5 * All rights reserved. See COPYRIGHT.
7 * this file provides the following functions:
8 * dsi_stream_write: just write a bunch of bytes.
9 * dsi_stream_read: just read a bunch of bytes.
10 * dsi_stream_send: send a DSI header + data.
11 * dsi_stream_receive: read a DSI header + data.
16 #endif /* HAVE_CONFIG_H */
29 #include <sys/types.h>
30 #include <sys/socket.h>
36 #include <atalk/logger.h>
37 #include <atalk/dsi.h>
38 #include <netatalk/endian.h>
39 #include <atalk/util.h>
41 #define min(a,b) ((a) < (b) ? (a) : (b))
44 #define MSG_MORE 0x8000
48 #define MSG_DONTWAIT 0x40
51 /* -------------------------
52 * we don't use a circular buffer.
54 static void dsi_init_buffer(DSI *dsi)
57 /* XXX config options */
58 dsi->maxsize = 6 * dsi->server_quantum;
60 dsi->maxsize = 6 * DSI_SERVQUANT_DEF;
61 dsi->buffer = malloc(dsi->maxsize);
65 dsi->start = dsi->buffer;
66 dsi->eof = dsi->buffer;
67 dsi->end = dsi->buffer + dsi->maxsize;
71 /* ----------------------
72 afpd is sleeping too much while trying to send something.
73 May be there's no reader or the reader is also sleeping in write,
74 look if there's some data for us to read, hopefully it will wake up
75 the reader so we can write again.
77 static int dsi_peek(DSI *dsi)
79 fd_set readfds, writefds;
86 FD_SET( dsi->socket, &readfds);
87 FD_SET( dsi->socket, &writefds);
88 maxfd = dsi->socket +1;
91 FD_SET( dsi->socket, &readfds);
92 FD_SET( dsi->socket, &writefds);
94 /* No timeout: if there's nothing to read nor nothing to write,
95 * we've got nothing to do at all */
96 if ((ret = select( maxfd, &readfds, &writefds, NULL, NULL)) <= 0) {
97 if (ret == -1 && errno == EINTR)
98 /* we might have been interrupted by out timer, so restart select */
101 LOG(log_error, logtype_dsi, "dsi_peek: unexpected select return: %d %s",
102 ret, ret < 0 ? strerror(errno) : "");
103 setnonblock(dsi->socket, 0);
107 /* Check if there's sth to read, hopefully reading that will unblock the client */
108 if (FD_ISSET(dsi->socket, &readfds)) {
109 dsi_init_buffer(dsi);
110 len = dsi->end - dsi->eof;
113 /* ouch, our buffer is full ! fall back to blocking IO
114 * could block and disconnect but it's better than a cpu hog */
115 LOG(log_error, logtype_dsi, "dsi_peek: read buffer is full");
116 setnonblock(dsi->socket, 0);
120 if ((len = read(dsi->socket, dsi->eof, len)) <= 0) {
121 LOG(log_error, logtype_dsi, "dsi_peek: read: %d %s",
122 len, len < 0 ? strerror(errno) : "");
130 if (FD_ISSET(dsi->socket, &writefds))
131 /* we can write again at last */
132 LOG(log_error, logtype_dsi, "dsi_peek: can write again");
139 /* ------------------------------
140 * write raw data. return actual bytes read. checks against EINTR
141 * aren't necessary if all of the signals have SA_RESTART
143 ssize_t dsi_stream_write(DSI *dsi, void *data, const size_t length, int mode)
147 unsigned int flags = 0;
152 LOG(log_maxdebug, logtype_dsi, "dsi_stream_write: sending %u bytes", length);
154 /* non blocking mode */
155 if (setnonblock(dsi->socket, 1) < 0) {
156 LOG(log_error, logtype_dsi, "dsi_stream_write: setnonblock: %s", strerror(errno));
160 while (written < length) {
161 len = send(dsi->socket, (u_int8_t *) data + written, length - written, flags);
170 if (errno == EAGAIN || errno == EWOULDBLOCK) {
171 if (mode == DSI_NOWAIT && written == 0) {
172 /* DSI_NOWAIT is used by attention give up in this case. */
177 /* Try to read sth. in order to break up possible deadlock */
178 if (dsi_peek(dsi) != 0) {
182 /* Now try writing again */
186 LOG(log_error, logtype_dsi, "dsi_stream_write: %s", strerror(errno));
191 dsi->write_count += written;
194 if (setnonblock(dsi->socket, 0) < 0) {
195 LOG(log_error, logtype_dsi, "dsi_stream_write: setnonblock: %s", strerror(errno));
204 /* ---------------------------------
207 ssize_t dsi_stream_read_file(DSI *dsi, int fromfd, off_t offset, const size_t length)
215 /* non blocking mode */
216 if (setnonblock(dsi->socket, 1) < 0) {
217 LOG(log_error, logtype_dsi, "dsi_stream_read_file: setnonblock: %s", strerror(errno));
221 while (written < length) {
222 len = sys_sendfile(dsi->socket, fromfd, &offset, length - written);
227 if (errno == EINVAL || errno == ENOSYS)
230 if (errno == EAGAIN || errno == EWOULDBLOCK) {
232 /* can't go back to blocking mode, exit, the next read
233 will return with an error and afpd will die.
239 LOG(log_error, logtype_dsi, "dsi_stream_write: %s", strerror(errno));
243 /* afpd is going to exit */
245 return -1; /* I think we're at EOF here... */
251 if (setnonblock(dsi->socket, 0) < 0) {
252 LOG(log_error, logtype_dsi, "dsi_stream_read_file: setnonblock: %s", strerror(errno));
256 dsi->write_count += written;
263 * Return all bytes up to count from dsi->buffer if there are any buffered there
265 static size_t from_buf(DSI *dsi, u_int8_t *buf, size_t count)
270 nbe = dsi->eof - dsi->start;
273 nbe = min((size_t)nbe, count);
274 memcpy(buf, dsi->start, nbe);
277 if (dsi->eof == dsi->start)
278 dsi->start = dsi->eof = dsi->buffer;
286 * Get bytes from buffer dsi->buffer or read from socket
288 * 1. Check if there are bytes in the the dsi->buffer buffer.
289 * 2. Return bytes from (1) if yes.
290 * Note: this may return fewer bytes then requested in count !!
291 * 3. If the buffer was empty, read from the socket.
293 static ssize_t buf_read(DSI *dsi, u_int8_t *buf, size_t count)
300 nbe = from_buf(dsi, buf, count); /* 1. */
304 return read(dsi->socket, buf, count); /* 3. */
308 * Essentially a loop around buf_read() to ensure "length" bytes are read
309 * from dsi->buffer and/or the socket.
311 size_t dsi_stream_read(DSI *dsi, void *data, const size_t length)
317 while (stored < length) {
318 len = buf_read(dsi, (u_int8_t *) data + stored, length - stored);
319 if (len == -1 && errno == EINTR) {
321 } else if (len > 0) {
323 } else { /* eof or error */
324 /* don't log EOF error if it's just after connect (OSX 10.3 probe) */
325 if (len || stored || dsi->read_count) {
326 if (! (dsi->flags & DSI_DISCONNECTED))
327 LOG(log_error, logtype_dsi, "dsi_stream_read(fd: %i): len:%d, %s",
328 dsi->socket, len, (len < 0) ? strerror(errno) : "unexpected EOF");
334 dsi->read_count += stored;
339 * Get "length" bytes from buffer and/or socket. In order to avoid frequent small reads
340 * this tries to read larger chunks (8192 bytes) into a buffer.
342 static size_t dsi_buffered_stream_read(DSI *dsi, u_int8_t *data, const size_t length)
347 dsi_init_buffer(dsi);
348 len = from_buf(dsi, data, length); /* read from buffer dsi->buffer */
349 dsi->read_count += len;
350 if (len == length) { /* got enough bytes from there ? */
351 return len; /* yes */
354 /* fill the buffer with 8192 bytes or until buffer is full */
355 buflen = min(8192, dsi->end - dsi->eof);
358 ret = read(dsi->socket, dsi->eof, buflen);
363 /* now get the remaining data */
364 len += dsi_stream_read(dsi, data + len, length - len);
368 /* ---------------------------------------
370 static void block_sig(DSI *dsi)
375 /* ---------------------------------------
377 static void unblock_sig(DSI *dsi)
382 /* ---------------------------------------
383 * write data. 0 on failure. this assumes that dsi_len will never
384 * cause an overflow in the data buffer.
386 int dsi_stream_send(DSI *dsi, void *buf, size_t length)
388 char block[DSI_BLOCKSIZ];
393 #endif /* USE_WRITEV */
395 block[0] = dsi->header.dsi_flags;
396 block[1] = dsi->header.dsi_command;
397 memcpy(block + 2, &dsi->header.dsi_requestID,
398 sizeof(dsi->header.dsi_requestID));
399 memcpy(block + 4, &dsi->header.dsi_code, sizeof(dsi->header.dsi_code));
400 memcpy(block + 8, &dsi->header.dsi_len, sizeof(dsi->header.dsi_len));
401 memcpy(block + 12, &dsi->header.dsi_reserved,
402 sizeof(dsi->header.dsi_reserved));
404 if (!length) { /* just write the header */
405 length = (dsi_stream_write(dsi, block, sizeof(block), 0) == sizeof(block));
406 return length; /* really 0 on failure, 1 on success */
412 iov[0].iov_base = block;
413 iov[0].iov_len = sizeof(block);
414 iov[1].iov_base = buf;
415 iov[1].iov_len = length;
417 towrite = sizeof(block) + length;
418 dsi->write_count += towrite;
419 while (towrite > 0) {
420 if (((len = writev(dsi->socket, iov, 2)) == -1 && errno == EINTR) ||
424 if ((size_t)len == towrite) /* wrote everything out */
426 else if (len < 0) { /* error */
427 if (errno == EAGAIN || errno == EWOULDBLOCK) {
428 if (!dsi_peek(dsi)) {
432 LOG(log_error, logtype_dsi, "dsi_stream_send: %s", strerror(errno));
438 if (towrite > length) { /* skip part of header */
439 iov[0].iov_base = (char *) iov[0].iov_base + len;
440 iov[0].iov_len -= len;
441 } else { /* skip to data */
442 if (iov[0].iov_len) {
443 len -= iov[0].iov_len;
446 iov[1].iov_base = (char *) iov[1].iov_base + len;
447 iov[1].iov_len -= len;
451 #else /* USE_WRITEV */
452 /* write the header then data */
453 if ((dsi_stream_write(dsi, block, sizeof(block), 1) != sizeof(block)) ||
454 (dsi_stream_write(dsi, buf, length, 0) != length)) {
458 #endif /* USE_WRITEV */
465 /* ---------------------------------------
466 * read data. function on success. 0 on failure. data length gets
467 * stored in length variable. this should really use size_t's, but
468 * that would require changes elsewhere. */
469 int dsi_stream_receive(DSI *dsi, void *buf, const size_t ilength,
472 char block[DSI_BLOCKSIZ];
474 /* read in the header */
475 if (dsi_buffered_stream_read(dsi, (u_int8_t *)block, sizeof(block)) != sizeof(block))
478 dsi->header.dsi_flags = block[0];
479 dsi->header.dsi_command = block[1];
480 /* FIXME, not the right place,
481 but we get a server disconnect without reason in the log
484 LOG(log_error, logtype_dsi, "dsi_stream_receive: invalid packet, fatal");
488 memcpy(&dsi->header.dsi_requestID, block + 2,
489 sizeof(dsi->header.dsi_requestID));
490 memcpy(&dsi->header.dsi_code, block + 4, sizeof(dsi->header.dsi_code));
491 memcpy(&dsi->header.dsi_len, block + 8, sizeof(dsi->header.dsi_len));
492 memcpy(&dsi->header.dsi_reserved, block + 12,
493 sizeof(dsi->header.dsi_reserved));
494 dsi->clientID = ntohs(dsi->header.dsi_requestID);
496 /* make sure we don't over-write our buffers. */
497 *rlength = min(ntohl(dsi->header.dsi_len), ilength);
498 if (dsi_stream_read(dsi, buf, *rlength) != *rlength)