]> git.ipfire.org Git - thirdparty/squid.git/blob - lib/rfcnb/session.c
Merge form trunk
[thirdparty/squid.git] / lib / rfcnb / session.c
1 #include "config.h"
2
3 /* UNIX RFCNB (RFC1001/RFC1002) NetBIOS implementation
4
5 Version 1.0
6 Session Routines ...
7
8 Copyright (C) Richard Sharpe 1996
9
10 */
11
12 /*
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 */
27
28 int RFCNB_errno = 0;
29 int RFCNB_saved_errno = 0;
30 #define RFCNB_ERRNO
31
32 #include "rfcnb/std-includes.h"
33 #include <netinet/tcp.h>
34 #include "rfcnb/rfcnb.h"
35 #include "rfcnb/rfcnb-priv.h"
36 #include "rfcnb/rfcnb-io.h"
37 #include "rfcnb/rfcnb-util.h"
38
39 #if HAVE_STRING_H
40 #include <string.h>
41 #endif
42
43 int RFCNB_Stats[RFCNB_MAX_STATS];
44
45 void (*Prot_Print_Routine)() = NULL; /* Pointer to print routine */
46
47 int RFCNB_Get_Last_Errno(void);
48 int RFCNB_Get_Error_Msg(int code, char *msg_buf, int len);
49 void RFCNB_Register_Print_Routine(void (*fn)());
50
51 /* Set up a session with a remote name. We are passed Called_Name as a
52 string which we convert to a NetBIOS name, ie space terminated, up to
53 16 characters only if we need to. If Called_Address is not empty, then
54 we use it to connect to the remote end, but put in Called_Name ... Called
55 Address can be a DNS based name, or a TCP/IP address ...
56 */
57
58 void *RFCNB_Call(char *Called_Name, char *Calling_Name, char *Called_Address,
59 int port)
60
61 {
62 struct RFCNB_Con *con;
63 struct in_addr Dest_IP;
64 int Client;
65 BOOL redirect;
66 struct redirect_addr *redir_addr;
67 char *Service_Address;
68
69 /* Now, we really should look up the port in /etc/services ... */
70
71 if (port == 0) port = RFCNB_Default_Port;
72
73 /* Create a connection structure first */
74
75 if ((con = (struct RFCNB_Con *)malloc(sizeof(struct RFCNB_Con))) == NULL) { /* Error in size */
76
77 RFCNB_errno = RFCNBE_NoSpace;
78 RFCNB_saved_errno = errno;
79 return(NULL);
80
81 }
82
83 con -> fd = -0; /* no descriptor yet */
84 con -> errn = 0; /* no error yet */
85 con -> timeout = 0; /* no timeout */
86 con -> redirects = 0;
87
88 /* Resolve that name into an IP address */
89
90 Service_Address = Called_Name;
91 if (strcmp(Called_Address, "") != 0) { /* If the Called Address = "" */
92 Service_Address = Called_Address;
93 }
94
95 if ((errno = RFCNB_Name_To_IP(Service_Address, &Dest_IP)) < 0) { /* Error */
96
97 /* No need to modify RFCNB_errno as it was done by RFCNB_Name_To_IP */
98 free(con);
99 return(NULL);
100
101 }
102
103 /* Now connect to the remote end */
104
105 redirect = TRUE; /* Fudge this one so we go once through */
106
107 while (redirect) { /* Connect and get session info etc */
108
109 redirect = FALSE; /* Assume all OK */
110
111 /* Build the redirect info. First one is first addr called */
112 /* And tack it onto the list of addresses we called */
113
114 if ((redir_addr = (struct redirect_addr *)malloc(sizeof(struct redirect_addr))) == NULL) { /* Could not get space */
115
116 RFCNB_errno = RFCNBE_NoSpace;
117 RFCNB_saved_errno = errno;
118 free(con);
119 return(NULL);
120
121 }
122
123 memcpy((char *)&(redir_addr -> ip_addr), (char *)&Dest_IP, sizeof(Dest_IP));
124 redir_addr -> port = port;
125 redir_addr -> next = NULL;
126
127 if (con -> redirect_list == NULL) { /* Stick on head */
128
129 con -> redirect_list = con -> last_addr = redir_addr;
130
131 } else {
132
133 con -> last_addr -> next = redir_addr;
134 con -> last_addr = redir_addr;
135
136 }
137
138 /* Now, make that connection */
139
140 if ((Client = RFCNB_IP_Connect(Dest_IP, port)) < 0) { /* Error */
141
142 /* No need to modify RFCNB_errno as it was done by RFCNB_IP_Connect */
143 free(con);
144 return(NULL);
145
146 }
147
148 con -> fd = Client;
149
150 /* Now send and handle the RFCNB session request */
151 /* If we get a redirect, we will comeback with redirect true
152 and a new IP address in DEST_IP */
153
154 if ((errno = RFCNB_Session_Req(con,
155 Called_Name,
156 Calling_Name,
157 &redirect, &Dest_IP, &port)) < 0) {
158
159 /* No need to modify RFCNB_errno as it was done by RFCNB_Session.. */
160
161 RFCNB_Close(con->fd); /* Close it */
162 free(con);
163 return(NULL);
164
165 }
166
167 if (redirect) {
168
169 /* We have to close the connection, and then try again */
170
171 (con -> redirects)++;
172
173 RFCNB_Close(con -> fd); /* Close it */
174
175 }
176 }
177
178 return(con);
179
180 }
181
182 /* We send a packet to the other end ... for the moment, we treat the
183 data as a series of pointers to blocks of data ... we should check the
184 length ... */
185
186 int RFCNB_Send(struct RFCNB_Con *Con_Handle, struct RFCNB_Pkt *udata, int Length)
187
188 {
189 struct RFCNB_Pkt *pkt;
190 char *hdr;
191 int len;
192
193 /* Plug in the header and send the data */
194
195 pkt = RFCNB_Alloc_Pkt(RFCNB_Pkt_Hdr_Len);
196
197 if (pkt == NULL) {
198
199 RFCNB_errno = RFCNBE_NoSpace;
200 RFCNB_saved_errno = errno;
201 return(RFCNBE_Bad);
202
203 }
204
205 pkt -> next = udata; /* The user data we want to send */
206
207 hdr = pkt -> data;
208
209 /* Following crap is for portability across multiple UNIX machines */
210
211 *(hdr + RFCNB_Pkt_Type_Offset) = RFCNB_SESSION_MESSAGE;
212 RFCNB_Put_Pkt_Len(hdr, Length);
213
214 #ifdef RFCNB_DEBUG
215
216 fprintf(stderr, "Sending packet: ");
217
218 #endif
219
220 if ((len = RFCNB_Put_Pkt(Con_Handle, pkt, Length + RFCNB_Pkt_Hdr_Len)) < 0) {
221
222 /* No need to change RFCNB_errno as it was done by put_pkt ... */
223
224 return(RFCNBE_Bad); /* Should be able to write that lot ... */
225
226 }
227
228 /* Now we have sent that lot, let's get rid of the RFCNB Header and return */
229
230 pkt -> next = NULL;
231
232 RFCNB_Free_Pkt(pkt);
233
234 return(len);
235
236 }
237
238 /* We pick up a message from the internet ... We have to worry about
239 non-message packets ... */
240
241 int RFCNB_Recv(void *con_Handle, struct RFCNB_Pkt *Data, int Length)
242
243 {
244 struct RFCNB_Pkt *pkt;
245 // struct RFCNB_Hdr *hdr;
246 int ret_len;
247
248 if (con_Handle == NULL) {
249
250 RFCNB_errno = RFCNBE_BadHandle;
251 RFCNB_saved_errno = errno;
252 return(RFCNBE_Bad);
253
254 }
255
256 /* Now get a packet from below. We allocate a header first */
257
258 /* Plug in the header and send the data */
259
260 pkt = RFCNB_Alloc_Pkt(RFCNB_Pkt_Hdr_Len);
261
262 if (pkt == NULL) {
263
264 RFCNB_errno = RFCNBE_NoSpace;
265 RFCNB_saved_errno = errno;
266 return(RFCNBE_Bad);
267
268 }
269
270 pkt -> next = Data; /* Plug in the data portion */
271
272 if ((ret_len = RFCNB_Get_Pkt(con_Handle, pkt, Length + RFCNB_Pkt_Hdr_Len)) < 0) {
273
274 #ifdef RFCNB_DEBUG
275 fprintf(stderr, "Bad packet return in RFCNB_Recv... \n");
276 #endif
277
278 return(RFCNBE_Bad);
279
280 }
281
282 /* We should check that we go a message and not a keep alive */
283
284 pkt -> next = NULL;
285
286 RFCNB_Free_Pkt(pkt);
287
288 return(ret_len);
289
290 }
291
292 /* We just disconnect from the other end, as there is nothing in the RFCNB */
293 /* protocol that specifies any exchange as far as I can see */
294
295 int RFCNB_Hangup(struct RFCNB_Con *con_Handle)
296
297 {
298
299 if (con_Handle != NULL) {
300 RFCNB_Close(con_Handle -> fd); /* Could this fail? */
301 free(con_Handle);
302 }
303
304 return 0;
305
306
307 }
308
309 /* Set TCP_NODELAY on the socket */
310
311 int RFCNB_Set_Sock_NoDelay(struct RFCNB_Con *con_Handle, BOOL yn)
312
313 {
314
315 return(setsockopt(con_Handle -> fd, IPPROTO_TCP, TCP_NODELAY,
316 (char *)&yn, sizeof(yn)));
317
318 }
319
320 #if NOT_IMPLEMENTED
321
322 /* Listen for a connection on a port???, when */
323 /* the connection comes in, we return with the connection */
324
325 void *RFCNB_Listen()
326
327 {
328
329 }
330 #endif
331
332 /* Pick up the last error response as a string, hmmm, this routine should */
333 /* have been different ... */
334
335 void RFCNB_Get_Error(char *buffer, int buf_len)
336
337 {
338
339 if (RFCNB_saved_errno <= 0) {
340 snprintf(buffer, (buf_len-1) ,"%s", RFCNB_Error_Strings[RFCNB_errno]);
341 } else {
342 snprintf(buffer, (buf_len-1), "%s\n\terrno:%s", RFCNB_Error_Strings[RFCNB_errno],
343 strerror(RFCNB_saved_errno));
344 }
345
346 }
347
348 /* Pick up the last error response and returns as a code */
349
350 int RFCNB_Get_Last_Error()
351
352 {
353
354 return(RFCNB_errno);
355
356 }
357
358 /* Pick up saved errno as well */
359
360 int RFCNB_Get_Last_Errno()
361
362 {
363
364 return(RFCNB_saved_errno);
365
366 }
367
368 /* Pick up the last error response and return in string ... */
369
370 int RFCNB_Get_Error_Msg(int code, char *msg_buf, int len)
371
372 {
373
374 return (strncpy(msg_buf, RFCNB_Error_Strings[abs(code)], len) != NULL);
375
376 }
377
378 /* Register a higher level protocol print routine */
379
380 void RFCNB_Register_Print_Routine(void (*fn)())
381
382 {
383
384 Prot_Print_Routine = fn;
385
386 }