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