]>
git.ipfire.org Git - thirdparty/squid.git/blob - lib/rfcnb/rfcnb-io.c
2 * Copyright (C) 1996-2016 The Squid Software Foundation and contributors
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.
9 /* UNIX RFCNB (RFC1001/RFC1002) NEtBIOS implementation
12 * RFCNB IO Routines ...
14 * Copyright (C) Richard Sharpe 1996
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.
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.
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.
34 #include "rfcnb/rfcnb-io.h"
35 #include "rfcnb/rfcnb-priv.h"
36 #include "rfcnb/rfcnb-util.h"
37 #include "rfcnb/std-includes.h"
47 int RFCNB_Timeout
= 0; /* Timeout in seconds ... */
49 static int RFCNB_Discard_Rest(struct RFCNB_Con
*con
, int len
);
56 fprintf(stderr
, "IO Timed out ...\n");
63 /* Set timeout value and setup signal handling */
65 RFCNB_Set_Timeout(int seconds
)
67 /* If we are on a Bezerkeley system, use sigvec, else sigaction */
69 #if ORIGINAL_SAMBA_CODE
71 struct sigvec invec
, outvec
;
73 struct sigaction inact
, outact
;
76 RFCNB_Timeout
= seconds
;
78 if (RFCNB_Timeout
> 0) { /* Set up handler to ignore but not restart */
81 invec
.sv_handler
= (void (*)()) rfcnb_alarm
;
83 invec
.sv_flags
= SV_INTERRUPT
;
85 if (sigvec(SIGALRM
, &invec
, &outvec
) < 0)
87 #else /* !SA_RESTART */
88 inact
.sa_handler
= (void (*)()) rfcnb_alarm
;
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;
96 inact
.sa_mask
= (sigset_t
) 0;
98 inact
.sa_flags
= 0; /* Don't restart */
100 if (sigaction(SIGALRM
, &inact
, &outact
) < 0)
103 #endif /* !SA_RESTART */
106 #else /* !ORIGINAL_SAMBA_CODE ADAPTED SQUID CODE */
108 struct sigaction inact
, outact
;
110 struct sigvec invec
, outvec
;
113 RFCNB_Timeout
= seconds
;
115 if (RFCNB_Timeout
> 0) { /* Set up handler to ignore but not restart */
118 inact
.sa_handler
= (void (*)()) rfcnb_alarm
;
119 sigemptyset(&inact
.sa_mask
);
120 inact
.sa_flags
= 0; /* Don't restart */
122 if (sigaction(SIGALRM
, &inact
, &outact
) < 0)
124 #else /* !HAVE_SIGACTION */
125 invec
.sv_handler
= (void (*)()) rfcnb_alarm
;
127 invec
.sv_flags
= SV_INTERRUPT
;
129 if (sigvec(SIGALRM
, &invec
, &outvec
) < 0)
131 #endif /* !HAVE_SIGACTION */
133 #endif /* !ORIGINAL_SAMBA_CODE ADAPTED SQUID CODE */
136 #endif /* NOT_USED */
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 ... */
142 RFCNB_Discard_Rest(struct RFCNB_Con
*con
, int len
)
144 char temp
[100]; /* Read into here */
145 int rest
, this_read
, bytes_read
;
147 /* len is the amount we should read */
150 fprintf(stderr
, "Discard_Rest called to discard: %i\n", len
);
157 this_read
= (rest
> sizeof(temp
) ? sizeof(temp
) : rest
);
159 bytes_read
= read(con
->fd
, temp
, this_read
);
161 if (bytes_read
<= 0) { /* Error so return */
164 RFCNB_errno
= RFCNBE_BadRead
;
166 RFCNB_errno
= RFCNBE_ConGone
;
168 RFCNB_saved_errno
= errno
;
172 rest
= rest
- bytes_read
;
180 /* Send an RFCNB packet to the connection.
182 * We just send each of the blocks linked together ...
184 * If we can, try to send it as one iovec ...
189 RFCNB_Put_Pkt(struct RFCNB_Con
*con
, struct RFCNB_Pkt
*pkt
, int len
)
191 int len_sent
, tot_sent
, this_len
;
192 struct RFCNB_Pkt
*pkt_ptr
;
195 struct iovec io_list
[10]; /* We should never have more */
196 /* If we do, this will blow up ... */
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 */
202 len_sent
= tot_sent
= 0; /* Nothing sent so far */
205 while ((pkt_ptr
!= NULL
) & (i
< 10)) { /* Watch that magic number! */
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 */
212 /* Now plug into the iovec ... */
214 io_list
[i
].iov_len
= this_len
;
215 io_list
[i
].iov_base
= this_data
;
218 tot_sent
+= this_len
;
221 break; /* Let's not send too much */
223 pkt_ptr
= pkt_ptr
->next
;
228 fprintf(stderr
, "Frags = %i, tot_sent = %i\n", i
, tot_sent
);
231 /* Set up an alarm if timeouts are set ... */
233 if (RFCNB_Timeout
> 0)
234 alarm(RFCNB_Timeout
);
236 if ((len_sent
= writev(con
->fd
, io_list
, i
)) < 0) { /* An error */
239 if (errno
== EINTR
) /* We were interrupted ... */
240 RFCNB_errno
= RFCNBE_Timeout
;
242 RFCNB_errno
= RFCNBE_BadWrite
;
243 RFCNB_saved_errno
= errno
;
247 if (len_sent
< tot_sent
) { /* Less than we wanted */
248 if (errno
== EINTR
) /* We were interrupted */
249 RFCNB_errno
= RFCNBE_Timeout
;
251 RFCNB_errno
= RFCNBE_BadWrite
;
252 RFCNB_saved_errno
= errno
;
255 if (RFCNB_Timeout
> 0)
256 alarm(0); /* Reset that sucker */
260 fprintf(stderr
, "Len sent = %i ...\n", len_sent
);
261 RFCNB_Print_Pkt(stderr
, "sent", pkt
, len_sent
); /* Print what send ... */
269 /* Read an RFCNB packet off the connection.
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
277 RFCNB_Get_Pkt(struct RFCNB_Con
*con
, struct RFCNB_Pkt
*pkt
, int len
)
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
;
285 /* Read that header straight into the buffer */
287 if (len
< RFCNB_Pkt_Hdr_Len
) { /* What a bozo */
290 fprintf(stderr
, "Trying to read less than a packet:");
293 RFCNB_errno
= RFCNBE_BadParam
;
297 /* We discard keep alives here ... */
299 if (RFCNB_Timeout
> 0)
300 alarm(RFCNB_Timeout
);
302 while (seen_keep_alive
) {
304 if ((read_len
= read(con
->fd
, hdr
, sizeof(hdr
))) < 0) { /* Problems */
306 fprintf(stderr
, "Reading the packet, we got:");
310 RFCNB_errno
= RFCNBE_Timeout
;
312 RFCNB_errno
= RFCNBE_BadRead
;
313 RFCNB_saved_errno
= errno
;
317 /* Now we check out what we got */
319 if (read_len
== 0) { /* Connection closed, send back eof? */
322 fprintf(stderr
, "Connection closed reading\n");
326 RFCNB_errno
= RFCNBE_Timeout
;
328 RFCNB_errno
= RFCNBE_ConGone
;
329 RFCNB_saved_errno
= errno
;
333 if (RFCNB_Pkt_Type(hdr
) == RFCNB_SESSION_KEEP_ALIVE
) {
336 fprintf(stderr
, "RFCNB KEEP ALIVE received\n");
340 seen_keep_alive
= FALSE
;
345 /* What if we got less than or equal to a hdr size in bytes? */
347 if (read_len
< sizeof(hdr
)) { /* We got a small packet */
349 /* Now we need to copy the hdr portion we got into the supplied packet */
351 memcpy(pkt
->data
, hdr
, read_len
); /*Copy data */
354 RFCNB_Print_Pkt(stderr
, "rcvd", pkt
, read_len
);
360 /* Now, if we got at least a hdr size, alloc space for rest, if we need it */
362 pkt_len
= RFCNB_Pkt_Len(hdr
);
365 fprintf(stderr
, "Reading Pkt: Length = %i\n", pkt_len
);
368 /* Now copy in the hdr */
370 memcpy(pkt
->data
, hdr
, sizeof(hdr
));
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 ... */
376 if (len
< pkt_len
) /* Only get as much as we have space for */
377 more
= len
- RFCNB_Pkt_Hdr_Len
;
383 /* We read for each fragment ... */
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 */
389 pkt_frag
= pkt
; /* Otherwise use rest of this frag */
390 offset
= RFCNB_Pkt_Hdr_Len
; /* Otherwise skip the header */
393 frag_len
= (pkt_frag
? pkt_frag
->len
: 0);
395 if (more
<= frag_len
) /* If len left to get less than frag space */
396 this_len
= more
; /* Get the rest ... */
398 this_len
= frag_len
- offset
;
402 if ((this_time
= read(con
->fd
, (pkt_frag
->data
) + offset
, this_len
)) <= 0) { /* Problems */
404 if (errno
== EINTR
) {
406 RFCNB_errno
= RFCNB_Timeout
;
410 RFCNB_errno
= RFCNBE_BadRead
;
412 RFCNB_errno
= RFCNBE_ConGone
;
415 RFCNB_saved_errno
= errno
;
420 fprintf(stderr
, "Frag_Len = %i, this_time = %i, this_len = %i, more = %i\n", frag_len
,
421 this_time
, this_len
, more
);
424 read_len
= read_len
+ this_time
; /* How much have we read ... */
426 /* Now set up the next part */
428 if (pkt_frag
->next
== NULL
)
429 break; /* That's it here */
431 pkt_frag
= pkt_frag
->next
;
432 this_len
= pkt_frag
->len
;
435 more
= more
- this_time
;
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
));
444 if (read_len
< (pkt_len
+ sizeof(hdr
))) { /* Discard the rest */
446 return (RFCNB_Discard_Rest(con
, (pkt_len
+ sizeof(hdr
)) - read_len
));
449 if (RFCNB_Timeout
> 0)
450 alarm(0); /* Reset that sucker */
452 return (read_len
+ sizeof(RFCNB_Hdr
));