]> arthur.barton.de Git - netatalk.git/blob - libatalk/dsi/dsi_stream.c
sendfile for LARGE_FILE. use sys_ftruncate in ad_open too, temporary fix with
[netatalk.git] / libatalk / dsi / dsi_stream.c
1 /*
2  * $Id: dsi_stream.c,v 1.11.6.1 2003-10-17 00:01:14 didg Exp $
3  *
4  * Copyright (c) 1998 Adrian Sun (asun@zoology.washington.edu)
5  * All rights reserved. See COPYRIGHT.
6  *
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.
12  */
13
14 #ifdef HAVE_CONFIG_H
15 #include "config.h"
16 #endif /* HAVE_CONFIG_H */
17
18 #define USE_WRITEV
19
20 #include <stdio.h>
21 #include <stdlib.h>
22
23 #ifdef HAVE_UNISTD_H
24 #include <unistd.h>
25 #endif
26
27 #include <string.h>
28 #include <errno.h>
29 #include <sys/types.h>
30 #include <sys/socket.h>
31
32 #ifdef USE_WRITEV
33 #include <sys/uio.h>
34 #endif
35
36 #include <atalk/logger.h>
37
38 #include <atalk/dsi.h>
39 #include <netatalk/endian.h>
40
41 #define min(a,b)  ((a) < (b) ? (a) : (b))
42
43 #ifndef MSG_MORE
44 #define MSG_MORE 0x8000
45 #endif
46
47 /* write raw data. return actual bytes read. checks against EINTR
48  * aren't necessary if all of the signals have SA_RESTART
49  * specified. */
50 size_t dsi_stream_write(DSI *dsi, void *data, const size_t length, int mode)
51 {
52   size_t written;
53   ssize_t len;
54   unsigned int flags = (mode)?MSG_MORE:0;
55
56   written = 0;
57   while (written < length) {
58     if ((-1 == (len = send(dsi->socket, (u_int8_t *) data + written,
59                       length - written, flags)) && errno == EINTR) ||
60         !len)
61       continue;
62
63     if (len < 0) {
64       LOG(log_error, logtype_default, "dsi_stream_write: %s", strerror(errno));
65       break;
66     }
67     
68     written += len;
69   }
70
71   dsi->write_count += written;
72   return written;
73 }
74
75 /* ---------------------------------------
76  * read raw data. return actual bytes read. this will wait until 
77  * it gets length bytes 
78  */
79 size_t dsi_stream_read(DSI *dsi, void *data, const size_t length)
80 {
81   size_t stored;
82   ssize_t len;
83   
84   stored = 0;
85   while (stored < length) {
86     len = read(dsi->socket, (u_int8_t *) data + stored, length - stored);
87     if (len == -1 && errno == EINTR)
88       continue;
89     else if (len > 0)
90       stored += len;
91     else { /* eof or error */
92       LOG(log_error, logtype_default, "dsi_stream_read(%d): %s", len, (len < 0)?strerror(errno):"unexpected EOF");
93       break;
94     }
95   }
96
97   dsi->read_count += stored;
98   return stored;
99 }
100
101 /* ---------------------------------------
102 */
103 void dsi_sleep(DSI *dsi, const int state)
104 {
105     dsi->asleep = state;
106 }
107
108 /* ---------------------------------------
109 */
110 static void block_sig(DSI *dsi)
111 {
112   if (!dsi->sigblocked) sigprocmask(SIG_BLOCK, &dsi->sigblockset, &dsi->oldset);
113 }
114
115 /* ---------------------------------------
116 */
117 static void unblock_sig(DSI *dsi)
118 {
119   if (!dsi->sigblocked) sigprocmask(SIG_SETMASK, &dsi->oldset, NULL);
120 }
121
122 /* ---------------------------------------
123  * write data. 0 on failure. this assumes that dsi_len will never
124  * cause an overflow in the data buffer. 
125  */
126 int dsi_stream_send(DSI *dsi, void *buf, size_t length)
127 {
128   char block[DSI_BLOCKSIZ];
129 #ifdef USE_WRITEV
130   struct iovec iov[2];
131   size_t towrite;
132   ssize_t len;
133 #endif /* USE_WRITEV */
134
135   block[0] = dsi->header.dsi_flags;
136   block[1] = dsi->header.dsi_command;
137   memcpy(block + 2, &dsi->header.dsi_requestID, 
138          sizeof(dsi->header.dsi_requestID));
139   memcpy(block + 4, &dsi->header.dsi_code, sizeof(dsi->header.dsi_code));
140   memcpy(block + 8, &dsi->header.dsi_len, sizeof(dsi->header.dsi_len));
141   memcpy(block + 12, &dsi->header.dsi_reserved,
142          sizeof(dsi->header.dsi_reserved));
143
144   /* block signals */
145   block_sig(dsi);
146
147   if (!length) { /* just write the header */
148     length = (dsi_stream_write(dsi, block, sizeof(block), 0) == sizeof(block));
149     unblock_sig(dsi);
150     return length; /* really 0 on failure, 1 on success */
151   }
152   
153 #ifdef USE_WRITEV
154   iov[0].iov_base = block;
155   iov[0].iov_len = sizeof(block);
156   iov[1].iov_base = buf;
157   iov[1].iov_len = length;
158   
159   towrite = sizeof(block) + length;
160   dsi->write_count += towrite;
161   while (towrite > 0) {
162     if (((len = writev(dsi->socket, iov, 2)) == -1 && errno == EINTR) || 
163         !len)
164       continue;
165     
166     if (len == towrite) /* wrote everything out */
167       break;
168     else if (len < 0) { /* error */
169       LOG(log_error, logtype_default, "dsi_stream_send: %s", strerror(errno));
170       unblock_sig(dsi);
171       return 0;
172     }
173     
174     towrite -= len;
175     if (towrite > length) { /* skip part of header */
176       iov[0].iov_base = (char *) iov[0].iov_base + len;
177       iov[0].iov_len -= len;
178     } else { /* skip to data */
179       if (iov[0].iov_len) {
180         len -= iov[0].iov_len;
181         iov[0].iov_len = 0;
182       }
183       iov[1].iov_base = (char *) iov[1].iov_base + len;
184       iov[1].iov_len -= len;
185     }
186   }
187   
188 #else /* USE_WRITEV */
189   /* write the header then data */
190   if ((dsi_stream_write(dsi, block, sizeof(block), 1) != sizeof(block)) ||
191             (dsi_stream_write(dsi, buf, length, 0) != length)) {
192       unblock_sig(dsi);
193       return 0;
194   }
195 #endif /* USE_WRITEV */
196
197   unblock_sig(dsi);
198   return 1;
199 }
200
201
202 /* ---------------------------------------
203  * read data. function on success. 0 on failure. data length gets
204  * stored in length variable. this should really use size_t's, but
205  * that would require changes elsewhere. */
206 int dsi_stream_receive(DSI *dsi, void *buf, const size_t ilength,
207                        size_t *rlength)
208 {
209   char block[DSI_BLOCKSIZ];
210
211   /* read in the header */
212   if (dsi_stream_read(dsi, block, sizeof(block)) != sizeof(block)) 
213     return 0;
214
215   dsi->header.dsi_flags = block[0];
216   dsi->header.dsi_command = block[1];
217   /* FIXME, not the right place, 
218      but we get a server disconnect without reason in the log
219   */
220   if (!block[1]) {
221       LOG(log_error, logtype_default, "dsi_stream_receive: invalid packet, fatal");
222       return 0;
223   }
224
225   memcpy(&dsi->header.dsi_requestID, block + 2, 
226          sizeof(dsi->header.dsi_requestID));
227   memcpy(&dsi->header.dsi_code, block + 4, sizeof(dsi->header.dsi_code));
228   memcpy(&dsi->header.dsi_len, block + 8, sizeof(dsi->header.dsi_len));
229   memcpy(&dsi->header.dsi_reserved, block + 12,
230          sizeof(dsi->header.dsi_reserved));
231   dsi->clientID = ntohs(dsi->header.dsi_requestID);
232   
233   /* make sure we don't over-write our buffers. */
234   *rlength = min(ntohl(dsi->header.dsi_len), ilength);
235   if (dsi_stream_read(dsi, buf, *rlength) != *rlength) 
236     return 0;
237
238   return block[1];
239 }