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