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