* ipc_c_tcp.c: Fixed up some #include/prototyping stuff, call memcpy()
[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(unsigned 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         buf[0] = 0;
208         do {
209                 buf[strlen(buf) + 1] = 0;
210                 if (strlen(buf) < 255) serv_read(&buf[strlen(buf)], 1);
211                 } while (buf[strlen(buf)-1] != 10);
212         if (strlen(buf) > 0) buf[strlen(buf)-1] = 0;
213         /* printf("> %s\n", buf); */
214         }
215
216
217 /*
218  * send line to server - implemented in terms of serv_write()
219  */
220 void serv_puts(char *buf)
221 {
222         /* printf("< %s\n", buf); */
223         serv_write(buf, strlen(buf));
224         serv_write("\n", 1);
225         }
226
227
228 /*
229  * attach to server
230  */
231 void attach_to_server(int argc, char **argv)
232 {
233         int a;
234         char cithost[256];      int host_copied = 0;
235         char citport[256];      int port_copied = 0;
236         char socks4[256];
237         unsigned char buf[256];
238         struct passwd *p;
239
240         strcpy(cithost,DEFAULT_HOST);   /* default host */
241         strcpy(citport,DEFAULT_PORT);   /* default port */
242         strcpy(socks4,"");              /* SOCKS v4 server */
243
244         for (a = 0; a < argc; ++a) {
245                 if (a == 0) {
246                         /* do nothing */
247                         }
248                 else if (!strcmp(argv[a],"-s")) {
249                         strcpy(socks4,argv[++a]);
250                         }
251                 else if (host_copied == 0) {
252                         host_copied = 1;
253                         strcpy(cithost,argv[a]);
254                         }
255                 else if (port_copied == 0) {
256                         port_copied = 1;
257                         strcpy(citport,argv[a]);
258                         }
259
260 /*
261                 else {
262                         fprintf(stderr,"%s: usage: ",argv[0]);
263                         fprintf(stderr,"%s [host] [port] ",argv[0]);
264                         fprintf(stderr,"[-s socks_server]\n");
265                         logoff(2);
266                         }
267 */
268                 }
269
270         server_is_local = 0;
271         if ( (!strcmp(cithost,"localhost"))
272            || (!strcmp(cithost,"127.0.0.1")) ) server_is_local = 1;
273
274         /* if not using a SOCKS proxy server, make the connection directly */
275         if (strlen(socks4)==0) {
276                 serv_sock = connectsock(cithost,citport,"tcp");
277                 return;
278                 }
279
280         /* if using SOCKS, connect first to the proxy... */
281         serv_sock = connectsock(socks4,"1080","tcp");
282         printf("Connected to SOCKS proxy at %s.\n",socks4);
283         printf("Attaching to server...\r");
284         fflush(stdout);
285
286         sprintf(buf,"%c%c",
287                 4,                      /* version 4 */
288                 1);                     /* method = connect */
289         serv_write(buf,2);
290
291         numericize(buf,cithost,citport,"tcp");
292         serv_write(buf,6);              /* port and address */
293
294         p = (struct passwd *) getpwuid(getuid());
295         serv_write(p->pw_name, strlen(p->pw_name)+1);
296                                         /* user name */
297
298         serv_read(buf,8);               /* get response */
299
300         if (buf[1] != 90) {
301                 printf("SOCKS server denied this proxy request.\n");
302                 logoff(3);
303                 }
304
305         }
306
307 /*
308  * return the file descriptor of the server socket so we can select() on it.
309  */
310 int getsockfd(void) {
311         return serv_sock;
312         }
313
314
315 /*
316  * return one character
317  */
318 char serv_getc(void) {
319         char buf[2];
320         char ch;
321
322         serv_read(buf, 1);
323         ch = (int) buf[0];
324
325         return(ch);
326         }