2 * $Id: dsi_stream.c,v 1.17 2009-10-25 06:13:11 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 <sys/ioctl.h>
42 #define min(a,b) ((a) < (b) ? (a) : (b))
45 #define MSG_MORE 0x8000
49 #define MSG_DONTWAIT 0x40
52 /* -------------------------
53 * we don't use a circular buffer.
55 static void dsi_init_buffer(DSI *dsi)
58 /* XXX config options */
59 dsi->maxsize = 6 * dsi->server_quantum;
61 dsi->maxsize = 6 * DSI_SERVQUANT_DEF;
62 dsi->buffer = malloc(dsi->maxsize);
66 dsi->start = dsi->buffer;
67 dsi->eof = dsi->buffer;
68 dsi->end = dsi->buffer + dsi->maxsize;
72 /* ----------------------
73 afpd is sleeping too much while trying to send something.
74 May be there's no reader or the reader is also sleeping in write,
75 look if there's some data for us to read, hopefully it will wake up
78 static int dsi_buffer(DSI *dsi)
80 fd_set readfds, writefds;
85 /* non blocking mode */
87 if (ioctl(dsi->socket, FIONBIO, &adr) < 0) {
88 /* can't do it! exit without error it will sleep to death below */
89 LOG(log_error, logtype_default, "dsi_buffer: ioctl non blocking mode %s", strerror(errno));
95 FD_SET( dsi->socket, &readfds);
96 FD_SET( dsi->socket, &writefds);
97 maxfd = dsi->socket +1;
99 FD_SET( dsi->socket, &readfds);
100 FD_SET( dsi->socket, &writefds);
101 if (select( maxfd, &readfds, &writefds, NULL, NULL) <= 0)
104 if ( !FD_ISSET(dsi->socket, &readfds)) {
105 /* nothing waiting in the read queue */
108 dsi_init_buffer(dsi);
109 len = dsi->end - dsi->eof;
112 /* ouch, our buffer is full !
113 * fall back to blocking IO
114 * could block and disconnect but it's better than a cpu hog
119 len = read(dsi->socket, dsi->eof, len);
123 if ( FD_ISSET(dsi->socket, &writefds)) {
124 /* we can write again at last */
129 if (ioctl(dsi->socket, FIONBIO, &adr) < 0) {
130 /* can't do it! afpd will fail very quickly */
131 LOG(log_error, logtype_default, "dsi_buffer: ioctl blocking mode %s", strerror(errno));
137 /* ------------------------------
138 * write raw data. return actual bytes read. checks against EINTR
139 * aren't necessary if all of the signals have SA_RESTART
141 ssize_t dsi_stream_write(DSI *dsi, void *data, const size_t length, int mode)
146 /* FIXME sometime it's slower */
147 unsigned int flags = (mode)?MSG_MORE:0;
149 unsigned int flags = 0;
152 /* XXX there's no MSG_DONTWAIT in recv ?? so we have to play with ioctl
154 flags |= MSG_DONTWAIT;
159 while (written < length) {
160 if ((-1 == (len = send(dsi->socket, (u_int8_t *) data + written,
161 length - written, flags)) && errno == EINTR) ||
166 if (errno == EAGAIN || errno == EWOULDBLOCK) {
167 if (mode == DSI_NOWAIT && written == 0) {
168 /* DSI_NOWAIT is used by attention
169 give up in this case.
173 if (dsi_buffer(dsi)) {
174 /* can't go back to blocking mode, exit, the next read
175 will return with an error and afpd will die.
181 LOG(log_error, logtype_default, "dsi_stream_write: %s", strerror(errno));
189 dsi->write_count += written;
194 /* ---------------------------------
196 static size_t from_buf(DSI *dsi, u_int8_t *buf, size_t count)
201 nbe = dsi->eof - dsi->start;
204 nbe = min((size_t)nbe, count);
205 memcpy(buf, dsi->start, nbe);
208 if (dsi->eof == dsi->start)
209 dsi->start = dsi->eof = dsi->buffer;
216 static ssize_t buf_read(DSI *dsi, u_int8_t *buf, size_t count)
223 nbe = from_buf(dsi, buf, count);
227 return read(dsi->socket, buf, count);
231 /* ---------------------------------------
232 * read raw data. return actual bytes read. this will wait until
233 * it gets length bytes
235 size_t dsi_stream_read(DSI *dsi, void *data, const size_t length)
241 while (stored < length) {
242 len = buf_read(dsi, (u_int8_t *) data + stored, length - stored);
243 if (len == -1 && errno == EINTR)
247 else { /* eof or error */
248 /* don't log EOF error if it's just after connect (OSX 10.3 probe) */
249 if (len || stored || dsi->read_count) {
250 LOG(log_error, logtype_default, "dsi_stream_read(%d): %s", len, (len < 0)?strerror(errno):"unexpected EOF");
256 dsi->read_count += stored;
260 /* ---------------------------------------
261 * read raw data. return actual bytes read. this will wait until
262 * it gets length bytes
264 static size_t dsi_buffered_stream_read(DSI *dsi, u_int8_t *data, const size_t length)
269 dsi_init_buffer(dsi);
270 len = from_buf(dsi, data, length);
271 dsi->read_count += len;
276 buflen = min(8192, dsi->end - dsi->eof);
279 ret = read(dsi->socket, dsi->eof, buflen);
283 return dsi_stream_read(dsi, data, length -len);
286 /* ---------------------------------------
288 void dsi_sleep(DSI *dsi, const int state)
293 /* ---------------------------------------
295 static void block_sig(DSI *dsi)
300 /* ---------------------------------------
302 static void unblock_sig(DSI *dsi)
307 /* ---------------------------------------
308 * write data. 0 on failure. this assumes that dsi_len will never
309 * cause an overflow in the data buffer.
311 int dsi_stream_send(DSI *dsi, void *buf, size_t length)
313 char block[DSI_BLOCKSIZ];
318 #endif /* USE_WRITEV */
320 block[0] = dsi->header.dsi_flags;
321 block[1] = dsi->header.dsi_command;
322 memcpy(block + 2, &dsi->header.dsi_requestID,
323 sizeof(dsi->header.dsi_requestID));
324 memcpy(block + 4, &dsi->header.dsi_code, sizeof(dsi->header.dsi_code));
325 memcpy(block + 8, &dsi->header.dsi_len, sizeof(dsi->header.dsi_len));
326 memcpy(block + 12, &dsi->header.dsi_reserved,
327 sizeof(dsi->header.dsi_reserved));
329 if (!length) { /* just write the header */
330 length = (dsi_stream_write(dsi, block, sizeof(block), 0) == sizeof(block));
331 return length; /* really 0 on failure, 1 on success */
337 iov[0].iov_base = block;
338 iov[0].iov_len = sizeof(block);
339 iov[1].iov_base = buf;
340 iov[1].iov_len = length;
342 towrite = sizeof(block) + length;
343 dsi->write_count += towrite;
344 while (towrite > 0) {
345 if (((len = writev(dsi->socket, iov, 2)) == -1 && errno == EINTR) ||
349 if ((size_t)len == towrite) /* wrote everything out */
351 else if (len < 0) { /* error */
352 if (errno == EAGAIN || errno == EWOULDBLOCK) {
353 if (!dsi_buffer(dsi)) {
357 LOG(log_error, logtype_default, "dsi_stream_send: %s", strerror(errno));
363 if (towrite > length) { /* skip part of header */
364 iov[0].iov_base = (char *) iov[0].iov_base + len;
365 iov[0].iov_len -= len;
366 } else { /* skip to data */
367 if (iov[0].iov_len) {
368 len -= iov[0].iov_len;
371 iov[1].iov_base = (char *) iov[1].iov_base + len;
372 iov[1].iov_len -= len;
376 #else /* USE_WRITEV */
377 /* write the header then data */
378 if ((dsi_stream_write(dsi, block, sizeof(block), 1) != sizeof(block)) ||
379 (dsi_stream_write(dsi, buf, length, 0) != length)) {
383 #endif /* USE_WRITEV */
390 /* ---------------------------------------
391 * read data. function on success. 0 on failure. data length gets
392 * stored in length variable. this should really use size_t's, but
393 * that would require changes elsewhere. */
394 int dsi_stream_receive(DSI *dsi, void *buf, const size_t ilength,
397 char block[DSI_BLOCKSIZ];
399 /* read in the header */
400 if (dsi_buffered_stream_read(dsi, (u_int8_t *)block, sizeof(block)) != sizeof(block))
403 dsi->header.dsi_flags = block[0];
404 dsi->header.dsi_command = block[1];
405 /* FIXME, not the right place,
406 but we get a server disconnect without reason in the log
409 LOG(log_error, logtype_default, "dsi_stream_receive: invalid packet, fatal");
413 memcpy(&dsi->header.dsi_requestID, block + 2,
414 sizeof(dsi->header.dsi_requestID));
415 memcpy(&dsi->header.dsi_code, block + 4, sizeof(dsi->header.dsi_code));
416 memcpy(&dsi->header.dsi_len, block + 8, sizeof(dsi->header.dsi_len));
417 memcpy(&dsi->header.dsi_reserved, block + 12,
418 sizeof(dsi->header.dsi_reserved));
419 dsi->clientID = ntohs(dsi->header.dsi_requestID);
421 /* make sure we don't over-write our buffers. */
422 *rlength = min(ntohl(dsi->header.dsi_len), ilength);
423 if (dsi_stream_read(dsi, buf, *rlength) != *rlength)