]> git.ipfire.org Git - thirdparty/squid.git/blob - lib/rfcnb/rfcnb-io.c
SourceFormat Enforcement
[thirdparty/squid.git] / lib / rfcnb / rfcnb-io.c
1 /*
2 * Copyright (C) 1996-2017 The Squid Software Foundation and contributors
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 */
8
9 /* UNIX RFCNB (RFC1001/RFC1002) NEtBIOS implementation
10 *
11 * Version 1.0
12 * RFCNB IO Routines ...
13 *
14 * Copyright (C) Richard Sharpe 1996
15 */
16
17 /*
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 */
32
33 #include "squid.h"
34 #include "rfcnb/rfcnb-io.h"
35 #include "rfcnb/rfcnb-priv.h"
36 #include "rfcnb/rfcnb-util.h"
37 #include "rfcnb/std-includes.h"
38
39 #if HAVE_SIGNAL_H
40 #include <signal.h>
41 #endif
42 #if HAVE_STRING_H
43 #include <string.h>
44 #endif
45 #include <sys/uio.h>
46
47 int RFCNB_Timeout = 0; /* Timeout in seconds ... */
48
49 static int RFCNB_Discard_Rest(struct RFCNB_Con *con, int len);
50
51 #ifdef NOT_USED
52 void
53 rfcnb_alarm(int sig)
54 {
55
56 fprintf(stderr, "IO Timed out ...\n");
57
58 }
59
60 #endif /* NOT_USED */
61
62 #ifdef NOT_USED
63 /* Set timeout value and setup signal handling */
64 int
65 RFCNB_Set_Timeout(int seconds)
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
78 if (RFCNB_Timeout > 0) { /* Set up handler to ignore but not restart */
79
80 #ifndef SA_RESTART
81 invec.sv_handler = (void (*)()) rfcnb_alarm;
82 invec.sv_mask = 0;
83 invec.sv_flags = SV_INTERRUPT;
84
85 if (sigvec(SIGALRM, &invec, &outvec) < 0)
86 return (-1);
87 #else /* !SA_RESTART */
88 inact.sa_handler = (void (*)()) rfcnb_alarm;
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;
95 #else /* !Solaris */
96 inact.sa_mask = (sigset_t) 0;
97 #endif /* Solaris */
98 inact.sa_flags = 0; /* Don't restart */
99
100 if (sigaction(SIGALRM, &inact, &outact) < 0)
101 return (-1);
102
103 #endif /* !SA_RESTART */
104
105 }
106 #else /* !ORIGINAL_SAMBA_CODE ADAPTED SQUID CODE */
107 #if HAVE_SIGACTION
108 struct sigaction inact, outact;
109 #else
110 struct sigvec invec, outvec;
111 #endif
112
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);
124 #else /* !HAVE_SIGACTION */
125 invec.sv_handler = (void (*)()) rfcnb_alarm;
126 invec.sv_mask = 0;
127 invec.sv_flags = SV_INTERRUPT;
128
129 if (sigvec(SIGALRM, &invec, &outvec) < 0)
130 return (-1);
131 #endif /* !HAVE_SIGACTION */
132 }
133 #endif /* !ORIGINAL_SAMBA_CODE ADAPTED SQUID CODE */
134 return (0);
135 }
136 #endif /* NOT_USED */
137
138 /* Discard the rest of an incoming packet as we do not have space for it
139 * in the buffer we allocated or were passed ... */
140
141 int
142 RFCNB_Discard_Rest(struct RFCNB_Con *con, int len)
143 {
144 char temp[100]; /* Read into here */
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
157 this_read = (rest > sizeof(temp) ? sizeof(temp) : rest);
158
159 bytes_read = read(con->fd, temp, this_read);
160
161 if (bytes_read <= 0) { /* Error so return */
162
163 if (bytes_read < 0)
164 RFCNB_errno = RFCNBE_BadRead;
165 else
166 RFCNB_errno = RFCNBE_ConGone;
167
168 RFCNB_saved_errno = errno;
169 return (RFCNBE_Bad);
170
171 }
172 rest = rest - bytes_read;
173
174 }
175
176 return (0);
177
178 }
179
180 /* Send an RFCNB packet to the connection.
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
188 int
189 RFCNB_Put_Pkt(struct RFCNB_Con *con, struct RFCNB_Pkt *pkt, int len)
190 {
191 int len_sent, tot_sent, this_len;
192 struct RFCNB_Pkt *pkt_ptr;
193 char *this_data;
194 int i;
195 struct iovec io_list[10]; /* We should never have more */
196 /* If we do, this will blow up ... */
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
201 pkt_ptr = pkt;
202 len_sent = tot_sent = 0; /* Nothing sent so far */
203 i = 0;
204
205 while ((pkt_ptr != NULL) & (i < 10)) { /* Watch that magic number! */
206
207 this_len = pkt_ptr->len;
208 this_data = pkt_ptr->data;
209 if ((tot_sent + this_len) > len)
210 this_len = len - tot_sent; /* Adjust so we don't send too much */
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
220 if (tot_sent == len)
221 break; /* Let's not send too much */
222
223 pkt_ptr = pkt_ptr->next;
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
236 if ((len_sent = writev(con->fd, io_list, i)) < 0) { /* An error */
237
238 con->errn = errno;
239 if (errno == EINTR) /* We were interrupted ... */
240 RFCNB_errno = RFCNBE_Timeout;
241 else
242 RFCNB_errno = RFCNBE_BadWrite;
243 RFCNB_saved_errno = errno;
244 return (RFCNBE_Bad);
245
246 }
247 if (len_sent < tot_sent) { /* Less than we wanted */
248 if (errno == EINTR) /* We were interrupted */
249 RFCNB_errno = RFCNBE_Timeout;
250 else
251 RFCNB_errno = RFCNBE_BadWrite;
252 RFCNB_saved_errno = errno;
253 return (RFCNBE_Bad);
254 }
255 if (RFCNB_Timeout > 0)
256 alarm(0); /* Reset that sucker */
257
258 #ifdef RFCNB_DEBUG
259
260 fprintf(stderr, "Len sent = %i ...\n", len_sent);
261 RFCNB_Print_Pkt(stderr, "sent", pkt, len_sent); /* Print what send ... */
262
263 #endif
264
265 return (len_sent);
266
267 }
268
269 /* Read an RFCNB packet off the connection.
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 */
275
276 int
277 RFCNB_Get_Pkt(struct RFCNB_Con *con, struct RFCNB_Pkt *pkt, int len)
278 {
279 int read_len, pkt_len;
280 char hdr[RFCNB_Pkt_Hdr_Len]; /* Local space for the header */
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
287 if (len < RFCNB_Pkt_Hdr_Len) { /* What a bozo */
288
289 #ifdef RFCNB_DEBUG
290 fprintf(stderr, "Trying to read less than a packet:");
291 perror("");
292 #endif
293 RFCNB_errno = RFCNBE_BadParam;
294 return (RFCNBE_Bad);
295
296 }
297 /* We discard keep alives here ... */
298
299 if (RFCNB_Timeout > 0)
300 alarm(RFCNB_Timeout);
301
302 while (seen_keep_alive) {
303
304 if ((read_len = read(con->fd, hdr, sizeof(hdr))) < 0) { /* Problems */
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;
314 return (RFCNBE_Bad);
315
316 }
317 /* Now we check out what we got */
318
319 if (read_len == 0) { /* Connection closed, send back eof? */
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;
330 return (RFCNBE_Bad);
331
332 }
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
347 if (read_len < sizeof(hdr)) { /* We got a small packet */
348
349 /* Now we need to copy the hdr portion we got into the supplied packet */
350
351 memcpy(pkt->data, hdr, read_len); /*Copy data */
352
353 #ifdef RFCNB_DEBUG
354 RFCNB_Print_Pkt(stderr, "rcvd", pkt, read_len);
355 #endif
356
357 return (read_len);
358
359 }
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
370 memcpy(pkt->data, hdr, sizeof(hdr));
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
376 if (len < pkt_len) /* Only get as much as we have space for */
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
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 */
388 } else {
389 pkt_frag = pkt; /* Otherwise use rest of this frag */
390 offset = RFCNB_Pkt_Hdr_Len; /* Otherwise skip the header */
391 }
392
393 frag_len = (pkt_frag ? pkt_frag->len : 0);
394
395 if (more <= frag_len) /* If len left to get less than frag space */
396 this_len = more; /* Get the rest ... */
397 else
398 this_len = frag_len - offset;
399
400 while (more > 0) {
401
402 if ((this_time = read(con->fd, (pkt_frag->data) + offset, this_len)) <= 0) { /* Problems */
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;
416 return (RFCNBE_Bad);
417
418 }
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
424 read_len = read_len + this_time; /* How much have we read ... */
425
426 /* Now set up the next part */
427
428 if (pkt_frag->next == NULL)
429 break; /* That's it here */
430
431 pkt_frag = pkt_frag->next;
432 this_len = pkt_frag->len;
433 offset = 0;
434
435 more = more - this_time;
436
437 }
438
439 #ifdef RFCNB_DEBUG
440 fprintf(stderr, "Pkt Len = %i, read_len = %i\n", pkt_len, read_len);
441 RFCNB_Print_Pkt(stderr, "rcvd", pkt, read_len + sizeof(hdr));
442 #endif
443
444 if (read_len < (pkt_len + sizeof(hdr))) { /* Discard the rest */
445
446 return (RFCNB_Discard_Rest(con, (pkt_len + sizeof(hdr)) - read_len));
447
448 }
449 if (RFCNB_Timeout > 0)
450 alarm(0); /* Reset that sucker */
451
452 return (read_len + sizeof(RFCNB_Hdr));
453 }
454