Open Source Telephony
 help / color / mirror / Atom feed
From: Philippe Nunes <philippe.nunes@linux.intel.com>
To: ofono@ofono.org
Subject: [PATCH v4 8/8] stk: Add read/write handlers
Date: Fri, 20 May 2011 18:26:21 +0200	[thread overview]
Message-ID: <1305908781-8322-8-git-send-email-philippe.nunes@linux.intel.com> (raw)
In-Reply-To: <1305908781-8322-1-git-send-email-philippe.nunes@linux.intel.com>

[-- Attachment #1: Type: text/plain, Size: 7470 bytes --]

---
 src/stk.c |  171 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 161 insertions(+), 10 deletions(-)

diff --git a/src/stk.c b/src/stk.c
index fbd93c3..72ca936 100644
--- a/src/stk.c
+++ b/src/stk.c
@@ -29,6 +29,8 @@
 #include <stdlib.h>
 #include <stdint.h>
 #include <arpa/inet.h>
+#include <unistd.h>
+#include <fcntl.h>
 
 #include <glib.h>
 #include <gdbus.h>
@@ -89,6 +91,10 @@ struct ofono_stk {
 	gboolean report_channel_status;
 	struct ofono_gprs *gprs;
 	struct stk_bearer_description bearer_desc;
+	enum stk_transport_protocol_type protocol;
+	struct sockaddr_in dest_addr;
+	GIOChannel *io;
+	guint read_watch;
 };
 
 struct envelope_op {
@@ -573,6 +579,9 @@ static void stk_close_channel(struct ofono_stk *stk)
 {
 	int err;
 
+	if (stk->read_watch > 0)
+		g_source_remove(stk->read_watch);
+
 	err = __ofono_gprs_remove_pdp_context(stk->gprs, stk->channel.id,
 			ofono_stk_remove_pdp_context_cb, stk);
 
@@ -636,6 +645,74 @@ static void stk_alpha_id_unset(struct ofono_stk *stk)
 	stk_agent_request_cancel(stk->current_agent);
 }
 
+gsize stk_channel_data_write(struct ofono_stk *stk)
+{
+	GIOStatus status;
+	gsize bytes_written;
+	gchar *data = (gchar *)(stk->tx_buffer.data.array);
+	gsize count = stk->tx_buffer.data.len - stk->tx_buffer.tx_avail;
+
+	if (stk->protocol == STK_TRANSPORT_PROTOCOL_UDP_CLIENT_REMOTE) {
+		bytes_written = sendto(g_io_channel_unix_get_fd(stk->io), data,
+				count, 0, &stk->dest_addr,
+				sizeof(stk->dest_addr));
+
+		if (bytes_written == -1 && stk->read_watch > 0) {
+			g_source_remove(stk->read_watch);
+			return 0;
+		}
+	} else {
+		status = g_io_channel_write_chars(stk->io, data,
+						count, &bytes_written, NULL);
+
+		if (status != G_IO_STATUS_NORMAL && stk->read_watch > 0) {
+			g_source_remove(stk->read_watch);
+			return 0;
+		}
+	}
+
+	DBG("Send %zd bytes", bytes_written);
+
+	stk->tx_buffer.tx_avail += bytes_written;
+	count = stk->tx_buffer.data.len - stk->rx_buffer.tx_avail;
+	if (count > 0)
+		memmove(stk->tx_buffer.data.array, stk->rx_buffer.data.array +
+			bytes_written, count);
+
+	return bytes_written;
+}
+
+static gboolean receive_callback(GIOChannel *channel, GIOCondition cond,
+				gpointer userdata)
+{
+	struct ofono_stk *stk = (struct ofono_stk *) userdata;
+	GIOStatus status;
+	gsize bytes_read;
+	gchar *buf = (gchar *)(stk->rx_buffer.data.array +
+						stk->rx_buffer.rx_remaining);
+	gsize count = stk->rx_buffer.data.len - stk->rx_buffer.rx_remaining;
+
+	if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP))
+		return FALSE;
+
+	if (cond & G_IO_IN) {
+		status = g_io_channel_read_chars(channel, buf, count,
+							&bytes_read, NULL);
+		DBG("Received %zd bytes", bytes_read);
+
+		if (bytes_read > 0 && stk->rx_buffer.rx_remaining == 0 &&
+				stk->report_data_available) {
+			stk_send_data_available_event(stk, bytes_read);
+		}
+
+		stk->rx_buffer.rx_remaining += bytes_read;
+
+		if (status != G_IO_STATUS_NORMAL && status != G_IO_STATUS_AGAIN)
+			return FALSE;
+	}
+	return TRUE;
+}
+
 static void ofono_stk_activate_pdp_context_cb(int error, const char *interface,
 						const char *ip,
 						void *data)
