1 /* UNIX RFCNB (RFC1001/RFC1002) NEtBIOS implementation
6 Copyright (C) Richard Sharpe 1996
7 Copyright 2006 The FreeRADIUS server project
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 2 of the License, or
15 (at your option) any later version.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 #include <freeradius-devel/ident.h>
30 /* #include <features.h> */
31 #include "std-includes.h"
32 #include "rfcnb-priv.h"
33 #include "rfcnb-util.h"
40 #ifdef HAVE_SYS_SIGNAL_H
41 #include <sys/signal.h>
46 int RFCNB_Timeout = 0; /* Timeout in seconds ... */
48 void rfcnb_alarm(int sig)
52 fprintf(stderr, "IO Timed out ...\n");
56 /* Set timeout value and setup signal handling */
58 int RFCNB_Set_Timeout(int seconds)
61 /* If we are on a Bezerkeley system, use sigvec, else sigaction */
63 struct sigvec invec, outvec;
65 struct sigaction inact, outact;
68 RFCNB_Timeout = seconds;
70 if (RFCNB_Timeout > 0) { /* Set up handler to ignore but not restart */
73 invec.sv_handler = (void (*)())rfcnb_alarm;
75 invec.sv_flags = SV_INTERRUPT;
77 if (sigvec(SIGALRM, &invec, &outvec) < 0)
80 inact.sa_handler = (void (*)())rfcnb_alarm;
81 sigemptyset(&inact.sa_mask);
82 inact.sa_flags = 0; /* Don't restart */
84 if (sigaction(SIGALRM, &inact, &outact) < 0)
95 /* Discard the rest of an incoming packet as we do not have space for it
96 in the buffer we allocated or were passed ... */
98 int RFCNB_Discard_Rest(struct RFCNB_Con *con, int len)
100 { char temp[100]; /* Read into here */
101 int rest, this_read, bytes_read;
103 /* len is the amount we should read */
106 fprintf(stderr, "Discard_Rest called to discard: %i\n", len);
113 this_read = (rest > sizeof(temp)?sizeof(temp):rest);
115 bytes_read = read(con -> fd, temp, this_read);
117 if (bytes_read <= 0) { /* Error so return */
120 RFCNB_errno = RFCNBE_BadRead;
122 RFCNB_errno = RFCNBE_ConGone;
124 RFCNB_saved_errno = errno;
129 rest = rest - bytes_read;
138 /* Send an RFCNB packet to the connection.
140 We just send each of the blocks linked together ...
142 If we can, try to send it as one iovec ...
146 int RFCNB_Put_Pkt(struct RFCNB_Con *con, struct RFCNB_Pkt *pkt, int len)
148 { int len_sent, tot_sent, this_len;
149 struct RFCNB_Pkt *pkt_ptr;
152 struct iovec io_list[10]; /* We should never have more */
153 /* If we do, this will blow up ...*/
155 /* Try to send the data ... We only send as many bytes as len claims */
156 /* We should try to stuff it into an IOVEC and send as one write */
160 len_sent = tot_sent = 0; /* Nothing sent so far */
163 while ((pkt_ptr != NULL) & (i < 10)) { /* Watch that magic number! */
165 this_len = pkt_ptr -> len;
166 this_data = pkt_ptr -> data;
167 if ((tot_sent + this_len) > len)
168 this_len = len - tot_sent; /* Adjust so we don't send too much */
170 /* Now plug into the iovec ... */
172 io_list[i].iov_len = this_len;
173 io_list[i].iov_base = this_data;
176 tot_sent += this_len;
178 if (tot_sent == len) break; /* Let's not send too much */
180 pkt_ptr = pkt_ptr -> next;
185 fprintf(stderr, "Frags = %i, tot_sent = %i\n", i, tot_sent);
188 /* Set up an alarm if timeouts are set ... */
190 if (RFCNB_Timeout > 0)
191 alarm(RFCNB_Timeout);
193 if ((len_sent = writev(con -> fd, io_list, i)) < 0) { /* An error */
195 con -> rfc_errno = errno;
196 if (errno == EINTR) /* We were interrupted ... */
197 RFCNB_errno = RFCNBE_Timeout;
199 RFCNB_errno = RFCNBE_BadWrite;
200 RFCNB_saved_errno = errno;
205 if (len_sent < tot_sent) { /* Less than we wanted */
206 if (errno == EINTR) /* We were interrupted */
207 RFCNB_errno = RFCNBE_Timeout;
209 RFCNB_errno = RFCNBE_BadWrite;
210 RFCNB_saved_errno = errno;
214 if (RFCNB_Timeout > 0)
215 alarm(0); /* Reset that sucker */
219 fprintf(stderr, "Len sent = %i ...\n", len_sent);
220 RFCNB_Print_Pkt(stderr, "sent", pkt, len_sent); /* Print what send ... */
228 /* Read an RFCNB packet off the connection.
230 We read the first 4 bytes, that tells us the length, then read the
231 rest. We should implement a timeout, but we don't just yet
236 int RFCNB_Get_Pkt(struct RFCNB_Con *con, struct RFCNB_Pkt *pkt, int len)
238 { int read_len, pkt_len;
239 char hdr[RFCNB_Pkt_Hdr_Len]; /* Local space for the header */
240 struct RFCNB_Pkt *pkt_frag;
241 int more, this_time, offset, frag_len, this_len;
242 BOOL seen_keep_alive = TRUE;
244 /* Read that header straight into the buffer */
246 if (len < RFCNB_Pkt_Hdr_Len) { /* What a bozo */
249 fprintf(stderr, "Trying to read less than a packet:");
252 RFCNB_errno = RFCNBE_BadParam;
257 /* We discard keep alives here ... */
259 if (RFCNB_Timeout > 0)
260 alarm(RFCNB_Timeout);
262 while (seen_keep_alive) {
264 if ((read_len = read(con -> fd, hdr, sizeof(hdr))) < 0) { /* Problems */
266 fprintf(stderr, "Reading the packet, we got:");
270 RFCNB_errno = RFCNBE_Timeout;
272 RFCNB_errno = RFCNBE_BadRead;
273 RFCNB_saved_errno = errno;
278 /* Now we check out what we got */
280 if (read_len == 0) { /* Connection closed, send back eof? */
283 fprintf(stderr, "Connection closed reading\n");
287 RFCNB_errno = RFCNBE_Timeout;
289 RFCNB_errno = RFCNBE_ConGone;
290 RFCNB_saved_errno = errno;
295 if (RFCNB_Pkt_Type(hdr) == RFCNB_SESSION_KEEP_ALIVE) {
298 fprintf(stderr, "RFCNB KEEP ALIVE received\n");
303 seen_keep_alive = FALSE;
308 /* What if we got less than or equal to a hdr size in bytes? */
310 if (read_len < sizeof(hdr)) { /* We got a small packet */
312 /* Now we need to copy the hdr portion we got into the supplied packet */
314 memcpy(pkt -> data, hdr, read_len); /*Copy data */
317 RFCNB_Print_Pkt(stderr, "rcvd", pkt, read_len);
324 /* Now, if we got at least a hdr size, alloc space for rest, if we need it */
326 pkt_len = RFCNB_Pkt_Len(hdr);
329 fprintf(stderr, "Reading Pkt: Length = %i\n", pkt_len);
332 /* Now copy in the hdr */
334 memcpy(pkt -> data, hdr, sizeof(hdr));
336 /* Get the rest of the packet ... first figure out how big our buf is? */
337 /* And make sure that we handle the fragments properly ... Sure should */
338 /* use an iovec ... */
340 if (len < pkt_len) /* Only get as much as we have space for */
341 more = len - RFCNB_Pkt_Hdr_Len;
347 /* We read for each fragment ... */
349 if (pkt -> len == read_len){ /* If this frag was exact size */
350 pkt_frag = pkt -> next; /* Stick next lot in next frag */
351 offset = 0; /* then we start at 0 in next */
354 pkt_frag = pkt; /* Otherwise use rest of this frag */
355 offset = RFCNB_Pkt_Hdr_Len; /* Otherwise skip the header */
358 frag_len = pkt_frag -> len;
360 if (more <= frag_len) /* If len left to get less than frag space */
361 this_len = more; /* Get the rest ... */
363 this_len = frag_len - offset;
367 if ((this_time = read(con -> fd, (pkt_frag -> data) + offset, this_len)) <= 0) { /* Problems */
369 if (errno == EINTR) {
371 RFCNB_errno = RFCNB_Timeout;
376 RFCNB_errno = RFCNBE_BadRead;
378 RFCNB_errno = RFCNBE_ConGone;
381 RFCNB_saved_errno = errno;
387 fprintf(stderr, "Frag_Len = %i, this_time = %i, this_len = %i, more = %i\n", frag_len,
388 this_time, this_len, more);
391 read_len = read_len + this_time; /* How much have we read ... */
393 /* Now set up the next part */
395 if (pkt_frag -> next == NULL) break; /* That's it here */
397 pkt_frag = pkt_frag -> next;
398 this_len = pkt_frag -> len;
401 more = more - this_time;
406 fprintf(stderr,"Pkt Len = %i, read_len = %i\n", pkt_len, read_len);
407 RFCNB_Print_Pkt(stderr, "rcvd", pkt, read_len + sizeof(hdr));
410 if (read_len < (pkt_len + sizeof(hdr))) { /* Discard the rest */
412 return(RFCNB_Discard_Rest(con, (pkt_len + sizeof(hdr)) - read_len));
416 if (RFCNB_Timeout > 0)
417 alarm(0); /* Reset that sucker */
419 return(read_len + sizeof(RFCNB_Hdr));