2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2001 Hiroyuki Yamamoto
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.
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.
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.
26 #include <sys/types.h>
27 #include <sys/socket.h>
29 #include <netinet/in.h>
30 #include <arpa/inet.h>
46 #error USE_GIO is currently not supported
52 static gint
sock_connect_by_hostname (gint sock
,
53 const gchar
*hostname
,
56 static gint
sock_connect_by_getaddrinfo (const gchar
*hostname
,
61 gint
fd_connect_unix(const gchar
*path
)
64 struct sockaddr_un addr
;
66 sock
= socket(PF_UNIX
, SOCK_STREAM
, 0);
68 perror("sock_connect_unix(): socket");
72 memset(&addr
, 0, sizeof(addr
));
73 addr
.sun_family
= AF_UNIX
;
74 strncpy(addr
.sun_path
, path
, sizeof(addr
.sun_path
) - 1);
76 if (connect(sock
, (struct sockaddr
*)&addr
, sizeof(addr
)) < 0) {
84 gint
fd_open_unix(const gchar
*path
)
87 struct sockaddr_un addr
;
89 sock
= socket(PF_UNIX
, SOCK_STREAM
, 0);
92 perror("sock_open_unix(): socket");
96 memset(&addr
, 0, sizeof(addr
));
97 addr
.sun_family
= AF_UNIX
;
98 strncpy(addr
.sun_path
, path
, sizeof(addr
.sun_path
) - 1);
100 if (bind(sock
, (struct sockaddr
*)&addr
, sizeof(addr
)) < 0) {
106 if (listen(sock
, 1) < 0) {
115 gint
fd_accept(gint sock
)
117 struct sockaddr_in caddr
;
120 caddr_len
= sizeof(caddr
);
121 return accept(sock
, (struct sockaddr
*)&caddr
, &caddr_len
);
125 static gint
set_nonblocking_mode(gint fd
, gboolean nonblock
)
129 flags
= fcntl(fd
, F_GETFL
, 0);
138 flags
&= ~O_NONBLOCK
;
140 return fcntl(fd
, F_SETFL
, flags
);
143 gint
sock_set_nonblocking_mode(SockInfo
*sock
, gboolean nonblock
)
145 g_return_val_if_fail(sock
!= NULL
, -1);
147 return set_nonblocking_mode(sock
->sock
, nonblock
);
151 static gboolean
is_nonblocking_mode(gint fd
)
155 flags
= fcntl(fd
, F_GETFL
, 0);
161 return ((flags
& O_NONBLOCK
) != 0);
164 gboolean
sock_is_nonblocking_mode(SockInfo
*sock
)
166 g_return_val_if_fail(sock
!= NULL
, FALSE
);
168 return is_nonblocking_mode(sock
->sock
);
173 static gint
sock_connect_by_hostname(gint sock
, const gchar
*hostname
,
177 struct sockaddr_in ad
;
178 #ifndef HAVE_INET_ATON
182 #endif /* HAVE_INET_ATON */
184 memset(&ad
, 0, sizeof(ad
));
185 ad
.sin_family
= AF_INET
;
186 ad
.sin_port
= htons(port
);
189 if (!inet_aton(hostname
, &ad
.sin_addr
)) {
192 inaddr
= inet_addr(hostname
);
194 memcpy(&ad
.sin_addr
, &inaddr
, sizeof(inaddr
));
199 #endif /* HAVE_INET_ATON */
200 if ((hp
= gethostbyname(hostname
)) == NULL
) {
201 fprintf(stderr
, "%s: unknown host.\n", hostname
);
206 if (hp
->h_length
!= 4 && hp
->h_length
!= 8) {
208 fprintf(stderr
, "illegal address length received for host %s\n", hostname
);
212 memcpy(&ad
.sin_addr
, hp
->h_addr
, hp
->h_length
);
215 return connect(sock
, (struct sockaddr
*)&ad
, sizeof(ad
));
219 static gint
sock_connect_by_getaddrinfo(const gchar
*hostname
, gushort port
)
221 gint sock
= -1, gai_error
;
222 struct addrinfo hints
, *res
, *ai
;
225 memset(&hints
, 0, sizeof(hints
));
226 /* hints.ai_flags = AI_CANONNAME; */
227 hints
.ai_family
= AF_UNSPEC
;
228 hints
.ai_socktype
= SOCK_STREAM
;
229 hints
.ai_protocol
= IPPROTO_TCP
;
231 /* convert port from integer to string. */
232 g_snprintf(port_str
, sizeof(port_str
), "%d", port
);
234 if ((gai_error
= getaddrinfo(hostname
, port_str
, &hints
, &res
)) != 0) {
235 fprintf(stderr
, "getaddrinfo for %s:%s failed: %s\n",
236 hostname
, port_str
, gai_strerror(gai_error
));
240 for (ai
= res
; ai
!= NULL
; ai
= ai
->ai_next
) {
241 sock
= socket(ai
->ai_family
, ai
->ai_socktype
, ai
->ai_protocol
);
245 if (connect(sock
, ai
->ai_addr
, ai
->ai_addrlen
) == 0)
262 SockInfo
*sock_connect_nb(const gchar
*hostname
, gushort port
)
269 if ((sock
= sock_connect_by_getaddrinfo(hostname
, port
)) < 0)
271 if (set_nonblocking_mode(sock
, TRUE
) < 0) return NULL
;
274 if ((sock
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0) {
279 if (set_nonblocking_mode(sock
, TRUE
) < 0) return NULL
;
281 ret
= sock_connect_by_hostname(sock
, hostname
, port
);
283 if (ret
< 0 && errno
!= EINPROGRESS
) {
284 if (errno
!= 0) perror("connect");
290 sockinfo
= g_new0(SockInfo
, 1);
291 sockinfo
->sock
= sock
;
292 sockinfo
->hostname
= g_strdup(hostname
);
293 sockinfo
->port
= port
;
294 sockinfo
->state
= CONN_LOOKUPSUCCESS
;
296 if (ret
< 0 && errno
== EINPROGRESS
) return sockinfo
;
298 sockinfo
->state
= CONN_ESTABLISHED
;
303 SockInfo
*sock_connect(const gchar
*hostname
, gushort port
)
309 if ((sock
= sock_connect_by_getaddrinfo(hostname
, port
)) < 0)
312 if ((sock
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0) {
317 if (sock_connect_by_hostname(sock
, hostname
, port
) < 0) {
318 if (errno
!= 0) perror("connect");
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
;
336 static void sock_connect_thread(SockInfo
*sockinfo
)
339 if ((sockinfo
->sock
= sock_connect_by_getaddrinfo
340 (sockinfo
->hostname
, sockinfo
->port
)) < 0)
341 pthread_exit((void *)1);
343 if (sock_connect_by_hostname(sockinfo
->sock
, sockinfo
->hostname
,
344 sockinfo
->port
) < 0) {
345 if (errno
!= 0) perror("connect");
346 sockinfo
->state
= CONN_FAILED
;
347 pthread_exit((void *)1);
350 sockinfo
->state
= CONN_ESTABLISHED
;
355 SockInfo
*sock_connect_with_thread(const gchar
*hostname
, gushort port
)
361 if ((sock
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0) {
367 sockinfo
= g_new0(SockInfo
, 1);
368 sockinfo
->sock
= sock
;
369 sockinfo
->hostname
= g_strdup(hostname
);
370 sockinfo
->port
= port
;
371 sockinfo
->state
= CONN_READY
;
373 pthread_create(&sockinfo
->connect_thr
, NULL
,
374 (void *)sock_connect_thread
,
376 pthread_mutex_init(&sockinfo
->mutex
, NULL
);
377 pthread_detach(sockinfo
->connect_thr
);
384 gint
sock_printf(SockInfo
*sock
, const gchar
*format
, ...)
389 va_start(args
, format
);
390 g_vsnprintf(buf
, sizeof(buf
), format
, args
);
393 return sock_write(sock
, buf
, strlen(buf
));
396 gint
sock_read(SockInfo
*sock
, gchar
*buf
, gint len
)
398 g_return_val_if_fail(sock
!= NULL
, -1);
402 return ssl_read(sock
->ssl
, buf
, len
);
405 return fd_read(sock
->sock
, buf
, len
);
408 gint
fd_read(gint fd
, gchar
*buf
, gint len
)
410 return read(fd
, buf
, len
);
414 gint
ssl_read(SSL
*ssl
, gchar
*buf
, gint len
)
416 return SSL_read(ssl
, buf
, len
);
420 gint
sock_write(SockInfo
*sock
, const gchar
*buf
, gint len
)
422 g_return_val_if_fail(sock
!= NULL
, -1);
426 return ssl_write(sock
->ssl
, buf
, len
);
429 return fd_write(sock
->sock
, buf
, len
);
432 gint
fd_write(gint fd
, const gchar
*buf
, gint len
)
437 n
= write(fd
, buf
, len
);
449 gint
ssl_write(SSL
*ssl
, const gchar
*buf
, gint len
)
454 n
= SSL_write(ssl
, buf
, len
);
466 gint
fd_gets(gint fd
, gchar
*buf
, gint len
)
468 gchar
*newline
, *bp
= buf
;
474 if ((n
= recv(fd
, bp
, len
, MSG_PEEK
)) <= 0)
476 if ((newline
= memchr(bp
, '\n', n
)) != NULL
)
477 n
= newline
- bp
+ 1;
478 if ((n
= read(fd
, bp
, n
)) < 0)
482 } while (!newline
&& len
);
489 gint
ssl_gets(SSL
*ssl
, gchar
*buf
, gint len
)
492 gboolean newline
= FALSE
;
497 while(len
> 0 && !newline
) {
499 if((n
= SSL_read(ssl
, buf2
, 1)) < 0)
512 gint
sock_gets(SockInfo
*sock
, gchar
*buf
, gint len
)
514 g_return_val_if_fail(sock
!= NULL
, -1);
518 return ssl_gets(sock
->ssl
, buf
, len
);
521 return fd_gets(sock
->sock
, buf
, len
);
524 gchar
*fd_getline(gint fd
)
531 while ((len
= fd_gets(fd
, buf
, sizeof(buf
))) > 0) {
536 str
= g_realloc(str
, size
);
539 if (buf
[len
- 1] == '\n')
547 gchar
*ssl_getline(SSL
*ssl
)
554 while ((len
= ssl_gets(ssl
, buf
, sizeof(buf
))) > 0) {
559 str
= g_realloc(str
, size
);
562 if (buf
[len
- 1] == '\n')
570 gchar
*sock_getline(SockInfo
*sock
)
572 g_return_val_if_fail(sock
!= NULL
, NULL
);
576 return ssl_getline(sock
->ssl
);
579 return fd_getline(sock
->sock
);
582 gint
sock_puts(SockInfo
*sock
, const gchar
*buf
)
586 if ((ret
= sock_write(sock
, buf
, strlen(buf
))) < 0)
588 return sock_write(sock
, "\r\n", 2);
591 /* peek at the next socket character without actually reading it */
592 gint
sock_peek(SockInfo
*sock
)
597 g_return_val_if_fail(sock
!= NULL
, -1);
599 if ((n
= recv(sock
->sock
, &ch
, 1, MSG_PEEK
)) < 0)
605 gint
sock_close(SockInfo
*sock
)
612 ret
= fd_close(sock
->sock
);
613 g_free(sock
->hostname
);
619 gint
fd_close(gint fd
)
624 gint
sock_gdk_input_add(SockInfo
*sock
,
625 GdkInputCondition condition
,
626 GdkInputFunction function
,
629 g_return_val_if_fail(sock
!= NULL
, -1);
631 /* :WK: We have to change some things here becuse most likey
632 function() does take SockInfo * and not an gint */
633 return gdk_input_add(sock
->sock
, condition
, function
, data
);