]>
Commit | Line | Data |
---|---|---|
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 | 39 | int RFCNB_Timeout = 0; /* Timeout in seconds ... */ |
7c16470c | 40 | |
231fda33 | 41 | static int RFCNB_Discard_Rest(struct RFCNB_Con *con, int len); |
7c16470c AJ |
42 | |
43 | #ifdef NOT_USED | |
6ca34f6f HN |
44 | void |
45 | rfcnb_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 */ | |
56 | int | |
57 | RFCNB_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 |
133 | int |
134 | RFCNB_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 | ||
180 | int | |
181 | RFCNB_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 |
268 | int |
269 | RFCNB_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 | } |