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