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
77 static int dsi_buffer(DSI *dsi)
79 fd_set readfds, writefds;
83 /* non blocking mode */
84 if (setnonblock(dsi->socket, 1) < 0) {
85 /* can't do it! exit without error it will sleep to death below */
86 LOG(log_error, logtype_default, "dsi_buffer: ioctl non blocking mode %s", strerror(errno));
92 FD_SET( dsi->socket, &readfds);
93 FD_SET( dsi->socket, &writefds);
94 maxfd = dsi->socket +1;
96 FD_SET( dsi->socket, &readfds);
97 FD_SET( dsi->socket, &writefds);
98 if (select( maxfd, &readfds, &writefds, NULL, NULL) <= 0)
101 if ( !FD_ISSET(dsi->socket, &readfds)) {
102 /* nothing waiting in the read queue */
105 dsi_init_buffer(dsi);
106 len = dsi->end - dsi->eof;
109 /* ouch, our buffer is full !
110 * fall back to blocking IO
111 * could block and disconnect but it's better than a cpu hog
116 len = read(dsi->socket, dsi->eof, len);
120 if ( FD_ISSET(dsi->socket, &writefds)) {
121 /* we can write again at last */
125 if (setnonblock(dsi->socket, 0) < 0) {
126 /* can't do it! afpd will fail very quickly */
127 LOG(log_error, logtype_default, "dsi_buffer: ioctl blocking mode %s", strerror(errno));
133 /* ------------------------------
134 * write raw data. return actual bytes read. checks against EINTR
135 * aren't necessary if all of the signals have SA_RESTART
137 ssize_t dsi_stream_write(DSI *dsi, void *data, const size_t length, int mode)
142 /* FIXME sometime it's slower */
143 unsigned int flags = (mode)?MSG_MORE:0;
145 unsigned int flags = 0;
148 /* XXX there's no MSG_DONTWAIT in recv ?? so we have to play with ioctl
150 flags |= MSG_DONTWAIT;
155 while (written < length) {
156 if ((-1 == (len = send(dsi->socket, (u_int8_t *) data + written,
157 length - written, flags)) && errno == EINTR) ||
162 if (errno == EAGAIN || errno == EWOULDBLOCK) {
163 if (mode == DSI_NOWAIT && written == 0) {
164 /* DSI_NOWAIT is used by attention
165 give up in this case.
169 if (dsi_buffer(dsi)) {
170 /* can't go back to blocking mode, exit, the next read
171 will return with an error and afpd will die.
177 LOG(log_error, logtype_default, "dsi_stream_write: %s", strerror(errno));
185 dsi->write_count += written;
191 /* ---------------------------------
194 ssize_t dsi_stream_read_file(DSI *dsi, int fromfd, off_t offset, const size_t length)
202 while (written < length) {
203 len = sys_sendfile(dsi->socket, fromfd, &offset, length - written);
208 if (errno == EINVAL || errno == ENOSYS)
211 if (errno == EAGAIN || errno == EWOULDBLOCK) {
212 if (dsi_buffer(dsi)) {
213 /* can't go back to blocking mode, exit, the next read
214 will return with an error and afpd will die.
220 LOG(log_error, logtype_default, "dsi_stream_write: %s", strerror(errno));
224 /* afpd is going to exit */
226 return -1; /* I think we're at EOF here... */
232 dsi->write_count += written;
239 * Return all bytes up to count from dsi->buffer if there are any buffered there
241 static size_t from_buf(DSI *dsi, u_int8_t *buf, size_t count)
246 nbe = dsi->eof - dsi->start;
249 nbe = min((size_t)nbe, count);
250 memcpy(buf, dsi->start, nbe);
253 if (dsi->eof == dsi->start)
254 dsi->start = dsi->eof = dsi->buffer;
262 * Get bytes from buffer dsi->buffer or read from socket
264 * 1. Check if there are bytes in the the dsi->buffer buffer.
265 * 2. Return bytes from (1) if yes.
266 * Note: this may return fewer bytes then requested in count !!
267 * 3. If the buffer was empty, read from the socket.
269 static ssize_t buf_read(DSI *dsi, u_int8_t *buf, size_t count)
276 nbe = from_buf(dsi, buf, count); /* 1. */
280 return read(dsi->socket, buf, count); /* 3. */
284 * Essentially a loop around buf_read() to ensure "length" bytes are read
285 * from dsi->buffer and/or the socket.
287 size_t dsi_stream_read(DSI *dsi, void *data, const size_t length)
293 while (stored < length) {
294 len = buf_read(dsi, (u_int8_t *) data + stored, length - stored);
295 if (len == -1 && errno == EINTR)
299 else { /* eof or error */
300 /* don't log EOF error if it's just after connect (OSX 10.3 probe) */
301 if (len || stored || dsi->read_count) {
302 LOG(log_error, logtype_default, "dsi_stream_read(%d): %s", len, (len < 0)?strerror(errno):"unexpected EOF");
308 dsi->read_count += stored;
313 * Get "length" bytes from buffer and/or socket. In order to avoid frequent small reads
314 * this tries to read larger chunks (8192 bytes) into a buffer.
316 static size_t dsi_buffered_stream_read(DSI *dsi, u_int8_t *data, const size_t length)
321 dsi_init_buffer(dsi);
322 len = from_buf(dsi, data, length); /* read from buffer dsi->buffer */
323 dsi->read_count += len;
324 if (len == length) { /* got enough bytes from there ? */
325 return len; /* yes */
328 /* fill the buffer with 8192 bytes or until buffer is full */
329 buflen = min(8192, dsi->end - dsi->eof);
332 ret = read(dsi->socket, dsi->eof, buflen);
337 /* now get the remaining data */
338 len += dsi_stream_read(dsi, data + len, length - len);
342 /* ---------------------------------------
344 void dsi_sleep(DSI *dsi, const int state)
349 /* ---------------------------------------
351 static void block_sig(DSI *dsi)
356 /* ---------------------------------------
358 static void unblock_sig(DSI *dsi)
363 /* ---------------------------------------
364 * write data. 0 on failure. this assumes that dsi_len will never
365 * cause an overflow in the data buffer.
367 int dsi_stream_send(DSI *dsi, void *buf, size_t length)
369 char block[DSI_BLOCKSIZ];
374 #endif /* USE_WRITEV */
376 block[0] = dsi->header.dsi_flags;
377 block[1] = dsi->header.dsi_command;
378 memcpy(block + 2, &dsi->header.dsi_requestID,
379 sizeof(dsi->header.dsi_requestID));
380 memcpy(block + 4, &dsi->header.dsi_code, sizeof(dsi->header.dsi_code));
381 memcpy(block + 8, &dsi->header.dsi_len, sizeof(dsi->header.dsi_len));
382 memcpy(block + 12, &dsi->header.dsi_reserved,
383 sizeof(dsi->header.dsi_reserved));
385 if (!length) { /* just write the header */
386 length = (dsi_stream_write(dsi, block, sizeof(block), 0) == sizeof(block));
387 return length; /* really 0 on failure, 1 on success */
393 iov[0].iov_base = block;
394 iov[0].iov_len = sizeof(block);
395 iov[1].iov_base = buf;
396 iov[1].iov_len = length;
398 towrite = sizeof(block) + length;
399 dsi->write_count += towrite;
400 while (towrite > 0) {
401 if (((len = writev(dsi->socket, iov, 2)) == -1 && errno == EINTR) ||
405 if ((size_t)len == towrite) /* wrote everything out */
407 else if (len < 0) { /* error */
408 if (errno == EAGAIN || errno == EWOULDBLOCK) {
409 if (!dsi_buffer(dsi)) {
413 LOG(log_error, logtype_default, "dsi_stream_send: %s", strerror(errno));
419 if (towrite > length) { /* skip part of header */
420 iov[0].iov_base = (char *) iov[0].iov_base + len;
421 iov[0].iov_len -= len;
422 } else { /* skip to data */
423 if (iov[0].iov_len) {
424 len -= iov[0].iov_len;
427 iov[1].iov_base = (char *) iov[1].iov_base + len;
428 iov[1].iov_len -= len;
432 #else /* USE_WRITEV */
433 /* write the header then data */
434 if ((dsi_stream_write(dsi, block, sizeof(block), 1) != sizeof(block)) ||
435 (dsi_stream_write(dsi, buf, length, 0) != length)) {
439 #endif /* USE_WRITEV */
446 /* ---------------------------------------
447 * read data. function on success. 0 on failure. data length gets
448 * stored in length variable. this should really use size_t's, but
449 * that would require changes elsewhere. */
450 int dsi_stream_receive(DSI *dsi, void *buf, const size_t ilength,
453 char block[DSI_BLOCKSIZ];
455 /* read in the header */
456 if (dsi_buffered_stream_read(dsi, (u_int8_t *)block, sizeof(block)) != sizeof(block))
459 dsi->header.dsi_flags = block[0];
460 dsi->header.dsi_command = block[1];
461 /* FIXME, not the right place,
462 but we get a server disconnect without reason in the log
465 LOG(log_error, logtype_default, "dsi_stream_receive: invalid packet, fatal");
469 memcpy(&dsi->header.dsi_requestID, block + 2,
470 sizeof(dsi->header.dsi_requestID));
471 memcpy(&dsi->header.dsi_code, block + 4, sizeof(dsi->header.dsi_code));
472 memcpy(&dsi->header.dsi_len, block + 8, sizeof(dsi->header.dsi_len));
473 memcpy(&dsi->header.dsi_reserved, block + 12,
474 sizeof(dsi->header.dsi_reserved));
475 dsi->clientID = ntohs(dsi->header.dsi_requestID);
477 /* make sure we don't over-write our buffers. */
478 *rlength = min(ntohl(dsi->header.dsi_len), ilength);
479 if (dsi_stream_read(dsi, buf, *rlength) != *rlength)