2 * $Id: dsi_stream.c,v 1.18 2009-10-25 09:47:05 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 /* ---------------------------------
198 ssize_t dsi_stream_read_file(DSI *dsi, int fromfd, off_t offset, const size_t length)
206 while (written < length) {
207 len = sys_sendfile(dsi->socket, fromfd, &offset, length - written);
212 if (errno == EINVAL || errno == ENOSYS)
215 if (errno == EAGAIN || errno == EWOULDBLOCK) {
216 if (dsi_buffer(dsi)) {
217 /* can't go back to blocking mode, exit, the next read
218 will return with an error and afpd will die.
224 LOG(log_error, logtype_default, "dsi_stream_write: %s", strerror(errno));
228 /* afpd is going to exit */
230 return -1; /* I think we're at EOF here... */
236 dsi->write_count += written;
241 /* ---------------------------------
243 static size_t from_buf(DSI *dsi, u_int8_t *buf, size_t count)
248 nbe = dsi->eof - dsi->start;
251 nbe = min((size_t)nbe, count);
252 memcpy(buf, dsi->start, nbe);
255 if (dsi->eof == dsi->start)
256 dsi->start = dsi->eof = dsi->buffer;
263 static ssize_t buf_read(DSI *dsi, u_int8_t *buf, size_t count)
270 nbe = from_buf(dsi, buf, count);
274 return read(dsi->socket, buf, count);
278 /* ---------------------------------------
279 * read raw data. return actual bytes read. this will wait until
280 * it gets length bytes
282 size_t dsi_stream_read(DSI *dsi, void *data, const size_t length)
288 while (stored < length) {
289 len = buf_read(dsi, (u_int8_t *) data + stored, length - stored);
290 if (len == -1 && errno == EINTR)
294 else { /* eof or error */
295 /* don't log EOF error if it's just after connect (OSX 10.3 probe) */
296 if (len || stored || dsi->read_count) {
297 LOG(log_error, logtype_default, "dsi_stream_read(%d): %s", len, (len < 0)?strerror(errno):"unexpected EOF");
303 dsi->read_count += stored;
307 /* ---------------------------------------
308 * read raw data. return actual bytes read. this will wait until
309 * it gets length bytes
311 static size_t dsi_buffered_stream_read(DSI *dsi, u_int8_t *data, const size_t length)
316 dsi_init_buffer(dsi);
317 len = from_buf(dsi, data, length);
318 dsi->read_count += len;
323 buflen = min(8192, dsi->end - dsi->eof);
326 ret = read(dsi->socket, dsi->eof, buflen);
330 return dsi_stream_read(dsi, data, length -len);
333 /* ---------------------------------------
335 void dsi_sleep(DSI *dsi, const int state)
340 /* ---------------------------------------
342 static void block_sig(DSI *dsi)
347 /* ---------------------------------------
349 static void unblock_sig(DSI *dsi)
354 /* ---------------------------------------
355 * write data. 0 on failure. this assumes that dsi_len will never
356 * cause an overflow in the data buffer.
358 int dsi_stream_send(DSI *dsi, void *buf, size_t length)
360 char block[DSI_BLOCKSIZ];
365 #endif /* USE_WRITEV */
367 block[0] = dsi->header.dsi_flags;
368 block[1] = dsi->header.dsi_command;
369 memcpy(block + 2, &dsi->header.dsi_requestID,
370 sizeof(dsi->header.dsi_requestID));
371 memcpy(block + 4, &dsi->header.dsi_code, sizeof(dsi->header.dsi_code));
372 memcpy(block + 8, &dsi->header.dsi_len, sizeof(dsi->header.dsi_len));
373 memcpy(block + 12, &dsi->header.dsi_reserved,
374 sizeof(dsi->header.dsi_reserved));
376 if (!length) { /* just write the header */
377 length = (dsi_stream_write(dsi, block, sizeof(block), 0) == sizeof(block));
378 return length; /* really 0 on failure, 1 on success */
384 iov[0].iov_base = block;
385 iov[0].iov_len = sizeof(block);
386 iov[1].iov_base = buf;
387 iov[1].iov_len = length;
389 towrite = sizeof(block) + length;
390 dsi->write_count += towrite;
391 while (towrite > 0) {
392 if (((len = writev(dsi->socket, iov, 2)) == -1 && errno == EINTR) ||
396 if ((size_t)len == towrite) /* wrote everything out */
398 else if (len < 0) { /* error */
399 if (errno == EAGAIN || errno == EWOULDBLOCK) {
400 if (!dsi_buffer(dsi)) {
404 LOG(log_error, logtype_default, "dsi_stream_send: %s", strerror(errno));
410 if (towrite > length) { /* skip part of header */
411 iov[0].iov_base = (char *) iov[0].iov_base + len;
412 iov[0].iov_len -= len;
413 } else { /* skip to data */
414 if (iov[0].iov_len) {
415 len -= iov[0].iov_len;
418 iov[1].iov_base = (char *) iov[1].iov_base + len;
419 iov[1].iov_len -= len;
423 #else /* USE_WRITEV */
424 /* write the header then data */
425 if ((dsi_stream_write(dsi, block, sizeof(block), 1) != sizeof(block)) ||
426 (dsi_stream_write(dsi, buf, length, 0) != length)) {
430 #endif /* USE_WRITEV */
437 /* ---------------------------------------
438 * read data. function on success. 0 on failure. data length gets
439 * stored in length variable. this should really use size_t's, but
440 * that would require changes elsewhere. */
441 int dsi_stream_receive(DSI *dsi, void *buf, const size_t ilength,
444 char block[DSI_BLOCKSIZ];
446 /* read in the header */
447 if (dsi_buffered_stream_read(dsi, (u_int8_t *)block, sizeof(block)) != sizeof(block))
450 dsi->header.dsi_flags = block[0];
451 dsi->header.dsi_command = block[1];
452 /* FIXME, not the right place,
453 but we get a server disconnect without reason in the log
456 LOG(log_error, logtype_default, "dsi_stream_receive: invalid packet, fatal");
460 memcpy(&dsi->header.dsi_requestID, block + 2,
461 sizeof(dsi->header.dsi_requestID));
462 memcpy(&dsi->header.dsi_code, block + 4, sizeof(dsi->header.dsi_code));
463 memcpy(&dsi->header.dsi_len, block + 8, sizeof(dsi->header.dsi_len));
464 memcpy(&dsi->header.dsi_reserved, block + 12,
465 sizeof(dsi->header.dsi_reserved));
466 dsi->clientID = ntohs(dsi->header.dsi_requestID);
468 /* make sure we don't over-write our buffers. */
469 *rlength = min(ntohl(dsi->header.dsi_len), ilength);
470 if (dsi_stream_read(dsi, buf, *rlength) != *rlength)