1 /* UNIX RFCNB (RFC1001/RFC1002) NetBIOS implementation
6 Copyright (C) Richard Sharpe 1996
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.
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.
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.
29 #include <netinet/in.h>
30 #include <netinet/tcp.h>
31 #include <sys/socket.h>
34 int RFCNB_saved_errno = 0;
37 #include "rfcnb-priv.h"
39 #include "rfcnb-util.h"
41 int RFCNB_Stats[RFCNB_MAX_STATS];
43 void (*Prot_Print_Routine)() = NULL; /* Pointer to print routine */
45 /* Set up a session with a remote name. We are passed Called_Name as a
46 string which we convert to a NetBIOS name, ie space terminated, up to
47 16 characters only if we need to. If Called_Address is not empty, then
48 we use it to connect to the remote end, but put in Called_Name ... Called
49 Address can be a DNS based name, or a TCP/IP address ...
52 void *RFCNB_Call(char *Called_Name, char *Calling_Name, char *Called_Address,
55 { struct RFCNB_Con *con;
56 struct in_addr Dest_IP;
58 bool redirect; struct redirect_addr *redir_addr;
59 char *Service_Address;
61 /* Now, we really should look up the port in /etc/services ... */
63 if (port == 0) port = RFCNB_Default_Port;
65 /* Create a connection structure first */
67 if ((con = (struct RFCNB_Con *)malloc(sizeof(struct RFCNB_Con))) == NULL) { /* Error in size */
69 RFCNB_errno = RFCNBE_NoSpace;
70 RFCNB_saved_errno = errno;
75 con -> fd = -0; /* no descriptor yet */
76 con -> rfc_errno = 0; /* no error yet */
77 con -> timeout = 0; /* no timeout */
79 con -> redirect_list = NULL; /* Fix bug still in version 0.50 */
81 /* Resolve that name into an IP address */
83 Service_Address = Called_Name;
84 if (strcmp(Called_Address, "") != 0) { /* If the Called Address = "" */
85 Service_Address = Called_Address;
88 if ((errno = RFCNB_Name_To_IP(Service_Address, &Dest_IP)) < 0) { /* Error */
90 /* No need to modify RFCNB_errno as it was done by RFCNB_Name_To_IP */
96 /* Now connect to the remote end */
98 redirect = true; /* Fudge this one so we go once through */
100 while (redirect) { /* Connect and get session info etc */
102 redirect = false; /* Assume all OK */
104 /* Build the redirect info. First one is first addr called */
105 /* And tack it onto the list of addresses we called */
107 if ((redir_addr = (struct redirect_addr *)malloc(sizeof(struct redirect_addr))) == NULL) { /* Could not get space */
109 RFCNB_errno = RFCNBE_NoSpace;
110 RFCNB_saved_errno = errno;
115 memcpy((char *)&(redir_addr -> ip_addr), (char *)&Dest_IP, sizeof(Dest_IP));
116 redir_addr -> port = port;
117 redir_addr -> next = NULL;
119 if (con -> redirect_list == NULL) { /* Stick on head */
121 con -> redirect_list = con -> last_addr = redir_addr;
125 con -> last_addr -> next = redir_addr;
126 con -> last_addr = redir_addr;
130 /* Now, make that connection */
132 if ((Client = RFCNB_IP_Connect(Dest_IP, port)) < 0) { /* Error */
134 /* No need to modify RFCNB_errno as it was done by RFCNB_IP_Connect */
142 /* Now send and handle the RFCNB session request */
143 /* If we get a redirect, we will comeback with redirect true
144 and a new IP address in DEST_IP */
146 if ((errno = RFCNB_Session_Req(con,
149 &redirect, &Dest_IP, &port)) < 0) {
151 /* No need to modify RFCNB_errno as it was done by RFCNB_Session.. */
159 /* We have to close the connection, and then try again */
161 (con -> redirects)++;
163 RFCNB_Close(con -> fd); /* Close it */
172 /* We send a packet to the other end ... for the moment, we treat the
173 data as a series of pointers to blocks of data ... we should check the
176 int RFCNB_Send(struct RFCNB_Con *Con_Handle, struct RFCNB_Pkt *udata, int Length)
178 { struct RFCNB_Pkt *pkt; char *hdr;
181 /* Plug in the header and send the data */
183 pkt = RFCNB_Alloc_Pkt(RFCNB_Pkt_Hdr_Len);
187 RFCNB_errno = RFCNBE_NoSpace;
188 RFCNB_saved_errno = errno;
193 pkt -> next = udata; /* The user data we want to send */
197 /* Following crap is for portability across multiple UNIX machines */
199 *(hdr + RFCNB_Pkt_Type_Offset) = RFCNB_SESSION_MESSAGE;
200 RFCNB_Put_Pkt_Len(hdr, Length);
204 fprintf(stderr, "Sending packet: ");
208 if ((len = RFCNB_Put_Pkt(Con_Handle, pkt, Length + RFCNB_Pkt_Hdr_Len)) < 0) {
210 /* No need to change RFCNB_errno as it was done by put_pkt ... */
212 return(RFCNBE_Bad); /* Should be able to write that lot ... */
216 /* Now we have sent that lot, let's get rid of the RFCNB Header and return */
226 /* We pick up a message from the internet ... We have to worry about
227 non-message packets ... */
229 int RFCNB_Recv(void *con_Handle, struct RFCNB_Pkt *Data, int Length)
231 { struct RFCNB_Pkt *pkt;
234 if (con_Handle == NULL){
236 RFCNB_errno = RFCNBE_BadHandle;
237 RFCNB_saved_errno = errno;
242 /* Now get a packet from below. We allocate a header first */
244 /* Plug in the header and send the data */
246 pkt = RFCNB_Alloc_Pkt(RFCNB_Pkt_Hdr_Len);
250 RFCNB_errno = RFCNBE_NoSpace;
251 RFCNB_saved_errno = errno;
256 pkt -> next = Data; /* Plug in the data portion */
258 if ((ret_len = RFCNB_Get_Pkt(con_Handle, pkt, Length + RFCNB_Pkt_Hdr_Len)) < 0) {
261 fprintf(stderr, "Bad packet return in RFCNB_Recv... \n");
268 /* We should check that we go a message and not a keep alive */
278 /* We just disconnect from the other end, as there is nothing in the RFCNB */
279 /* protocol that specifies any exchange as far as I can see */
281 int RFCNB_Hangup(struct RFCNB_Con *con_Handle)
285 if (con_Handle != NULL) {
286 RFCNB_Close(con_Handle -> fd); /* Could this fail? */
295 /* Set TCP_NODELAY on the socket */
297 int RFCNB_Set_Sock_NoDelay(struct RFCNB_Con *con_Handle, bool yn)
301 return(setsockopt(con_Handle -> fd, IPPROTO_TCP, TCP_NODELAY,
302 (char *)&yn, sizeof(yn)));