]> git.ipfire.org Git - thirdparty/squid.git/blame - lib/rfcnb/rfcnb-io.c
SourceFormat Enforcement
[thirdparty/squid.git] / lib / rfcnb / rfcnb-io.c
CommitLineData
f7f3304a 1#include "squid.h"
7c16470c
AJ
2
3/* UNIX RFCNB (RFC1001/RFC1002) NEtBIOS implementation
6ca34f6f
HN
4 *
5 * Version 1.0
6 * RFCNB IO Routines ...
7 *
8 * Copyright (C) Richard Sharpe 1996
9 *
10 */
7c16470c
AJ
11
12/*
6ca34f6f
HN
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 */
7c16470c
AJ
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
6ca34f6f 39int RFCNB_Timeout = 0; /* Timeout in seconds ... */
7c16470c 40
231fda33 41static int RFCNB_Discard_Rest(struct RFCNB_Con *con, int len);
7c16470c
AJ
42
43#ifdef NOT_USED
6ca34f6f
HN
44void
45rfcnb_alarm(int sig)
7c16470c
AJ
46{
47
48 fprintf(stderr, "IO Timed out ...\n");
49
50}
51
6ca34f6f 52#endif /* NOT_USED */
7c16470c 53
6ca34f6f
HN
54#ifdef NOT_USED
55/* Set timeout value and setup signal handling */
56int
57RFCNB_Set_Timeout(int seconds)
7c16470c
AJ
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
6ca34f6f 70 if (RFCNB_Timeout > 0) { /* Set up handler to ignore but not restart */
7c16470c
AJ
71
72#ifndef SA_RESTART
6ca34f6f 73 invec.sv_handler = (void (*)()) rfcnb_alarm;
7c16470c
AJ
74 invec.sv_mask = 0;
75 invec.sv_flags = SV_INTERRUPT;
76
6ca34f6f
HN
77 if (sigvec(SIGALRM, &invec, &outvec) < 0)
78 return (-1);
79#else /* !SA_RESTART */
80 inact.sa_handler = (void (*)()) rfcnb_alarm;
7c16470c
AJ
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;
6ca34f6f
HN
87#else /* !Solaris */
88 inact.sa_mask = (sigset_t) 0;
89#endif /* Solaris */
90 inact.sa_flags = 0; /* Don't restart */
7c16470c
AJ
91
92 if (sigaction(SIGALRM, &inact, &outact) < 0)
6ca34f6f 93 return (-1);
7c16470c 94
6ca34f6f 95#endif /* !SA_RESTART */
7c16470c
AJ
96
97 }
6ca34f6f 98#else /* !ORIGINAL_SAMBA_CODE ADAPTED SQUID CODE */
7c16470c
AJ
99#if HAVE_SIGACTION
100 struct sigaction inact, outact;
101#else
102 struct sigvec invec, outvec;
103#endif
3c96dd46 104
7c16470c
AJ
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);
6ca34f6f 116#else /* !HAVE_SIGACTION */
3c96dd46
A
117 invec.sv_handler = (void (*)()) rfcnb_alarm;
118 invec.sv_mask = 0;
119 invec.sv_flags = SV_INTERRUPT;
7c16470c 120
3c96dd46
A
121 if (sigvec(SIGALRM, &invec, &outvec) < 0)
122 return (-1);
6ca34f6f
HN
123#endif /* !HAVE_SIGACTION */
124 }
125#endif /* !ORIGINAL_SAMBA_CODE ADAPTED SQUID CODE */
126 return (0);
7c16470c 127}
6ca34f6f 128#endif /* NOT_USED */
7c16470c
AJ
129
130/* Discard the rest of an incoming packet as we do not have space for it
6ca34f6f 131 * in the buffer we allocated or were passed ... */
7c16470c 132
6ca34f6f
HN
133int
134RFCNB_Discard_Rest(struct RFCNB_Con *con, int len)
7c16470c 135{
6ca34f6f 136 char temp[100]; /* Read into here */
7c16470c
AJ
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
6ca34f6f 149 this_read = (rest > sizeof(temp) ? sizeof(temp) : rest);
7c16470c 150
6ca34f6f 151 bytes_read = read(con->fd, temp, this_read);
7c16470c 152
6ca34f6f 153 if (bytes_read <= 0) { /* Error so return */
7c16470c
AJ
154
155 if (bytes_read < 0)
156 RFCNB_errno = RFCNBE_BadRead;
157 else
158 RFCNB_errno = RFCNBE_ConGone;
159
160 RFCNB_saved_errno = errno;
6ca34f6f 161 return (RFCNBE_Bad);
7c16470c
AJ
162
163 }
7c16470c
AJ
164 rest = rest - bytes_read;
165
166 }
167
6ca34f6f 168 return (0);
7c16470c
AJ
169
170}
171
7c16470c 172/* Send an RFCNB packet to the connection.
6ca34f6f
HN
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
180int
181RFCNB_Put_Pkt(struct RFCNB_Con *con, struct RFCNB_Pkt *pkt, int len)
7c16470c
AJ
182{
183 int len_sent, tot_sent, this_len;
184 struct RFCNB_Pkt *pkt_ptr;
185 char *this_data;
186 int i;
6ca34f6f
HN
187 struct iovec io_list[10]; /* We should never have more */
188 /* If we do, this will blow up ... */
7c16470c
AJ
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
7c16470c 193 pkt_ptr = pkt;
6ca34f6f 194 len_sent = tot_sent = 0; /* Nothing sent so far */
7c16470c
AJ
195 i = 0;
196
6ca34f6f 197 while ((pkt_ptr != NULL) & (i < 10)) { /* Watch that magic number! */
7c16470c 198
6ca34f6f
HN
199 this_len = pkt_ptr->len;
200 this_data = pkt_ptr->data;
7c16470c 201 if ((tot_sent + this_len) > len)
6ca34f6f 202 this_len = len - tot_sent; /* Adjust so we don't send too much */
7c16470c
AJ
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
6ca34f6f
HN
212 if (tot_sent == len)
213 break; /* Let's not send too much */
7c16470c 214
6ca34f6f 215 pkt_ptr = pkt_ptr->next;
7c16470c
AJ
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
6ca34f6f 228 if ((len_sent = writev(con->fd, io_list, i)) < 0) { /* An error */
7c16470c 229
6ca34f6f
HN
230 con->errn = errno;
231 if (errno == EINTR) /* We were interrupted ... */
7c16470c
AJ
232 RFCNB_errno = RFCNBE_Timeout;
233 else
234 RFCNB_errno = RFCNBE_BadWrite;
235 RFCNB_saved_errno = errno;
6ca34f6f 236 return (RFCNBE_Bad);
7c16470c
AJ
237
238 }
6ca34f6f
HN
239 if (len_sent < tot_sent) { /* Less than we wanted */
240 if (errno == EINTR) /* We were interrupted */
7c16470c
AJ
241 RFCNB_errno = RFCNBE_Timeout;
242 else
243 RFCNB_errno = RFCNBE_BadWrite;
244 RFCNB_saved_errno = errno;
6ca34f6f 245 return (RFCNBE_Bad);
7c16470c 246 }
7c16470c 247 if (RFCNB_Timeout > 0)
6ca34f6f 248 alarm(0); /* Reset that sucker */
7c16470c
AJ
249
250#ifdef RFCNB_DEBUG
251
252 fprintf(stderr, "Len sent = %i ...\n", len_sent);
6ca34f6f 253 RFCNB_Print_Pkt(stderr, "sent", pkt, len_sent); /* Print what send ... */
7c16470c
AJ
254
255#endif
256
6ca34f6f 257 return (len_sent);
7c16470c
AJ
258
259}
260
261/* Read an RFCNB packet off the connection.
6ca34f6f
HN
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 */
7c16470c 267
6ca34f6f
HN
268int
269RFCNB_Get_Pkt(struct RFCNB_Con *con, struct RFCNB_Pkt *pkt, int len)
7c16470c
AJ
270{
271 int read_len, pkt_len;
6ca34f6f 272 char hdr[RFCNB_Pkt_Hdr_Len]; /* Local space for the header */
7c16470c
AJ
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
6ca34f6f 279 if (len < RFCNB_Pkt_Hdr_Len) { /* What a bozo */
7c16470c
AJ
280
281#ifdef RFCNB_DEBUG
282 fprintf(stderr, "Trying to read less than a packet:");
283 perror("");
284#endif
285 RFCNB_errno = RFCNBE_BadParam;
6ca34f6f 286 return (RFCNBE_Bad);
7c16470c
AJ
287
288 }
7c16470c
AJ
289 /* We discard keep alives here ... */
290
291 if (RFCNB_Timeout > 0)
292 alarm(RFCNB_Timeout);
293
294 while (seen_keep_alive) {
295
6ca34f6f 296 if ((read_len = read(con->fd, hdr, sizeof(hdr))) < 0) { /* Problems */
7c16470c
AJ
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;
6ca34f6f 306 return (RFCNBE_Bad);
7c16470c
AJ
307
308 }
7c16470c
AJ
309 /* Now we check out what we got */
310
6ca34f6f 311 if (read_len == 0) { /* Connection closed, send back eof? */
7c16470c
AJ
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;
6ca34f6f 322 return (RFCNBE_Bad);
7c16470c
AJ
323
324 }
7c16470c
AJ
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
6ca34f6f 339 if (read_len < sizeof(hdr)) { /* We got a small packet */
7c16470c
AJ
340
341 /* Now we need to copy the hdr portion we got into the supplied packet */
342
6ca34f6f 343 memcpy(pkt->data, hdr, read_len); /*Copy data */
7c16470c
AJ
344
345#ifdef RFCNB_DEBUG
346 RFCNB_Print_Pkt(stderr, "rcvd", pkt, read_len);
347#endif
348
6ca34f6f 349 return (read_len);
7c16470c
AJ
350
351 }
7c16470c
AJ
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
6ca34f6f 362 memcpy(pkt->data, hdr, sizeof(hdr));
7c16470c
AJ
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
6ca34f6f 368 if (len < pkt_len) /* Only get as much as we have space for */
7c16470c
AJ
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
6ca34f6f
HN
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 */
7c16470c 380 } else {
6ca34f6f
HN
381 pkt_frag = pkt; /* Otherwise use rest of this frag */
382 offset = RFCNB_Pkt_Hdr_Len; /* Otherwise skip the header */
7c16470c
AJ
383 }
384
6ca34f6f 385 frag_len = pkt_frag->len;
7c16470c 386
6ca34f6f 387 if (more <= frag_len) /* If len left to get less than frag space */
7c16470c
AJ
388 this_len = more; /* Get the rest ... */
389 else
390 this_len = frag_len - offset;
391
392 while (more > 0) {
393
6ca34f6f 394 if ((this_time = read(con->fd, (pkt_frag->data) + offset, this_len)) <= 0) { /* Problems */
7c16470c
AJ
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;
6ca34f6f 408 return (RFCNBE_Bad);
7c16470c
AJ
409
410 }
7c16470c
AJ
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
6ca34f6f 416 read_len = read_len + this_time; /* How much have we read ... */
7c16470c
AJ
417
418 /* Now set up the next part */
419
6ca34f6f
HN
420 if (pkt_frag->next == NULL)
421 break; /* That's it here */
7c16470c 422
6ca34f6f
HN
423 pkt_frag = pkt_frag->next;
424 this_len = pkt_frag->len;
7c16470c
AJ
425 offset = 0;
426
427 more = more - this_time;
428
429 }
430
431#ifdef RFCNB_DEBUG
6ca34f6f 432 fprintf(stderr, "Pkt Len = %i, read_len = %i\n", pkt_len, read_len);
7c16470c
AJ
433 RFCNB_Print_Pkt(stderr, "rcvd", pkt, read_len + sizeof(hdr));
434#endif
435
6ca34f6f 436 if (read_len < (pkt_len + sizeof(hdr))) { /* Discard the rest */
7c16470c 437
6ca34f6f 438 return (RFCNB_Discard_Rest(con, (pkt_len + sizeof(hdr)) - read_len));
7c16470c
AJ
439
440 }
7c16470c 441 if (RFCNB_Timeout > 0)
6ca34f6f 442 alarm(0); /* Reset that sucker */
7c16470c 443
6ca34f6f 444 return (read_len + sizeof(RFCNB_Hdr));
7c16470c 445}