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 <atalk/util.h>
40 #define min(a,b) ((a) < (b) ? (a) : (b))
43 #define MSG_MORE 0x8000
47 #define MSG_DONTWAIT 0x40
50 /* -------------------------
51 * we don't use a circular buffer.
53 static void dsi_init_buffer(DSI *dsi)
56 /* XXX config options */
57 dsi->maxsize = 6 * dsi->server_quantum;
59 dsi->maxsize = 6 * DSI_SERVQUANT_DEF;
60 dsi->buffer = malloc(dsi->maxsize);
64 dsi->start = dsi->buffer;
65 dsi->eof = dsi->buffer;
66 dsi->end = dsi->buffer + dsi->maxsize;
70 /* ----------------------
71 afpd is sleeping too much while trying to send something.
72 May be there's no reader or the reader is also sleeping in write,
73 look if there's some data for us to read, hopefully it will wake up
74 the reader so we can write again.
76 static int dsi_peek(DSI *dsi)
78 fd_set readfds, writefds;
85 FD_SET( dsi->socket, &readfds);
86 FD_SET( dsi->socket, &writefds);
87 maxfd = dsi->socket +1;
90 FD_SET( dsi->socket, &readfds);
91 FD_SET( dsi->socket, &writefds);
93 /* No timeout: if there's nothing to read nor nothing to write,
94 * we've got nothing to do at all */
95 if ((ret = select( maxfd, &readfds, &writefds, NULL, NULL)) <= 0) {
96 if (ret == -1 && errno == EINTR)
97 /* we might have been interrupted by out timer, so restart select */
103 /* Check if there's sth to read, hopefully reading that will unblock the client */
104 if (FD_ISSET(dsi->socket, &readfds)) {
105 dsi_init_buffer(dsi);
106 len = dsi->end - dsi->eof;
109 /* ouch, our buffer is full ! fall back to blocking IO
110 * could block and disconnect but it's better than a cpu hog */
114 len = read(dsi->socket, dsi->eof, len);
120 if (FD_ISSET(dsi->socket, &writefds))
121 /* we can write again at last */
128 /* ------------------------------
129 * write raw data. return actual bytes read. checks against EINTR
130 * aren't necessary if all of the signals have SA_RESTART
132 ssize_t dsi_stream_write(DSI *dsi, void *data, const size_t length, int mode)
136 unsigned int flags = 0;
141 LOG(log_maxdebug, logtype_dsi, "dsi_stream_write: sending %u bytes", length);
143 /* non blocking mode */
144 if (setnonblock(dsi->socket, 1) < 0) {
145 LOG(log_error, logtype_dsi, "dsi_stream_write: setnonblock: %s", strerror(errno));
149 while (written < length) {
150 len = send(dsi->socket, (u_int8_t *) data + written, length - written, flags);
159 if (errno == EAGAIN || errno == EWOULDBLOCK) {
160 if (mode == DSI_NOWAIT && written == 0) {
161 /* DSI_NOWAIT is used by attention give up in this case. */
166 /* Try to read sth. in order to break up possible deadlock */
167 if (dsi_peek(dsi) != 0) {
171 /* Now try writing again */
175 LOG(log_error, logtype_dsi, "dsi_stream_write: %s", strerror(errno));
180 dsi->write_count += written;
183 if (setnonblock(dsi->socket, 0) < 0) {
184 LOG(log_error, logtype_dsi, "dsi_stream_write: setnonblock: %s", strerror(errno));
193 /* ---------------------------------
196 ssize_t dsi_stream_read_file(DSI *dsi, int fromfd, off_t offset, const size_t length)
204 /* non blocking mode */
205 if (setnonblock(dsi->socket, 1) < 0) {
206 LOG(log_error, logtype_dsi, "dsi_stream_read_file: setnonblock: %s", strerror(errno));
210 while (written < length) {
211 len = sys_sendfile(dsi->socket, fromfd, &offset, length - written);
216 if (errno == EINVAL || errno == ENOSYS)
219 if (errno == EAGAIN || errno == EWOULDBLOCK) {
221 /* can't go back to blocking mode, exit, the next read
222 will return with an error and afpd will die.
228 LOG(log_error, logtype_dsi, "dsi_stream_write: %s", strerror(errno));
232 /* afpd is going to exit */
234 return -1; /* I think we're at EOF here... */
240 if (setnonblock(dsi->socket, 0) < 0) {
241 LOG(log_error, logtype_dsi, "dsi_stream_read_file: setnonblock: %s", strerror(errno));
245 dsi->write_count += written;
252 * Return all bytes up to count from dsi->buffer if there are any buffered there
254 static size_t from_buf(DSI *dsi, u_int8_t *buf, size_t count)
259 nbe = dsi->eof - dsi->start;
262 nbe = min((size_t)nbe, count);
263 memcpy(buf, dsi->start, nbe);
266 if (dsi->eof == dsi->start)
267 dsi->start = dsi->eof = dsi->buffer;
275 * Get bytes from buffer dsi->buffer or read from socket
277 * 1. Check if there are bytes in the the dsi->buffer buffer.
278 * 2. Return bytes from (1) if yes.
279 * Note: this may return fewer bytes then requested in count !!
280 * 3. If the buffer was empty, read from the socket.
282 static ssize_t buf_read(DSI *dsi, u_int8_t *buf, size_t count)
289 nbe = from_buf(dsi, buf, count); /* 1. */
293 return read(dsi->socket, buf, count); /* 3. */
297 * Essentially a loop around buf_read() to ensure "length" bytes are read
298 * from dsi->buffer and/or the socket.
300 size_t dsi_stream_read(DSI *dsi, void *data, const size_t length)
306 while (stored < length) {
307 len = buf_read(dsi, (u_int8_t *) data + stored, length - stored);
308 if (len == -1 && errno == EINTR) {
310 } else if (len > 0) {
312 } else { /* eof or error */
313 /* don't log EOF error if it's just after connect (OSX 10.3 probe) */
314 if (len || stored || dsi->read_count) {
315 if (! (dsi->flags & DSI_DISCONNECTED))
316 LOG(log_error, logtype_dsi, "dsi_stream_read(fd: %i): len:%d, %s",
317 dsi->socket, len, (len < 0) ? strerror(errno) : "unexpected EOF");
323 dsi->read_count += stored;
328 * Get "length" bytes from buffer and/or socket. In order to avoid frequent small reads
329 * this tries to read larger chunks (8192 bytes) into a buffer.
331 static size_t dsi_buffered_stream_read(DSI *dsi, u_int8_t *data, const size_t length)
336 dsi_init_buffer(dsi);
337 len = from_buf(dsi, data, length); /* read from buffer dsi->buffer */
338 dsi->read_count += len;
339 if (len == length) { /* got enough bytes from there ? */
340 return len; /* yes */
343 /* fill the buffer with 8192 bytes or until buffer is full */
344 buflen = min(8192, dsi->end - dsi->eof);
347 ret = read(dsi->socket, dsi->eof, buflen);
352 /* now get the remaining data */
353 len += dsi_stream_read(dsi, data + len, length - len);
357 /* ---------------------------------------
359 void dsi_sleep(DSI *dsi, const int state)
362 dsi->flags |= DSI_SLEEPING;
364 dsi->flags &= ~DSI_SLEEPING;
367 /* ---------------------------------------
369 static void block_sig(DSI *dsi)
374 /* ---------------------------------------
376 static void unblock_sig(DSI *dsi)
381 /* ---------------------------------------
382 * write data. 0 on failure. this assumes that dsi_len will never
383 * cause an overflow in the data buffer.
385 int dsi_stream_send(DSI *dsi, void *buf, size_t length)
387 char block[DSI_BLOCKSIZ];
392 #endif /* USE_WRITEV */
394 block[0] = dsi->header.dsi_flags;
395 block[1] = dsi->header.dsi_command;
396 memcpy(block + 2, &dsi->header.dsi_requestID,
397 sizeof(dsi->header.dsi_requestID));
398 memcpy(block + 4, &dsi->header.dsi_code, sizeof(dsi->header.dsi_code));
399 memcpy(block + 8, &dsi->header.dsi_len, sizeof(dsi->header.dsi_len));
400 memcpy(block + 12, &dsi->header.dsi_reserved,
401 sizeof(dsi->header.dsi_reserved));
403 if (!length) { /* just write the header */
404 length = (dsi_stream_write(dsi, block, sizeof(block), 0) == sizeof(block));
405 return length; /* really 0 on failure, 1 on success */
411 iov[0].iov_base = block;
412 iov[0].iov_len = sizeof(block);
413 iov[1].iov_base = buf;
414 iov[1].iov_len = length;
416 towrite = sizeof(block) + length;
417 dsi->write_count += towrite;
418 while (towrite > 0) {
419 if (((len = writev(dsi->socket, iov, 2)) == -1 && errno == EINTR) ||
423 if ((size_t)len == towrite) /* wrote everything out */
425 else if (len < 0) { /* error */
426 if (errno == EAGAIN || errno == EWOULDBLOCK) {
427 if (!dsi_peek(dsi)) {
431 LOG(log_error, logtype_dsi, "dsi_stream_send: %s", strerror(errno));
437 if (towrite > length) { /* skip part of header */
438 iov[0].iov_base = (char *) iov[0].iov_base + len;
439 iov[0].iov_len -= len;
440 } else { /* skip to data */
441 if (iov[0].iov_len) {
442 len -= iov[0].iov_len;
445 iov[1].iov_base = (char *) iov[1].iov_base + len;
446 iov[1].iov_len -= len;
450 #else /* USE_WRITEV */
451 /* write the header then data */
452 if ((dsi_stream_write(dsi, block, sizeof(block), 1) != sizeof(block)) ||
453 (dsi_stream_write(dsi, buf, length, 0) != length)) {
457 #endif /* USE_WRITEV */
464 /* ---------------------------------------
465 * read data. function on success. 0 on failure. data length gets
466 * stored in length variable. this should really use size_t's, but
467 * that would require changes elsewhere. */
468 int dsi_stream_receive(DSI *dsi, void *buf, const size_t ilength,
471 char block[DSI_BLOCKSIZ];
473 /* read in the header */
474 if (dsi_buffered_stream_read(dsi, (u_int8_t *)block, sizeof(block)) != sizeof(block))
477 dsi->header.dsi_flags = block[0];
478 dsi->header.dsi_command = block[1];
479 /* FIXME, not the right place,
480 but we get a server disconnect without reason in the log
483 LOG(log_error, logtype_dsi, "dsi_stream_receive: invalid packet, fatal");
487 memcpy(&dsi->header.dsi_requestID, block + 2,
488 sizeof(dsi->header.dsi_requestID));
489 memcpy(&dsi->header.dsi_code, block + 4, sizeof(dsi->header.dsi_code));
490 memcpy(&dsi->header.dsi_len, block + 8, sizeof(dsi->header.dsi_len));
491 memcpy(&dsi->header.dsi_reserved, block + 12,
492 sizeof(dsi->header.dsi_reserved));
493 dsi->clientID = ntohs(dsi->header.dsi_requestID);
495 /* make sure we don't over-write our buffers. */
496 *rlength = min(ntohl(dsi->header.dsi_len), ilength);
497 if (dsi_stream_read(dsi, buf, *rlength) != *rlength)