loudmouth/lm-socket.c
changeset 243 fa0794ef3570
parent 212 87bc6b37a9e9
child 244 8a05b79bad24
equal deleted inserted replaced
242:b0b17385a143 243:fa0794ef3570
     1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
     1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
     2 /*
     2 /*
     3  * Copyright (C) 2006 Imendio AB
     3  * Copyright (C) 2006 Imendio AB
       
     4  * Copyright (C) 2006 Nokia Corporation. All rights reserved.
       
     5  * Copyright (C) 2007 Collabora Ltd.
     4  *
     6  *
     5  * This program is free software; you can redistribute it and/or
     7  * This program is free software; you can redistribute it and/or
     6  * modify it under the terms of the GNU Lesser General Public License as
     8  * modify it under the terms of the GNU Lesser General Public License as
     7  * published by the Free Software Foundation; either version 2 of the
     9  * published by the Free Software Foundation; either version 2 of the
     8  * License, or (at your option) any later version.
    10  * License, or (at your option) any later version.
    19  */
    21  */
    20 
    22 
    21 #include <config.h>
    23 #include <config.h>
    22 
    24 
    23 #include <string.h>
    25 #include <string.h>
       
    26 #include <arpa/nameser.h>
       
    27 #include <resolv.h>
    24 
    28 
    25 #include "lm-debug.h"
    29 #include "lm-debug.h"
    26 #include "lm-internals.h"
    30 #include "lm-internals.h"
    27 #include "lm-misc.h"
    31 #include "lm-misc.h"
    28 #include "lm-ssl.h"
    32 #include "lm-ssl.h"
   610 	}
   614 	}
   611 
   615 
   612 	return TRUE;
   616 	return TRUE;
   613 }
   617 }
   614 
   618 
       
   619 static gboolean
       
   620 _parse_srv_response (unsigned char *srv, int srv_len, gchar **out_server, guint *out_port)
       
   621 {
       
   622 	int qdcount;
       
   623 	int ancount;
       
   624 	int len;
       
   625 	const unsigned char *pos = srv + sizeof(HEADER);
       
   626 	unsigned char *end = srv + srv_len;
       
   627 	HEADER *head = (HEADER *)srv;
       
   628 	char name[256];
       
   629 	char pref_name[256];
       
   630 	guint pref_port = 0;
       
   631 	guint pref_prio = 9999;
       
   632 
       
   633 	pref_name[0] = 0;
       
   634 
       
   635 	qdcount = ntohs (head->qdcount);
       
   636 	ancount = ntohs (head->ancount);
       
   637 
       
   638 	/* Ignore the questions */
       
   639 	while (qdcount-- > 0 && (len = dn_expand (srv, end, pos, name, 255)) >= 0) {
       
   640 		g_assert (len >= 0);
       
   641 		pos += len + QFIXEDSZ;
       
   642 	}
       
   643 
       
   644 	/* Parse the answers */
       
   645 	while (ancount-- > 0 && (len = dn_expand (srv, end, pos, name, 255)) >= 0) {
       
   646 		/* Ignore the initial string */
       
   647 		uint16_t pref, weight, port;
       
   648 		g_assert (len >= 0);
       
   649 		pos += len;
       
   650 		/* Ignore type, ttl, class and dlen */
       
   651 		pos += 10;
       
   652 		GETSHORT (pref, pos);
       
   653 		GETSHORT (weight, pos);
       
   654 		GETSHORT (port, pos);
       
   655 		len = dn_expand (srv, end, pos, name, 255);
       
   656 		if (pref < pref_prio) {
       
   657 			pref_prio = pref;
       
   658 			strcpy (pref_name, name);
       
   659 			pref_port = port;
       
   660 		}
       
   661 		pos += len;
       
   662 	}
       
   663 
       
   664 	if (pref_name[0]) {
       
   665 		*out_server = g_strdup (pref_name);
       
   666 		*out_port = pref_port;
       
   667 		return TRUE;
       
   668 	} 
       
   669 	return FALSE;
       
   670 }
       
   671 
   615 LmSocket *
   672 LmSocket *
   616 lm_socket_create (GMainContext      *context,
   673 lm_socket_create (GMainContext      *context,
   617 		  IncomingDataFunc   func,
   674 		  IncomingDataFunc   func,
   618 		  gpointer           user_data,
   675 		  gpointer           user_data,
   619 		  LmConnection      *connection,
   676 		  LmConnection      *connection,
   625 		  GError           **error)
   682 		  GError           **error)
   626 {
   683 {
   627 	LmSocket        *socket;
   684 	LmSocket        *socket;
   628 	struct addrinfo  req;
   685 	struct addrinfo  req;
   629 	struct addrinfo *ans;
   686 	struct addrinfo *ans;
       
   687 	const char      *remote_addr;
   630 	LmConnectData   *data;
   688 	LmConnectData   *data;
       
   689 	int              err;
       
   690 	char            *srv;
       
   691 #define SRV_LEN 8192
       
   692 	unsigned char    srv_ans[SRV_LEN];
   631 
   693 
   632 	g_return_val_if_fail (server != NULL, NULL);
   694 	g_return_val_if_fail (server != NULL, NULL);
   633 	g_return_val_if_fail ((port >= MIN_PORT && port <= MAX_PORT), NULL);
   695 	g_return_val_if_fail ((port >= MIN_PORT && port <= MAX_PORT), NULL);
   634 	g_return_val_if_fail (func != NULL, NULL);
   696 	g_return_val_if_fail (func != NULL, NULL);
   635 
   697 
   651 	socket->proxy = NULL;
   713 	socket->proxy = NULL;
   652 	socket->blocking = blocking;
   714 	socket->blocking = blocking;
   653 	socket->func = func;
   715 	socket->func = func;
   654 	socket->user_data = user_data;
   716 	socket->user_data = user_data;
   655 
   717 
       
   718 	res_init ();
       
   719 	srv = g_strdup_printf ("_xmpp-client._tcp.%s", socket->server);
       
   720 	err = res_query (srv, C_IN, T_SRV, srv_ans, SRV_LEN);
       
   721 	if (err > 0) {
       
   722 		_parse_srv_response (srv_ans, err, &(socket->server), &(socket->port));
       
   723 	}
       
   724 	g_free (srv);
       
   725 
   656 	if (context) {
   726 	if (context) {
   657 		socket->context = g_main_context_ref (context);
   727 		socket->context = g_main_context_ref (context);
   658 	}
   728 	}
   659 
   729 
   660 	if (proxy) {
   730 	if (proxy) {
   661 		int          err;
       
   662 		const gchar *proxy_server;
       
   663 
       
   664 		socket->proxy = lm_proxy_ref (proxy);
   731 		socket->proxy = lm_proxy_ref (proxy);
   665 
   732 		remote_addr = lm_proxy_get_server (socket->proxy);
   666 		proxy_server = lm_proxy_get_server (socket->proxy);
   733 	} else {
   667 
   734 	    	remote_addr = socket->server;
   668 		/* Connect through proxy */
   735 	}
   669 		g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET,
   736 
   670 		       "Going to connect to proxy %s\n", proxy_server);
   737 	g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET,
   671 
   738 	       "Going to connect to %s%s:%u\n", (proxy) ? "proxy " : "",
   672 		err = getaddrinfo (proxy_server, NULL, &req, &ans);
   739 	       remote_addr, socket->port);
   673 		if (err != 0) {
   740 
   674 			const char *str;
   741 	err = getaddrinfo (remote_addr, NULL, &req, &ans);
   675 
   742 	if (err != 0) {
   676 			str = _lm_sock_addrinfo_get_error_str (err);
   743 		const char *str;
   677 			g_set_error (error,
   744 
   678 				     LM_ERROR,                 
   745 		str = _lm_sock_addrinfo_get_error_str (err);
   679 				     LM_ERROR_CONNECTION_FAILED,   
   746 		g_set_error (error,
   680 				     str);
   747 			     LM_ERROR,                 
   681 			return NULL;
   748 			     LM_ERROR_CONNECTION_FAILED,   
   682 		}
   749 			     str);
   683 	} else { 
   750 		return NULL;
   684 		int err;
       
   685 
       
   686 		/* Connect directly */
       
   687 		g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET,
       
   688 		       "Going to connect to %s\n", 
       
   689 		       socket->server);
       
   690 
       
   691 		err = getaddrinfo (socket->server, 
       
   692 				   NULL, &req, &ans);
       
   693 		if (err != 0) {
       
   694 			const char *str;
       
   695 
       
   696 			str = _lm_sock_addrinfo_get_error_str (err);
       
   697 			g_set_error (error,
       
   698 				     LM_ERROR,                 
       
   699 				     LM_ERROR_CONNECTION_FAILED,   
       
   700 				     str);
       
   701 			return NULL;
       
   702 		}
       
   703 	}
   751 	}
   704 
   752 
   705 	if (ssl) {
   753 	if (ssl) {
   706 		socket->ssl = lm_ssl_ref (ssl);
   754 		socket->ssl = lm_ssl_ref (ssl);
   707 		_lm_ssl_initialize (socket->ssl);
   755 		_lm_ssl_initialize (socket->ssl);