]>
git.ipfire.org Git - thirdparty/squid.git/blob - lib/rfcnb/rfcnb-io.c
2 * Copyright (C) 1996-2014 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"
43 #include <sys/signal.h>
45 int RFCNB_Timeout
= 0; /* Timeout in seconds ... */
47 static int RFCNB_Discard_Rest(struct RFCNB_Con
*con
, int len
);
54 fprintf(stderr
, "IO Timed out ...\n");
61 /* Set timeout value and setup signal handling */
63 RFCNB_Set_Timeout(int seconds
)
65 /* If we are on a Bezerkeley system, use sigvec, else sigaction */
67 #if ORIGINAL_SAMBA_CODE
69 struct sigvec invec
, outvec
;
71 struct sigaction inact
, outact
;
74 RFCNB_Timeout
= seconds
;
76 if (RFCNB_Timeout
> 0) { /* Set up handler to ignore but not restart */
79 invec
.sv_handler
= (void (*)()) rfcnb_alarm
;
81 invec
.sv_flags
= SV_INTERRUPT
;
83 if (sigvec(SIGALRM
, &invec
, &outvec
) < 0)
85 #else /* !SA_RESTART */
86 inact
.sa_handler
= (void (*)()) rfcnb_alarm
;
88 /* Solaris seems to have an array of vectors ... */
89 inact
.sa_mask
.__sigbits
[0] = 0;
90 inact
.sa_mask
.__sigbits
[1] = 0;
91 inact
.sa_mask
.__sigbits
[2] = 0;
92 inact
.sa_mask
.__sigbits
[3] = 0;
94 inact
.sa_mask
= (sigset_t
) 0;
96 inact
.sa_flags
= 0; /* Don't restart */
98 if (sigaction(SIGALRM
, &inact
, &outact
) < 0)
101 #endif /* !SA_RESTART */
104 #else /* !ORIGINAL_SAMBA_CODE ADAPTED SQUID CODE */
106 struct sigaction inact
, outact
;
108 struct sigvec invec
, outvec
;
111 RFCNB_Timeout
= seconds
;
113 if (RFCNB_Timeout
> 0) { /* Set up handler to ignore but not restart */
116 inact
.sa_handler
= (void (*)()) rfcnb_alarm
;
117 sigemptyset(&inact
.sa_mask
);
118 inact
.sa_flags
= 0; /* Don't restart */
120 if (sigaction(SIGALRM
, &inact
, &outact
) < 0)
122 #else /* !HAVE_SIGACTION */
123 invec
.sv_handler
= (void (*)()) rfcnb_alarm
;
125 invec
.sv_flags
= SV_INTERRUPT
;
127 if (sigvec(SIGALRM
, &invec
, &outvec
) < 0)
129 #endif /* !HAVE_SIGACTION */
131 #endif /* !ORIGINAL_SAMBA_CODE ADAPTED SQUID CODE */
134 #endif /* NOT_USED */
136 /* Discard the rest of an incoming packet as we do not have space for it
137 * in the buffer we allocated or were passed ... */
140 RFCNB_Discard_Rest(struct RFCNB_Con
*con
, int len
)
142 char temp
[100]; /* Read into here */
143 int rest
, this_read
, bytes_read
;
145 /* len is the amount we should read */
148 fprintf(stderr
, "Discard_Rest called to discard: %i\n", len
);
155 this_read
= (rest
> sizeof(temp
) ? sizeof(temp
) : rest
);
157 bytes_read
= read(con
->fd
, temp
, this_read
);
159 if (bytes_read
<= 0) { /* Error so return */
162 RFCNB_errno
= RFCNBE_BadRead
;
164 RFCNB_errno
= RFCNBE_ConGone
;
166 RFCNB_saved_errno
= errno
;
170 rest
= rest
- bytes_read
;
178 /* Send an RFCNB packet to the connection.
180 * We just send each of the blocks linked together ...
182 * If we can, try to send it as one iovec ...
187 RFCNB_Put_Pkt(struct RFCNB_Con
*con
, struct RFCNB_Pkt
*pkt
, int len
)
189 int len_sent
, tot_sent
, this_len
;
190 struct RFCNB_Pkt
*pkt_ptr
;
193 struct iovec io_list
[10]; /* We should never have more */
194 /* If we do, this will blow up ... */
196 /* Try to send the data ... We only send as many bytes as len claims */
197 /* We should try to stuff it into an IOVEC and send as one write */
200 len_sent
= tot_sent
= 0; /* Nothing sent so far */
203 while ((pkt_ptr
!= NULL
) & (i
< 10)) { /* Watch that magic number! */
205 this_len
= pkt_ptr
->len
;
206 this_data
= pkt_ptr
->data
;
207 if ((tot_sent
+ this_len
) > len
)
208 this_len
= len
- tot_sent
; /* Adjust so we don't send too much */
210 /* Now plug into the iovec ... */
212 io_list
[i
].iov_len
= this_len
;
213 io_list
[i
].iov_base
= this_data
;
216 tot_sent
+= this_len
;
219 break; /* Let's not send too much */
221 pkt_ptr
= pkt_ptr
->next
;
226 fprintf(stderr
, "Frags = %i, tot_sent = %i\n", i
, tot_sent
);
229 /* Set up an alarm if timeouts are set ... */
231 if (RFCNB_Timeout
> 0)
232 alarm(RFCNB_Timeout
);
234 if ((len_sent
= writev(con
->fd
, io_list
, i
)) < 0) { /* An error */
237 if (errno
== EINTR
) /* We were interrupted ... */
238 RFCNB_errno
= RFCNBE_Timeout
;
240 RFCNB_errno
= RFCNBE_BadWrite
;
241 RFCNB_saved_errno
= errno
;
245 if (len_sent
< tot_sent
) { /* Less than we wanted */
246 if (errno
== EINTR
) /* We were interrupted */
247 RFCNB_errno
= RFCNBE_Timeout
;
249 RFCNB_errno
= RFCNBE_BadWrite
;
250 RFCNB_saved_errno
= errno
;
253 if (RFCNB_Timeout
> 0)
254 alarm(0); /* Reset that sucker */
258 fprintf(stderr
, "Len sent = %i ...\n", len_sent
);
259 RFCNB_Print_Pkt(stderr
, "sent", pkt
, len_sent
); /* Print what send ... */
267 /* Read an RFCNB packet off the connection.
269 * We read the first 4 bytes, that tells us the length, then read the
270 * rest. We should implement a timeout, but we don't just yet
275 RFCNB_Get_Pkt(struct RFCNB_Con
*con
, struct RFCNB_Pkt
*pkt
, int len
)
277 int read_len
, pkt_len
;
278 char hdr
[RFCNB_Pkt_Hdr_Len
]; /* Local space for the header */
279 struct RFCNB_Pkt
*pkt_frag
;
280 int more
, this_time
, offset
, frag_len
, this_len
;
281 BOOL seen_keep_alive
= TRUE
;
283 /* Read that header straight into the buffer */
285 if (len
< RFCNB_Pkt_Hdr_Len
) { /* What a bozo */
288 fprintf(stderr
, "Trying to read less than a packet:");
291 RFCNB_errno
= RFCNBE_BadParam
;
295 /* We discard keep alives here ... */
297 if (RFCNB_Timeout
> 0)
298 alarm(RFCNB_Timeout
);
300 while (seen_keep_alive
) {
302 if ((read_len
= read(con
->fd
, hdr
, sizeof(hdr
))) < 0) { /* Problems */
304 fprintf(stderr
, "Reading the packet, we got:");
308 RFCNB_errno
= RFCNBE_Timeout
;
310 RFCNB_errno
= RFCNBE_BadRead
;
311 RFCNB_saved_errno
= errno
;
315 /* Now we check out what we got */
317 if (read_len
== 0) { /* Connection closed, send back eof? */
320 fprintf(stderr
, "Connection closed reading\n");
324 RFCNB_errno
= RFCNBE_Timeout
;
326 RFCNB_errno
= RFCNBE_ConGone
;
327 RFCNB_saved_errno
= errno
;
331 if (RFCNB_Pkt_Type(hdr
) == RFCNB_SESSION_KEEP_ALIVE
) {
334 fprintf(stderr
, "RFCNB KEEP ALIVE received\n");
338 seen_keep_alive
= FALSE
;
343 /* What if we got less than or equal to a hdr size in bytes? */
345 if (read_len
< sizeof(hdr
)) { /* We got a small packet */
347 /* Now we need to copy the hdr portion we got into the supplied packet */
349 memcpy(pkt
->data
, hdr
, read_len
); /*Copy data */
352 RFCNB_Print_Pkt(stderr
, "rcvd", pkt
, read_len
);
358 /* Now, if we got at least a hdr size, alloc space for rest, if we need it */
360 pkt_len
= RFCNB_Pkt_Len(hdr
);
363 fprintf(stderr
, "Reading Pkt: Length = %i\n", pkt_len
);
366 /* Now copy in the hdr */
368 memcpy(pkt
->data
, hdr
, sizeof(hdr
));
370 /* Get the rest of the packet ... first figure out how big our buf is? */
371 /* And make sure that we handle the fragments properly ... Sure should */
372 /* use an iovec ... */
374 if (len
< pkt_len
) /* Only get as much as we have space for */
375 more
= len
- RFCNB_Pkt_Hdr_Len
;
381 /* We read for each fragment ... */
383 if (pkt
->len
== read_len
) { /* If this frag was exact size */
384 pkt_frag
= pkt
->next
; /* Stick next lot in next frag */
385 offset
= 0; /* then we start at 0 in next */
387 pkt_frag
= pkt
; /* Otherwise use rest of this frag */
388 offset
= RFCNB_Pkt_Hdr_Len
; /* Otherwise skip the header */
391 frag_len
= (pkt_frag
? pkt_frag
->len
: 0);
393 if (more
<= frag_len
) /* If len left to get less than frag space */
394 this_len
= more
; /* Get the rest ... */
396 this_len
= frag_len
- offset
;
400 if ((this_time
= read(con
->fd
, (pkt_frag
->data
) + offset
, this_len
)) <= 0) { /* Problems */
402 if (errno
== EINTR
) {
404 RFCNB_errno
= RFCNB_Timeout
;
408 RFCNB_errno
= RFCNBE_BadRead
;
410 RFCNB_errno
= RFCNBE_ConGone
;
413 RFCNB_saved_errno
= errno
;
418 fprintf(stderr
, "Frag_Len = %i, this_time = %i, this_len = %i, more = %i\n", frag_len
,
419 this_time
, this_len
, more
);
422 read_len
= read_len
+ this_time
; /* How much have we read ... */
424 /* Now set up the next part */
426 if (pkt_frag
->next
== NULL
)
427 break; /* That's it here */
429 pkt_frag
= pkt_frag
->next
;
430 this_len
= pkt_frag
->len
;
433 more
= more
- this_time
;
438 fprintf(stderr
, "Pkt Len = %i, read_len = %i\n", pkt_len
, read_len
);
439 RFCNB_Print_Pkt(stderr
, "rcvd", pkt
, read_len
+ sizeof(hdr
));
442 if (read_len
< (pkt_len
+ sizeof(hdr
))) { /* Discard the rest */
444 return (RFCNB_Discard_Rest(con
, (pkt_len
+ sizeof(hdr
)) - read_len
));
447 if (RFCNB_Timeout
> 0)
448 alarm(0); /* Reset that sucker */
450 return (read_len
+ sizeof(RFCNB_Hdr
));