@@ -643,6 +720,8 @@ static void ofono_stk_activate_pdp_context_cb(int error, const char *interface,
 	struct ofono_stk *stk = data;
 	struct stk_response rsp;
 	struct ofono_error failure = { .type = OFONO_ERROR_TYPE_FAILURE };
+	GIOChannel *io;
+	int sk;
 
 	DBG("");
 
@@ -656,6 +735,67 @@ static void ofono_stk_activate_pdp_context_cb(int error, const char *interface,
 		stk->channel.status = STK_CHANNEL_PACKET_DATA_SERVICE_ACTIVATED;
 	}
 
+	if (stk->protocol == STK_TRANSPORT_PROTOCOL_TCP_CLIENT_REMOTE) {
+		sk = socket(AF_INET, SOCK_STREAM, 0);
+		if (sk < 0) {
+			rsp.result.type = STK_RESULT_TYPE_NOT_CAPABLE;
+			goto out;
+		}
+
+		error = connect(sk, (struct sockaddr *) &stk->dest_addr,
+						sizeof(stk->dest_addr));
+
+		if (error < 0) {
+			close(sk);
+			rsp.result.type = STK_RESULT_TYPE_NOT_CAPABLE;
+			goto out;
+		}
+	} else if (stk->protocol == STK_TRANSPORT_PROTOCOL_UDP_CLIENT_REMOTE) {
+		struct sockaddr_in addr;
+
+		sk = socket(AF_INET, SOCK_DGRAM, 0);
+		if (sk < 0) {
+			rsp.result.type = STK_RESULT_TYPE_NOT_CAPABLE;
+			goto out;
+		}
+
+		memset(&addr, 0, sizeof(addr));
+		addr.sin_family = AF_INET;
+		addr.sin_addr.s_addr = htonl(INADDR_ANY);
+		addr.sin_port = htons(0);
+
+		error = bind(sk, (struct sockaddr *) &addr, sizeof(addr));
+		if (error < 0) {
+			close(sk);
+			rsp.result.type = STK_RESULT_TYPE_NOT_CAPABLE;
+			goto out;
+		}
+	} else {
+		/* raw IP */
+		sk = open(interface, O_RDWR);
+		if (sk < 0)
+			return;
+	}
+
+	io = g_io_channel_unix_new(sk);
+	if (io == NULL) {
+		close(sk);
+		error = -ENOMEM;
+		rsp.result.type = STK_RESULT_TYPE_NOT_CAPABLE;
+		goto out;
+	}
+
+	g_io_channel_set_close_on_unref(io, TRUE);
+	g_io_channel_set_flags(io, G_IO_FLAG_NONBLOCK, NULL);
+	g_io_channel_set_encoding(io, NULL, NULL);
+	g_io_channel_set_buffered(io, FALSE);
+
+	stk->read_watch = g_io_add_watch_full(io, G_PRIORITY_DEFAULT,
+				G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+				receive_callback, stk, NULL);
+	stk->io = io;
+	g_io_channel_unref(io);
+
 	if (stk->pending_cmd == NULL) {
 		if (stk->report_channel_status)
 			stk_send_channel_status_event(stk);
@@ -670,11 +810,13 @@ static void ofono_stk_activate_pdp_context_cb(int error, const char *interface,
 				sizeof(struct stk_bearer_description));
 	} else if (stk->pending_cmd->type == STK_COMMAND_TYPE_SEND_DATA &&
 			stk->link_on_demand) {
-		/*
-		 * TODO
-		 * send the data immediately, flush the tx buffer
-		 */
-
+		while (stk->tx_buffer.data.len - stk->tx_buffer.tx_avail) {
+			if (stk_channel_data_write(stk) == 0) {
+				ofono_error("Failed to send data");
+				rsp.result.type = STK_RESULT_TYPE_NOT_CAPABLE;
+				goto out;
+			}
+		}
 		rsp.send_data.tx_avail = stk->tx_buffer.tx_avail;
 	}
 
@@ -711,6 +853,11 @@ static void stk_open_channel(struct ofono_stk *stk)
 		memset(host, 0, sizeof(host));
 		addr.s_addr = oc->data_dest_addr.addr.ipv4;
 		inet_ntop(AF_INET, &addr, host, INET_ADDRSTRLEN);
+
+		memset(&stk->dest_addr, 0, sizeof(stk->dest_addr));
+		stk->dest_addr.sin_family = AF_INET;
+		stk->dest_addr.sin_port = htons(oc->uti.port);
+		stk->dest_addr.sin_addr.s_addr = oc->data_dest_addr.addr.ipv4;
 	} else {
 		/*
 		 * For now, only the bearer type "GPRS / UTRAN packet service /
@@ -760,6 +907,7 @@ static void stk_open_channel(struct ofono_stk *stk)
 
 	memcpy(&stk->bearer_desc, &oc->bearer_desc,
 					sizeof(struct stk_bearer_description));
+	stk->protocol = oc->uti.protocol;
 	stk->link_on_demand = (stk->pending_cmd->qualifier &
 				STK_OPEN_CHANNEL_FLAG_IMMEDIATE) ? FALSE : TRUE;
 
@@ -848,11 +996,14 @@ static void stk_send_data(struct ofono_stk *stk,
 
 		return;
 	} else {
-		/*
-		 * TODO
-		 * send the data immediately, flush the tx buffer
-		 */
-		rsp.send_data.tx_avail = stk->tx_buffer.data.len;
+		while (stk->tx_buffer.data.len - stk->tx_buffer.tx_avail) {
+			if (stk_channel_data_write(stk) == 0) {
+				ofono_error("Failed to send data");
+				rsp.result.type = STK_RESULT_TYPE_NOT_CAPABLE;
+				goto out;
+			}
+		}
+		rsp.send_data.tx_avail = stk->tx_buffer.tx_avail;
 	}
 
 out:
