]> git.ipfire.org Git - thirdparty/squid.git/blob - lib/rfcnb/rfcnb-io.c
SourceFormat Enforcement
[thirdparty/squid.git] / lib / rfcnb / rfcnb-io.c
1 #include "squid.h"
2
3 /* UNIX RFCNB (RFC1001/RFC1002) NEtBIOS implementation
4 *
5 * Version 1.0
6 * RFCNB IO Routines ...
7 *
8 * Copyright (C) Richard Sharpe 1996
9 *
10 */
11
12 /*
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 */
27
28 #include "rfcnb/std-includes.h"
29 #include "rfcnb/rfcnb-priv.h"
30 #include "rfcnb/rfcnb-util.h"
31 #include "rfcnb/rfcnb-io.h"
32 #include <sys/uio.h>
33 #include <sys/signal.h>
34
35 #if HAVE_STRING_H
36 #include <string.h>
37 #endif
38
39 int RFCNB_Timeout = 0; /* Timeout in seconds ... */
40
41 static int RFCNB_Discard_Rest(struct RFCNB_Con *con, int len);
42
43 #ifdef NOT_USED
44 void
45 rfcnb_alarm(int sig)
46 {
47
48 fprintf(stderr, "IO Timed out ...\n");
49
50 }
51
52 #endif /* NOT_USED */
53
54 #ifdef NOT_USED
55 /* Set timeout value and setup signal handling */
56 int
57 RFCNB_Set_Timeout(int seconds)
58 {
59 /* If we are on a Bezerkeley system, use sigvec, else sigaction */
60
61 #if ORIGINAL_SAMBA_CODE
62 #ifndef SA_RESTART
63 struct sigvec invec, outvec;
64 #else
65 struct sigaction inact, outact;
66 #endif
67
68 RFCNB_Timeout = seconds;
69
70 if (RFCNB_Timeout > 0) { /* Set up handler to ignore but not restart */
71
72 #ifndef SA_RESTART
73 invec.sv_handler = (void (*)()) rfcnb_alarm;
74 invec.sv_mask = 0;
75 invec.sv_flags = SV_INTERRUPT;
76
77 if (sigvec(SIGALRM, &invec, &outvec) < 0)
78 return (-1);
79 #else /* !SA_RESTART */
80 inact.sa_handler = (void (*)()) rfcnb_alarm;
81 #ifdef Solaris
82 /* Solaris seems to have an array of vectors ... */
83 inact.sa_mask.__sigbits[0] = 0;
84 inact.sa_mask.__sigbits[1] = 0;
85 inact.sa_mask.__sigbits[2] = 0;
86 inact.sa_mask.__sigbits[3] = 0;
87 #else /* !Solaris */
88 inact.sa_mask = (sigset_t) 0;
89 #endif /* Solaris */
90 inact.sa_flags = 0; /* Don't restart */
91
92 if (sigaction(SIGALRM, &inact, &outact) < 0)
93 return (-1);
94
95 #endif /* !SA_RESTART */
96
97 }
98 #else /* !ORIGINAL_SAMBA_CODE ADAPTED SQUID CODE */
99 #if HAVE_SIGACTION
100 struct sigaction inact, outact;
101 #else
102 struct sigvec invec, outvec;
103 #endif
104
105 RFCNB_Timeout = seconds;
106
107 if (RFCNB_Timeout > 0) { /* Set up handler to ignore but not restart */
108
109 #if HAVE_SIGACTION
110 inact.sa_handler = (void (*)()) rfcnb_alarm;
111 sigemptyset(&inact.sa_mask);
112 inact.sa_flags = 0; /* Don't restart */
113
114 if (sigaction(SIGALRM, &inact, &outact) < 0)
115 return (-1);
116 #else /* !HAVE_SIGACTION */
117 invec.sv_handler = (void (*)()) rfcnb_alarm;
118 invec.sv_mask = 0;
119 invec.sv_flags = SV_INTERRUPT;
120
121 if (sigvec(SIGALRM, &invec, &outvec) < 0)
122 return (-1);
123 #endif /* !HAVE_SIGACTION */
124 }
125 #endif /* !ORIGINAL_SAMBA_CODE ADAPTED SQUID CODE */
126 return (0);
127 }
128 #endif /* NOT_USED */
129
130 /* Discard the rest of an incoming packet as we do not have space for it
131 * in the buffer we allocated or were passed ... */
132
133 int
134 RFCNB_Discard_Rest(struct RFCNB_Con *con, int len)
135 {
136 char temp[100]; /* Read into here */
137 int rest, this_read, bytes_read;
138
139 /* len is the amount we should read */
140
141 #ifdef RFCNB_DEBUG
142 fprintf(stderr, "Discard_Rest called to discard: %i\n", len);
143 #endif
144
145 rest = len;
146
147 while (rest > 0) {
148
149 this_read = (rest > sizeof(temp) ? sizeof(temp) : rest);
150
151 bytes_read = read(con->fd, temp, this_read);
152
153 if (bytes_read <= 0) { /* Error so return */
154
155 if (bytes_read < 0)
156 RFCNB_errno = RFCNBE_BadRead;
157 else
158 RFCNB_errno = RFCNBE_ConGone;
159
160 RFCNB_saved_errno = errno;
161 return (RFCNBE_Bad);
162
163 }
164 rest = rest - bytes_read;
165
166 }
167
168 return (0);
169
170 }
171
172 /* Send an RFCNB packet to the connection.
173 *
174 * We just send each of the blocks linked together ...
175 *
176 * If we can, try to send it as one iovec ...
177 *
178 */
179
180 int
181 RFCNB_Put_Pkt(struct RFCNB_Con *con, struct RFCNB_Pkt *pkt, int len)
182 {
183 int len_sent, tot_sent, this_len;
184 struct RFCNB_Pkt *pkt_ptr;
185 char *this_data;
186 int i;
187 struct iovec io_list[10]; /* We should never have more */
188 /* If we do, this will blow up ... */
189
190 /* Try to send the data ... We only send as many bytes as len claims */
191 /* We should try to stuff it into an IOVEC and send as one write */
192
193 pkt_ptr = pkt;
194 len_sent = tot_sent = 0; /* Nothing sent so far */
195 i = 0;
196
197 while ((pkt_ptr != NULL) & (i < 10)) { /* Watch that magic number! */
198
199 this_len = pkt_ptr->len;
200 this_data = pkt_ptr->data;
201 if ((tot_sent + this_len) > len)
202 this_len = len - tot_sent; /* Adjust so we don't send too much */
203
204 /* Now plug into the iovec ... */
205
206 io_list[i].iov_len = this_len;
207 io_list[i].iov_base = this_data;
208 i++;
209
210 tot_sent += this_len;
211
212 if (tot_sent == len)
213 break; /* Let's not send too much */
214
215 pkt_ptr = pkt_ptr->next;
216
217 }
218
219 #ifdef RFCNB_DEBUG
220 fprintf(stderr, "Frags = %i, tot_sent = %i\n", i, tot_sent);
221 #endif
222
223 /* Set up an alarm if timeouts are set ... */
224
225 if (RFCNB_Timeout > 0)
226 alarm(RFCNB_Timeout);
227
228 if ((len_sent = writev(con->fd, io_list, i)) < 0) { /* An error */
229
230 con->errn = errno;
231 if (errno == EINTR) /* We were interrupted ... */
232 RFCNB_errno = RFCNBE_Timeout;
233 else
234 RFCNB_errno = RFCNBE_BadWrite;
235 RFCNB_saved_errno = errno;
236 return (RFCNBE_Bad);
237
238 }
239 if (len_sent < tot_sent) { /* Less than we wanted */
240 if (errno == EINTR) /* We were interrupted */
241 RFCNB_errno = RFCNBE_Timeout;
242 else
243 RFCNB_errno = RFCNBE_BadWrite;
244 RFCNB_saved_errno = errno;
245 return (RFCNBE_Bad);
246 }
247 if (RFCNB_Timeout > 0)
248 alarm(0); /* Reset that sucker */
249
250 #ifdef RFCNB_DEBUG
251
252 fprintf(stderr, "Len sent = %i ...\n", len_sent);
253 RFCNB_Print_Pkt(stderr, "sent", pkt, len_sent); /* Print what send ... */
254
255 #endif
256
257 return (len_sent);
258
259 }
260
261 /* Read an RFCNB packet off the connection.
262 *
263 * We read the first 4 bytes, that tells us the length, then read the
264 * rest. We should implement a timeout, but we don't just yet
265 *
266 */
267
268 int
269 RFCNB_Get_Pkt(struct RFCNB_Con *con, struct RFCNB_Pkt *pkt, int len)
270 {
271 int read_len, pkt_len;
272 char hdr[RFCNB_Pkt_Hdr_Len]; /* Local space for the header */
273 struct RFCNB_Pkt *pkt_frag;
274 int more, this_time, offset, frag_len, this_len;
275 BOOL seen_keep_alive = TRUE;
276
277 /* Read that header straight into the buffer */
278
279 if (len < RFCNB_Pkt_Hdr_Len) { /* What a bozo */
280
281 #ifdef RFCNB_DEBUG
282 fprintf(stderr, "Trying to read less than a packet:");
283 perror("");
284 #endif
285 RFCNB_errno = RFCNBE_BadParam;
286 return (RFCNBE_Bad);
287
288 }
289 /* We discard keep alives here ... */
290
291 if (RFCNB_Timeout > 0)
292 alarm(RFCNB_Timeout);
293
294 while (seen_keep_alive) {
295
296 if ((read_len = read(con->fd, hdr, sizeof(hdr))) < 0) { /* Problems */
297 #ifdef RFCNB_DEBUG
298 fprintf(stderr, "Reading the packet, we got:");
299 perror("");
300 #endif
301 if (errno == EINTR)
302 RFCNB_errno = RFCNBE_Timeout;
303 else
304 RFCNB_errno = RFCNBE_BadRead;
305 RFCNB_saved_errno = errno;
306 return (RFCNBE_Bad);
307
308 }
309 /* Now we check out what we got */
310
311 if (read_len == 0) { /* Connection closed, send back eof? */
312
313 #ifdef RFCNB_DEBUG
314 fprintf(stderr, "Connection closed reading\n");
315 #endif
316
317 if (errno == EINTR)
318 RFCNB_errno = RFCNBE_Timeout;
319 else
320 RFCNB_errno = RFCNBE_ConGone;
321 RFCNB_saved_errno = errno;
322 return (RFCNBE_Bad);
323
324 }
325 if (RFCNB_Pkt_Type(hdr) == RFCNB_SESSION_KEEP_ALIVE) {
326
327 #ifdef RFCNB_DEBUG
328 fprintf(stderr, "RFCNB KEEP ALIVE received\n");
329 #endif
330
331 } else {
332 seen_keep_alive = FALSE;
333 }
334
335 }
336
337 /* What if we got less than or equal to a hdr size in bytes? */
338
339 if (read_len < sizeof(hdr)) { /* We got a small packet */
340
341 /* Now we need to copy the hdr portion we got into the supplied packet */
342
343 memcpy(pkt->data, hdr, read_len); /*Copy data */
344
345 #ifdef RFCNB_DEBUG
346 RFCNB_Print_Pkt(stderr, "rcvd", pkt, read_len);
347 #endif
348
349 return (read_len);
350
351 }
352 /* Now, if we got at least a hdr size, alloc space for rest, if we need it */
353
354 pkt_len = RFCNB_Pkt_Len(hdr);
355
356 #ifdef RFCNB_DEBUG
357 fprintf(stderr, "Reading Pkt: Length = %i\n", pkt_len);
358 #endif
359
360 /* Now copy in the hdr */
361
362 memcpy(pkt->data, hdr, sizeof(hdr));
363
364 /* Get the rest of the packet ... first figure out how big our buf is? */
365 /* And make sure that we handle the fragments properly ... Sure should */
366 /* use an iovec ... */
367
368 if (len < pkt_len) /* Only get as much as we have space for */
369 more = len - RFCNB_Pkt_Hdr_Len;
370 else
371 more = pkt_len;
372
373 this_time = 0;
374
375 /* We read for each fragment ... */
376
377 if (pkt->len == read_len) { /* If this frag was exact size */
378 pkt_frag = pkt->next; /* Stick next lot in next frag */
379 offset = 0; /* then we start at 0 in next */
380 } else {
381 pkt_frag = pkt; /* Otherwise use rest of this frag */
382 offset = RFCNB_Pkt_Hdr_Len; /* Otherwise skip the header */
383 }
384
385 frag_len = pkt_frag->len;
386
387 if (more <= frag_len) /* If len left to get less than frag space */
388 this_len = more; /* Get the rest ... */
389 else
390 this_len = frag_len - offset;
391
392 while (more > 0) {
393
394 if ((this_time = read(con->fd, (pkt_frag->data) + offset, this_len)) <= 0) { /* Problems */
395
396 if (errno == EINTR) {
397
398 RFCNB_errno = RFCNB_Timeout;
399
400 } else {
401 if (this_time < 0)
402 RFCNB_errno = RFCNBE_BadRead;
403 else
404 RFCNB_errno = RFCNBE_ConGone;
405 }
406
407 RFCNB_saved_errno = errno;
408 return (RFCNBE_Bad);
409
410 }
411 #ifdef RFCNB_DEBUG
412 fprintf(stderr, "Frag_Len = %i, this_time = %i, this_len = %i, more = %i\n", frag_len,
413 this_time, this_len, more);
414 #endif
415
416 read_len = read_len + this_time; /* How much have we read ... */
417
418 /* Now set up the next part */
419
420 if (pkt_frag->next == NULL)
421 break; /* That's it here */
422
423 pkt_frag = pkt_frag->next;
424 this_len = pkt_frag->len;
425 offset = 0;
426
427 more = more - this_time;
428
429 }
430
431 #ifdef RFCNB_DEBUG
432 fprintf(stderr, "Pkt Len = %i, read_len = %i\n", pkt_len, read_len);
433 RFCNB_Print_Pkt(stderr, "rcvd", pkt, read_len + sizeof(hdr));
434 #endif
435
436 if (read_len < (pkt_len + sizeof(hdr))) { /* Discard the rest */
437
438 return (RFCNB_Discard_Rest(con, (pkt_len + sizeof(hdr)) - read_len));
439
440 }
441 if (RFCNB_Timeout > 0)
442 alarm(0); /* Reset that sucker */
443
444 return (read_len + sizeof(RFCNB_Hdr));
445 }