]> code.citadel.org Git - citadel.git/blob - citadel/ipc_c_tcp.c
* citadel.c: added some experimental code to automatically reconnect
[citadel.git] / citadel / ipc_c_tcp.c
1 /*
2  * ipc_c_tcp.c
3  * 
4  * Citadel/UX client/server IPC - client module using TCP/IP
5  *
6  * version 1.3 $Id$
7  *
8  */
9
10 #define DEFAULT_HOST    "127.0.0.1"
11 #define DEFAULT_PORT    "citadel"
12
13
14 #include "sysdep.h"
15 #include <stdlib.h>
16 #include <unistd.h>
17 #include <stdio.h>
18 #include <signal.h>
19 #include <sys/types.h>
20 #include <sys/socket.h>
21 #include <netinet/in.h>
22 #include <arpa/inet.h>
23 #include <netdb.h>
24 #include <string.h>
25 #include <pwd.h>
26 #include <errno.h>
27 #include "citadel_decls.h"
28 #include "ipc.h"
29
30 /*
31  * If server_is_local is set to nonzero, the client assumes that it is running
32  * on the same computer as the server.  Several things happen when this is
33  * the case, including the ability to map a specific tty to a particular login
34  * session in the "<W>ho is online" listing, the ability to run external
35  * programs, and the ability to download files directly off the disk without
36  * having to first fetch them from the server.
37  * Set the flag to 1 if this IPC is local (as is the case with pipes, or a
38  * network session to the local machine) or 0 if the server is executing on
39  * a remote computer.
40  */
41 char server_is_local = 0;
42
43 #ifndef INADDR_NONE
44 #define INADDR_NONE 0xffffffff
45 #endif
46
47 int serv_sock;
48
49 void timeout(int signum) {
50         printf("\rConnection timed out.\n");
51         logoff(3);
52         }
53
54 int connectsock(char *host, char *service, char *protocol)
55 {
56         struct hostent *phe;
57         struct servent *pse;
58         struct protoent *ppe;
59         struct sockaddr_in sin;
60         int s,type;
61
62         bzero((char *)&sin,sizeof(sin));
63         sin.sin_family = AF_INET;
64
65         pse=getservbyname(service,protocol);
66         if (pse) {
67                 sin.sin_port = pse->s_port;
68                 }
69         else if ((sin.sin_port = htons((u_short)atoi(service))) == 0) {
70                 fprintf(stderr,"Can't get %s service entry: %s\n",
71                         service,strerror(errno));
72                 logoff(3);
73                 }
74         
75         phe=gethostbyname(host);
76         if (phe) {
77                 memcpy(&sin.sin_addr,phe->h_addr,phe->h_length);
78                 }
79         else if ((sin.sin_addr.s_addr = inet_addr(host))==INADDR_NONE) {
80                 fprintf(stderr,"Can't get %s host entry: %s\n",
81                         host,strerror(errno));
82                 logoff(3);
83                 }
84
85         if ((ppe=getprotobyname(protocol))==0) {
86                 fprintf(stderr,"Can't get %s protocol entry: %s\n",
87                         protocol,strerror(errno));
88                 logoff(3);
89                 }
90
91         if (!strcmp(protocol,"udp")) {
92                 type = SOCK_DGRAM;
93                 }
94         else {
95                 type = SOCK_STREAM;
96                 }
97
98         s = socket(PF_INET,type,ppe->p_proto);
99         if (s<0) {
100                 fprintf(stderr,"Can't create socket: %s\n",strerror(errno));
101                 logoff(3);
102                 }
103
104
105         signal(SIGALRM,timeout);
106         alarm(30);
107
108         if (connect(s,(struct sockaddr *)&sin,sizeof(sin))<0) {
109                 fprintf(stderr,"can't connect to %s.%s: %s\n",
110                         host,service,strerror(errno));
111                 logoff(3);
112                 }
113
114         alarm(0);
115         signal(SIGALRM,SIG_IGN);
116
117         return(s);
118         }
119
120 /*
121  * convert service and host entries into a six-byte numeric in the format
122  * expected by a SOCKS v4 server
123  */
124 void numericize(char *buf, char *host, char *service, char *protocol)
125 {
126         struct hostent *phe;
127         struct servent *pse;
128         struct sockaddr_in sin;
129
130         bzero((char *)&sin,sizeof(sin));
131         sin.sin_family = AF_INET;
132
133         pse=getservbyname(service,protocol);
134         if (pse) {
135                 sin.sin_port = pse->s_port;
136                 }
137         else if ((sin.sin_port = htons((u_short)atoi(service))) == 0) {
138                 fprintf(stderr,"Can't get %s service entry: %s\n",
139                         service,strerror(errno));
140                 logoff(3);
141                 }
142
143         buf[1] = (((sin.sin_port) & 0xFF00) >> 8);
144         buf[0] = ((sin.sin_port) & 0x00FF);
145         
146         phe=gethostbyname(host);
147         if (phe) {
148                 memcpy(&sin.sin_addr,phe->h_addr,phe->h_length);
149                 }
150         else if ((sin.sin_addr.s_addr = inet_addr(host))==INADDR_NONE) {
151                 fprintf(stderr,"Can't get %s host entry: %s\n",
152                         host,strerror(errno));
153                 logoff(3);
154                 }
155         buf[5] = ((sin.sin_addr.s_addr) & 0xFF000000) >> 24;
156         buf[4] = ((sin.sin_addr.s_addr) & 0x00FF0000) >> 16;
157         buf[3] = ((sin.sin_addr.s_addr) & 0x0000FF00) >> 8;
158         buf[2] = ((sin.sin_addr.s_addr) & 0x000000FF) ;
159         }
160
161 /*
162  * input binary data from socket
163  */
164 void serv_read(char *buf, int bytes)
165 {
166         int len,rlen;
167
168         len = 0;
169         while(len<bytes) {
170                 rlen = read(serv_sock,&buf[len],bytes-len);
171                 if (rlen<1) {
172                         /* printf("\rNetwork error - connection terminated.\n");
173                         printf("%s\n", strerror(errno)); */
174                         logoff(3);
175                         }
176                 len = len + rlen;
177                 }
178         }
179
180
181 /*
182  * send binary to server
183  */
184 void serv_write(char *buf, int nbytes)
185 {
186         int bytes_written = 0;
187         int retval;
188         while (bytes_written < nbytes) {
189                 retval = write(serv_sock, &buf[bytes_written],
190                         nbytes - bytes_written);
191                 if (retval < 1) {
192                         /*
193                         printf("\rNetwork error - connection terminated.\n");
194                         printf("%s\n", strerror(errno)); */
195                         logoff(3);
196                         }
197                 bytes_written = bytes_written + retval;
198                 }
199         }
200
201
202
203 /*
204  * input string from socket - implemented in terms of serv_read()
205  */
206 void serv_gets(char *buf)
207 {
208         int i;
209
210         /* Read one character at a time.
211          */
212         for (i = 0;;i++) {
213                 serv_read(&buf[i], 1);
214                 if (buf[i] == '\n' || i == 255)
215                         break;
216                 }
217
218         /* If we got a long line, discard characters until the newline.
219          */
220         if (i == 255)
221                 while (buf[i] != '\n')
222                         serv_read(&buf[i], 1);
223
224         /* Strip the trailing newline.
225          */
226         buf[i] = 0;
227         }
228
229
230 /*
231  * send line to server - implemented in terms of serv_write()
232  */
233 void serv_puts(char *buf)
234 {
235         /* printf("< %s\n", buf); */
236         serv_write(buf, strlen(buf));
237         serv_write("\n", 1);
238         }
239
240
241 /*
242  * attach to server
243  */
244 void attach_to_server(int argc, char **argv)
245 {
246         int a;
247         char cithost[256];      int host_copied = 0;
248         char citport[256];      int port_copied = 0;
249         char socks4[256];
250         char buf[256];
251         struct passwd *p;
252
253         strcpy(cithost,DEFAULT_HOST);   /* default host */
254         strcpy(citport,DEFAULT_PORT);   /* default port */
255         strcpy(socks4,"");              /* SOCKS v4 server */
256
257         for (a = 0; a < argc; ++a) {
258                 if (a == 0) {
259                         /* do nothing */
260                         }
261                 else if (!strcmp(argv[a],"-s")) {
262                         strcpy(socks4,argv[++a]);
263                         }
264                 else if (host_copied == 0) {
265                         host_copied = 1;
266                         strcpy(cithost,argv[a]);
267                         }
268                 else if (port_copied == 0) {
269                         port_copied = 1;
270                         strcpy(citport,argv[a]);
271                         }
272
273 /*
274                 else {
275                         fprintf(stderr,"%s: usage: ",argv[0]);
276                         fprintf(stderr,"%s [host] [port] ",argv[0]);
277                         fprintf(stderr,"[-s socks_server]\n");
278                         logoff(2);
279                         }
280 */
281                 }
282
283         server_is_local = 0;
284         if ( (!strcmp(cithost,"localhost"))
285            || (!strcmp(cithost,"127.0.0.1")) ) server_is_local = 1;
286
287         /* if not using a SOCKS proxy server, make the connection directly */
288         if (strlen(socks4)==0) {
289                 serv_sock = connectsock(cithost,citport,"tcp");
290                 return;
291                 }
292
293         /* if using SOCKS, connect first to the proxy... */
294         serv_sock = connectsock(socks4,"1080","tcp");
295         printf("Connected to SOCKS proxy at %s.\n",socks4);
296         printf("Attaching to server...\r");
297         fflush(stdout);
298
299         snprintf(buf,sizeof buf,"%c%c",
300                 4,                      /* version 4 */
301                 1);                     /* method = connect */
302         serv_write(buf,2);
303
304         numericize(buf,cithost,citport,"tcp");
305         serv_write(buf,6);              /* port and address */
306
307         p = (struct passwd *) getpwuid(getuid());
308         serv_write(p->pw_name, strlen(p->pw_name)+1);
309                                         /* user name */
310
311         serv_read(buf,8);               /* get response */
312
313         if (buf[1] != 90) {
314                 printf("SOCKS server denied this proxy request.\n");
315                 logoff(3);
316                 }
317
318         }
319
320 /*
321  * return the file descriptor of the server socket so we can select() on it.
322  */
323 int getsockfd(void) {
324         return serv_sock;
325         }
326
327
328 /*
329  * return one character
330  */
331 char serv_getc(void) {
332         char buf[2];
333         char ch;
334
335         serv_read(buf, 1);
336         ch = (int) buf[0];
337
338         return(ch);
339         }