-- 
1.7.1


  parent reply	other threads:[~2011-05-20 16:26 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-05-20 16:26 [PATCH v4 1/8] stk: Clear 'respond_on_exit' flag after sending the terminal response Philippe Nunes
2011-05-20 16:26 ` [PATCH v4 2/8] stk: Introduce BIP command handlers Philippe Nunes
2011-06-02  0:28   ` Denis Kenzior
2011-06-10 14:03     ` Philippe Nunes
2011-06-08  8:01       ` Denis Kenzior
2011-05-20 16:26 ` [PATCH v4 3/8] gprs: Add 'stk' gprs context type Philippe Nunes
2011-06-01  5:30   ` Denis Kenzior
2011-05-20 16:26 ` [PATCH v4 4/8] gprs: Add private APIs for adding/activating/removing hidden PDP contexts Philippe Nunes
2011-06-01  6:18   ` Denis Kenzior
2011-06-10  9:44     ` Philippe Nunes
2011-06-08  7:46       ` Denis Kenzior
2011-05-20 16:26 ` [PATCH v4 5/8] stk: Use Gprs private APIs to handle the Open channel/Close Channel Philippe Nunes
2011-05-20 16:26 ` [PATCH v4 6/8] gprs: Add a host route for STK context type Philippe Nunes
2011-06-01  6:26   ` Denis Kenzior
2011-05-20 16:26 ` [PATCH v4 7/8] stk: Add support of the Setup event list proactive command Philippe Nunes
2011-05-20 16:26 ` Philippe Nunes [this message]
2011-06-01  5:26 ` [PATCH v4 1/8] stk: Clear 'respond_on_exit' flag after sending the terminal response Denis Kenzior

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1305908781-8322-8-git-send-email-philippe.nunes@linux.intel.com \
    --to=philippe.nunes@linux.intel.com \
    --cc=ofono@ofono.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox