[meego-commits] 8568: Changes to MeeGo:1.1:Core/connman

Rolla Selbak no_reply at build.meego.com
Mon Oct 18 06:53:38 UTC 2010


Hi,
I have made the following changes to connman in project MeeGo:1.1:Core. Please review and accept ASAP.

Thank You,
Rolla Selbak

[This message was auto-generated]

---

Request #8568:

  submit:   MeeGo:1.1:Core:Testing/connman(r2) -> MeeGo:1.1:Core/connman


Message:
    Promote from MeeGo:1.1:Core:Testing

State:   new          2010-10-17T23:53:36 rolla
Comment: None



changes files:
--------------
--- connman.changes
+++ connman.changes
@@ -0,0 +1,3 @@
+* Sat Oct 09 2010 Martin Xu <martin.xu at intel.com> - 0.60.5
+- upgrade to 0.60.5 to fix BMC #7497
+

old:
----
  connman-0.60.3.tar.bz2

new:
----
  connman-0.60.5.tar.bz2

spec files:
-----------
--- connman.spec
+++ connman.spec
@@ -7,7 +7,7 @@
 
 Name:       connman
 Summary:    Connection Manager
-Version:    0.60.3
+Version:    0.60.5
 Release:    1
 Group:      System/Networking
 License:    GPLv2

other changes:
--------------

++++++ connman-0.60.3.tar.bz2 -> connman-0.60.5.tar.bz2
--- ChangeLog
+++ ChangeLog
@@ -1,3 +1,14 @@
+ver 0.60.5
+	Remove EDNS0 option (Fixes BMC #4818)
+	Implement DNS over TCP for dnsproxy
+
+ver 0.60.4
+	Do not remove wifi network upon disconnection (Fixes BMC #7730, #7734)
+	Set WiFi task scanning flag when receiving a Scanning event
+	Implement WiFi network driver remove hook
+	RemoveProvider argument is an object path
+	Remove providers based on their VPN service path
+
 ver 0.60.3
 	Fix bug to remove vpn services if offline mode is on (Fixes BMC # 6591)
 	Schedule delayed scan if disconnected from an AP (Fixes BMC #6831)
--- configure
+++ configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.64 for connman 0.60.3.
+# Generated by GNU Autoconf 2.64 for connman 0.60.5.
 #
 # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
 # 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software
@@ -695,8 +695,8 @@
 # Identity of this package.
 PACKAGE_NAME='connman'
 PACKAGE_TARNAME='connman'
-PACKAGE_VERSION='0.60.3'
-PACKAGE_STRING='connman 0.60.3'
+PACKAGE_VERSION='0.60.5'
+PACKAGE_STRING='connman 0.60.5'
 PACKAGE_BUGREPORT=''
 PACKAGE_URL=''
 
@@ -1573,7 +1573,7 @@
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures connman 0.60.3 to adapt to many kinds of systems.
+\`configure' configures connman 0.60.5 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1643,7 +1643,7 @@
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of connman 0.60.3:";;
+     short | recursive ) echo "Configuration of connman 0.60.5:";;
    esac
   cat <<\_ACEOF
 
@@ -1808,7 +1808,7 @@
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-connman configure 0.60.3
+connman configure 0.60.5
 generated by GNU Autoconf 2.64
 
 Copyright (C) 2009 Free Software Foundation, Inc.
@@ -2266,7 +2266,7 @@
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by connman $as_me 0.60.3, which was
+It was created by connman $as_me 0.60.5, which was
 generated by GNU Autoconf 2.64.  Invocation command line was
 
   $ $0 $@
@@ -3075,7 +3075,7 @@
 
 # Define the identity of the package.
  PACKAGE='connman'
- VERSION='0.60.3'
+ VERSION='0.60.5'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -13740,7 +13740,7 @@
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by connman $as_me 0.60.3, which was
+This file was extended by connman $as_me 0.60.5, which was
 generated by GNU Autoconf 2.64.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -13804,7 +13804,7 @@
 _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_version="\\
-connman config.status 0.60.3
+connman config.status 0.60.5
 configured by $0, generated by GNU Autoconf 2.64,
   with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
 
--- configure.ac
+++ configure.ac
@@ -1,5 +1,5 @@
 AC_PREREQ(2.60)
-AC_INIT(connman, 0.60.3)
+AC_INIT(connman, 0.60.5)
 
 AM_INIT_AUTOMAKE([foreign subdir-objects])
 AM_CONFIG_HEADER(config.h)
--- plugins/dnsproxy.c
+++ plugins/dnsproxy.c
@@ -79,18 +79,24 @@
 	char *interface;
 	char *domain;
 	char *server;
+	int protocol;
 	GIOChannel *channel;
 	guint watch;
+	guint timeout;
 	gboolean enabled;
+	gboolean connected;
 };
 
 struct request_data {
 	struct sockaddr_in sin;
+	int client_sk;
+	int protocol;
 	socklen_t len;
 	guint16 srcid;
 	guint16 dstid;
 	guint16 altid;
 	guint timeout;
+	guint watch;
 	guint numserv;
 	guint numresp;
 	gpointer request;
@@ -105,8 +111,25 @@
 static GSList *request_pending_list = NULL;
 static guint16 request_id = 0x0000;
 
-static GIOChannel *listener_channel = NULL;
-static guint listener_watch = 0;
+static GIOChannel *udp_listener_channel = NULL;
+static guint udp_listener_watch = 0;
+static GIOChannel *tcp_listener_channel = NULL;
+static guint tcp_listener_watch = 0;
+
+static int protocol_offset(int protocol)
+{
+	switch (protocol) {
+	case IPPROTO_UDP:
+		return 0;
+
+	case IPPROTO_TCP:
+		return 2;
+
+	default:
+		return -EINVAL;
+	}
+
+}
 
 static struct request_data *find_request(guint16 id)
 {
@@ -123,7 +146,8 @@
 }
 
 static struct server_data *find_server(const char *interface,
-					const char *domain, const char *server)
+					const char *domain, const char *server,
+						int protocol)
 {
 	GSList *list;
 
@@ -136,7 +160,8 @@
 			continue;
 
 		if (g_str_equal(data->interface, interface) == TRUE &&
-				g_str_equal(data->server, server) == TRUE) {
+				g_str_equal(data->server, server) == TRUE &&
+				data->protocol == protocol) {
 			if (domain == NULL) {
 				if (data->domain == NULL)
 					return data;
@@ -151,155 +176,80 @@
 	return NULL;
 }
 
-static gboolean server_event(GIOChannel *channel, GIOCondition condition,
-							gpointer user_data)
+
+static void send_response(int sk, unsigned char *buf, int len,
+				const struct sockaddr *to, socklen_t tolen,
+				int protocol)
 {
-	struct server_data *data = user_data;
-	struct request_data *req;
-	unsigned char buf[4096];
-	struct domain_hdr *hdr = (void *) &buf;
-	int sk, err, len;
+	struct domain_hdr *hdr;
+	int err, offset = protocol_offset(protocol);
 
-	if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
-		connman_error("Error with server channel");
-		data->watch = 0;
-		return FALSE;
-	}
+	DBG("");
 
-	sk = g_io_channel_unix_get_fd(channel);
+	if (offset < 0)
+		return;
 
-	len = recv(sk, buf, sizeof(buf), 0);
 	if (len < 12)
-		return TRUE;
-
-	DBG("Received %d bytes (id 0x%04x)", len, buf[0] | buf[1] << 8);
-
-	req = find_request(buf[0] | buf[1] << 8);
-	if (req == NULL)
-		return TRUE;
-
-	DBG("id 0x%04x rcode %d", hdr->id, hdr->rcode);
-
-	buf[0] = req->srcid & 0xff;
-	buf[1] = req->srcid >> 8;
-
-	req->numresp++;
-
-	if (hdr->rcode == 0 || req->resp == NULL) {
-		g_free(req->resp);
-		req->resplen = 0;
-
-		req->resp = g_try_malloc(len);
-		if (req->resp == NULL)
-			return TRUE;
-
-		memcpy(req->resp, buf, len);
-		req->resplen = len;
-	}
-
-	if (hdr->rcode > 0 && req->numresp < req->numserv)
-		return TRUE;
-
-	if (req->timeout > 0)
-		g_source_remove(req->timeout);
+		return;
 
-	request_list = g_slist_remove(request_list, req);
+	hdr = (void*) (buf + offset);
 
-	sk = g_io_channel_unix_get_fd(listener_channel);
+	DBG("id 0x%04x qr %d opcode %d", hdr->id, hdr->qr, hdr->opcode);
 
-	err = sendto(sk, req->resp, req->resplen, 0,
-				(struct sockaddr *) &req->sin, req->len);
+	hdr->qr = 1;
+	hdr->rcode = 2;
 
-	g_free(req->resp);
-	g_free(req);
+	hdr->ancount = 0;
+	hdr->nscount = 0;
+	hdr->arcount = 0;
 
-	return TRUE;
+	err = sendto(sk, buf, len, 0, to, tolen);
 }
 
-static struct server_data *create_server(const char *interface,
-					const char *domain, const char *server)
+static gboolean request_timeout(gpointer user_data)
 {
-	struct server_data *data;
-	struct sockaddr_in sin;
-	int sk;
+	struct request_data *req = user_data;
 
-	DBG("interface %s server %s", interface, server);
+	DBG("id 0x%04x", req->srcid);
 
-	sk = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
-	if (sk < 0) {
-		connman_error("Failed to create server %s socket", server);
-		return NULL;
-	}
+	if (req == NULL)
+		return FALSE;
 
-	if (interface != NULL) {
-		if (setsockopt(sk, SOL_SOCKET, SO_BINDTODEVICE,
-				interface, strlen(interface) + 1) < 0) {
-			connman_error("Failed to bind server %s "
-						"to interface %s",
-							server, interface);
-			close(sk);
-			return NULL;
-		}
-	}
+	request_list = g_slist_remove(request_list, req);
+	req->numserv--;
 
-	memset(&sin, 0, sizeof(sin));
-	sin.sin_family = AF_INET;
-	sin.sin_port = htons(53);
-	sin.sin_addr.s_addr = inet_addr(server);
+	if (req->resplen > 0 && req->resp != NULL) {
+		int sk, err;
 
-	if (connect(sk, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
-		connman_error("Failed to connect server %s", server);
-		close(sk);
-		return NULL;
-	}
+		sk = g_io_channel_unix_get_fd(udp_listener_channel);
 
-	data = g_try_new0(struct server_data, 1);
-	if (data == NULL) {
-		connman_error("Failed to allocate server %s data", server);
-		close(sk);
-		return NULL;
-	}
+		err = sendto(sk, req->resp, req->resplen, 0,
+				(struct sockaddr *) &req->sin, req->len);
+	} else if (req->request && req->numserv == 0) {
+		struct domain_hdr *hdr;
 
-	data->channel = g_io_channel_unix_new(sk);
-	if (data->channel == NULL) {
-		connman_error("Failed to create server %s channel", server);
-		close(sk);
-		g_free(data);
-		return NULL;
+		if (req->protocol == IPPROTO_TCP) {
+			hdr = (void *) (req->request + 2);
+			hdr->id = req->srcid;
+			send_response(req->client_sk, req->request,
+					req->request_len, NULL, 0, IPPROTO_TCP);
+
+		} else if (req->protocol == IPPROTO_UDP) {
+			int sk;
+
+			hdr = (void *) (req->request);
+			hdr->id = req->srcid;
+			sk = g_io_channel_unix_get_fd(udp_listener_channel);
+			send_response(sk, req->request, req->request_len,
+					(struct sockaddr *)&req->sin,
+						sizeof(req->sin), IPPROTO_UDP);
+		}
 	}
 
-	g_io_channel_set_close_on_unref(data->channel, TRUE);
-
-	data->watch = g_io_add_watch(data->channel, G_IO_IN,
-						server_event, data);
-
-	data->interface = g_strdup(interface);
-	data->domain = g_strdup(domain);
-	data->server = g_strdup(server);
-
-	/* Enable new servers by default */
-	data->enabled = TRUE;
-
-	connman_info("Adding DNS server %s", data->server);
-
-	return data;
-}
-
-static void destroy_server(struct server_data *data)
-{
-	DBG("interface %s server %s", data->interface, data->server);
-
-	if (data->watch > 0)
-		g_source_remove(data->watch);
-
-	g_io_channel_unref(data->channel);
-
-	connman_info("Removing DNS server %s", data->server);
+	g_free(req->resp);
+	g_free(req);
 
-	g_free(data->server);
-	g_free(data->domain);
-	g_free(data->interface);
-	g_free(data);
+	return FALSE;
 }
 
 static int append_query(unsigned char *buf, unsigned int size,
@@ -357,84 +307,427 @@
 	return ptr - buf;
 }
 
-static gboolean request_timeout(gpointer user_data)
+static int ns_resolv(struct server_data *server, struct request_data *req,
+				gpointer request, gpointer name)
 {
-	struct request_data *req = user_data;
+	int sk, err;
 
-	DBG("id 0x%04x", req->srcid);
+	sk = g_io_channel_unix_get_fd(server->channel);
 
-	request_list = g_slist_remove(request_list, req);
+	err = send(sk, request, req->request_len, 0);
 
-	if (req->resplen > 0 && req->resp != NULL) {
-		int sk, err;
+	req->numserv++;
+
+	if (server->domain != NULL) {
+		unsigned char alt[1024];
+		struct domain_hdr *hdr = (void *) &alt;
+		int altlen, domlen, offset;
+
+		offset = protocol_offset(server->protocol);
+		if (offset < 0)
+			return offset;
+
+		domlen = strlen(server->domain) + 1;
+		if (domlen < 5)
+			return -EINVAL;
+
+		alt[offset] = req->altid & 0xff;
+		alt[offset + 1] = req->altid >> 8;
+
+		memcpy(alt + offset + 2, request + offset + 2, 10);
+		hdr->qdcount = htons(1);
+
+		altlen = append_query(alt + offset + 12, sizeof(alt) - 12,
+					name, server->domain);
+		if (altlen < 0)
+			return -EINVAL;
+
+		altlen += 12;
+
+		memcpy(alt + offset + altlen,
+			request + offset + altlen - domlen,
+				req->request_len - altlen + domlen);
+
+		if (server->protocol == IPPROTO_TCP) {
+			int req_len = req->request_len + domlen - 1;
+
+			alt[0] = (req_len >> 8) & 0xff;
+			alt[1] = req_len & 0xff;
+		}
+
+		err = send(sk, alt, req->request_len + domlen + 1, 0);
+
+		req->numserv++;
+	}
+
+	return 0;
+}
+
+static int forward_dns_reply(unsigned char *reply, int reply_len, int protocol)
+{
+	struct domain_hdr *hdr;
+	struct request_data *req;
+	int dns_id, sk, err, offset = protocol_offset(protocol);
+
+	if (offset < 0)
+		return offset;
+
+	hdr = (void *)(reply + offset);
+	dns_id = reply[offset] | reply[offset + 1] << 8;
+
+	DBG("Received %d bytes (id 0x%04x)", reply_len, dns_id);
+
+	req = find_request(dns_id);
+	if (req == NULL)
+		return -EINVAL;
+
+	DBG("id 0x%04x rcode %d", hdr->id, hdr->rcode);
+
+	reply[offset] = req->srcid & 0xff;
+	reply[offset + 1] = req->srcid >> 8;
+
+	req->numresp++;
+
+	if (hdr->rcode == 0 || req->resp == NULL) {
+		g_free(req->resp);
+		req->resplen = 0;
+
+		req->resp = g_try_malloc(reply_len);
+		if (req->resp == NULL)
+			return -ENOMEM;
+
+		memcpy(req->resp, reply, reply_len);
+		req->resplen = reply_len;
+	}
+
+	if (hdr->rcode > 0 && req->numresp < req->numserv)
+		return -EINVAL;
 
-		sk = g_io_channel_unix_get_fd(listener_channel);
+	if (req->timeout > 0)
+		g_source_remove(req->timeout);
+
+	request_list = g_slist_remove(request_list, req);
 
+	if (protocol == IPPROTO_UDP) {
+		sk = g_io_channel_unix_get_fd(udp_listener_channel);
 		err = sendto(sk, req->resp, req->resplen, 0,
 				(struct sockaddr *) &req->sin, req->len);
+	} else {
+		sk = req->client_sk;
+		err = send(sk, req->resp, req->resplen, 0);
+		close(sk);
 	}
 
 	g_free(req->resp);
 	g_free(req);
 
-	return FALSE;
+	return err;
 }
 
-static gboolean resolv(struct request_data *req,
-				gpointer request, gpointer name)
+static void destroy_server(struct server_data *server)
 {
-	int sk, err;
-	GSList *list;
+	DBG("interface %s server %s", server->interface, server->server);
 
-	request_list = g_slist_append(request_list, req);
+	server_list = g_slist_remove(server_list, server);
 
-	req->numserv = 0;
-	req->timeout = g_timeout_add_seconds(5, request_timeout, req);
+	if (server->watch > 0)
+		g_source_remove(server->watch);
 
-	for (list = server_list; list; list = list->next) {
-		struct server_data *data = list->data;
+	if (server->timeout > 0)
+		g_source_remove(server->timeout);
 
-		DBG("server %s domain %s enabled %d",
-				data->server, data->domain, data->enabled);
+	g_io_channel_unref(server->channel);
 
-		if (data->enabled == FALSE)
-			continue;
+	if (server->protocol == IPPROTO_UDP)
+		connman_info("Removing DNS server %s", server->server);
 
-		sk = g_io_channel_unix_get_fd(data->channel);
+	g_free(server->server);
+	g_free(server->domain);
+	g_free(server->interface);
+	g_free(server);
+}
 
-		err = send(sk, request, req->request_len, 0);
+static gboolean udp_server_event(GIOChannel *channel, GIOCondition condition,
+							gpointer user_data)
+{
+	struct server_data *data = user_data;
+	unsigned char buf[4096];
+	int sk, err, len;
 
-		req->numserv++;
+	if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
+		connman_error("Error with server channel");
+		data->watch = 0;
+		return FALSE;
+	}
 
-		if (data->domain != NULL) {
-			unsigned char alt[1024];
-			struct domain_hdr *hdr = (void *) &alt;
-			int altlen, domlen;
+	sk = g_io_channel_unix_get_fd(channel);
+
+	len = recv(sk, buf, sizeof(buf), 0);
+	if (len < 12)
+		return TRUE;
+
+	err = forward_dns_reply(buf, len, IPPROTO_UDP);
+
+	return TRUE;
+}
+
+static gboolean tcp_server_event(GIOChannel *channel, GIOCondition condition,
+							gpointer user_data)
+{
+	int sk;
+	struct server_data *server = user_data;
+
+	sk = g_io_channel_unix_get_fd(channel);
+	if (sk == 0)
+		return FALSE;
+
+	if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
+		GSList *list;
+
+		DBG("TCP server channel closed");
 
-			domlen = strlen(data->domain) + 1;
-			if (domlen < 5)
+		for (list = request_list; list; list = list->next) {
+			struct request_data *req = list->data;
+			struct domain_hdr *hdr;
+
+			if (req->protocol == IPPROTO_UDP)
+				continue;
+
+			if (req->request == NULL)
 				continue;
 
-			alt[0] = req->altid & 0xff;
-			alt[1] = req->altid >> 8;
+			/*
+			 * If we're not waiting for any further response
+			 * from another name server, then we send an error
+			 * response to the client.
+			 */
+			if (req->numserv && --(req->numserv))
+				continue;
+
+			hdr = (void *) (req->request + 2);
+			hdr->id = req->srcid;
+			send_response(req->client_sk, req->request,
+					req->request_len, NULL, 0, IPPROTO_TCP);
+
+			request_list = g_slist_remove(request_list, req);
+		}
+
+		destroy_server(server);
+
+		return FALSE;
+	}
+
+	if ((condition & G_IO_OUT) && !server->connected) {
+		GSList *list;
+
+		server->connected = TRUE;
+		server_list = g_slist_append(server_list, server);
+
+		if (server->timeout > 0) {
+			g_source_remove(server->timeout);
+			server->timeout = 0;
+		}
 
-			memcpy(alt + 2, request + 2, 10);
-			hdr->qdcount = htons(1);
+		for (list = request_list; list; list = list->next) {
+			struct request_data *req = list->data;
 
-			altlen = append_query(alt + 12, sizeof(alt) - 12,
-						name, data->domain);
-			if (altlen < 0)
+			if (req->protocol == IPPROTO_UDP)
 				continue;
 
-			altlen += 12;
+			DBG("Sending req %s over TCP", (char *)req->name);
+
+			if (req->timeout > 0)
+				g_source_remove(req->timeout);
+
+			req->timeout = g_timeout_add_seconds(30,
+						request_timeout, req);
+			ns_resolv(server, req, req->request, req->name);
+		}
+
+	} else if (condition & G_IO_IN) {
+		int len, bytes_recv, total_bytes_recv;
+		unsigned char reply_len_buf[2];
+		uint16_t reply_len;
+		unsigned char *reply;
 
-			memcpy(alt + altlen, request + altlen - domlen,
-					req->request_len - altlen + domlen);
+		len = recv(sk, reply_len_buf, 2, 0);
+		if (len < 2)
+			return TRUE;
+
+		reply_len = reply_len_buf[1] | reply_len_buf[0] << 8;
+
+		DBG("TCP reply %d bytes", reply_len);
+
+		reply = g_try_malloc(reply_len + 2);
+		if (reply == NULL)
+			return TRUE;
+
+		reply[0] = reply_len_buf[0];
+		reply[1] = reply_len_buf[1];
 
-			err = send(sk, alt, req->request_len + domlen + 1, 0);
+		total_bytes_recv = bytes_recv = 0;
+		while (total_bytes_recv < reply_len) {
+			bytes_recv = recv(sk, reply + 2, reply_len, 0);
+			if (bytes_recv < 0)
+				break;
 
-			req->numserv++;
+			total_bytes_recv += bytes_recv;
 		}
+
+		forward_dns_reply(reply, reply_len + 2, IPPROTO_TCP);
+
+		g_free(reply);
+
+		destroy_server(server);
+
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static gboolean tcp_idle_timeout(gpointer user_data)
+{
+	struct server_data *server = user_data;
+
+	DBG("");
+
+	if (server == NULL)
+		return FALSE;
+
+	destroy_server(server);
+
+	return FALSE;
+}
+
+static struct server_data *create_server(const char *interface,
+					const char *domain, const char *server,
+					int protocol)
+{
+	struct server_data *data;
+	struct sockaddr_in sin;
+	int sk, type, ret;
+
+	DBG("interface %s server %s", interface, server);
+
+	switch (protocol) {
+	case IPPROTO_UDP:
+		type = SOCK_DGRAM;
+		break;
+
+	case IPPROTO_TCP:
+		type = SOCK_STREAM;
+		break;
+
+	default:
+		return NULL;
+	}
+
+	data = find_server(interface, domain, server, protocol);
+	if (data) {
+		if (data->watch > 0)
+			g_source_remove(data->watch);
+		data->watch = g_io_add_watch(data->channel,
+			G_IO_OUT | G_IO_IN | G_IO_HUP | G_IO_NVAL | G_IO_ERR,
+						tcp_server_event, data);
+		return data;
+	}
+
+	sk = socket(AF_INET, type, protocol);
+	if (sk < 0) {
+		connman_error("Failed to create server %s socket", server);
+		return NULL;
+	}
+
+	if (interface != NULL) {
+		if (setsockopt(sk, SOL_SOCKET, SO_BINDTODEVICE,
+				interface, strlen(interface) + 1) < 0) {
+			connman_error("Failed to bind server %s "
+						"to interface %s",
+							server, interface);
+			close(sk);
+			return NULL;
+		}
+	}
+
+	data = g_try_new0(struct server_data, 1);
+	if (data == NULL) {
+		connman_error("Failed to allocate server %s data", server);
+		close(sk);
+		return NULL;
+	}
+
+	data->channel = g_io_channel_unix_new(sk);
+	if (data->channel == NULL) {
+		connman_error("Failed to create server %s channel", server);
+		close(sk);
+		g_free(data);
+		return NULL;
+	}
+
+	g_io_channel_set_close_on_unref(data->channel, TRUE);
+
+	if (protocol == IPPROTO_TCP) {
+		g_io_channel_set_flags(data->channel, G_IO_FLAG_NONBLOCK, NULL);
+		data->watch = g_io_add_watch(data->channel,
+			G_IO_OUT | G_IO_IN | G_IO_HUP | G_IO_NVAL | G_IO_ERR,
+						tcp_server_event, data);
+		data->timeout = g_timeout_add_seconds(30, tcp_idle_timeout,
+								data);
+	} else
+		data->watch = g_io_add_watch(data->channel, G_IO_IN,
+						udp_server_event, data);
+
+	data->interface = g_strdup(interface);
+	data->domain = g_strdup(domain);
+	data->server = g_strdup(server);
+	data->protocol = protocol;
+
+	memset(&sin, 0, sizeof(sin));
+	sin.sin_family = AF_INET;
+	sin.sin_port = htons(53);
+	sin.sin_addr.s_addr = inet_addr(server);
+
+	ret = connect(sk, (struct sockaddr *) &sin, sizeof(sin));
+	if (ret < 0) {
+		if ((protocol == IPPROTO_TCP && errno != EINPROGRESS) ||
+				protocol == IPPROTO_UDP) {
+			connman_error("Failed to connect to server %s", server);
+			close(sk);
+			g_free(data);
+			return NULL;
+		}
+	}
+
+	if (protocol == IPPROTO_UDP) {
+		/* Enable new servers by default */
+		data->enabled = TRUE;
+		connman_info("Adding DNS server %s", data->server);
+
+		server_list = g_slist_append(server_list, data);
+
+		return data;
+	}
+
+	return NULL;
+}
+
+static gboolean resolv(struct request_data *req,
+				gpointer request, gpointer name)
+{
+	GSList *list;
+
+	for (list = server_list; list; list = list->next) {
+		struct server_data *data = list->data;
+
+		DBG("server %s domain %s enabled %d",
+				data->server, data->domain, data->enabled);
+
+		if (data->enabled == FALSE)
+			continue;
+
+		if (ns_resolv(data, req, request, name) < 0)
+			continue;
 	}
 
 	return TRUE;
@@ -450,32 +743,35 @@
 	if (g_str_equal(server, "127.0.0.1") == TRUE)
 		return -ENODEV;
 
-	data = create_server(interface, domain, server);
+	data = create_server(interface, domain, server, IPPROTO_UDP);
 	if (data == NULL)
 		return -EIO;
 
-	server_list = g_slist_append(server_list, data);
-
 	return 0;
 }
 
-static int dnsproxy_remove(const char *interface, const char *domain,
-							const char *server)
+static void remove_server(const char *interface, const char *domain,
+			const char *server, int protocol)
 {
 	struct server_data *data;
 
+	data = find_server(interface, domain, server, protocol);
+	if (data == NULL)
+		return;
+
+	destroy_server(data);
+}
+
+static int dnsproxy_remove(const char *interface, const char *domain,
+							const char *server)
+{
 	DBG("interface %s server %s", interface, server);
 
 	if (g_str_equal(server, "127.0.0.1") == TRUE)
 		return -ENODEV;
 
-	data = find_server(interface, domain, server);
-	if (data == NULL)
-		return 0;
-
-	server_list = g_slist_remove(server_list, data);
-
-	destroy_server(data);
+	remove_server(interface, domain, server, IPPROTO_UDP);
+	remove_server(interface, domain, server, IPPROTO_TCP);
 
 	return 0;
 }
@@ -637,28 +933,121 @@
 	return 0;
 }
 
-static void send_response(int sk, unsigned char *buf, int len,
-				const struct sockaddr *to, socklen_t tolen)
+static gboolean tcp_listener_event(GIOChannel *channel, GIOCondition condition,
+							gpointer user_data)
 {
-	struct domain_hdr *hdr = (void *) buf;
-	int err;
+	unsigned char buf[768];
+	char query[512];
+	struct request_data *req;
+	struct server_data *server;
+	int sk, client_sk, len, err;
+	struct sockaddr client_addr;
+	socklen_t client_addr_len;
+	GSList *list;
 
-	if (len < 12)
-		return;
+	DBG("condition 0x%x", condition);
 
-	DBG("id 0x%04x qr %d opcode %d", hdr->id, hdr->qr, hdr->opcode);
+	if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
+		if (tcp_listener_watch > 0)
+			g_source_remove(tcp_listener_watch);
+		tcp_listener_watch = 0;
 
-	hdr->qr = 1;
-	hdr->rcode = 2;
+		connman_error("Error with TCP listener channel");
 
-	hdr->ancount = 0;
-	hdr->nscount = 0;
-	hdr->arcount = 0;
+		return FALSE;
+	}
 
-	err = sendto(sk, buf, len, 0, to, tolen);
+	sk = g_io_channel_unix_get_fd(channel);
+
+	client_addr_len = sizeof(struct sockaddr);
+	client_sk = accept(sk, &client_addr, &client_addr_len);
+	if (client_sk < 0) {
+		connman_error("Accept failure on TCP listener");
+		tcp_listener_watch = 0;
+		return FALSE;
+	}
+
+	len = recv(client_sk, buf, sizeof(buf), 0);
+	if (len < 2)
+		return TRUE;
+
+	DBG("Received %d bytes (id 0x%04x)", len, buf[2] | buf[3] << 8);
+
+	err = parse_request(buf + 2, len - 2, query, sizeof(query));
+	if (err < 0 || (g_slist_length(server_list) == 0 &&
+				connman_ondemand_connected())) {
+		send_response(client_sk, buf, len, NULL, 0, IPPROTO_TCP);
+		return TRUE;
+	}
+
+	req = g_try_new0(struct request_data, 1);
+	if (req == NULL)
+		return TRUE;
+
+	memcpy(&req->sin, (struct sockaddr_in *)&client_addr, sizeof(req->sin));
+	req->client_sk = client_sk;
+	req->protocol = IPPROTO_TCP;
+	req->len = client_addr_len;
+
+	request_id += 2;
+	if (request_id == 0x0000 || request_id == 0xffff)
+		request_id += 2;
+
+	req->srcid = buf[2] | (buf[3] << 8);
+	req->dstid = request_id;
+	req->altid = request_id + 1;
+	req->request_len = len;
+
+	buf[2] = req->dstid & 0xff;
+	buf[3] = req->dstid >> 8;
+
+	req->numserv = 0;
+	request_list = g_slist_append(request_list, req);
+
+	for (list = server_list; list; list = list->next) {
+		struct server_data *data = list->data;
+
+		if (data->protocol != IPPROTO_UDP || data->enabled == FALSE)
+			continue;
+
+		server = create_server(data->interface, data->domain,
+					data->server, IPPROTO_TCP);
+
+		/*
+		 * If server is NULL, we're not connected yet.
+		 * Copy the relevant buffers and continue with
+		 * the next nameserver.
+		 * The request will actually be sent once we're
+		 * properly connected over TCP to this nameserver.
+		 */
+		if (server == NULL) {
+			req->request = g_try_malloc0(req->request_len);
+			if (req->request == NULL)
+				return TRUE;
+
+			memcpy(req->request, buf, req->request_len);
+
+			req->name = g_try_malloc0(sizeof(query));
+			if (req->name == NULL) {
+				g_free(req->request);
+				return TRUE;
+			}
+			memcpy(req->name, query, sizeof(query));
+
+			continue;
+		}
+
+		if (req->timeout > 0)
+			g_source_remove(req->timeout);
+
+		req->timeout = g_timeout_add_seconds(30, request_timeout, req);
+		ns_resolv(server, req, buf, query);
+	}
+
+	return TRUE;
 }
 
-static gboolean listener_event(GIOChannel *channel, GIOCondition condition,
+static gboolean udp_listener_event(GIOChannel *channel, GIOCondition condition,
 							gpointer user_data)
 {
 	unsigned char buf[768];
@@ -669,8 +1058,8 @@
 	int sk, err, len;
 
 	if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
-		connman_error("Error with listener channel");
-		listener_watch = 0;
+		connman_error("Error with UDP listener channel");
+		udp_listener_watch = 0;
 		return FALSE;
 	}
 
@@ -687,7 +1076,8 @@
 	err = parse_request(buf, len, query, sizeof(query));
 	if (err < 0 || (g_slist_length(server_list) == 0 &&
 				connman_ondemand_connected())) {
-		send_response(sk, buf, len, (struct sockaddr *) &sin, size);
+		send_response(sk, buf, len, (struct sockaddr *) &sin, size,
+				IPPROTO_UDP);
 		return TRUE;
 	}
 
@@ -696,6 +1086,8 @@
 		return TRUE;
 
 	memcpy(&req->sin, &sin, sizeof(sin));
+	req->client_sk = 0;
+	req->protocol = IPPROTO_UDP;
 	req->len = size;
 
 	request_id += 2;
@@ -737,29 +1129,47 @@
 		return TRUE;
 	}
 
+
+	req->numserv = 0;
+	req->timeout = g_timeout_add_seconds(5, request_timeout, req);
+	request_list = g_slist_append(request_list, req);
+
 	return resolv(req, buf, query);
 }
 
-static int create_listener(void)
+static int create_dns_listener(int protocol)
 {
-	const char *ifname = "lo";
+	GIOChannel *channel;
+	const char *ifname = "lo", *proto;
 	struct sockaddr_in sin;
-	int sk;
+	int sk, type;
 
 	DBG("");
 
-	sk = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+	switch (protocol) {
+	case IPPROTO_UDP:
+		proto = "UDP";
+		type = SOCK_DGRAM;
+		break;
+
+	case IPPROTO_TCP:
+		proto = "TCP";
+		type = SOCK_STREAM;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	sk = socket(AF_INET, type, protocol);
 	if (sk < 0) {
-		connman_error("Failed to create listener socket");
+		connman_error("Failed to create %s listener socket", proto);
 		return -EIO;
 	}
 
-	//setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
-	//setsockopt(sk, SOL_IP, IP_PKTINFO, &opt, sizeof(opt));
-
 	if (setsockopt(sk, SOL_SOCKET, SO_BINDTODEVICE,
 					ifname, strlen(ifname) + 1) < 0) {
-		connman_error("Failed to bind listener interface");
+		connman_error("Failed to bind %s listener interface", proto);
 		close(sk);
 		return -EIO;
 	}
@@ -768,25 +1178,75 @@
 	sin.sin_family = AF_INET;
 	sin.sin_port = htons(53);
 	sin.sin_addr.s_addr = inet_addr("127.0.0.1");
-	//sin.sin_addr.s_addr = INADDR_ANY;
+	sin.sin_addr.s_addr = htonl(INADDR_ANY);
 
 	if (bind(sk, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
-		connman_error("Failed to bind listener socket");
+		connman_error("Failed to bind %s listener socket", proto);
+		close(sk);
+		return -EIO;
+	}
+
+	if (protocol == IPPROTO_TCP && listen(sk, 10) < 0) {
+		connman_error("Failed to listen on TCP socket");
 		close(sk);
 		return -EIO;
 	}
 
-	listener_channel = g_io_channel_unix_new(sk);
-	if (listener_channel == NULL) {
-		connman_error("Failed to create listener channel");
+	channel = g_io_channel_unix_new(sk);
+	if (channel == NULL) {
+		connman_error("Failed to create %s listener channel", proto);
 		close(sk);
 		return -EIO;
 	}
 
-	g_io_channel_set_close_on_unref(listener_channel, TRUE);
+	g_io_channel_set_close_on_unref(channel, TRUE);
+
+	if (protocol == IPPROTO_TCP) {
+		tcp_listener_channel = channel;
+		tcp_listener_watch = g_io_add_watch(channel,
+					G_IO_IN, tcp_listener_event, NULL);
+	} else {
+		udp_listener_channel = channel;
+		udp_listener_watch = g_io_add_watch(channel,
+					G_IO_IN, udp_listener_event, NULL);
+	}
+
+	return 0;
+}
+
+static void destroy_udp_listener(void)
+{
+	DBG("");
+
+	if (udp_listener_watch > 0)
+		g_source_remove(udp_listener_watch);
+
+	g_io_channel_unref(udp_listener_channel);
+}
+
+static void destroy_tcp_listener(void)
+{
+	DBG("");
 
-	listener_watch = g_io_add_watch(listener_channel, G_IO_IN,
-							listener_event, NULL);
+	if (tcp_listener_watch > 0)
+		g_source_remove(tcp_listener_watch);
+
+	g_io_channel_unref(tcp_listener_channel);
+}
+
+static int create_listener(void)
+{
+	int err;
+
+	err = create_dns_listener(IPPROTO_UDP);
+	if (err < 0)
+		return err;
+
+	err = create_dns_listener(IPPROTO_TCP);
+	if (err < 0) {
+		destroy_udp_listener();
+		return err;
+	}
 
 	connman_resolver_append("lo", NULL, "127.0.0.1");
 
@@ -797,13 +1257,8 @@
 {
 	GSList *list;
 
-	DBG("");
-
 	connman_resolver_remove_all("lo");
 
-	if (listener_watch > 0)
-		g_source_remove(listener_watch);
-
 	for (list = request_pending_list; list; list = list->next) {
 		struct request_data *req = list->data;
 
@@ -836,7 +1291,8 @@
 	g_slist_free(request_list);
 	request_list = NULL;
 
-	g_io_channel_unref(listener_channel);
+	destroy_tcp_listener();
+	destroy_udp_listener();
 }
 
 static int dnsproxy_init(void)
--- plugins/supplicant.c
+++ plugins/supplicant.c
@@ -2189,15 +2189,9 @@
 
 	connman_info("%s scanning %s", task->ifname,
 				scanning == TRUE ? "started" : "finished");
-}
-
-static gboolean delayed_scan(gpointer user_data)
-{
-	struct supplicant_task *task = user_data;
 
-	supplicant_scan(task->device);
-
-	return FALSE;
+	if (scanning == TRUE)
+		task->scanning = TRUE;
 }
 
 static void state_change(struct supplicant_task *task, DBusMessage *msg)
@@ -2293,13 +2287,7 @@
 				task_connect(task);
 			} else
 				task->network = NULL;
-		} else {
-			if (task->state == WPA_DISCONNECTED)
-				g_timeout_add_seconds(10, delayed_scan, task);
-
-			remove_network(task);
 		}
-
 		break;
 
 	default:
@@ -2522,6 +2510,25 @@
 	return 0;
 }
 
+void supplicant_remove_network(struct connman_network *network)
+{
+	struct supplicant_task *task;
+	int index;
+
+	DBG("network %p", network);
+
+	index = connman_network_get_index(network);
+
+	task = find_task_by_index(index);
+	if (task == NULL)
+		return;
+
+	if (task->network != network)
+		return;
+
+	remove_network(task);
+}
+
 static void supplicant_activate(DBusConnection *conn)
 {
 	DBusMessage *message;
--- plugins/supplicant.h
+++ plugins/supplicant.h
@@ -37,3 +37,5 @@
 
 int supplicant_connect(struct connman_network *network);
 int supplicant_disconnect(struct connman_network *network);
+
+void supplicant_remove_network(struct connman_network *network);
--- plugins/wifi.c
+++ plugins/wifi.c
@@ -62,6 +62,8 @@
 static void network_remove(struct connman_network *network)
 {
 	DBG("network %p", network);
+
+	supplicant_remove_network(network);
 }
 
 static int network_connect(struct connman_network *network)
--- src/inet.c
+++ src/inet.c
@@ -420,7 +420,7 @@
 {
 	enum connman_device_mode mode = CONNMAN_DEVICE_MODE_UNKNOWN;
 	enum connman_device_type type;
-	struct connman_device *device;
+	struct connman_device *device = NULL;
 	char *devname, *ident = NULL;
 	char *addr = NULL, *name = NULL, *node = NULL;
 
@@ -459,6 +459,11 @@
 		break;
 	}
 
+	if (g_strcmp0(addr, "00:00:00:00:00:00") == 0) {
+		connman_info("Wrong address ignoring interface %s ", devname);
+		goto done;
+	}
+
 	device = connman_device_create(name, type);
 	if (device == NULL)
 		goto done;
--- src/manager.c
+++ src/manager.c
@@ -224,8 +224,8 @@
 
 	DBG("conn %p", conn);
 
-	dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &path,
-			      DBUS_TYPE_INVALID);
+	dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+							DBUS_TYPE_INVALID);
 
 	if (__connman_security_check_privilege(msg,
 				CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
@@ -657,7 +657,7 @@
 	{ "GetState",          "",      "s",     get_state          },
 	{ "CreateProfile",     "s",     "o",     create_profile     },
 	{ "RemoveProfile",     "o",     "",      remove_profile     },
-	{ "RemoveProvider",    "s",     "",      remove_provider    },
+	{ "RemoveProvider",    "o",     "",      remove_provider    },
 	{ "RequestScan",       "s",     "",      request_scan       },
 	{ "EnableTechnology",  "s",     "",      enable_technology,
 						G_DBUS_METHOD_FLAG_ASYNC },
--- src/provider.c
+++ src/provider.c
@@ -216,18 +216,30 @@
 int __connman_provider_remove(const char *path)
 {
 	struct connman_provider *provider;
+	GHashTableIter iter;
+	gpointer value, key;
 
 	DBG("path %s", path);
 
-	provider = g_hash_table_lookup(provider_hash, path);
-	if (provider == NULL) {
-		DBG("patch %s not found", path);
-		return -ENXIO;
-	}
+	g_hash_table_iter_init(&iter, provider_hash);
+	while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
+		const char *srv_path;
+		provider = value;
+
+		if (provider->vpn_service == NULL)
+			continue;
 
-	g_hash_table_remove(provider_hash, path);
+		srv_path = __connman_service_get_path(provider->vpn_service);
+
+		if (g_strcmp0(srv_path, path) == 0) {
+			DBG("Removing VPN %s", provider->identifier);
+			g_hash_table_remove(provider_hash,
+						provider->identifier);
+			return 0;
+		}
+	}
 
-	return 0;
+	return -ENXIO;
 }
 
 static int set_connected(struct connman_provider *provider,
--- src/resolver.c
+++ src/resolver.c
@@ -389,8 +389,7 @@
 	unsigned int count;
 	mode_t old_umask;
 
-	content = g_string_new("# Generated by Connection Manager\n"
-						"options edns0\n");
+	content = g_string_new("# Generated by Connection Manager\n");
 
 	/*
 	 * Nameservers are added in reverse so that the most recently
--- test/disconnect-vpn
+++ test/disconnect-vpn
@@ -4,7 +4,7 @@
 import dbus
 
 if (len(sys.argv) < 2):
-	print "Usage: %s <provider name> " % (sys.argv[0])
+	print "Usage: %s <VPN service path> " % (sys.argv[0])
 	sys.exit(1)
 
 bus = dbus.SystemBus()
@@ -18,5 +18,4 @@
 
 manager.RemoveProvider(sys.argv[1])
 
-print "remove path is %s" %(path)
 

++++++ connman.yaml
--- connman.yaml
+++ connman.yaml
@@ -1,6 +1,6 @@
 Name: connman
 Summary: Connection Manager
-Version: 0.60.3
+Version: 0.60.5
 Release: 1
 Group: System/Networking
 License: GPLv2




More information about the MeeGo-commits mailing list