1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * soup-socket.c: Platform neutral socket networking code.
6 * David Helder (dhelder@umich.edu)
7 * Alex Graveley (alex@ximian.com)
9 * Original code compliments of David Helder's GNET Networking Library, and is
10 * Copyright (C) 2000 David Helder & Andrew Lanoix.
12 * All else Copyright (C) 2000, Ximian, Inc.
22 #include "soup-private.h"
23 #include "soup-socket.h"
27 # define socklen_t size_t
30 #ifndef INET_ADDRSTRLEN
31 # define INET_ADDRSTRLEN 16
32 # define INET6_ADDRSTRLEN 46
35 #define SOUP_SOCKADDR_IN(s) (*((struct sockaddr_in*) &s))
38 SoupSocketConnectFn func;
43 } SoupSocketConnectState;
46 soup_address_new_sync_cb (SoupAddress *addr,
47 SoupAddressStatus status,
50 SoupAddress **ret = user_data;
55 soup_address_new_sync (const gchar *name, const gint port)
57 SoupAddress *ret = (SoupAddress *) 0xdeadbeef;
59 soup_address_new (name, port, soup_address_new_sync_cb, &ret);
62 g_main_iteration (TRUE);
63 if (ret != (SoupAddress *) 0xdeadbeef) return ret;
71 * @ia: SoupAddress to reference
73 * Increment the reference counter of the SoupAddress.
76 soup_address_ref (SoupAddress* ia)
78 g_return_if_fail (ia != NULL);
85 * @ia: SoupAddress to copy
87 * Creates a copy of the given SoupAddress
90 soup_address_copy (SoupAddress* ia)
93 g_return_val_if_fail (ia != NULL, NULL);
95 new_ia = g_new0(SoupAddress, 1);
96 new_ia->ref_count = 1;
98 new_ia->name = g_strdup (ia->name);
99 memcpy (&new_ia->sa, &ia->sa, sizeof(struct sockaddr));
105 soup_address_get_name_sync_cb (SoupAddress *addr,
106 SoupAddressStatus status,
110 const char **ret = user_data;
115 soup_address_get_name_sync (SoupAddress *addr)
117 const char *ret = (const char *) 0xdeadbeef;
119 soup_address_get_name (addr,
120 soup_address_get_name_sync_cb,
124 g_main_iteration (TRUE);
125 if (ret != (const char *) 0xdeadbeef) return ret;
132 * soup_address_get_canonical_name:
133 * @ia: Address to get the canonical name of.
135 * Get the "canonical" name of an address (eg, for IP4 the dotted
136 * decimal name 141.213.8.59).
138 * Returns: NULL if there was an error. The caller is responsible
139 * for deleting the returned string.
142 soup_address_get_canonical_name (SoupAddress* ia)
144 gchar buffer [INET_ADDRSTRLEN]; /* defined in netinet/in.h */
145 guchar* p = (guchar*) &(SOUP_SOCKADDR_IN(ia->sa).sin_addr);
147 g_return_val_if_fail (ia != NULL, NULL);
157 return g_strdup (buffer);
161 * soup_address_get_port:
162 * @ia: Address to get the port number of.
164 * Get the port number.
165 * Returns: the port number.
168 soup_address_get_port (const SoupAddress* ia)
170 g_return_val_if_fail(ia != NULL, -1);
172 return (gint) g_ntohs (((struct sockaddr_in*) &ia->sa)->sin_port);
176 * soup_address_get_sockaddr:
177 * @ia: The %SoupAddress.
178 * @addrlen: Pointer to socklen_t the returned sockaddr's length is to be
181 * Return value: const pointer to @ia's sockaddr buffer.
183 const struct sockaddr *
184 soup_address_get_sockaddr (SoupAddress *ia, guint *addrlen)
186 g_return_val_if_fail (ia != NULL, NULL);
189 *addrlen = sizeof (struct sockaddr_in);
196 * @p: Pointer to an #SoupAddress.
198 * Hash the address. This is useful for glib containers.
200 * Returns: hash value.
203 soup_address_hash (const gpointer p)
205 const SoupAddress* ia;
211 ia = (const SoupAddress*) p;
214 * We do pay attention to network byte order just in case the hash
215 * result is saved or sent to a different host.
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);
220 return (port ^ addr);
224 * soup_address_equal:
225 * @p1: Pointer to first #SoupAddress.
226 * @p2: Pointer to second #SoupAddress.
228 * Compare two #SoupAddress's.
230 * Returns: 1 if they are the same; 0 otherwise.
233 soup_address_equal (const gpointer p1, const gpointer p2)
235 const SoupAddress* ia1 = (const SoupAddress*) p1;
236 const SoupAddress* ia2 = (const SoupAddress*) p2;
238 g_assert (p1 != NULL && p2 != NULL);
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));
248 * soup_address_noport_equal:
249 * @p1: Pointer to first SoupAddress.
250 * @p2: Pointer to second SoupAddress.
252 * Compare two #SoupAddress's, but does not compare the port numbers.
254 * Returns: 1 if they are the same; 0 otherwise.
257 soup_address_noport_equal (const gpointer p1, const gpointer p2)
259 const SoupAddress* ia1 = (const SoupAddress*) p1;
260 const SoupAddress* ia2 = (const SoupAddress*) p2;
262 g_assert (p1 != NULL && p2 != NULL);
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);
270 * soup_address_gethostaddr:
272 * Get the primary host's #SoupAddress.
274 * Returns: the #SoupAddress of the host; NULL if there was an error.
275 * The caller is responsible for deleting the returned #SoupAddress.
278 soup_address_gethostaddr (void)
281 struct sockaddr_in* sa_in, sa;
282 SoupAddress* ia = NULL;
284 name = soup_address_gethostname ();
286 if (name && soup_gethostbyname (name, &sa, NULL)) {
287 ia = g_new0 (SoupAddress, 1);
288 ia->name = g_strdup (name);
291 sa_in = (struct sockaddr_in*) &ia->sa;
292 sa_in->sin_family = AF_INET;
294 memcpy (&sa_in->sin_addr, &sa.sin_addr, 4);
302 soup_socket_connect_tcp_cb (SoupSocket* socket,
303 SoupSocketConnectStatus status,
306 SoupSocketConnectState* state = (SoupSocketConnectState*) data;
307 SoupSocketConnectFn func = state->func;
308 gpointer user_data = state->data;
310 if (status == SOUP_SOCKET_NEW_STATUS_OK)
312 SOUP_SOCKET_CONNECT_ERROR_NONE,
316 SOUP_SOCKET_CONNECT_ERROR_NETWORK,
324 soup_socket_connect_inetaddr_cb (SoupAddress* inetaddr,
325 SoupAddressStatus status,
328 SoupSocketConnectState* state = (SoupSocketConnectState*) data;
330 if (status == SOUP_ADDRESS_STATUS_OK) {
331 state->tcp_id = soup_socket_new (inetaddr,
332 soup_socket_connect_tcp_cb,
334 soup_address_unref (inetaddr);
336 SoupSocketConnectFn func = state->func;
337 gpointer user_data = state->data;
340 SOUP_SOCKET_CONNECT_ERROR_ADDR_RESOLVE,
344 if (state->inetaddr_id && !state->tcp_id)
347 state->inetaddr_id = NULL;
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.
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.
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.
369 soup_socket_connect (const gchar* hostname,
371 SoupSocketConnectFn func,
374 SoupSocketConnectState* state;
375 SoupAddress *cached_addr;
377 g_return_val_if_fail (hostname != NULL, NULL);
378 g_return_val_if_fail (func != NULL, NULL);
380 state = g_new0 (SoupSocketConnectState, 1);
384 /* Check if a cached version of the address already exists */
385 cached_addr = soup_address_lookup_in_cache (hostname, port);
387 state->tcp_id = soup_socket_new (cached_addr,
388 soup_socket_connect_tcp_cb,
390 soup_address_unref (cached_addr);
392 state->inetaddr_id = soup_address_new (hostname,
394 soup_socket_connect_inetaddr_cb,
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.
402 if (state->tcp_id || state->inetaddr_id)
411 * soup_socket_connect_cancel:
412 * @id: Id of the connection.
414 * Cancel an asynchronous connection that was started with
415 * soup_socket_connect().
418 soup_socket_connect_cancel (SoupSocketConnectId id)
420 SoupSocketConnectState* state = (SoupSocketConnectState*) id;
422 g_return_if_fail (state != NULL);
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);
433 soup_socket_connect_sync_cb (SoupSocket *socket,
434 SoupSocketConnectStatus status,
437 SoupSocket **ret = data;
442 soup_socket_connect_sync (const gchar *name,
445 SoupSocket *ret = (SoupSocket *) 0xdeadbeef;
447 soup_socket_connect (name, port, soup_socket_connect_sync_cb, &ret);
450 g_main_iteration (TRUE);
451 if (ret != (SoupSocket *) 0xdeadbeef) return ret;
458 soup_socket_new_sync_cb (SoupSocket* socket,
459 SoupSocketNewStatus status,
462 SoupSocket **ret = data;
467 soup_socket_new_sync (SoupAddress *addr)
469 SoupSocket *ret = (SoupSocket *) 0xdeadbeef;
471 soup_socket_new (addr, soup_socket_new_sync_cb, &ret);
474 g_main_iteration (TRUE);
475 if (ret != (SoupSocket *) 0xdeadbeef) return ret;
483 * @s: SoupSocket to reference
485 * Increment the reference counter of the SoupSocket.
488 soup_socket_ref (SoupSocket* s)
490 g_return_if_fail (s != NULL);
497 * @s: #SoupSocket to unreference
499 * Remove a reference from the #SoupSocket. When reference count
500 * reaches 0, the socket is deleted.
503 soup_socket_unref (SoupSocket* s)
505 g_return_if_fail(s != NULL);
509 if (s->ref_count == 0) {
511 if (s->addr) soup_address_unref (s->addr);
512 if (s->iochannel) g_io_channel_unref (s->iochannel);
519 * soup_socket_get_iochannel:
520 * @socket: SoupSocket to get GIOChannel from.
522 * Get the #GIOChannel for the #SoupSocket.
524 * For a client socket, the #GIOChannel represents the data stream.
525 * Use it like you would any other #GIOChannel.
527 * For a server socket however, the #GIOChannel represents incoming
528 * connections. If you can read from it, there's a connection
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.
536 * Returns: A #GIOChannel; NULL on failure.
540 soup_socket_get_iochannel (SoupSocket* socket)
542 g_return_val_if_fail (socket != NULL, NULL);
544 if (socket->iochannel == NULL)
545 socket->iochannel = g_io_channel_unix_new (socket->sockfd);
547 g_io_channel_ref (socket->iochannel);
549 return socket->iochannel;
553 * soup_socket_get_address:
554 * @socket: #SoupSocket to get address of.
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
563 * Returns: #SoupAddress of socket; NULL on failure.
566 soup_socket_get_address (const SoupSocket* socket)
568 g_return_val_if_fail (socket != NULL, NULL);
569 g_return_val_if_fail (socket->addr != NULL, NULL);
571 soup_address_ref (socket->addr);
577 * soup_socket_get_port:
578 * @socket: SoupSocket to get the port number of.
580 * Get the port number the socket is bound to.
582 * Returns: Port number of the socket.
585 soup_socket_get_port(const SoupSocket* socket)
587 g_return_val_if_fail (socket != NULL, 0);
589 return g_ntohs (SOUP_SOCKADDR_IN (socket->addr->sa).sin_port);
593 * soup_socket_server_new:
594 * @port: Port number for the socket (SOUP_SERVER_ANY_PORT if you don't care).
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
601 * Returns: a new #SoupSocket, or NULL if there was a failure.
604 soup_socket_server_new (const gint port)
607 struct sockaddr_in* sa_in;
613 s = g_new0 (SoupSocket, 1);
616 if ((s->sockfd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
621 s->addr = g_new0 (SoupAddress, 1);
622 s->addr->ref_count = 1;
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);
630 /* Set REUSEADDR so we can reuse the port */
631 if (setsockopt (s->sockfd,
636 g_warning("Can't set reuse on tcp socket\n");
638 /* Get the flags (should all be 0?) */
639 flags = fcntl (s->sockfd, F_GETFL, 0);
640 if (flags == -1) goto SETUP_ERROR;
642 /* Make the socket non-blocking */
643 if (fcntl (s->sockfd, F_SETFL, flags | O_NONBLOCK) == -1)
647 if (bind (s->sockfd, &s->addr->sa, sizeof (s->addr->sa)) != 0)
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);
655 if (listen (s->sockfd, 10) != 0) goto SETUP_ERROR;