chiark / gitweb /
debugging for thing that crashed
[innduct.git] / authprogs / smbval / rfcnb-io.c
1 /* UNIX RFCNB (RFC1001/RFC1002) NEtBIOS implementation
2
3    Version 1.0
4    RFCNB IO Routines ...
5
6    Copyright (C) Richard Sharpe 1996
7
8 */
9
10 /*
11    This program is free software; you can redistribute it and/or modify
12    it under the terms of the GNU General Public License as published by
13    the Free Software Foundation; either version 2 of the License, or
14    (at your option) any later version.
15    
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License for more details.
20    
21    You should have received a copy of the GNU General Public License
22    along with this program; if not, write to the Free Software
23    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26 #include "config.h"
27 #include "clibrary.h"
28 #include <errno.h>
29 #include <sys/uio.h>
30
31 #include "rfcnb-priv.h"
32 #include "rfcnb-util.h"
33 #include "rfcnb-io.h"
34
35 int RFCNB_Timeout = 0;    /* Timeout in seconds ... */
36
37 /* Discard the rest of an incoming packet as we do not have space for it
38    in the buffer we allocated or were passed ...                         */
39
40 int RFCNB_Discard_Rest(struct RFCNB_Con *con, int len)
41
42 { char temp[100];   /* Read into here */
43   int rest, this_read, bytes_read;
44
45   /* len is the amount we should read */
46
47   rest = len;
48
49   while (rest > 0) {
50
51     this_read = (rest > sizeof(temp)?sizeof(temp):rest);
52
53     bytes_read = read(con -> fd, temp, this_read);
54
55     if (bytes_read <= 0) { /* Error so return */
56
57       if (bytes_read < 0) 
58         RFCNB_errno = RFCNBE_BadRead;
59       else
60         RFCNB_errno = RFCNBE_ConGone;
61
62       RFCNB_saved_errno = errno;
63       return(RFCNBE_Bad);
64
65     }
66     
67     rest = rest - bytes_read;
68
69   }
70
71   return(0);
72
73 }
74
75
76 /* Send an RFCNB packet to the connection.
77
78    We just send each of the blocks linked together ... 
79
80    If we can, try to send it as one iovec ... 
81
82 */
83
84 int RFCNB_Put_Pkt(struct RFCNB_Con *con, struct RFCNB_Pkt *pkt, int len)
85
86 { int len_sent, tot_sent, this_len;
87   struct RFCNB_Pkt *pkt_ptr;
88   char *this_data;
89   int i;
90   struct iovec io_list[10];          /* We should never have more      */
91                                      /* If we do, this will blow up ...*/
92
93   /* Try to send the data ... We only send as many bytes as len claims */
94   /* We should try to stuff it into an IOVEC and send as one write     */
95
96
97   pkt_ptr = pkt;
98   len_sent =  tot_sent = 0;             /* Nothing sent so far */
99   i = 0;
100
101   while ((pkt_ptr != NULL) & (i < 10)) {  /* Watch that magic number! */
102
103     this_len = pkt_ptr -> len;
104     this_data = pkt_ptr -> data;
105     if ((tot_sent + this_len) > len) 
106       this_len = len - tot_sent;        /* Adjust so we don't send too much */
107
108     /* Now plug into the iovec ... */
109
110     io_list[i].iov_len = this_len;
111     io_list[i].iov_base = this_data;
112     i++;
113
114     tot_sent += this_len;
115
116     if (tot_sent == len) break;   /* Let's not send too much */
117
118     pkt_ptr = pkt_ptr -> next;
119
120   }
121
122   /* Set up an alarm if timeouts are set ... */
123
124   if (RFCNB_Timeout > 0) 
125     alarm(RFCNB_Timeout);
126
127   if ((len_sent = writev(con -> fd, io_list, i)) < 0) { /* An error */
128
129     con -> rfc_errno = errno;
130     if (errno == EINTR)  /* We were interrupted ... */
131       RFCNB_errno = RFCNBE_Timeout;
132     else
133       RFCNB_errno = RFCNBE_BadWrite;
134     RFCNB_saved_errno = errno;
135     return(RFCNBE_Bad);
136
137   }
138
139   if (len_sent < tot_sent) { /* Less than we wanted */
140     if (errno == EINTR)      /* We were interrupted */
141       RFCNB_errno = RFCNBE_Timeout;
142     else
143       RFCNB_errno = RFCNBE_BadWrite;
144     RFCNB_saved_errno = errno;
145     return(RFCNBE_Bad);
146   }
147
148   if (RFCNB_Timeout > 0)
149     alarm(0);                /* Reset that sucker */
150
151   return(len_sent);
152
153 }
154
155 /* Read an RFCNB packet off the connection. 
156
157    We read the first 4 bytes, that tells us the length, then read the
158    rest. We should implement a timeout, but we don't just yet 
159
160 */
161
162
163 int RFCNB_Get_Pkt(struct RFCNB_Con *con, struct RFCNB_Pkt *pkt, int len)
164
165 { int read_len, pkt_len;
166   char hdr[RFCNB_Pkt_Hdr_Len];      /* Local space for the header */
167   struct RFCNB_Pkt *pkt_frag;
168   int more, this_time, offset, frag_len, this_len;
169   bool seen_keep_alive = true;
170
171   /* Read that header straight into the buffer */
172
173   if (len < RFCNB_Pkt_Hdr_Len) { /* What a bozo */
174
175     RFCNB_errno = RFCNBE_BadParam;
176     return(RFCNBE_Bad);
177
178   }
179
180   /* We discard keep alives here ... */
181
182   if (RFCNB_Timeout > 0) 
183     alarm(RFCNB_Timeout);
184
185   while (seen_keep_alive) {
186
187     if ((read_len = read(con -> fd, hdr, sizeof(hdr))) < 0) { /* Problems */
188       if (errno == EINTR)
189         RFCNB_errno = RFCNBE_Timeout;
190       else
191         RFCNB_errno = RFCNBE_BadRead;
192       RFCNB_saved_errno = errno;
193       return(RFCNBE_Bad);
194
195     }
196
197     /* Now we check out what we got */
198
199     if (read_len == 0) { /* Connection closed, send back eof?  */
200
201       if (errno == EINTR) 
202         RFCNB_errno = RFCNBE_Timeout;
203       else
204         RFCNB_errno = RFCNBE_ConGone;
205       RFCNB_saved_errno = errno;
206       return(RFCNBE_Bad);
207
208     }
209
210     if (RFCNB_Pkt_Type(hdr) != RFCNB_SESSION_KEEP_ALIVE) {
211       seen_keep_alive = false;
212     }
213
214   }
215  
216   /* What if we got less than or equal to a hdr size in bytes? */
217
218   if (read_len < sizeof(hdr)) { /* We got a small packet */
219
220     /* Now we need to copy the hdr portion we got into the supplied packet */
221
222     memcpy(pkt -> data, hdr, read_len);  /*Copy data */
223
224     return(read_len);
225
226   }
227
228   /* Now, if we got at least a hdr size, alloc space for rest, if we need it */
229
230   pkt_len = RFCNB_Pkt_Len(hdr);
231
232   /* Now copy in the hdr */
233
234   memcpy(pkt -> data, hdr, sizeof(hdr));
235
236   /* Get the rest of the packet ... first figure out how big our buf is? */
237   /* And make sure that we handle the fragments properly ... Sure should */
238   /* use an iovec ...                                                    */
239
240   if (len < pkt_len)            /* Only get as much as we have space for */
241     more = len - RFCNB_Pkt_Hdr_Len;
242   else
243     more = pkt_len;
244
245   this_time = 0;
246
247   /* We read for each fragment ... */
248
249   if (pkt -> len == read_len){     /* If this frag was exact size */
250     pkt_frag = pkt -> next;        /* Stick next lot in next frag */
251     offset = 0;                    /* then we start at 0 in next  */
252   }
253   else {
254     pkt_frag = pkt;                /* Otherwise use rest of this frag */
255     offset = RFCNB_Pkt_Hdr_Len;    /* Otherwise skip the header       */
256   }
257
258   frag_len = pkt_frag -> len;
259
260   if (more <= frag_len)     /* If len left to get less than frag space */
261     this_len = more;        /* Get the rest ...                        */
262   else
263     this_len = frag_len - offset;
264
265   while (more > 0) {
266
267     if ((this_time = read(con -> fd, (pkt_frag -> data) + offset, this_len)) <= 0) { /* Problems */
268
269       if (errno == EINTR) {
270
271         RFCNB_errno = RFCNB_Timeout;
272
273       }
274       else {
275         if (this_time < 0)
276           RFCNB_errno = RFCNBE_BadRead;
277         else
278           RFCNB_errno = RFCNBE_ConGone;
279       }
280
281       RFCNB_saved_errno = errno;
282       return(RFCNBE_Bad);
283
284     }
285
286     read_len = read_len + this_time;  /* How much have we read ... */
287
288     /* Now set up the next part */
289
290     if (pkt_frag -> next == NULL) break;       /* That's it here */
291
292     pkt_frag = pkt_frag -> next;
293     this_len = pkt_frag -> len;
294     offset = 0;
295
296     more = more - this_time;
297
298   }
299
300   if (read_len < (pkt_len + sizeof(hdr))) {  /* Discard the rest */
301
302     return(RFCNB_Discard_Rest(con, (pkt_len + sizeof(hdr)) - read_len));
303
304   }
305
306   if (RFCNB_Timeout > 0)
307     alarm(0);                /* Reset that sucker */
308
309   return(read_len + sizeof(RFCNB_Hdr));
310 }