remove unneeded file
[claws.git] / src / socket.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2001 Hiroyuki Yamamoto
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #  include "config.h"
22 #endif
23
24 #include <glib.h>
25 #include <sys/time.h>
26 #include <sys/types.h>
27 #include <sys/socket.h>
28 #include <sys/un.h>
29 #include <netinet/in.h>
30 #include <arpa/inet.h>
31 #include <netdb.h>
32 #include <signal.h>
33 #include <unistd.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <stdarg.h>
37 #include <fcntl.h>
38 #include <errno.h>
39
40 #include "socket.h"
41 #include "utils.h"
42 #if USE_SSL
43 #  include "ssl.h"
44 #endif
45
46 #if USE_GIO
47 #error USE_GIO is currently not supported
48 #endif
49
50 #define BUFFSIZE        8192
51
52 #ifndef INET6
53 static gint sock_connect_by_hostname    (gint            sock,
54                                          const gchar    *hostname,
55                                          gushort         port);
56 #else
57 static gint sock_connect_by_getaddrinfo (const gchar    *hostname,
58                                          gushort         port);
59 #endif
60
61 static SockInfo *sockinfo_from_fd(const gchar *hostname,
62                                   gushort port,
63                                   gint sock);
64
65 gint fd_connect_unix(const gchar *path)
66 {
67         gint sock;
68         struct sockaddr_un addr;
69
70         sock = socket(PF_UNIX, SOCK_STREAM, 0);
71         if (sock < 0) {
72                 perror("sock_connect_unix(): socket");
73                 return -1;
74         }
75
76         memset(&addr, 0, sizeof(addr));
77         addr.sun_family = AF_UNIX;
78         strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
79
80         if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
81                 close(sock);
82                 return -1;
83         }
84
85         return sock;
86 }
87
88 gint fd_open_unix(const gchar *path)
89 {
90         gint sock;
91         struct sockaddr_un addr;
92
93         sock = socket(PF_UNIX, SOCK_STREAM, 0);
94
95         if (sock < 0) {
96                 perror("sock_open_unix(): socket");
97                 return -1;
98         }
99
100         memset(&addr, 0, sizeof(addr));
101         addr.sun_family = AF_UNIX;
102         strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
103
104         if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
105                 perror("bind");
106                 close(sock);
107                 return -1;
108         }
109
110         if (listen(sock, 1) < 0) {
111                 perror("listen");
112                 close(sock);
113                 return -1;              
114         }
115
116         return sock;
117 }
118
119 gint fd_accept(gint sock)
120 {
121         struct sockaddr_in caddr;
122         gint caddr_len;
123
124         caddr_len = sizeof(caddr);
125         return accept(sock, (struct sockaddr *)&caddr, &caddr_len);
126 }
127
128
129 static gint set_nonblocking_mode(gint fd, gboolean nonblock)
130 {
131         gint flags;
132
133         flags = fcntl(fd, F_GETFL, 0);
134         if (flags < 0) {
135                 perror("fcntl");
136                 return -1;
137         }
138
139         if (nonblock)
140                 flags |= O_NONBLOCK;
141         else
142                 flags &= ~O_NONBLOCK;
143
144         return fcntl(fd, F_SETFL, flags);
145 }
146
147 gint sock_set_nonblocking_mode(SockInfo *sock, gboolean nonblock)
148 {
149         g_return_val_if_fail(sock != NULL, -1);
150
151         return set_nonblocking_mode(sock->sock, nonblock);
152 }
153
154
155 static gboolean is_nonblocking_mode(gint fd)
156 {
157         gint flags;
158
159         flags = fcntl(fd, F_GETFL, 0);
160         if (flags < 0) {
161                 perror("fcntl");
162                 return FALSE;
163         }
164
165         return ((flags & O_NONBLOCK) != 0);
166 }
167
168 gboolean sock_is_nonblocking_mode(SockInfo *sock)
169 {
170         g_return_val_if_fail(sock != NULL, FALSE);
171
172         return is_nonblocking_mode(sock->sock);
173 }
174
175
176 #ifndef INET6
177 static gint sock_connect_by_hostname(gint sock, const gchar *hostname,
178                                      gushort port)
179 {
180         struct hostent *hp;
181         struct sockaddr_in ad;
182 #ifndef HAVE_INET_ATON
183 #if HAVE_INET_ADDR
184         guint32 inaddr;
185 #endif
186 #endif /* HAVE_INET_ATON */
187
188         memset(&ad, 0, sizeof(ad));
189         ad.sin_family = AF_INET;
190         ad.sin_port = htons(port);
191
192 #if HAVE_INET_ATON
193         if (!inet_aton(hostname, &ad.sin_addr)) {
194 #else
195 #if HAVE_INET_ADDR
196         inaddr = inet_addr(hostname);
197         if (inaddr != -1)
198                 memcpy(&ad.sin_addr, &inaddr, sizeof(inaddr));
199         else {
200 #else
201         {
202 #endif
203 #endif /* HAVE_INET_ATON */
204                 if ((hp = gethostbyname(hostname)) == NULL) {
205                         fprintf(stderr, "%s: unknown host.\n", hostname);
206                         errno = 0;
207                         return -1;
208                 }
209
210                 if (hp->h_length != 4 && hp->h_length != 8) {
211                         fprintf(stderr, "illegal address length received for host %s\n", hostname);
212                         errno = 0;
213                         return -1;
214                 }
215
216                 memcpy(&ad.sin_addr, hp->h_addr, hp->h_length);
217         }
218
219         return connect(sock, (struct sockaddr *)&ad, sizeof(ad));
220 }
221
222 #else /* INET6 */
223 static gint sock_connect_by_getaddrinfo(const gchar *hostname, gushort  port)
224 {
225         gint sock = -1, gai_error;
226         struct addrinfo hints, *res, *ai;
227         gchar port_str[6];
228
229         memset(&hints, 0, sizeof(hints));
230         /* hints.ai_flags = AI_CANONNAME; */
231         hints.ai_family = AF_UNSPEC;
232         hints.ai_socktype = SOCK_STREAM;
233         hints.ai_protocol = IPPROTO_TCP;
234
235         /* convert port from integer to string. */
236         g_snprintf(port_str, sizeof(port_str), "%d", port);
237
238         if ((gai_error = getaddrinfo(hostname, port_str, &hints, &res)) != 0) {
239                 fprintf(stderr, "getaddrinfo for %s:%s failed: %s\n",
240                         hostname, port_str, gai_strerror(gai_error));
241                 return -1;
242         }
243
244         for (ai = res; ai != NULL; ai = ai->ai_next) {
245                 sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
246                 if (sock < 0)
247                         continue;
248
249                 if (connect(sock, ai->ai_addr, ai->ai_addrlen) == 0)
250                         break;
251
252                 close(sock);
253         }
254
255         if (res != NULL)
256                 freeaddrinfo(res);
257
258         if (ai == NULL)
259                 return -1;
260
261         return sock;
262 }
263 #endif /* !INET6 */
264
265
266 /* Open a connection using an external program.  May be useful when
267  * you need to tunnel through a SOCKS or other firewall, or to
268  * establish an IMAP-over-SSH connection. */
269 /* TODO: Recreate this for sock_connect_thread() */
270 SockInfo *sock_connect_cmd(const gchar *hostname, const gchar *tunnelcmd)
271 {
272         gint fd[2];
273         int r;
274                      
275         if ((r = socketpair(AF_UNIX, SOCK_STREAM, 0, fd)) == -1) {
276                 perror("socketpair");
277                 return NULL;
278         }
279         log_message("launching tunnel command \"%s\"\n", tunnelcmd);
280         if (fork() == 0) {
281                 close(fd[0]);
282                 close(0);
283                 close(1);
284                 dup(fd[1]);     /* set onto stdin */
285                 dup(fd[1]);
286                 execlp("/bin/sh", "/bin/sh", "-c", tunnelcmd, NULL);
287         }
288
289         close(fd[1]);
290         return sockinfo_from_fd(hostname, 0, fd[0]);
291 }
292
293
294 SockInfo *sock_connect(const gchar *hostname, gushort port)
295 {
296         gint sock;
297
298 #ifdef INET6
299         if ((sock = sock_connect_by_getaddrinfo(hostname, port)) < 0)
300                 return NULL;
301 #else
302         if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
303                 perror("socket");
304                 return NULL;
305         }
306
307         if (sock_connect_by_hostname(sock, hostname, port) < 0) {
308                 if (errno != 0) perror("connect");
309                 close(sock);
310                 return NULL;
311         }
312 #endif /* INET6 */
313
314         return sockinfo_from_fd(hostname, port, sock);
315 }
316
317
318 static SockInfo *sockinfo_from_fd(const gchar *hostname,
319                                   gushort port,
320                                   gint sock)
321 {
322         SockInfo *sockinfo;
323         
324         sockinfo = g_new0(SockInfo, 1);
325         sockinfo->sock = sock;
326         sockinfo->hostname = g_strdup(hostname);
327         sockinfo->port = port;
328         sockinfo->state = CONN_ESTABLISHED;
329
330         usleep(100000);
331
332         return sockinfo;
333 }
334
335 gint sock_printf(SockInfo *sock, const gchar *format, ...)
336 {
337         va_list args;
338         gchar buf[BUFFSIZE];
339
340         va_start(args, format);
341         g_vsnprintf(buf, sizeof(buf), format, args);
342         va_end(args);
343
344         return sock_write(sock, buf, strlen(buf));
345 }
346
347 gint sock_read(SockInfo *sock, gchar *buf, gint len)
348 {
349         g_return_val_if_fail(sock != NULL, -1);
350
351 #if USE_SSL
352         if (sock->ssl)
353                 return ssl_read(sock->ssl, buf, len);
354 #endif
355         return fd_read(sock->sock, buf, len);
356 }
357
358 gint fd_read(gint fd, gchar *buf, gint len)
359 {
360         return read(fd, buf, len);
361 }
362
363 #if USE_SSL
364 gint ssl_read(SSL *ssl, gchar *buf, gint len)
365 {
366         return SSL_read(ssl, buf, len);
367 }
368 #endif
369
370 gint sock_write(SockInfo *sock, const gchar *buf, gint len)
371 {
372         g_return_val_if_fail(sock != NULL, -1);
373
374 #if USE_SSL
375         if (sock->ssl)
376                 return ssl_write(sock->ssl, buf, len);
377 #endif
378         return fd_write(sock->sock, buf, len);
379 }
380
381 gint fd_write(gint fd, const gchar *buf, gint len)
382 {
383         gint n, wrlen = 0;
384
385         while (len) {
386                 signal(SIGPIPE, SIG_IGN);
387                 n = write(fd, buf, len);
388                 if (n <= 0) {
389                         log_error("write on fd%d: %s\n", fd, strerror(errno));
390                         return -1;
391                 }
392                 len -= n;
393                 wrlen += n;
394                 buf += n;
395         }
396
397         return wrlen;
398 }
399
400 #if USE_SSL
401 gint ssl_write(SSL *ssl, const gchar *buf, gint len)
402 {
403         gint n, wrlen = 0;
404
405         while (len) {
406                 n = SSL_write(ssl, buf, len);
407                 if (n <= 0)
408                         return -1;
409                 len -= n;
410                 wrlen += n;
411                 buf += n;
412         }
413
414         return wrlen;
415 }
416 #endif
417
418 gint fd_gets(gint fd, gchar *buf, gint len)
419 {
420         gchar *newline, *bp = buf;
421         gint n;
422
423         if (--len < 1)
424                 return -1;
425         do {
426                 if ((n = recv(fd, bp, len, MSG_PEEK)) <= 0)
427                         return -1;
428                 if ((newline = memchr(bp, '\n', n)) != NULL)
429                         n = newline - bp + 1;
430                 if ((n = read(fd, bp, n)) < 0)
431                         return -1;
432                 bp += n;
433                 len -= n;
434         } while (!newline && len);
435
436         *bp = '\0';
437         return bp - buf;
438 }
439
440 #if USE_SSL
441 gint ssl_gets(SSL *ssl, gchar *buf, gint len)
442 {
443         gchar *newline, *bp = buf;
444         gint n;
445
446         if (--len < 1)
447                 return -1;
448         do {
449                 if ((n = SSL_peek(ssl, bp, len)) <= 0)
450                         return -1;
451                 if ((newline = memchr(bp, '\n', n)) != NULL)
452                         n = newline - bp + 1;
453                 if ((n = SSL_read(ssl, bp, n)) < 0)
454                         return -1;
455                 bp += n;
456                 len -= n;
457         } while (!newline && len);
458
459         *bp = '\0';
460         return bp - buf;
461 }
462 #endif
463
464 gint sock_gets(SockInfo *sock, gchar *buf, gint len)
465 {
466         g_return_val_if_fail(sock != NULL, -1);
467
468 #if USE_SSL
469         if (sock->ssl)
470                 return ssl_gets(sock->ssl, buf, len);
471 #endif
472         return fd_gets(sock->sock, buf, len);
473 }
474
475 gchar *fd_getline(gint fd)
476 {
477         gchar buf[BUFFSIZE];
478         gchar *str = NULL;
479         gint len;
480         gulong size = 1;
481
482         while ((len = fd_gets(fd, buf, sizeof(buf))) > 0) {
483                 size += len;
484                 if (!str)
485                         str = g_strdup(buf);
486                 else {
487                         str = g_realloc(str, size);
488                         strcat(str, buf);
489                 }
490                 if (buf[len - 1] == '\n')
491                         break;
492         }
493         if (len == -1) {
494                 log_error("Read from socket fd%d failed: %s\n",
495                           fd, strerror(errno));
496                 if (str)
497                         g_free(str);
498                 return NULL;
499         }
500
501         return str;
502 }
503
504 #if USE_SSL
505 gchar *ssl_getline(SSL *ssl)
506 {
507         gchar buf[BUFFSIZE];
508         gchar *str = NULL;
509         gint len;
510         gulong size = 1;
511
512         while ((len = ssl_gets(ssl, buf, sizeof(buf))) > 0) {
513                 size += len;
514                 if (!str)
515                         str = g_strdup(buf);
516                 else {
517                         str = g_realloc(str, size);
518                         strcat(str, buf);
519                 }
520                 if (buf[len - 1] == '\n')
521                         break;
522         }
523
524         return str;
525 }
526 #endif
527
528 gchar *sock_getline(SockInfo *sock)
529 {
530         g_return_val_if_fail(sock != NULL, NULL);
531
532 #if USE_SSL
533         if (sock->ssl)
534                 return ssl_getline(sock->ssl);
535 #endif
536         return fd_getline(sock->sock);
537 }
538
539 gint sock_puts(SockInfo *sock, const gchar *buf)
540 {
541         gint ret;
542
543         if ((ret = sock_write(sock, buf, strlen(buf))) < 0)
544                 return ret;
545         return sock_write(sock, "\r\n", 2);
546 }
547
548 /* peek at the next socket character without actually reading it */
549 gint sock_peek(SockInfo *sock)
550 {
551         gint n;
552         gchar ch;
553
554         g_return_val_if_fail(sock != NULL, -1);
555
556         if ((n = recv(sock->sock, &ch, 1, MSG_PEEK)) < 0)
557                 return -1;
558         else
559                 return ch;
560 }
561
562 gint sock_close(SockInfo *sock)
563 {
564         gint ret;
565
566         if (!sock)
567                 return 0;
568
569 #if USE_SSL
570         if (sock->ssl)
571                 ssl_done_socket(sock);
572 #endif
573         ret = fd_close(sock->sock); 
574         g_free(sock->hostname);
575         g_free(sock);
576
577         return ret;
578 }
579
580 gint fd_close(gint fd)
581 {
582         return close(fd);
583 }
584
585 gint sock_gdk_input_add(SockInfo *sock,
586                         GdkInputCondition condition,
587                         GdkInputFunction function,
588                         gpointer data)
589 {
590         g_return_val_if_fail(sock != NULL, -1);
591
592         /* :WK: We have to change some things here becuse most likey
593            function() does take SockInfo * and not an gint */
594         return gdk_input_add(sock->sock, condition, function, data);
595 }