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_dsi, "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_dsi, "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 len = send(dsi->socket, (u_int8_t *) data + written, length - written, flags);
157 if ((len == 0) || (len == -1 && errno == EINTR))
161 if (errno == EAGAIN || errno == EWOULDBLOCK) {
162 if (mode == DSI_NOWAIT && written == 0) {
163 /* DSI_NOWAIT is used by attention give up in this case. */
166 if (dsi_buffer(dsi)) {
167 /* can't go back to blocking mode, exit, the next read
168 will return with an error and afpd will die.
174 LOG(log_error, logtype_dsi, "dsi_stream_write: %s", strerror(errno));
182 dsi->write_count += written;
188 /* ---------------------------------
191 ssize_t dsi_stream_read_file(DSI *dsi, int fromfd, off_t offset, const size_t length)
199 while (written < length) {
200 len = sys_sendfile(dsi->socket, fromfd, &offset, length - written);
205 if (errno == EINVAL || errno == ENOSYS)
208 if (errno == EAGAIN || errno == EWOULDBLOCK) {
209 if (dsi_buffer(dsi)) {
210 /* can't go back to blocking mode, exit, the next read
211 will return with an error and afpd will die.
217 LOG(log_error, logtype_dsi, "dsi_stream_write: %s", strerror(errno));
221 /* afpd is going to exit */
223 return -1; /* I think we're at EOF here... */
229 dsi->write_count += written;
236 * Return all bytes up to count from dsi->buffer if there are any buffered there
238 static size_t from_buf(DSI *dsi, u_int8_t *buf, size_t count)
243 nbe = dsi->eof - dsi->start;
246 nbe = min((size_t)nbe, count);
247 memcpy(buf, dsi->start, nbe);
250 if (dsi->eof == dsi->start)
251 dsi->start = dsi->eof = dsi->buffer;
259 * Get bytes from buffer dsi->buffer or read from socket
261 * 1. Check if there are bytes in the the dsi->buffer buffer.
262 * 2. Return bytes from (1) if yes.
263 * Note: this may return fewer bytes then requested in count !!
264 * 3. If the buffer was empty, read from the socket.
266 static ssize_t buf_read(DSI *dsi, u_int8_t *buf, size_t count)
273 nbe = from_buf(dsi, buf, count); /* 1. */
277 return read(dsi->socket, buf, count); /* 3. */
281 * Essentially a loop around buf_read() to ensure "length" bytes are read
282 * from dsi->buffer and/or the socket.
284 size_t dsi_stream_read(DSI *dsi, void *data, const size_t length)
290 while (stored < length) {
291 len = buf_read(dsi, (u_int8_t *) data + stored, length - stored);
292 if (len == -1 && errno == EINTR)
296 else { /* eof or error */
297 /* don't log EOF error if it's just after connect (OSX 10.3 probe) */
298 if (len || stored || dsi->read_count) {
299 LOG(log_error, logtype_dsi, "dsi_stream_read(%d): %s", len, (len < 0)?strerror(errno):"unexpected EOF");
305 dsi->read_count += stored;
310 * Get "length" bytes from buffer and/or socket. In order to avoid frequent small reads
311 * this tries to read larger chunks (8192 bytes) into a buffer.
313 static size_t dsi_buffered_stream_read(DSI *dsi, u_int8_t *data, const size_t length)
318 dsi_init_buffer(dsi);
319 len = from_buf(dsi, data, length); /* read from buffer dsi->buffer */
320 dsi->read_count += len;
321 if (len == length) { /* got enough bytes from there ? */
322 return len; /* yes */
325 /* fill the buffer with 8192 bytes or until buffer is full */
326 buflen = min(8192, dsi->end - dsi->eof);
329 ret = read(dsi->socket, dsi->eof, buflen);
334 /* now get the remaining data */
335 len += dsi_stream_read(dsi, data + len, length - len);
339 /* ---------------------------------------
341 void dsi_sleep(DSI *dsi, const int state)
346 /* ---------------------------------------
348 static void block_sig(DSI *dsi)
353 /* ---------------------------------------
355 static void unblock_sig(DSI *dsi)
360 /* ---------------------------------------
361 * write data. 0 on failure. this assumes that dsi_len will never
362 * cause an overflow in the data buffer.
364 int dsi_stream_send(DSI *dsi, void *buf, size_t length)
366 char block[DSI_BLOCKSIZ];
371 #endif /* USE_WRITEV */
373 block[0] = dsi->header.dsi_flags;
374 block[1] = dsi->header.dsi_command;
375 memcpy(block + 2, &dsi->header.dsi_requestID,
376 sizeof(dsi->header.dsi_requestID));
377 memcpy(block + 4, &dsi->header.dsi_code, sizeof(dsi->header.dsi_code));
378 memcpy(block + 8, &dsi->header.dsi_len, sizeof(dsi->header.dsi_len));
379 memcpy(block + 12, &dsi->header.dsi_reserved,
380 sizeof(dsi->header.dsi_reserved));
382 if (!length) { /* just write the header */
383 length = (dsi_stream_write(dsi, block, sizeof(block), 0) == sizeof(block));
384 return length; /* really 0 on failure, 1 on success */
390 iov[0].iov_base = block;
391 iov[0].iov_len = sizeof(block);
392 iov[1].iov_base = buf;
393 iov[1].iov_len = length;
395 towrite = sizeof(block) + length;
396 dsi->write_count += towrite;
397 while (towrite > 0) {
398 if (((len = writev(dsi->socket, iov, 2)) == -1 && errno == EINTR) ||
402 if ((size_t)len == towrite) /* wrote everything out */
404 else if (len < 0) { /* error */
405 if (errno == EAGAIN || errno == EWOULDBLOCK) {
406 if (!dsi_buffer(dsi)) {
410 LOG(log_error, logtype_dsi, "dsi_stream_send: %s", strerror(errno));
416 if (towrite > length) { /* skip part of header */
417 iov[0].iov_base = (char *) iov[0].iov_base + len;
418 iov[0].iov_len -= len;
419 } else { /* skip to data */
420 if (iov[0].iov_len) {
421 len -= iov[0].iov_len;
424 iov[1].iov_base = (char *) iov[1].iov_base + len;
425 iov[1].iov_len -= len;
429 #else /* USE_WRITEV */
430 /* write the header then data */
431 if ((dsi_stream_write(dsi, block, sizeof(block), 1) != sizeof(block)) ||
432 (dsi_stream_write(dsi, buf, length, 0) != length)) {
436 #endif /* USE_WRITEV */
443 /* ---------------------------------------
444 * read data. function on success. 0 on failure. data length gets
445 * stored in length variable. this should really use size_t's, but
446 * that would require changes elsewhere. */
447 int dsi_stream_receive(DSI *dsi, void *buf, const size_t ilength,
450 char block[DSI_BLOCKSIZ];
452 /* read in the header */
453 if (dsi_buffered_stream_read(dsi, (u_int8_t *)block, sizeof(block)) != sizeof(block))
456 dsi->header.dsi_flags = block[0];
457 dsi->header.dsi_command = block[1];
458 /* FIXME, not the right place,
459 but we get a server disconnect without reason in the log
462 LOG(log_error, logtype_dsi, "dsi_stream_receive: invalid packet, fatal");
466 memcpy(&dsi->header.dsi_requestID, block + 2,
467 sizeof(dsi->header.dsi_requestID));
468 memcpy(&dsi->header.dsi_code, block + 4, sizeof(dsi->header.dsi_code));
469 memcpy(&dsi->header.dsi_len, block + 8, sizeof(dsi->header.dsi_len));
470 memcpy(&dsi->header.dsi_reserved, block + 12,
471 sizeof(dsi->header.dsi_reserved));
472 dsi->clientID = ntohs(dsi->header.dsi_requestID);
474 /* make sure we don't over-write our buffers. */
475 *rlength = min(ntohl(dsi->header.dsi_len), ilength);
476 if (dsi_stream_read(dsi, buf, *rlength) != *rlength)