2 * Copyright (c) 1998 Adrian Sun (asun@zoology.washington.edu)
3 * All rights reserved. See COPYRIGHT.
5 * this file provides the following functions:
6 * dsi_stream_write: just write a bunch of bytes.
7 * dsi_stream_read: just read a bunch of bytes.
8 * dsi_stream_send: send a DSI header + data.
9 * dsi_stream_receive: read a DSI header + data.
14 #endif /* HAVE_CONFIG_H */
25 #include <sys/types.h>
26 #include <sys/socket.h>
29 #include <atalk/logger.h>
30 #include <atalk/dsi.h>
31 #include <netatalk/endian.h>
32 #include <atalk/util.h>
34 #define min(a,b) ((a) < (b) ? (a) : (b))
37 #define MSG_MORE 0x8000
41 #define MSG_DONTWAIT 0x40
44 /* ----------------------
45 afpd is sleeping too much while trying to send something.
46 May be there's no reader or the reader is also sleeping in write,
47 look if there's some data for us to read, hopefully it will wake up
48 the reader so we can write again.
50 static int dsi_peek(DSI *dsi)
52 fd_set readfds, writefds;
57 LOG(log_debug, logtype_dsi, "dsi_peek");
61 FD_SET( dsi->socket, &readfds);
62 FD_SET( dsi->socket, &writefds);
63 maxfd = dsi->socket +1;
66 FD_SET( dsi->socket, &readfds);
67 FD_SET( dsi->socket, &writefds);
69 /* No timeout: if there's nothing to read nor nothing to write,
70 * we've got nothing to do at all */
71 if ((ret = select( maxfd, &readfds, &writefds, NULL, NULL)) <= 0) {
72 if (ret == -1 && errno == EINTR)
73 /* we might have been interrupted by out timer, so restart select */
76 LOG(log_error, logtype_dsi, "dsi_peek: unexpected select return: %d %s",
77 ret, ret < 0 ? strerror(errno) : "");
81 /* Check if there's sth to read, hopefully reading that will unblock the client */
82 if (FD_ISSET(dsi->socket, &readfds)) {
83 len = dsi->end - dsi->eof;
84 LOG(log_note, logtype_dsi, "dsi_peek: used read buffer space: %d bytes", dsi->eof - dsi->buffer);
87 /* ouch, our buffer is full ! fall back to blocking IO
88 * could block and disconnect but it's better than a cpu hog */
89 LOG(log_warning, logtype_dsi, "dsi_peek: read buffer is full");
93 if ((len = read(dsi->socket, dsi->eof, len)) <= 0) {
95 LOG(log_error, logtype_dsi, "dsi_peek: EOF");
98 LOG(log_error, logtype_dsi, "dsi_peek: read: %s", strerror(errno));
103 LOG(log_debug, logtype_dsi, "dsi_peek: read %d bytes", len);
108 if (FD_ISSET(dsi->socket, &writefds)) {
109 /* we can write again */
110 LOG(log_debug, logtype_dsi, "dsi_peek: can write again");
118 /* ------------------------------
119 * write raw data. return actual bytes read. checks against EINTR
120 * aren't necessary if all of the signals have SA_RESTART
122 ssize_t dsi_stream_write(DSI *dsi, void *data, const size_t length, int mode)
126 unsigned int flags = 0;
131 LOG(log_maxdebug, logtype_dsi, "dsi_stream_write: sending %u bytes", length);
133 while (written < length) {
134 len = send(dsi->socket, (u_int8_t *) data + written, length - written, flags);
143 if (errno == EAGAIN || errno == EWOULDBLOCK) {
144 LOG(log_debug, logtype_dsi, "dsi_stream_write: send: %s", strerror(errno));
146 if (mode == DSI_NOWAIT && written == 0) {
147 /* DSI_NOWAIT is used by attention give up in this case. */
152 /* Try to read sth. in order to break up possible deadlock */
153 if (dsi_peek(dsi) != 0) {
157 /* Now try writing again */
161 LOG(log_error, logtype_dsi, "dsi_stream_write: %s", strerror(errno));
166 dsi->write_count += written;
174 /* ---------------------------------
177 ssize_t dsi_stream_read_file(DSI *dsi, int fromfd, off_t offset, const size_t length)
182 LOG(log_maxdebug, logtype_dsi, "dsi_stream_read_file: sending %u bytes", length);
187 while (written < length) {
188 len = sys_sendfile(dsi->socket, fromfd, &offset, length - written);
193 if (errno == EINVAL || errno == ENOSYS)
196 if (errno == EAGAIN || errno == EWOULDBLOCK) {
198 /* can't go back to blocking mode, exit, the next read
199 will return with an error and afpd will die.
205 LOG(log_error, logtype_dsi, "dsi_stream_read_file: %s", strerror(errno));
209 /* afpd is going to exit */
211 return -1; /* I think we're at EOF here... */
217 dsi->write_count += written;
224 * Return all bytes up to count from dsi->buffer if there are any buffered there
226 static size_t from_buf(DSI *dsi, u_int8_t *buf, size_t count)
230 LOG(log_maxdebug, logtype_dsi, "from_buf: %u bytes", count);
233 nbe = dsi->eof - dsi->start;
236 nbe = min((size_t)nbe, count);
237 memcpy(buf, dsi->start, nbe);
240 if (dsi->eof == dsi->start)
241 dsi->start = dsi->eof = dsi->buffer;
246 LOG(log_maxdebug, logtype_dsi, "from_buf(dead: %u, unread:%u , space left: %u): returning %u",
247 dsi->start - dsi->buffer, dsi->eof - dsi->start, dsi->end - dsi->eof, nbe);
252 * Get bytes from buffer dsi->buffer or read from socket
254 * 1. Check if there are bytes in the the dsi->buffer buffer.
255 * 2. Return bytes from (1) if yes.
256 * Note: this may return fewer bytes then requested in count !!
257 * 3. If the buffer was empty, read from the socket.
259 static ssize_t buf_read(DSI *dsi, u_int8_t *buf, size_t count)
263 LOG(log_maxdebug, logtype_dsi, "buf_read(%u bytes)", count);
268 len = from_buf(dsi, buf, count); /* 1. */
272 len = readt(dsi->socket, buf, count, 0, 1); /* 3. */
274 LOG(log_maxdebug, logtype_dsi, "buf_read(%u bytes): got: %d", count, len);
280 * Essentially a loop around buf_read() to ensure "length" bytes are read
281 * from dsi->buffer and/or the socket.
283 size_t dsi_stream_read(DSI *dsi, void *data, const size_t length)
288 LOG(log_maxdebug, logtype_dsi, "dsi_stream_read(%u bytes)", length);
291 while (stored < length) {
292 len = buf_read(dsi, (u_int8_t *) data + stored, length - stored);
293 if (len == -1 && (errno == EINTR || errno == EAGAIN)) {
294 LOG(log_debug, logtype_dsi, "dsi_stream_read: select read loop");
296 } else if (len > 0) {
298 } else { /* eof or error */
299 /* don't log EOF error if it's just after connect (OSX 10.3 probe) */
300 if (len || stored || dsi->read_count) {
301 if (! (dsi->flags & DSI_DISCONNECTED)) {
302 LOG(log_error, logtype_dsi, "dsi_stream_read: len:%d, %s",
303 len, (len < 0) ? strerror(errno) : "unexpected EOF");
311 dsi->read_count += stored;
313 LOG(log_maxdebug, logtype_dsi, "dsi_stream_read(%u bytes): got: %u", length, stored);
318 * Get "length" bytes from buffer and/or socket. In order to avoid frequent small reads
319 * this tries to read larger chunks (65536 bytes) into a buffer.
321 static size_t dsi_buffered_stream_read(DSI *dsi, u_int8_t *data, const size_t length)
326 LOG(log_maxdebug, logtype_dsi, "dsi_buffered_stream_read: %u bytes", length);
328 len = from_buf(dsi, data, length); /* read from buffer dsi->buffer */
329 dsi->read_count += len;
330 if (len == length) { /* got enough bytes from there ? */
331 return len; /* yes */
334 /* fill the buffer with 65536 bytes or until buffer is full */
335 buflen = min(65536, dsi->end - dsi->eof);
338 ret = read(dsi->socket, dsi->eof, buflen);
343 /* now get the remaining data */
344 len += dsi_stream_read(dsi, data + len, length - len);
348 /* ---------------------------------------
350 static void block_sig(DSI *dsi)
355 /* ---------------------------------------
357 static void unblock_sig(DSI *dsi)
362 /* ---------------------------------------
363 * write data. 0 on failure. this assumes that dsi_len will never
364 * cause an overflow in the data buffer.
366 int dsi_stream_send(DSI *dsi, void *buf, size_t length)
368 char block[DSI_BLOCKSIZ];
373 LOG(log_maxdebug, logtype_dsi, "dsi_stream_send: %u bytes",
374 length ? length : sizeof(block));
376 block[0] = dsi->header.dsi_flags;
377 block[1] = dsi->header.dsi_command;
378 memcpy(block + 2, &dsi->header.dsi_requestID,
379 sizeof(dsi->header.dsi_requestID));
380 memcpy(block + 4, &dsi->header.dsi_code, sizeof(dsi->header.dsi_code));
381 memcpy(block + 8, &dsi->header.dsi_len, sizeof(dsi->header.dsi_len));
382 memcpy(block + 12, &dsi->header.dsi_reserved,
383 sizeof(dsi->header.dsi_reserved));
385 if (!length) { /* just write the header */
386 length = (dsi_stream_write(dsi, block, sizeof(block), 0) == sizeof(block));
387 return length; /* really 0 on failure, 1 on success */
392 iov[0].iov_base = block;
393 iov[0].iov_len = sizeof(block);
394 iov[1].iov_base = buf;
395 iov[1].iov_len = length;
397 towrite = sizeof(block) + length;
398 dsi->write_count += towrite;
399 while (towrite > 0) {
400 if (((len = writev(dsi->socket, iov, 2)) == -1 && errno == EINTR) || (len == 0))
403 if ((size_t)len == towrite) /* wrote everything out */
405 else if (len < 0) { /* error */
406 if (errno == EAGAIN || errno == EWOULDBLOCK) {
407 if (!dsi_peek(dsi)) {
411 LOG(log_error, logtype_dsi, "dsi_stream_send: %s", strerror(errno));
417 if (towrite > length) { /* skip part of header */
418 iov[0].iov_base = (char *) iov[0].iov_base + len;
419 iov[0].iov_len -= len;
420 } else { /* skip to data */
421 if (iov[0].iov_len) {
422 len -= iov[0].iov_len;
425 iov[1].iov_base = (char *) iov[1].iov_base + len;
426 iov[1].iov_len -= len;
435 /* ---------------------------------------
436 * read data. function on success. 0 on failure. data length gets
437 * stored in length variable. this should really use size_t's, but
438 * that would require changes elsewhere. */
439 int dsi_stream_receive(DSI *dsi, void *buf, const size_t ilength,
442 char block[DSI_BLOCKSIZ];
444 LOG(log_maxdebug, logtype_dsi, "dsi_stream_receive: %u bytes", ilength);
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_dsi, "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)