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.
23 #include "soup-private.h"
24 #include "soup-socket.h"
27 # define socklen_t gint32
28 # define SOUP_CLOSE_SOCKET(fd) closesocket(fd)
29 # define SOUP_SOCKET_IOCHANNEL_NEW(fd) g_io_channel_win32_new_stream_socket(fd)
30 # ifndef INET_ADDRSTRLEN
31 # define INET_ADDRSTRLEN 16
32 # define INET6_ADDRSTRLEN 46
37 # define socklen_t size_t
39 # define SOUP_CLOSE_SOCKET(fd) close(fd)
40 # define SOUP_SOCKET_IOCHANNEL_NEW(fd) g_io_channel_unix_new(fd)
43 #define SOUP_SOCKADDR_IN(s) (*((struct sockaddr_in*) &s))
46 SoupSocketConnectFn func;
51 } SoupSocketConnectState;
54 soup_address_new_sync_cb (SoupAddress *addr,
55 SoupAddressStatus status,
58 SoupAddress **ret = user_data;
63 soup_address_new_sync (const gchar *name, const gint port)
65 SoupAddress *ret = (SoupAddress *) 0xdeadbeef;
67 soup_address_new (name, port, soup_address_new_sync_cb, &ret);
70 g_main_iteration (TRUE);
71 if (ret != (SoupAddress *) 0xdeadbeef) return ret;
79 * @ia: SoupAddress to reference
81 * Increment the reference counter of the SoupAddress.
84 soup_address_ref (SoupAddress* ia)
86 g_return_if_fail (ia != NULL);
93 * @ia: SoupAddress to copy
95 * Creates a copy of the given SoupAddress
98 soup_address_copy (SoupAddress* ia)
101 g_return_val_if_fail (ia != NULL, NULL);
103 new_ia = g_new0(SoupAddress, 1);
104 new_ia->ref_count = 1;
106 new_ia->name = g_strdup (ia->name);
107 memcpy (&new_ia->sa, &ia->sa, sizeof(struct sockaddr));
113 soup_address_get_name_sync_cb (SoupAddress *addr,
114 SoupAddressStatus status,
118 const char **ret = user_data;
123 soup_address_get_name_sync (SoupAddress *addr)
125 const char *ret = (const char *) 0xdeadbeef;
127 soup_address_get_name (addr,
128 soup_address_get_name_sync_cb,
132 g_main_iteration (TRUE);
133 if (ret != (const char *) 0xdeadbeef) return ret;
140 * soup_address_get_canonical_name:
141 * @ia: Address to get the canonical name of.
143 * Get the "canonical" name of an address (eg, for IP4 the dotted
144 * decimal name 141.213.8.59).
146 * Returns: NULL if there was an error. The caller is responsible
147 * for deleting the returned string.
150 soup_address_get_canonical_name (SoupAddress* ia)
152 gchar buffer [INET_ADDRSTRLEN]; /* defined in netinet/in.h */
153 guchar* p = (guchar*) &(SOUP_SOCKADDR_IN(ia->sa).sin_addr);
155 g_return_val_if_fail (ia != NULL, NULL);
165 return g_strdup (buffer);
169 * soup_address_get_port:
170 * @ia: Address to get the port number of.
172 * Get the port number.
173 * Returns: the port number.
176 soup_address_get_port (const SoupAddress* ia)
178 g_return_val_if_fail(ia != NULL, -1);
180 return (gint) g_ntohs (((struct sockaddr_in*) &ia->sa)->sin_port);
184 * soup_address_set_port:
185 * @ia: Address to set the port number of.
186 * @port: New port number
188 * Set the port number.
191 soup_address_set_port (const SoupAddress* ia, guint port)
193 g_return_if_fail (ia != NULL);
195 ((struct sockaddr_in*) &ia->sa)->sin_port = g_htons (port);
200 * @p: Pointer to an #SoupAddress.
202 * Hash the address. This is useful for glib containers.
204 * Returns: hash value.
207 soup_address_hash (const gpointer p)
209 const SoupAddress* ia;
215 ia = (const SoupAddress*) p;
216 /* We do pay attention to network byte order just in case the hash
217 result is saved or sent to a different host. */
218 port = (guint32) g_ntohs (((struct sockaddr_in*) &ia->sa)->sin_port);
219 addr = g_ntohl (((struct sockaddr_in*) &ia->sa)->sin_addr.s_addr);
221 return (port ^ addr);
225 * soup_address_equal:
226 * @p1: Pointer to first #SoupAddress.
227 * @p2: Pointer to second #SoupAddress.
229 * Compare two #SoupAddress's.
231 * Returns: 1 if they are the same; 0 otherwise.
234 soup_address_equal (const gpointer p1, const gpointer p2)
236 const SoupAddress* ia1 = (const SoupAddress*) p1;
237 const SoupAddress* ia2 = (const SoupAddress*) p2;
239 g_assert(p1 != NULL && p2 != NULL);
241 /* Note network byte order doesn't matter */
242 return ((SOUP_SOCKADDR_IN(ia1->sa).sin_addr.s_addr ==
243 SOUP_SOCKADDR_IN(ia2->sa).sin_addr.s_addr) &&
244 (SOUP_SOCKADDR_IN(ia1->sa).sin_port ==
245 SOUP_SOCKADDR_IN(ia2->sa).sin_port));
249 * soup_address_noport_equal:
250 * @p1: Pointer to first SoupAddress.
251 * @p2: Pointer to second SoupAddress.
253 * Compare two #SoupAddress's, but does not compare the port numbers.
255 * Returns: 1 if they are the same; 0 otherwise.
258 soup_address_noport_equal (const gpointer p1, const gpointer p2)
260 const SoupAddress* ia1 = (const SoupAddress*) p1;
261 const SoupAddress* ia2 = (const SoupAddress*) p2;
263 g_assert (p1 != NULL && p2 != NULL);
265 /* Note network byte order doesn't matter */
266 return (SOUP_SOCKADDR_IN(ia1->sa).sin_addr.s_addr ==
267 SOUP_SOCKADDR_IN(ia2->sa).sin_addr.s_addr);
271 * soup_address_gethostaddr:
273 * Get the primary host's #SoupAddress.
275 * Returns: the #SoupAddress of the host; NULL if there was an error.
276 * The caller is responsible for deleting the returned #SoupAddress.
279 soup_address_gethostaddr (void)
282 struct sockaddr_in* sa_in, sa;
283 SoupAddress* ia = NULL;
285 name = soup_address_gethostname ();
287 if (name && soup_gethostbyname (name, &sa, NULL)) {
288 ia = g_new0 (SoupAddress, 1);
289 ia->name = g_strdup (name);
292 sa_in = (struct sockaddr_in*) &ia->sa;
293 sa_in->sin_family = AF_INET;
295 memcpy (&sa_in->sin_addr, &sa.sin_addr, 4);
303 soup_socket_connect_tcp_cb (SoupSocket* socket,
304 SoupSocketConnectStatus status,
307 SoupSocketConnectState* state = (SoupSocketConnectState*) data;
309 if (status == SOUP_SOCKET_NEW_STATUS_OK)
310 (*state->func) (socket,
311 SOUP_SOCKET_CONNECT_ERROR_NONE,
314 (*state->func) (NULL,
315 SOUP_SOCKET_CONNECT_ERROR_NETWORK,
322 soup_socket_connect_inetaddr_cb (SoupAddress* inetaddr,
323 SoupAddressStatus status,
326 SoupSocketConnectState* state = (SoupSocketConnectState*) data;
328 if (status == SOUP_ADDRESS_STATUS_OK) {
329 state->inetaddr_id = NULL;
330 state->tcp_id = soup_socket_new (inetaddr,
331 soup_socket_connect_tcp_cb,
333 soup_address_unref (inetaddr);
335 (*state->func) (NULL,
336 SOUP_SOCKET_CONNECT_ERROR_ADDR_RESOLVE,
343 * soup_socket_connect:
344 * @hostname: Name of host to connect to
345 * @port: Port to connect to
346 * @func: Callback function
347 * @data: User data passed when callback function is called.
349 * A quick and easy non-blocking #SoupSocket constructor. This
350 * connects to the specified address and port and then calls the
351 * callback with the data. Use this function when you're a client
352 * connecting to a server and you don't want to block or mess with
353 * #SoupAddress's. It may call the callback before the function
354 * returns. It will call the callback if there is a failure.
356 * Returns: ID of the connection which can be used with
357 * soup_socket_connect_cancel() to cancel it; NULL on
361 soup_socket_connect (const gchar* hostname,
363 SoupSocketConnectFn func,
366 SoupSocketConnectState* state;
369 g_return_val_if_fail (hostname != NULL, NULL);
370 g_return_val_if_fail (func != NULL, NULL);
372 state = g_new0 (SoupSocketConnectState, 1);
376 id = soup_address_new (hostname,
378 soup_socket_connect_inetaddr_cb,
381 /* Note that soup_address_new can fail immediately and call
382 our callback which will delete the state. The users callback
383 would be called in the process. */
385 if (id == NULL) return NULL;
387 state->inetaddr_id = id;
393 * soup_socket_connect_cancel:
394 * @id: Id of the connection.
396 * Cancel an asynchronous connection that was started with
397 * soup_socket_connect().
400 soup_socket_connect_cancel (SoupSocketConnectId id)
402 SoupSocketConnectState* state = (SoupSocketConnectState*) id;
404 g_return_if_fail (state != NULL);
406 if (state->inetaddr_id)
407 soup_address_new_cancel (state->inetaddr_id);
408 else if (state->tcp_id)
409 soup_socket_new_cancel (state->tcp_id);
415 soup_socket_connect_sync_cb (SoupSocket *socket,
416 SoupSocketConnectStatus status,
419 SoupSocket **ret = data;
424 soup_socket_connect_sync (const gchar *name,
427 SoupSocket *ret = (SoupSocket *) 0xdeadbeef;
429 soup_socket_connect (name, port, soup_socket_connect_sync_cb, &ret);
432 g_main_iteration (TRUE);
433 if (ret != (SoupSocket *) 0xdeadbeef) return ret;
440 soup_socket_new_sync_cb (SoupSocket* socket,
441 SoupSocketNewStatus status,
444 SoupSocket **ret = data;
449 soup_socket_new_sync (SoupAddress *addr)
451 SoupSocket *ret = (SoupSocket *) 0xdeadbeef;
453 soup_socket_new (addr, soup_socket_new_sync_cb, &ret);
456 g_main_iteration (TRUE);
457 if (ret != (SoupSocket *) 0xdeadbeef) return ret;
465 * @s: SoupSocket to reference
467 * Increment the reference counter of the SoupSocket.
470 soup_socket_ref (SoupSocket* s)
472 g_return_if_fail (s != NULL);
479 * @s: #SoupSocket to unreference
481 * Remove a reference from the #SoupSocket. When reference count
482 * reaches 0, the socket is deleted.
485 soup_socket_unref (SoupSocket* s)
487 g_return_if_fail(s != NULL);
491 if (s->ref_count == 0) {
492 SOUP_CLOSE_SOCKET (s->sockfd);
493 if (s->addr) soup_address_unref (s->addr);
494 if (s->iochannel) g_io_channel_unref (s->iochannel);
501 * soup_socket_get_iochannel:
502 * @socket: SoupSocket to get GIOChannel from.
504 * Get the #GIOChannel for the #SoupSocket.
506 * For a client socket, the #GIOChannel represents the data stream.
507 * Use it like you would any other #GIOChannel.
509 * For a server socket however, the #GIOChannel represents incoming
510 * connections. If you can read from it, there's a connection
513 * There is one channel for every socket. This function refs the
514 * channel before returning it. You should unref the channel when
515 * you are done with it. However, you should not close the channel -
516 * this is done when you delete the socket.
518 * Returns: A #GIOChannel; NULL on failure.
522 soup_socket_get_iochannel (SoupSocket* socket)
524 g_return_val_if_fail (socket != NULL, NULL);
526 if (socket->iochannel == NULL)
527 socket->iochannel = SOUP_SOCKET_IOCHANNEL_NEW (socket->sockfd);
529 g_io_channel_ref (socket->iochannel);
531 return socket->iochannel;
535 * soup_socket_get_address:
536 * @socket: #SoupSocket to get address of.
538 * Get the address of the socket. If the socket is client socket,
539 * the address is the address of the remote host it is connected to.
540 * If the socket is a server socket, the address is the address of
541 * the local host. (Though you should use
542 * soup_address_gethostaddr() to get the #SoupAddress of the local
545 * Returns: #SoupAddress of socket; NULL on failure.
548 soup_socket_get_address (const SoupSocket* socket)
550 g_return_val_if_fail (socket != NULL, NULL);
551 g_return_val_if_fail (socket->addr != NULL, NULL);
553 soup_address_ref (socket->addr);
559 * soup_socket_get_port:
560 * @socket: SoupSocket to get the port number of.
562 * Get the port number the socket is bound to.
564 * Returns: Port number of the socket.
567 soup_socket_get_port(const SoupSocket* socket)
569 g_return_val_if_fail (socket != NULL, 0);
571 return g_ntohs (SOUP_SOCKADDR_IN (socket->addr->sa).sin_port);
575 * soup_socket_server_new:
576 * @port: Port number for the socket (SOUP_SERVER_ANY_PORT if you don't care).
578 * Create and open a new #SoupSocket with the specified port number.
579 * Use this sort of socket when your are a server and you know what
580 * the port number should be (or pass 0 if you don't care what the
583 * Returns: a new #SoupSocket, or NULL if there was a failure.
586 soup_socket_server_new (const gint port)
589 struct sockaddr_in* sa_in;
593 s = g_new0 (SoupSocket, 1);
596 if ((s->sockfd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
601 s->addr = g_new0 (SoupAddress, 1);
602 s->addr->ref_count = 1;
604 /* Set up address and port for connection */
605 sa_in = (struct sockaddr_in*) &s->addr->sa;
606 sa_in->sin_family = AF_INET;
607 sa_in->sin_addr.s_addr = g_htonl (INADDR_ANY);
608 sa_in->sin_port = g_htons (port);
610 /* The socket is set to non-blocking mode later in the Windows
617 /* Set REUSEADDR so we can reuse the port */
618 if (setsockopt (s->sockfd,
623 g_warning("Can't set reuse on tcp socket\n");
625 /* Get the flags (should all be 0?) */
626 flags = fcntl (s->sockfd, F_GETFL, 0);
627 if (flags == -1) goto SETUP_ERROR;
629 /* Make the socket non-blocking */
630 if (fcntl (s->sockfd, F_SETFL, flags | O_NONBLOCK) == -1)
636 if (bind (s->sockfd, &s->addr->sa, sizeof (s->addr->sa)) != 0)
639 /* Get the socket name - don't care if it fails */
640 socklen = sizeof (s->addr->sa);
641 getsockname (s->sockfd, &s->addr->sa, &socklen);
644 if (listen (s->sockfd, 10) != 0) goto SETUP_ERROR;
649 SOUP_CLOSE_SOCKET (s->sockfd);