Split libsoup out of soup. ChangeLog.old contains the original soup
[platform/upstream/libsoup.git] / libsoup / soup-socket.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * soup-socket.c: Platform neutral socket networking code.
4  *
5  * Authors:
6  *      David Helder  (dhelder@umich.edu)
7  *      Alex Graveley (alex@ximian.com)
8  *
9  * Original code compliments of David Helder's GNET Networking Library, and is
10  * Copyright (C) 2000  David Helder & Andrew Lanoix.
11  *
12  * All else Copyright (C) 2000, Ximian, Inc.
13  */
14
15 #ifdef HAVE_CONFIG_H
16 #include <config.h>
17 #endif
18 #include <fcntl.h>
19 #include <glib.h>
20 #include <string.h>
21
22 #include "soup-private.h"
23 #include "soup-socket.h"
24
25 #include <unistd.h>
26 #ifndef socklen_t
27 #  define socklen_t size_t
28 #endif
29
30 #ifndef INET_ADDRSTRLEN
31 #  define INET_ADDRSTRLEN 16
32 #  define INET6_ADDRSTRLEN 46
33 #endif
34
35 #define SOUP_SOCKADDR_IN(s) (*((struct sockaddr_in*) &s))
36
37 typedef struct {
38         SoupSocketConnectFn  func;
39         gpointer             data;
40
41         gpointer             inetaddr_id;
42         gpointer             tcp_id;
43 } SoupSocketConnectState;
44
45 static void
46 soup_address_new_sync_cb (SoupAddress *addr,
47                           SoupAddressStatus  status,
48                           gpointer           user_data)
49 {
50         SoupAddress **ret = user_data;
51         *ret = addr;
52 }
53
54 SoupAddress *
55 soup_address_new_sync (const gchar *name, const gint port)
56 {
57         SoupAddress *ret = (SoupAddress *) 0xdeadbeef;
58
59         soup_address_new (name, port, soup_address_new_sync_cb, &ret);
60
61         while (1) {
62                 g_main_iteration (TRUE);
63                 if (ret != (SoupAddress *) 0xdeadbeef) return ret;
64         }
65
66         return ret;
67 }
68
69 /**
70  * soup_address_ref
71  * @ia: SoupAddress to reference
72  *
73  * Increment the reference counter of the SoupAddress.
74  **/
75 void
76 soup_address_ref (SoupAddress* ia)
77 {
78         g_return_if_fail (ia != NULL);
79
80         ++ia->ref_count;
81 }
82
83 /**
84  * soup_address_copy
85  * @ia: SoupAddress to copy
86  *
87  * Creates a copy of the given SoupAddress
88  **/
89 SoupAddress *
90 soup_address_copy (SoupAddress* ia)
91 {
92         SoupAddress* new_ia;
93         g_return_val_if_fail (ia != NULL, NULL);
94
95         new_ia = g_new0(SoupAddress, 1);
96         new_ia->ref_count = 1;
97
98         new_ia->name = g_strdup (ia->name);
99         memcpy (&new_ia->sa, &ia->sa, sizeof(struct sockaddr));
100
101         return new_ia;
102 }
103
104 static void
105 soup_address_get_name_sync_cb (SoupAddress       *addr,
106                                SoupAddressStatus  status,
107                                const char        *name,
108                                gpointer           user_data)
109 {
110         const char **ret = user_data;
111         *ret = name;
112 }
113
114 const gchar *
115 soup_address_get_name_sync (SoupAddress *addr)
116 {
117         const char *ret = (const char *) 0xdeadbeef;
118
119         soup_address_get_name (addr, 
120                                soup_address_get_name_sync_cb, 
121                                (gpointer) &ret);
122
123         while (1) {
124                 g_main_iteration (TRUE);
125                 if (ret != (const char *) 0xdeadbeef) return ret;
126         }
127
128         return ret;
129 }
130
131 /**
132  * soup_address_get_canonical_name:
133  * @ia: Address to get the canonical name of.
134  *
135  * Get the "canonical" name of an address (eg, for IP4 the dotted
136  * decimal name 141.213.8.59).
137  *
138  * Returns: NULL if there was an error.  The caller is responsible
139  * for deleting the returned string.
140  **/
141 gchar*
142 soup_address_get_canonical_name (SoupAddress* ia)
143 {
144         gchar buffer [INET_ADDRSTRLEN]; /* defined in netinet/in.h */
145         guchar* p = (guchar*) &(SOUP_SOCKADDR_IN(ia->sa).sin_addr);
146
147         g_return_val_if_fail (ia != NULL, NULL);
148
149         g_snprintf(buffer,
150                    sizeof (buffer),
151                    "%d.%d.%d.%d",
152                    p [0],
153                    p [1],
154                    p [2],
155                    p [3]);
156
157         return g_strdup (buffer);
158 }
159
160 /**
161  * soup_address_get_port:
162  * @ia: Address to get the port number of.
163  *
164  * Get the port number.
165  * Returns: the port number.
166  */
167 gint
168 soup_address_get_port (const SoupAddress* ia)
169 {
170         g_return_val_if_fail(ia != NULL, -1);
171
172         return (gint) g_ntohs (((struct sockaddr_in*) &ia->sa)->sin_port);
173 }
174
175 /**
176  * soup_address_get_sockaddr:
177  * @ia: The %SoupAddress.
178  * @addrlen: Pointer to socklen_t the returned sockaddr's length is to be 
179  * placed in.
180  *
181  * Return value: const pointer to @ia's sockaddr buffer.
182  **/
183 const struct sockaddr *
184 soup_address_get_sockaddr (SoupAddress *ia, guint *addrlen)
185 {
186         g_return_val_if_fail (ia != NULL, NULL);
187
188         if (addrlen)
189                 *addrlen = sizeof (struct sockaddr_in);
190
191         return &ia->sa;
192 }
193
194 /**
195  * soup_address_hash:
196  * @p: Pointer to an #SoupAddress.
197  *
198  * Hash the address.  This is useful for glib containers.
199  *
200  * Returns: hash value.
201  **/
202 guint
203 soup_address_hash (const gpointer p)
204 {
205         const SoupAddress* ia;
206         guint32 port;
207         guint32 addr;
208
209         g_assert(p != NULL);
210
211         ia = (const SoupAddress*) p;
212
213         /* 
214          * We do pay attention to network byte order just in case the hash
215          * result is saved or sent to a different host.  
216          */
217         port = (guint32) g_ntohs (((struct sockaddr_in*) &ia->sa)->sin_port);
218         addr = g_ntohl (((struct sockaddr_in*) &ia->sa)->sin_addr.s_addr);
219
220         return (port ^ addr);
221 }
222
223 /**
224  * soup_address_equal:
225  * @p1: Pointer to first #SoupAddress.
226  * @p2: Pointer to second #SoupAddress.
227  *
228  * Compare two #SoupAddress's.
229  *
230  * Returns: 1 if they are the same; 0 otherwise.
231  **/
232 gint
233 soup_address_equal (const gpointer p1, const gpointer p2)
234 {
235         const SoupAddress* ia1 = (const SoupAddress*) p1;
236         const SoupAddress* ia2 = (const SoupAddress*) p2;
237
238         g_assert (p1 != NULL && p2 != NULL);
239
240         /* Note network byte order doesn't matter */
241         return ((SOUP_SOCKADDR_IN(ia1->sa).sin_addr.s_addr ==
242                  SOUP_SOCKADDR_IN(ia2->sa).sin_addr.s_addr) &&
243                 (SOUP_SOCKADDR_IN(ia1->sa).sin_port ==
244                  SOUP_SOCKADDR_IN(ia2->sa).sin_port));
245 }
246
247 /**
248  * soup_address_noport_equal:
249  * @p1: Pointer to first SoupAddress.
250  * @p2: Pointer to second SoupAddress.
251  *
252  * Compare two #SoupAddress's, but does not compare the port numbers.
253  *
254  * Returns: 1 if they are the same; 0 otherwise.
255  **/
256 gint
257 soup_address_noport_equal (const gpointer p1, const gpointer p2)
258 {
259         const SoupAddress* ia1 = (const SoupAddress*) p1;
260         const SoupAddress* ia2 = (const SoupAddress*) p2;
261
262         g_assert (p1 != NULL && p2 != NULL);
263
264         /* Note network byte order doesn't matter */
265         return (SOUP_SOCKADDR_IN(ia1->sa).sin_addr.s_addr ==
266                 SOUP_SOCKADDR_IN(ia2->sa).sin_addr.s_addr);
267 }
268
269 /**
270  * soup_address_gethostaddr:
271  *
272  * Get the primary host's #SoupAddress.
273  *
274  * Returns: the #SoupAddress of the host; NULL if there was an error.
275  * The caller is responsible for deleting the returned #SoupAddress.
276  **/
277 SoupAddress *
278 soup_address_gethostaddr (void)
279 {
280         gchar* name;
281         struct sockaddr_in* sa_in, sa;
282         SoupAddress* ia = NULL;
283
284         name = soup_address_gethostname ();
285
286         if (name && soup_gethostbyname (name, &sa, NULL)) {
287                 ia = g_new0 (SoupAddress, 1);
288                 ia->name = g_strdup (name);
289                 ia->ref_count = 1;
290
291                 sa_in = (struct sockaddr_in*) &ia->sa;
292                 sa_in->sin_family = AF_INET;
293                 sa_in->sin_port = 0;
294                 memcpy (&sa_in->sin_addr, &sa.sin_addr, 4);
295         }
296
297         return ia;
298 }
299
300
301 static void
302 soup_socket_connect_tcp_cb (SoupSocket* socket,
303                             SoupSocketConnectStatus status,
304                             gpointer data)
305 {
306         SoupSocketConnectState* state = (SoupSocketConnectState*) data;
307         SoupSocketConnectFn func = state->func;
308         gpointer user_data = state->data;
309
310         if (status == SOUP_SOCKET_NEW_STATUS_OK)
311                 (*func) (socket,
312                          SOUP_SOCKET_CONNECT_ERROR_NONE,
313                          user_data);
314         else
315                 (*func) (NULL,
316                          SOUP_SOCKET_CONNECT_ERROR_NETWORK,
317                          user_data);
318
319         if (state->tcp_id)
320                 g_free (state);
321 }
322
323 static void
324 soup_socket_connect_inetaddr_cb (SoupAddress* inetaddr,
325                                  SoupAddressStatus status,
326                                  gpointer data)
327 {
328         SoupSocketConnectState* state = (SoupSocketConnectState*) data;
329
330         if (status == SOUP_ADDRESS_STATUS_OK) {
331                 state->tcp_id = soup_socket_new (inetaddr,
332                                                  soup_socket_connect_tcp_cb,
333                                                  state);
334                 soup_address_unref (inetaddr);
335         } else {
336                 SoupSocketConnectFn func = state->func;
337                 gpointer user_data = state->data;
338
339                 (*func) (NULL, 
340                          SOUP_SOCKET_CONNECT_ERROR_ADDR_RESOLVE, 
341                          user_data);
342         }
343
344         if (state->inetaddr_id && !state->tcp_id)
345                 g_free (state);
346         else
347                 state->inetaddr_id = NULL;
348 }
349
350 /**
351  * soup_socket_connect:
352  * @hostname: Name of host to connect to
353  * @port: Port to connect to
354  * @func: Callback function
355  * @data: User data passed when callback function is called.
356  *
357  * A quick and easy non-blocking #SoupSocket constructor.  This
358  * connects to the specified address and port and then calls the
359  * callback with the data.  Use this function when you're a client
360  * connecting to a server and you don't want to block or mess with
361  * #SoupAddress's.  It may call the callback before the function
362  * returns.  It will call the callback if there is a failure.
363  *
364  * Returns: ID of the connection which can be used with
365  * soup_socket_connect_cancel() to cancel it; NULL if it succeeds
366  * or fails immediately.
367  **/
368 SoupSocketConnectId
369 soup_socket_connect (const gchar*        hostname,
370                      const gint          port,
371                      SoupSocketConnectFn func,
372                      gpointer            data)
373 {
374         SoupSocketConnectState* state;
375         SoupAddress *cached_addr;
376
377         g_return_val_if_fail (hostname != NULL, NULL);
378         g_return_val_if_fail (func != NULL, NULL);
379
380         state = g_new0 (SoupSocketConnectState, 1);
381         state->func = func;
382         state->data = data;
383
384         /* Check if a cached version of the address already exists */
385         cached_addr = soup_address_lookup_in_cache (hostname, port);
386         if (cached_addr) {
387                 state->tcp_id = soup_socket_new (cached_addr,
388                                                  soup_socket_connect_tcp_cb,
389                                                  state);
390                 soup_address_unref (cached_addr);
391         } else {
392                 state->inetaddr_id = soup_address_new (hostname,
393                                                        port,
394                                                        soup_socket_connect_inetaddr_cb,
395                                                        state);
396                 /* NOTE: soup_address_new could succeed immediately
397                  * and call our callback, in which case state->inetaddr_id
398                  * will be NULL but state->tcp_id may be set.
399                  */
400         }
401
402         if (state->tcp_id || state->inetaddr_id)
403                 return state;
404         else {
405                 g_free (state);
406                 return NULL;
407         }
408 }
409
410 /**
411  * soup_socket_connect_cancel:
412  * @id: Id of the connection.
413  *
414  * Cancel an asynchronous connection that was started with
415  * soup_socket_connect().
416  */
417 void
418 soup_socket_connect_cancel (SoupSocketConnectId id)
419 {
420         SoupSocketConnectState* state = (SoupSocketConnectState*) id;
421
422         g_return_if_fail (state != NULL);
423
424         if (state->inetaddr_id)
425                 soup_address_new_cancel (state->inetaddr_id);
426         else if (state->tcp_id)
427                 soup_socket_new_cancel (state->tcp_id);
428
429         g_free (state);
430 }
431
432 static void
433 soup_socket_connect_sync_cb (SoupSocket              *socket,
434                              SoupSocketConnectStatus  status,
435                              gpointer                 data)
436 {
437         SoupSocket **ret = data;
438         *ret = socket;
439 }
440
441 SoupSocket *
442 soup_socket_connect_sync (const gchar *name,
443                           const gint   port)
444 {
445         SoupSocket *ret = (SoupSocket *) 0xdeadbeef;
446
447         soup_socket_connect (name, port, soup_socket_connect_sync_cb, &ret);
448
449         while (1) {
450                 g_main_iteration (TRUE);
451                 if (ret != (SoupSocket *) 0xdeadbeef) return ret;
452         }
453
454         return ret;
455 }
456
457 static void
458 soup_socket_new_sync_cb (SoupSocket*         socket,
459                          SoupSocketNewStatus status,
460                          gpointer            data)
461 {
462         SoupSocket **ret = data;
463         *ret = socket;
464 }
465
466 SoupSocket *
467 soup_socket_new_sync (SoupAddress *addr)
468 {
469         SoupSocket *ret = (SoupSocket *) 0xdeadbeef;
470
471         soup_socket_new (addr, soup_socket_new_sync_cb, &ret);
472
473         while (1) {
474                 g_main_iteration (TRUE);
475                 if (ret != (SoupSocket *) 0xdeadbeef) return ret;
476         }
477
478         return ret;
479 }
480
481 /**
482  * soup_socket_ref
483  * @s: SoupSocket to reference
484  *
485  * Increment the reference counter of the SoupSocket.
486  **/
487 void
488 soup_socket_ref (SoupSocket* s)
489 {
490         g_return_if_fail (s != NULL);
491
492         ++s->ref_count;
493 }
494
495 /**
496  * soup_socket_unref
497  * @s: #SoupSocket to unreference
498  *
499  * Remove a reference from the #SoupSocket.  When reference count
500  * reaches 0, the socket is deleted.
501  **/
502 void
503 soup_socket_unref (SoupSocket* s)
504 {
505         g_return_if_fail(s != NULL);
506
507         --s->ref_count;
508
509         if (s->ref_count == 0) {
510                 close (s->sockfd);
511                 if (s->addr) soup_address_unref (s->addr);
512                 if (s->iochannel) g_io_channel_unref (s->iochannel);
513
514                 g_free(s);
515         }
516 }
517
518 /**
519  * soup_socket_get_iochannel:
520  * @socket: SoupSocket to get GIOChannel from.
521  *
522  * Get the #GIOChannel for the #SoupSocket.
523  *
524  * For a client socket, the #GIOChannel represents the data stream.
525  * Use it like you would any other #GIOChannel.
526  *
527  * For a server socket however, the #GIOChannel represents incoming
528  * connections.  If you can read from it, there's a connection
529  * waiting.
530  *
531  * There is one channel for every socket.  This function refs the
532  * channel before returning it.  You should unref the channel when
533  * you are done with it.  However, you should not close the channel -
534  * this is done when you delete the socket.
535  *
536  * Returns: A #GIOChannel; NULL on failure.
537  *
538  **/
539 GIOChannel*
540 soup_socket_get_iochannel (SoupSocket* socket)
541 {
542         g_return_val_if_fail (socket != NULL, NULL);
543
544         if (socket->iochannel == NULL)
545                 socket->iochannel = g_io_channel_unix_new (socket->sockfd);
546
547         g_io_channel_ref (socket->iochannel);
548
549         return socket->iochannel;
550 }
551
552 /**
553  * soup_socket_get_address:
554  * @socket: #SoupSocket to get address of.
555  *
556  * Get the address of the socket.  If the socket is client socket,
557  * the address is the address of the remote host it is connected to.
558  * If the socket is a server socket, the address is the address of
559  * the local host.  (Though you should use
560  * soup_address_gethostaddr() to get the #SoupAddress of the local
561  * host.)
562  *
563  * Returns: #SoupAddress of socket; NULL on failure.
564  **/
565 SoupAddress *
566 soup_socket_get_address (const SoupSocket* socket)
567 {
568         g_return_val_if_fail (socket != NULL, NULL);
569         g_return_val_if_fail (socket->addr != NULL, NULL);
570
571         soup_address_ref (socket->addr);
572
573         return socket->addr;
574 }
575
576 /**
577  * soup_socket_get_port:
578  * @socket: SoupSocket to get the port number of.
579  *
580  * Get the port number the socket is bound to.
581  *
582  * Returns: Port number of the socket.
583  **/
584 gint
585 soup_socket_get_port(const SoupSocket* socket)
586 {
587         g_return_val_if_fail (socket != NULL, 0);
588
589         return g_ntohs (SOUP_SOCKADDR_IN (socket->addr->sa).sin_port);
590 }
591
592 /**
593  * soup_socket_server_new:
594  * @port: Port number for the socket (SOUP_SERVER_ANY_PORT if you don't care).
595  *
596  * Create and open a new #SoupSocket with the specified port number.
597  * Use this sort of socket when your are a server and you know what
598  * the port number should be (or pass 0 if you don't care what the
599  * port is).
600  *
601  * Returns: a new #SoupSocket, or NULL if there was a failure.
602  **/
603 SoupSocket *
604 soup_socket_server_new (const gint port)
605 {
606         SoupSocket* s;
607         struct sockaddr_in* sa_in;
608         socklen_t socklen;
609         const int on = 1;
610         gint flags;
611
612         /* Create socket */
613         s = g_new0 (SoupSocket, 1);
614         s->ref_count = 1;
615
616         if ((s->sockfd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
617                 g_free (s);
618                 return NULL;
619         }
620
621         s->addr = g_new0 (SoupAddress, 1);
622         s->addr->ref_count = 1;
623
624         /* Set up address and port for connection */
625         sa_in = (struct sockaddr_in*) &s->addr->sa;
626         sa_in->sin_family = AF_INET;
627         sa_in->sin_addr.s_addr = g_htonl (INADDR_ANY);
628         sa_in->sin_port = g_htons (port);
629
630         /* Set REUSEADDR so we can reuse the port */
631         if (setsockopt (s->sockfd,
632                         SOL_SOCKET,
633                         SO_REUSEADDR,
634                         &on,
635                         sizeof (on)) != 0)
636                 g_warning("Can't set reuse on tcp socket\n");
637
638         /* Get the flags (should all be 0?) */
639         flags = fcntl (s->sockfd, F_GETFL, 0);
640         if (flags == -1) goto SETUP_ERROR;
641
642         /* Make the socket non-blocking */
643         if (fcntl (s->sockfd, F_SETFL, flags | O_NONBLOCK) == -1)
644                 goto SETUP_ERROR;
645
646         /* Bind */
647         if (bind (s->sockfd, &s->addr->sa, sizeof (s->addr->sa)) != 0)
648                 goto SETUP_ERROR;
649
650         /* Get the socket name - don't care if it fails */
651         socklen = sizeof (s->addr->sa);
652         getsockname (s->sockfd, &s->addr->sa, &socklen);
653
654         /* Listen */
655         if (listen (s->sockfd, 10) != 0) goto SETUP_ERROR;
656
657         return s;
658
659  SETUP_ERROR:
660         close (s->sockfd);
661         g_free (s->addr);
662         g_free (s);
663         return NULL;
664 }