2 * $Id: dsi_stream.c,v 1.11.6.4 2004-02-10 10:21:50 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>
41 #define min(a,b) ((a) < (b) ? (a) : (b))
44 #define MSG_MORE 0x8000
48 #define MSG_DONTWAIT 0x40
51 /* -------------------------
52 * we don't use a circular buffer.
54 const void dsi_buffer(DSI *dsi)
56 fd_set readfds, writefds;
62 FD_SET( dsi->socket, &readfds);
63 FD_SET( dsi->socket, &writefds);
64 maxfd = dsi->socket +1;
65 if (select( maxfd, &readfds, &writefds, NULL, NULL) <= 0)
68 if ( !FD_ISSET(dsi->socket, &readfds)) {
69 /* nothing waiting in the queue */
73 /* XXX config options */
74 dsi->maxsize = 6 * dsi->server_quantum;
76 dsi->maxsize = 6 * DSI_SERVQUANT_DEF;
77 dsi->buffer = malloc(dsi->maxsize);
79 /* fall back to blocking IO */
83 dsi->start = dsi->buffer;
84 dsi->eof = dsi->buffer;
85 dsi->end = dsi->buffer + dsi->maxsize;
87 len = dsi->end - dsi->eof;
90 /* ouch, our buffer is full !
91 * fall back to blocking IO
92 * could block and disconnect but it's better than a cpu hog
98 len = read(dsi->socket, dsi->eof, len);
104 /* ------------------------------
105 * write raw data. return actual bytes read. checks against EINTR
106 * aren't necessary if all of the signals have SA_RESTART
108 size_t dsi_stream_write(DSI *dsi, void *data, const size_t length, int mode)
113 /* FIXME sometime it's slower */
114 unsigned int flags = (mode)?MSG_MORE:0;
116 unsigned int flags = 0;
119 /* XXX there's no MSG_DONTWAIT in recv ?? so we have to play with ioctl
121 if (dsi->noblocking) {
122 flags |= MSG_DONTWAIT;
127 while (written < length) {
128 if ((-1 == (len = send(dsi->socket, (u_int8_t *) data + written,
129 length - written, flags)) && errno == EINTR) ||
134 if (dsi->noblocking && errno == EAGAIN) {
135 /* non blocking mode but will block
136 * read data in input queue.
142 LOG(log_error, logtype_default, "dsi_stream_write: %s", strerror(errno));
151 dsi->write_count += written;
155 /* ---------------------------------
157 static ssize_t buf_read(DSI *dsi, u_int8_t *buf, size_t count)
166 nbe = dsi->eof - dsi->start;
169 nbe = min((size_t)nbe, count);
170 memcpy(buf, dsi->start, nbe);
173 if (dsi->eof == dsi->start)
174 dsi->start = dsi->eof = dsi->buffer;
185 ret = read(dsi->socket, buf, count);
192 /* ---------------------------------------
193 * read raw data. return actual bytes read. this will wait until
194 * it gets length bytes
196 size_t dsi_stream_read(DSI *dsi, void *data, const size_t length)
202 while (stored < length) {
203 len = buf_read(dsi, (u_int8_t *) data + stored, length - stored);
204 if (len == -1 && errno == EINTR)
208 else { /* eof or error */
209 /* don't log EOF error if it's just after connect (OSX 10.3 probe) */
210 if (len || stored || dsi->read_count) {
211 LOG(log_error, logtype_default, "dsi_stream_read(%d): %s", len, (len < 0)?strerror(errno):"unexpected EOF");
217 dsi->read_count += stored;
221 /* ---------------------------------------
223 void dsi_sleep(DSI *dsi, const int state)
228 /* ---------------------------------------
230 static void block_sig(DSI *dsi)
232 if (!dsi->sigblocked) sigprocmask(SIG_BLOCK, &dsi->sigblockset, &dsi->oldset);
235 /* ---------------------------------------
237 static void unblock_sig(DSI *dsi)
239 if (!dsi->sigblocked) sigprocmask(SIG_SETMASK, &dsi->oldset, NULL);
242 /* ---------------------------------------
243 * write data. 0 on failure. this assumes that dsi_len will never
244 * cause an overflow in the data buffer.
246 int dsi_stream_send(DSI *dsi, void *buf, size_t length)
248 char block[DSI_BLOCKSIZ];
253 #endif /* USE_WRITEV */
255 block[0] = dsi->header.dsi_flags;
256 block[1] = dsi->header.dsi_command;
257 memcpy(block + 2, &dsi->header.dsi_requestID,
258 sizeof(dsi->header.dsi_requestID));
259 memcpy(block + 4, &dsi->header.dsi_code, sizeof(dsi->header.dsi_code));
260 memcpy(block + 8, &dsi->header.dsi_len, sizeof(dsi->header.dsi_len));
261 memcpy(block + 12, &dsi->header.dsi_reserved,
262 sizeof(dsi->header.dsi_reserved));
267 if (!length) { /* just write the header */
268 length = (dsi_stream_write(dsi, block, sizeof(block), 0) == sizeof(block));
270 return length; /* really 0 on failure, 1 on success */
274 iov[0].iov_base = block;
275 iov[0].iov_len = sizeof(block);
276 iov[1].iov_base = buf;
277 iov[1].iov_len = length;
279 towrite = sizeof(block) + length;
280 dsi->write_count += towrite;
281 while (towrite > 0) {
282 if (((len = writev(dsi->socket, iov, 2)) == -1 && errno == EINTR) ||
286 if (len == towrite) /* wrote everything out */
288 else if (len < 0) { /* error */
289 LOG(log_error, logtype_default, "dsi_stream_send: %s", strerror(errno));
295 if (towrite > length) { /* skip part of header */
296 iov[0].iov_base = (char *) iov[0].iov_base + len;
297 iov[0].iov_len -= len;
298 } else { /* skip to data */
299 if (iov[0].iov_len) {
300 len -= iov[0].iov_len;
303 iov[1].iov_base = (char *) iov[1].iov_base + len;
304 iov[1].iov_len -= len;
308 #else /* USE_WRITEV */
309 /* write the header then data */
310 if ((dsi_stream_write(dsi, block, sizeof(block), 1) != sizeof(block)) ||
311 (dsi_stream_write(dsi, buf, length, 0) != length)) {
315 #endif /* USE_WRITEV */
322 /* ---------------------------------------
323 * read data. function on success. 0 on failure. data length gets
324 * stored in length variable. this should really use size_t's, but
325 * that would require changes elsewhere. */
326 int dsi_stream_receive(DSI *dsi, void *buf, const size_t ilength,
329 char block[DSI_BLOCKSIZ];
331 /* read in the header */
332 if (dsi_stream_read(dsi, block, sizeof(block)) != sizeof(block))
335 dsi->header.dsi_flags = block[0];
336 dsi->header.dsi_command = block[1];
337 /* FIXME, not the right place,
338 but we get a server disconnect without reason in the log
341 LOG(log_error, logtype_default, "dsi_stream_receive: invalid packet, fatal");
345 memcpy(&dsi->header.dsi_requestID, block + 2,
346 sizeof(dsi->header.dsi_requestID));
347 memcpy(&dsi->header.dsi_code, block + 4, sizeof(dsi->header.dsi_code));
348 memcpy(&dsi->header.dsi_len, block + 8, sizeof(dsi->header.dsi_len));
349 memcpy(&dsi->header.dsi_reserved, block + 12,
350 sizeof(dsi->header.dsi_reserved));
351 dsi->clientID = ntohs(dsi->header.dsi_requestID);
353 /* make sure we don't over-write our buffers. */
354 *rlength = min(ntohl(dsi->header.dsi_len), ilength);
355 if (dsi_stream_read(dsi, buf, *rlength) != *rlength)