]> arthur.barton.de Git - netatalk.git/blob - libatalk/dsi/dsi_stream.c
Initial revision
[netatalk.git] / libatalk / dsi / dsi_stream.c
1 /*
2  * Copyright (c) 1998 Adrian Sun (asun@zoology.washington.edu)
3  * All rights reserved. See COPYRIGHT.
4  *
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.
10  */
11
12 #define USE_WRITEV
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <unistd.h>
17 #include <string.h>
18 #include <errno.h>
19 #include <sys/types.h>
20 #ifdef USE_WRITEV
21 #include <sys/uio.h>
22 #endif
23 #include <syslog.h>
24
25 #include <atalk/dsi.h>
26 #include <netatalk/endian.h>
27
28 #define min(a,b)  ((a) < (b) ? (a) : (b))
29
30
31 /* write raw data. return actual bytes read. checks against EINTR
32  * aren't necessary if all of the signals have SA_RESTART
33  * specified. */
34 size_t dsi_stream_write(DSI *dsi, void *data, const size_t length)
35 {
36   size_t written;
37   ssize_t len;
38
39   written = 0;
40   while (written < length) {
41     if (((len = write(dsi->socket, (u_int8_t *) data + written,
42                       length - written)) == -1 && errno == EINTR) ||
43         !len)
44       continue;
45
46     if (len < 0) {
47       syslog(LOG_ERR, "dsi_stream_write: %m");
48       break;
49     }
50     
51     written += len;
52   }
53
54   dsi->write_count += written;
55   return written;
56 }
57
58 /* read raw data. return actual bytes read. this will wait until 
59  * it gets length bytes */
60 size_t dsi_stream_read(DSI *dsi, void *data, const size_t length)
61 {
62   size_t stored;
63   ssize_t len;
64   
65   stored = 0;
66   while (stored < length) {
67     if ((len = read(dsi->socket, (u_int8_t *) data + stored, 
68                     length - stored)) == -1 && errno == EINTR)
69       continue;
70
71     if (len > 0)
72       stored += len;
73     else {/* eof or error */
74       syslog(LOG_ERR, "dsi_stream_read(%d): %m", len);
75       break;
76     }
77   }
78
79   dsi->read_count += stored;
80   return stored;
81 }
82
83
84 /* write data. 0 on failure. this assumes that dsi_len will never
85  * cause an overflow in the data buffer. */
86 int dsi_stream_send(DSI *dsi, void *buf, size_t length)
87 {
88   char block[DSI_BLOCKSIZ];
89   sigset_t oldset;
90 #ifdef USE_WRITEV
91   struct iovec iov[2];
92   size_t  towrite;
93   ssize_t len;
94 #endif
95
96   block[0] = dsi->header.dsi_flags;
97   block[1] = dsi->header.dsi_command;
98   memcpy(block + 2, &dsi->header.dsi_requestID, 
99          sizeof(dsi->header.dsi_requestID));
100   memcpy(block + 4, &dsi->header.dsi_code, sizeof(dsi->header.dsi_code));
101   memcpy(block + 8, &dsi->header.dsi_len, sizeof(dsi->header.dsi_len));
102   memcpy(block + 12, &dsi->header.dsi_reserved,
103          sizeof(dsi->header.dsi_reserved));
104
105   /* block signals */
106   sigprocmask(SIG_BLOCK, &dsi->sigblockset, &oldset);
107
108   if (!length) { /* just write the header */
109     length = (dsi_stream_write(dsi, block, sizeof(block)) == sizeof(block));
110     sigprocmask(SIG_SETMASK, &oldset, NULL);
111     return length; /* really 0 on failure, 1 on success */
112   }
113   
114 #ifdef USE_WRITEV
115   iov[0].iov_base = block;
116   iov[0].iov_len = sizeof(block);
117   iov[1].iov_base = buf;
118   iov[1].iov_len = length;
119   
120   towrite = sizeof(block) + length;
121   dsi->write_count += towrite;
122   while (towrite > 0) {
123     if (((len = writev(dsi->socket, iov, 2)) == -1 && errno == EINTR) || 
124         !len)
125       continue;
126     
127     if (len == towrite) /* wrote everything out */
128       break;
129     else if (len < 0) { /* error */
130       syslog(LOG_ERR, "dsi_stream_send: %m");
131       sigprocmask(SIG_SETMASK, &oldset, NULL);
132       return 0;
133     }
134     
135     towrite -= len;
136     if (towrite > length) { /* skip part of header */
137       iov[0].iov_base = (char *) iov[0].iov_base + len;
138       iov[0].iov_len -= len;
139     } else { /* skip to data */
140       if (iov[0].iov_len) {
141         len -= iov[0].iov_len;
142         iov[0].iov_len = 0;
143       }
144       iov[1].iov_base = (char *) iov[1].iov_base + len;
145       iov[1].iov_len -= len;
146     }
147   }
148   
149 #else
150   /* write the header then data */
151   if ((dsi_stream_write(dsi, block, sizeof(block)) != sizeof(block)) ||
152       (dsi_stream_write(dsi, buf, length) != length)) {
153     sigprocmask(SIG_SETMASK, &oldset, NULL);
154     return 0;
155   }
156 #endif
157
158   sigprocmask(SIG_SETMASK, &oldset, NULL);
159   return 1;
160 }
161
162
163 /* read data. function on success. 0 on failure. data length gets
164  * stored in length variable. this should really use size_t's, but
165  * that would require changes elsewhere. */
166 int dsi_stream_receive(DSI *dsi, void *buf, const int ilength,
167                        int *rlength)
168 {
169   char block[DSI_BLOCKSIZ];
170
171   /* read in the header */
172   if (dsi_stream_read(dsi, block, sizeof(block)) != sizeof(block)) 
173     return 0;
174
175   dsi->header.dsi_flags = block[0];
176   dsi->header.dsi_command = block[1];
177   memcpy(&dsi->header.dsi_requestID, block + 2, 
178          sizeof(dsi->header.dsi_requestID));
179   memcpy(&dsi->header.dsi_code, block + 4, sizeof(dsi->header.dsi_code));
180   memcpy(&dsi->header.dsi_len, block + 8, sizeof(dsi->header.dsi_len));
181   memcpy(&dsi->header.dsi_reserved, block + 12,
182          sizeof(dsi->header.dsi_reserved));
183   dsi->clientID = ntohs(dsi->header.dsi_requestID);
184   
185   /* make sure we don't over-write our buffers. */
186   *rlength = min(ntohl(dsi->header.dsi_len), ilength);
187   if (dsi_stream_read(dsi, buf, *rlength) != *rlength) 
188     return 0;
189
190   return block[1];
191 }