2 * $Id: dsi_stream.c,v 1.19 2009-10-25 12:09:00 didg 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>
38 #include <atalk/dsi.h>
39 #include <netatalk/endian.h>
40 #include <atalk/util.h>
41 #include <sys/ioctl.h>
43 #define min(a,b) ((a) < (b) ? (a) : (b))
46 #define MSG_MORE 0x8000
50 #define MSG_DONTWAIT 0x40
53 /* -------------------------
54 * we don't use a circular buffer.
56 static void dsi_init_buffer(DSI *dsi)
59 /* XXX config options */
60 dsi->maxsize = 6 * dsi->server_quantum;
62 dsi->maxsize = 6 * DSI_SERVQUANT_DEF;
63 dsi->buffer = malloc(dsi->maxsize);
67 dsi->start = dsi->buffer;
68 dsi->eof = dsi->buffer;
69 dsi->end = dsi->buffer + dsi->maxsize;
73 /* ----------------------
74 afpd is sleeping too much while trying to send something.
75 May be there's no reader or the reader is also sleeping in write,
76 look if there's some data for us to read, hopefully it will wake up
79 static int dsi_buffer(DSI *dsi)
81 fd_set readfds, writefds;
86 /* non blocking mode */
88 if (ioctl(dsi->socket, FIONBIO, &adr) < 0) {
89 /* can't do it! exit without error it will sleep to death below */
90 LOG(log_error, logtype_default, "dsi_buffer: ioctl non blocking mode %s", strerror(errno));
96 FD_SET( dsi->socket, &readfds);
97 FD_SET( dsi->socket, &writefds);
98 maxfd = dsi->socket +1;
100 FD_SET( dsi->socket, &readfds);
101 FD_SET( dsi->socket, &writefds);
102 if (select( maxfd, &readfds, &writefds, NULL, NULL) <= 0)
105 if ( !FD_ISSET(dsi->socket, &readfds)) {
106 /* nothing waiting in the read queue */
109 dsi_init_buffer(dsi);
110 len = dsi->end - dsi->eof;
113 /* ouch, our buffer is full !
114 * fall back to blocking IO
115 * could block and disconnect but it's better than a cpu hog
120 len = read(dsi->socket, dsi->eof, len);
124 if ( FD_ISSET(dsi->socket, &writefds)) {
125 /* we can write again at last */
130 if (ioctl(dsi->socket, FIONBIO, &adr) < 0) {
131 /* can't do it! afpd will fail very quickly */
132 LOG(log_error, logtype_default, "dsi_buffer: ioctl blocking mode %s", strerror(errno));
138 /* ------------------------------
139 * write raw data. return actual bytes read. checks against EINTR
140 * aren't necessary if all of the signals have SA_RESTART
142 ssize_t dsi_stream_write(DSI *dsi, void *data, const size_t length, int mode)
147 /* FIXME sometime it's slower */
148 unsigned int flags = (mode)?MSG_MORE:0;
150 unsigned int flags = 0;
153 /* XXX there's no MSG_DONTWAIT in recv ?? so we have to play with ioctl
155 flags |= MSG_DONTWAIT;
160 while (written < length) {
161 if ((-1 == (len = send(dsi->socket, (u_int8_t *) data + written,
162 length - written, flags)) && errno == EINTR) ||
167 if (errno == EAGAIN || errno == EWOULDBLOCK) {
168 if (mode == DSI_NOWAIT && written == 0) {
169 /* DSI_NOWAIT is used by attention
170 give up in this case.
174 if (dsi_buffer(dsi)) {
175 /* can't go back to blocking mode, exit, the next read
176 will return with an error and afpd will die.
182 LOG(log_error, logtype_default, "dsi_stream_write: %s", strerror(errno));
190 dsi->write_count += written;
196 /* ---------------------------------
199 ssize_t dsi_stream_read_file(DSI *dsi, int fromfd, off_t offset, const size_t length)
207 while (written < length) {
208 len = sys_sendfile(dsi->socket, fromfd, &offset, length - written);
213 if (errno == EINVAL || errno == ENOSYS)
216 if (errno == EAGAIN || errno == EWOULDBLOCK) {
217 if (dsi_buffer(dsi)) {
218 /* can't go back to blocking mode, exit, the next read
219 will return with an error and afpd will die.
225 LOG(log_error, logtype_default, "dsi_stream_write: %s", strerror(errno));
229 /* afpd is going to exit */
231 return -1; /* I think we're at EOF here... */
237 dsi->write_count += written;
243 /* ---------------------------------
245 static size_t from_buf(DSI *dsi, u_int8_t *buf, size_t count)
250 nbe = dsi->eof - dsi->start;
253 nbe = min((size_t)nbe, count);
254 memcpy(buf, dsi->start, nbe);
257 if (dsi->eof == dsi->start)
258 dsi->start = dsi->eof = dsi->buffer;
265 static ssize_t buf_read(DSI *dsi, u_int8_t *buf, size_t count)
272 nbe = from_buf(dsi, buf, count);
276 return read(dsi->socket, buf, count);
280 /* ---------------------------------------
281 * read raw data. return actual bytes read. this will wait until
282 * it gets length bytes
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_default, "dsi_stream_read(%d): %s", len, (len < 0)?strerror(errno):"unexpected EOF");
305 dsi->read_count += stored;
309 /* ---------------------------------------
310 * read raw data. return actual bytes read. this will wait until
311 * it gets length bytes
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);
320 dsi->read_count += len;
325 buflen = min(8192, dsi->end - dsi->eof);
328 ret = read(dsi->socket, dsi->eof, buflen);
332 return dsi_stream_read(dsi, data, length -len);
335 /* ---------------------------------------
337 void dsi_sleep(DSI *dsi, const int state)
342 /* ---------------------------------------
344 static void block_sig(DSI *dsi)
349 /* ---------------------------------------
351 static void unblock_sig(DSI *dsi)
356 /* ---------------------------------------
357 * write data. 0 on failure. this assumes that dsi_len will never
358 * cause an overflow in the data buffer.
360 int dsi_stream_send(DSI *dsi, void *buf, size_t length)
362 char block[DSI_BLOCKSIZ];
367 #endif /* USE_WRITEV */
369 block[0] = dsi->header.dsi_flags;
370 block[1] = dsi->header.dsi_command;
371 memcpy(block + 2, &dsi->header.dsi_requestID,
372 sizeof(dsi->header.dsi_requestID));
373 memcpy(block + 4, &dsi->header.dsi_code, sizeof(dsi->header.dsi_code));
374 memcpy(block + 8, &dsi->header.dsi_len, sizeof(dsi->header.dsi_len));
375 memcpy(block + 12, &dsi->header.dsi_reserved,
376 sizeof(dsi->header.dsi_reserved));
378 if (!length) { /* just write the header */
379 length = (dsi_stream_write(dsi, block, sizeof(block), 0) == sizeof(block));
380 return length; /* really 0 on failure, 1 on success */
386 iov[0].iov_base = block;
387 iov[0].iov_len = sizeof(block);
388 iov[1].iov_base = buf;
389 iov[1].iov_len = length;
391 towrite = sizeof(block) + length;
392 dsi->write_count += towrite;
393 while (towrite > 0) {
394 if (((len = writev(dsi->socket, iov, 2)) == -1 && errno == EINTR) ||
398 if ((size_t)len == towrite) /* wrote everything out */
400 else if (len < 0) { /* error */
401 if (errno == EAGAIN || errno == EWOULDBLOCK) {
402 if (!dsi_buffer(dsi)) {
406 LOG(log_error, logtype_default, "dsi_stream_send: %s", strerror(errno));
412 if (towrite > length) { /* skip part of header */
413 iov[0].iov_base = (char *) iov[0].iov_base + len;
414 iov[0].iov_len -= len;
415 } else { /* skip to data */
416 if (iov[0].iov_len) {
417 len -= iov[0].iov_len;
420 iov[1].iov_base = (char *) iov[1].iov_base + len;
421 iov[1].iov_len -= len;
425 #else /* USE_WRITEV */
426 /* write the header then data */
427 if ((dsi_stream_write(dsi, block, sizeof(block), 1) != sizeof(block)) ||
428 (dsi_stream_write(dsi, buf, length, 0) != length)) {
432 #endif /* USE_WRITEV */
439 /* ---------------------------------------
440 * read data. function on success. 0 on failure. data length gets
441 * stored in length variable. this should really use size_t's, but
442 * that would require changes elsewhere. */
443 int dsi_stream_receive(DSI *dsi, void *buf, const size_t ilength,
446 char block[DSI_BLOCKSIZ];
448 /* read in the header */
449 if (dsi_buffered_stream_read(dsi, (u_int8_t *)block, sizeof(block)) != sizeof(block))
452 dsi->header.dsi_flags = block[0];
453 dsi->header.dsi_command = block[1];
454 /* FIXME, not the right place,
455 but we get a server disconnect without reason in the log
458 LOG(log_error, logtype_default, "dsi_stream_receive: invalid packet, fatal");
462 memcpy(&dsi->header.dsi_requestID, block + 2,
463 sizeof(dsi->header.dsi_requestID));
464 memcpy(&dsi->header.dsi_code, block + 4, sizeof(dsi->header.dsi_code));
465 memcpy(&dsi->header.dsi_len, block + 8, sizeof(dsi->header.dsi_len));
466 memcpy(&dsi->header.dsi_reserved, block + 12,
467 sizeof(dsi->header.dsi_reserved));
468 dsi->clientID = ntohs(dsi->header.dsi_requestID);
470 /* make sure we don't over-write our buffers. */
471 *rlength = min(ntohl(dsi->header.dsi_len), ilength);
472 if (dsi_stream_read(dsi, buf, *rlength) != *rlength)