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