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