]> code.citadel.org Git - citadel.git/blob - citadel/ipc_c_tcp.c
* sysdep.c (client_gets), ipc_c_tcp.c (serv_gets): improved handling
[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
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                         printf("\rNetwork error - connection terminated.\n");
193                         printf("%s\n", strerror(errno));
194                         logoff(3);
195                         }
196                 bytes_written = bytes_written + retval;
197                 }
198         }
199
200
201
202 /*
203  * input string from socket - implemented in terms of serv_read()
204  */
205 void serv_gets(char *buf)
206 {
207         int i;
208
209         /* Read one character at a time.
210          */
211         for (i = 0;;i++) {
212                 serv_read(&buf[i], 1);
213                 if (buf[i] == '\n' || i == 255)
214                         break;
215                 }
216
217         /* If we got a long line, discard characters until the newline.
218          */
219         if (i == 255)
220                 while (buf[i] != '\n')
221                         serv_read(&buf[i], 1);
222
223         /* Strip the trailing newline.
224          */
225         buf[i] = 0;
226         }
227
228
229 /*
230  * send line to server - implemented in terms of serv_write()
231  */
232 void serv_puts(char *buf)
233 {
234         /* printf("< %s\n", buf); */
235         serv_write(buf, strlen(buf));
236         serv_write("\n", 1);
237         }
238
239
240 /*
241  * attach to server
242  */
243 void attach_to_server(int argc, char **argv)
244 {
245         int a;
246         char cithost[256];      int host_copied = 0;
247         char citport[256];      int port_copied = 0;
248         char socks4[256];
249         char buf[256];
250         struct passwd *p;
251
252         strcpy(cithost,DEFAULT_HOST);   /* default host */
253         strcpy(citport,DEFAULT_PORT);   /* default port */
254         strcpy(socks4,"");              /* SOCKS v4 server */
255
256         for (a = 0; a < argc; ++a) {
257                 if (a == 0) {
258                         /* do nothing */
259                         }
260                 else if (!strcmp(argv[a],"-s")) {
261                         strcpy(socks4,argv[++a]);
262                         }
263                 else if (host_copied == 0) {
264                         host_copied = 1;
265                         strcpy(cithost,argv[a]);
266                         }
267                 else if (port_copied == 0) {
268                         port_copied = 1;
269                         strcpy(citport,argv[a]);
270                         }
271
272 /*
273                 else {
274                         fprintf(stderr,"%s: usage: ",argv[0]);
275                         fprintf(stderr,"%s [host] [port] ",argv[0]);
276                         fprintf(stderr,"[-s socks_server]\n");
277                         logoff(2);
278                         }
279 */
280                 }
281
282         server_is_local = 0;
283         if ( (!strcmp(cithost,"localhost"))
284            || (!strcmp(cithost,"127.0.0.1")) ) server_is_local = 1;
285
286         /* if not using a SOCKS proxy server, make the connection directly */
287         if (strlen(socks4)==0) {
288                 serv_sock = connectsock(cithost,citport,"tcp");
289                 return;
290                 }
291
292         /* if using SOCKS, connect first to the proxy... */
293         serv_sock = connectsock(socks4,"1080","tcp");
294         printf("Connected to SOCKS proxy at %s.\n",socks4);
295         printf("Attaching to server...\r");
296         fflush(stdout);
297
298         sprintf(buf,"%c%c",
299                 4,                      /* version 4 */
300                 1);                     /* method = connect */
301         serv_write(buf,2);
302
303         numericize(buf,cithost,citport,"tcp");
304         serv_write(buf,6);              /* port and address */
305
306         p = (struct passwd *) getpwuid(getuid());
307         serv_write(p->pw_name, strlen(p->pw_name)+1);
308                                         /* user name */
309
310         serv_read(buf,8);               /* get response */
311
312         if (buf[1] != 90) {
313                 printf("SOCKS server denied this proxy request.\n");
314                 logoff(3);
315                 }
316
317         }
318
319 /*
320  * return the file descriptor of the server socket so we can select() on it.
321  */
322 int getsockfd(void) {
323         return serv_sock;
324         }
325
326
327 /*
328  * return one character
329  */
330 char serv_getc(void) {
331         char buf[2];
332         char ch;
333
334         serv_read(buf, 1);
335         ch = (int) buf[0];
336
337         return(ch);
338         }