All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/4] Add gatutil.c to share common APIs with GAtServer
@ 2010-01-11 10:53 Zhenhua Zhang
  2010-01-11 10:53 ` [PATCH 2/4] Add GAtServer basic parsing support Zhenhua Zhang
  2010-01-14 15:49 ` [PATCH 1/4] Add gatutil.c to share common APIs with GAtServer Denis Kenzior
  0 siblings, 2 replies; 10+ messages in thread
From: Zhenhua Zhang @ 2010-01-11 10:53 UTC (permalink / raw)
  To: ofono

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

Add gatutil.c/gatutil.h and move shared typedef and APIs into it.
So that they can be shared by GAtServer.
---
 Makefile.am       |    3 +-
 gatchat/gatchat.c |   98 +++-------------------------------------
 gatchat/gatchat.h |    8 +---
 gatchat/gatutil.c |  131 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 gatchat/gatutil.h |   46 +++++++++++++++++++
 5 files changed, 186 insertions(+), 100 deletions(-)
 create mode 100644 gatchat/gatutil.c
 create mode 100644 gatchat/gatutil.h

diff --git a/Makefile.am b/Makefile.am
index 276b478..67882b9 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -51,7 +51,8 @@ gatchat_sources = gatchat/gatchat.h gatchat/gatchat.c \
 				gatchat/ringbuffer.h gatchat/ringbuffer.c \
 				gatchat/gatmux.h gatchat/gatmux.c \
 				gatchat/gsm0710.h gatchat/gsm0710.c \
-				gatchat/gattty.h gatchat/gattty.c
+				gatchat/gattty.h gatchat/gattty.c \
+				gatchat/gatutil.h gatchat/gatutil.c
 
 udev_files = plugins/ofono.rules
 
diff --git a/gatchat/gatchat.c b/gatchat/gatchat.c
index 8045c6b..e5cf235 100644
--- a/gatchat/gatchat.c
+++ b/gatchat/gatchat.c
@@ -40,7 +40,6 @@
 static const char *none_prefix[] = { NULL };
 
 static void g_at_chat_wakeup_writer(GAtChat *chat);
-static void debug_chat(GAtChat *chat, gboolean in, const char *str, gsize len);
 
 struct at_command {
 	char *cmd;
@@ -686,81 +685,6 @@ static void new_bytes(GAtChat *p)
 	g_at_chat_unref(p);
 }
 
-static void debug_chat(GAtChat *chat, gboolean in, const char *str, gsize len)
-{
-	char type = in ? '<' : '>';
-	gsize escaped = 2; /* Enough for '<', ' ' */
-	char *escaped_str;
-	const char *esc = "<ESC>";
-	gsize esc_size = strlen(esc);
-	const char *ctrlz = "<CtrlZ>";
-	gsize ctrlz_size = strlen(ctrlz);
-	gsize i;
-
-	if (!chat->debugf || !len)
-		return;
-
-	for (i = 0; i < len; i++) {
-		char c = str[i];
-
-		if (isprint(c))
-			escaped += 1;
-		else if (c == '\r' || c == '\t' || c == '\n')
-			escaped += 2;
-		else if (c == 26)
-			escaped += ctrlz_size;
-		else if (c == 25)
-			escaped += esc_size;
-		else
-			escaped += 4;
-	}
-
-	escaped_str = g_malloc(escaped + 1);
-	escaped_str[0] = type;
-	escaped_str[1] = ' ';
-	escaped_str[2] = '\0';
-	escaped_str[escaped] = '\0';
-
-	for (escaped = 2, i = 0; i < len; i++) {
-		char c = str[i];
-
-		switch (c) {
-		case '\r':
-			escaped_str[escaped++] = '\\';
-			escaped_str[escaped++] = 'r';
-			break;
-		case '\t':
-			escaped_str[escaped++] = '\\';
-			escaped_str[escaped++] = 't';
-			break;
-		case '\n':
-			escaped_str[escaped++] = '\\';
-			escaped_str[escaped++] = 'n';
-			break;
-		case 26:
-			strncpy(&escaped_str[escaped], ctrlz, ctrlz_size);
-			escaped += ctrlz_size;
-			break;
-		case 25:
-			strncpy(&escaped_str[escaped], esc, esc_size);
-			escaped += esc_size;
-			break;
-		default:
-			if (isprint(c))
-				escaped_str[escaped++] = c;
-			else {
-				escaped_str[escaped++] = '\\';
-				escaped_str[escaped++] = '0' + ((c >> 6) & 07);
-				escaped_str[escaped++] = '0' + ((c >> 3) & 07);
-				escaped_str[escaped++] = '0' + (c & 07);
-			}
-		}
-	}
-
-	chat->debugf(escaped_str, chat->debug_data);
-	g_free(escaped_str);
-}
-
 static gboolean received_data(GIOChannel *channel, GIOCondition cond,
 				gpointer data)
 {
@@ -786,7 +710,8 @@ static gboolean received_data(GIOChannel *channel, GIOCondition cond,
 		buf = ring_buffer_write_ptr(chat->buf);
 
 		err = g_io_channel_read(channel, (char *) buf, toread, &rbytes);
-		debug_chat(chat, TRUE, (char *)buf, rbytes);
+		g_at_util_debug_chat(chat->debugf, TRUE, (char *)buf, rbytes,
+							chat->debug_data);
 
 		total_read += rbytes;
 
@@ -932,8 +857,9 @@ static gboolean can_write_data(GIOChannel *channel, GIOCondition cond,
 		return FALSE;
 	}
 
-	debug_chat(chat, FALSE, cmd->cmd + chat->cmd_bytes_written,
-			bytes_written);
+	g_at_util_debug_chat(chat->debugf, FALSE,
+					cmd->cmd + chat->cmd_bytes_written,
+					bytes_written, chat->debug_data);
 	chat->cmd_bytes_written += bytes_written;
 
 	if (bytes_written < towrite)
@@ -961,7 +887,6 @@ static void g_at_chat_wakeup_writer(GAtChat *chat)
 GAtChat *g_at_chat_new(GIOChannel *channel, GAtSyntax *syntax)
 {
 	GAtChat *chat;
-	GIOFlags io_flags;
 
 	if (!channel)
 		return NULL;
@@ -992,20 +917,9 @@ GAtChat *g_at_chat_new(GIOChannel *channel, GAtSyntax *syntax)
 	chat->notify_list = g_hash_table_new_full(g_str_hash, g_str_equal,
 				g_free, (GDestroyNotify)at_notify_destroy);
 
-	if (g_io_channel_set_encoding(channel, NULL, NULL) !=
-			G_IO_STATUS_NORMAL)
-		goto error;
-
-	io_flags = g_io_channel_get_flags(channel);
-
-	io_flags |= G_IO_FLAG_NONBLOCK;
-
-	if (g_io_channel_set_flags(channel, io_flags, NULL) !=
-			G_IO_STATUS_NORMAL)
+	if (!g_at_util_set_io(channel))
 		goto error;
 
-	g_io_channel_set_close_on_unref(channel, TRUE);
-
 	chat->channel = channel;
 	chat->read_watch = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT,
 				G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
diff --git a/gatchat/gatchat.h b/gatchat/gatchat.h
index 999b92d..3c3fa5d 100644
--- a/gatchat/gatchat.h
+++ b/gatchat/gatchat.h
@@ -26,19 +26,13 @@
 extern "C" {
 #endif
 
-#include "gatresult.h"
 #include "gatsyntax.h"
+#include "gatutil.h"
 
 struct _GAtChat;
 
 typedef struct _GAtChat GAtChat;
 
-typedef void (*GAtResultFunc)(gboolean success, GAtResult *result,
-				gpointer user_data);
-typedef void (*GAtNotifyFunc)(GAtResult *result, gpointer user_data);
-typedef void (*GAtDisconnectFunc)(gpointer user_data);
-typedef void (*GAtDebugFunc)(const char *str, gpointer user_data);
-
 GAtChat *g_at_chat_new(GIOChannel *channel, GAtSyntax *syntax);
 
 GIOChannel *g_at_chat_get_channel(GAtChat *chat);
diff --git a/gatchat/gatutil.c b/gatchat/gatutil.c
new file mode 100644
index 0000000..585a590
--- /dev/null
+++ b/gatchat/gatutil.c
@@ -0,0 +1,131 @@
+/*
+ *
+ *  AT chat library with GLib integration
+ *
+ *  Copyright (C) 2008-2010  Intel Corporation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <ctype.h>
+
+#include <glib.h>
+
+#include "gatutil.h"
+
+void g_at_util_debug_chat(GAtDebugFunc debugf, gboolean in, const char *str,
+						gsize len, gpointer user_data)
+{
+	char type = in ? '<' : '>';
+	gsize escaped = 2; /* Enough for '<', ' ' */
+	char *escaped_str;
+	const char *esc = "<ESC>";
+	gsize esc_size = strlen(esc);
+	const char *ctrlz = "<CtrlZ>";
+	gsize ctrlz_size = strlen(ctrlz);
+	gsize i;
+
+	if (!debugf || !len)
+		return;
+
+	for (i = 0; i < len; i++) {
+		char c = str[i];
+
+		if (isprint(c))
+			escaped += 1;
+		else if (c == '\r' || c == '\t' || c == '\n')
+			escaped += 2;
+		else if (c == 26)
+			escaped += ctrlz_size;
+		else if (c == 25)
+			escaped += esc_size;
+		else
+			escaped += 4;
+	}
+
+	escaped_str = g_malloc(escaped + 1);
+	escaped_str[0] = type;
+	escaped_str[1] = ' ';
+	escaped_str[2] = '\0';
+	escaped_str[escaped] = '\0';
+
+	for (escaped = 2, i = 0; i < len; i++) {
+		char c = str[i];
+
+		switch (c) {
+		case '\r':
+			escaped_str[escaped++] = '\\';
+			escaped_str[escaped++] = 'r';
+			break;
+		case '\t':
+			escaped_str[escaped++] = '\\';
+			escaped_str[escaped++] = 't';
+			break;
+		case '\n':
+			escaped_str[escaped++] = '\\';
+			escaped_str[escaped++] = 'n';
+			break;
+		case 26:
+			strncpy(&escaped_str[escaped], ctrlz, ctrlz_size);
+			escaped += ctrlz_size;
+			break;
+		case 25:
+			strncpy(&escaped_str[escaped], esc, esc_size);
+			escaped += esc_size;
+			break;
+		default:
+			if (isprint(c))
+				escaped_str[escaped++] = c;
+			else {
+				escaped_str[escaped++] = '\\';
+				escaped_str[escaped++] = '0' + ((c >> 6) & 07);
+				escaped_str[escaped++] = '0' + ((c >> 3) & 07);
+				escaped_str[escaped++] = '0' + (c & 07);
+			}
+		}
+	}
+
+	debugf(escaped_str, user_data);
+	g_free(escaped_str);
+}
+
+gboolean g_at_util_set_io(GIOChannel *io)
+{
+	GIOFlags io_flags;
+
+	if (g_io_channel_set_encoding(io, NULL, NULL) !=
+			G_IO_STATUS_NORMAL)
+		return FALSE;
+
+	io_flags = g_io_channel_get_flags(io);
+
+	io_flags |= G_IO_FLAG_NONBLOCK;
+	io_flags |= G_IO_FLAG_IS_READABLE;
+	io_flags |= G_IO_FLAG_IS_WRITEABLE;
+
+	if (g_io_channel_set_flags(io, io_flags, NULL) !=
+			G_IO_STATUS_NORMAL)
+		return FALSE;
+
+	g_io_channel_set_close_on_unref(io, TRUE);
+
+	return TRUE;
+}
+
diff --git a/gatchat/gatutil.h b/gatchat/gatutil.h
new file mode 100644
index 0000000..63bbfff
--- /dev/null
+++ b/gatchat/gatutil.h
@@ -0,0 +1,46 @@
+/*
+ *
+ *  AT chat library with GLib integration
+ *
+ *  Copyright (C) 2008-2010  Intel Corporation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef __GATUTIL_H
+#define __GATUTIL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "gatresult.h"
+
+typedef void (*GAtResultFunc)(gboolean success, GAtResult *result,
+				gpointer user_data);
+typedef void (*GAtNotifyFunc)(GAtResult *result, gpointer user_data);
+typedef void (*GAtDisconnectFunc)(gpointer user_data);
+typedef void (*GAtDebugFunc)(const char *str, gpointer user_data);
+
+void g_at_util_debug_chat(GAtDebugFunc debugf, gboolean in, const char *str,
+						gsize len, gpointer user_data);
+
+gboolean g_at_util_set_io(GIOChannel *io);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GATUTIL_H */
-- 
1.6.3.3


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 2/4] Add GAtServer basic parsing support
  2010-01-11 10:53 [PATCH 1/4] Add gatutil.c to share common APIs with GAtServer Zhenhua Zhang
@ 2010-01-11 10:53 ` Zhenhua Zhang
  2010-01-11 10:53   ` [PATCH 3/4] Add AT command parsing support and interface Zhenhua Zhang
  2010-01-14 17:24   ` [PATCH 2/4] Add GAtServer basic parsing support Denis Kenzior
  2010-01-14 15:49 ` [PATCH 1/4] Add gatutil.c to share common APIs with GAtServer Denis Kenzior
  1 sibling, 2 replies; 10+ messages in thread
From: Zhenhua Zhang @ 2010-01-11 10:53 UTC (permalink / raw)
  To: ofono

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

It's the basic skeleton of GAtServer, including new/shutdown, ref/
unref, received_data/parse_buffer and set_discuss/set_debug.

GAtServer is to emulate the server side of AT conversation. It
complies with V.250 and 27.007 spec to accept AT command like
ATV1, ATE0 and extended command like AT+CLCC. Upper layer could
create customize server to expose TTY, tcp or unix socket to client
side application.
---
 Makefile.am         |    3 +-
 gatchat/gatserver.c |  428 +++++++++++++++++++++++++++++++++++++++++++++++++++
 gatchat/gatserver.h |   65 ++++++++
 3 files changed, 495 insertions(+), 1 deletions(-)
 create mode 100644 gatchat/gatserver.c
 create mode 100644 gatchat/gatserver.h

diff --git a/Makefile.am b/Makefile.am
index 67882b9..50dabca 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -52,7 +52,8 @@ gatchat_sources = gatchat/gatchat.h gatchat/gatchat.c \
 				gatchat/gatmux.h gatchat/gatmux.c \
 				gatchat/gsm0710.h gatchat/gsm0710.c \
 				gatchat/gattty.h gatchat/gattty.c \
-				gatchat/gatutil.h gatchat/gatutil.c
+				gatchat/gatutil.h gatchat/gatutil.c \
+				gatchat/gatserver.h gatchat/gatserver.c
 
 udev_files = plugins/ofono.rules
 
diff --git a/gatchat/gatserver.c b/gatchat/gatserver.c
new file mode 100644
index 0000000..e861e25
--- /dev/null
+++ b/gatchat/gatserver.c
@@ -0,0 +1,428 @@
+/*
+ *
+ *  AT server library with GLib integration
+ *
+ *  Copyright (C) 2008-2010  Intel Corporation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <glib.h>
+
+#include "ringbuffer.h"
+#include "gatresult.h"
+#include "gatserver.h"
+
+#define DBG(fmt, arg...) g_print("%s:%s() " fmt, __FILE__, __FUNCTION__ , ## arg)
+
+struct result_codes {
+	const char *v1;
+	unsigned int v0;
+};
+
+/* V.250 Table 1/V.250 Result codes */
+static struct result_codes at_server_result_codes[] = {
+	{ "OK",			0, },
+	{ "CONNECT",		1, },
+	{ "RING",		2, },
+	{ "NO CARRIER",		3, },
+	{ "ERROR",		4, },
+	{ "NO DIALTONE",	5, },
+	{ "BUSY",		6, },
+	{ "NO ANSWER",		7, },
+	{ "CONNECT",		8, },
+	{ NULL },
+};
+
+/* Basic command setting for V.250 */
+struct v250_settings {
+	char s3;			/* set by S3=<val> */
+	char s4;			/* set by S4=<val> */
+	char s5;			/* set by S5=<val> */
+	gboolean echo;			/* set by E<val> */
+	gboolean quiet;			/* set by Q<val> */
+	gboolean is_v1;			/* set by V<val>, v0 or v1 */
+	unsigned int res_format;	/* set by X<val> */
+	unsigned int c109;		/* set by &C<val> */
+	unsigned int c108;		/* set by &D<val> */
+};
+
+struct _GAtServer {
+	gint ref_count;				/* Ref count */
+	struct v250_settings *v250;		/* V.250 command setting */
+	GIOChannel *server_io;			/* Server IO */
+	int server_watch;			/* Watch for server IO */
+	char *modem_path;			/* Emulated modem path */
+	GAtDisconnectFunc user_disconnect;	/* User disconnect func */
+	gpointer user_disconnect_data;		/* User disconnect data */
+	GAtDebugFunc debugf;			/* Debugging output function */
+	gpointer debug_data;			/* Data to pass to debug func */
+	struct ring_buffer *buf;		/* Current read buffer */
+};
+
+static int at_server_parse(GAtServer *server, char *buf);
+
+static void g_at_server_send_result_code(GAtServer *server, int error)
+{
+	struct v250_settings *v250 = server->v250;
+	char buf[1024];
+	char text[1024];
+	char t = v250->s3;
+	char r = v250->s4;
+	struct result_codes c;
+	gsize wbuf;
+
+	memset(buf, 0, sizeof(buf));
+	memset(text, 0, sizeof(text));
+
+	if (v250->quiet)
+		return;
+
+	c = at_server_result_codes[error];
+
+	if (v250->is_v1)
+		sprintf(text, "%s", c.v1);
+	else
+		sprintf(text, "%d", c.v0);
+
+	if (v250->is_v1)
+		sprintf(buf, "%c%c%s%c%c", t, r, text, t, r);
+	else
+		sprintf(buf, "%s%c", text, t);
+
+	g_at_util_debug_chat(server->debugf, FALSE, buf, strlen(buf),
+							server->debug_data);
+
+	g_io_channel_write(server->server_io, (char *) buf, strlen(buf),
+							&wbuf);
+}
+
+static gsize skip_space(const char *buf, gsize pos)
+{
+	gsize i = pos;
+	char c = buf[i];
+
+	while (c == ' ')
+		c = buf[++i];
+
+	return i;
+}
+
+static int parse_v250_settings(GAtServer *server, char *buf)
+{
+	int res = G_AT_SERVER_RESULT_ERROR;
+
+	return res;
+}
+
+static int at_server_parse(GAtServer *server, char *buf)
+{
+	int res = G_AT_SERVER_RESULT_ERROR;
+	struct v250_settings *v250 = server->v250;
+	gsize i = 0;
+	char c;
+
+	/* skip space after "AT" or previous command */
+	i = skip_space(buf, i);
+
+	c = buf[i];
+	/* skip semicolon */
+	if (c == ';')
+		c = buf[++i];
+
+	if (g_ascii_isalpha(c) || c == '&')
+		res = parse_v250_settings(server, buf + i);
+	else if (c == v250->s3)
+		res = G_AT_SERVER_RESULT_OK;
+
+	return res;
+}
+
+static void parse_buffer(GAtServer *server, unsigned int len)
+{
+	int res = G_AT_SERVER_RESULT_ERROR;
+	gsize i = 0;
+	char *buf = NULL;
+
+	g_at_server_ref(server);
+
+	buf = g_try_new0(char, len+1);
+
+	if (!buf)
+		goto out;
+
+	if (-1 == ring_buffer_read(server->buf, buf, len))
+		goto out;
+
+	buf[len] = '\0';
+
+	DBG("received %s\n", buf);
+
+	/* skip header space */
+	buf += skip_space(buf, i);
+
+	/* Make sure the command line prefix is "AT" or "at" */
+	if (g_str_has_prefix(buf, "AT") ||
+				g_str_has_prefix(buf, "at"))
+		res = at_server_parse(server, (char *) buf + 2);
+
+	g_at_server_send_result_code(server, res);
+
+out:
+	/* We're overflowing the buffer, shutdown the socket */
+	if (server->buf && ring_buffer_avail(server->buf) == 0)
+		g_at_server_shutdown(server);
+
+	g_at_server_unref(server);
+}
+
+static gboolean received_data(GIOChannel *chan, GIOCondition cond,
+				gpointer data)
+{
+	GAtServer *server = data;
+	struct v250_settings *v250 = server->v250;
+	GIOError err;
+	gsize rbytes;
+	gsize total_read = 0;
+	unsigned char *total_buf = ring_buffer_write_ptr(server->buf);
+	static gsize total_len;
+
+	if (cond & G_IO_NVAL)
+		return FALSE;
+
+	if (cond & (G_IO_HUP | G_IO_ERR)) {
+		g_at_server_shutdown(server);
+
+		return FALSE;
+	}
+
+	/* Regardless of condition, try to read all the data available */
+	do {
+		unsigned char *buf;
+		gsize toread;
+
+		rbytes = 0;
+
+		toread = ring_buffer_avail_no_wrap(server->buf);
+
+		if (toread == 0)
+			break;
+
+		buf = ring_buffer_write_ptr(server->buf);
+
+		err = g_io_channel_read(chan, (char *) buf, toread, &rbytes);
+
+		total_read += rbytes;
+
+		if (rbytes > 0)
+			ring_buffer_write_advance(server->buf, rbytes);
+
+	} while (err == G_IO_ERROR_NONE && rbytes > 0);
+
+	g_at_util_debug_chat(server->debugf, TRUE, (char *) total_buf,
+						total_read, server->debug_data);
+
+	if (total_read == 0) {
+		g_at_server_shutdown(server);
+
+		return FALSE;
+	}
+
+	total_len += total_read;
+
+	/* Add '\0' to perform strchr */
+	total_buf[total_read] = '\0';
+
+	/* Parse buffer until we meet the terminator so that
+	 * all preceding characters will be processed
+	 */
+	if (strchr((char *) total_buf, v250->s3)) {
+		parse_buffer(server, total_len);
+
+		total_len = 0;
+	}
+
+	if (err != G_IO_ERROR_NONE && err != G_IO_ERROR_AGAIN)
+		return FALSE;
+
+	return TRUE;
+}
+
+static struct v250_settings *v250_settings_create()
+{
+	struct v250_settings *v250;
+
+	v250 = g_try_new0(struct v250_settings, 1);
+
+	if (!v250)
+		return NULL;
+
+	v250->s3 = '\r';
+	v250->s4 = '\n';
+	v250->s5 = '\b';
+	v250->echo = TRUE;
+	v250->quiet = FALSE;
+	v250->is_v1 = TRUE;
+	v250->res_format = 0;
+	v250->c109 = 1;
+	v250->c108 = 0;
+
+	return v250;
+}
+
+GAtServer *g_at_server_new(GIOChannel *io, const char *modem_path)
+{
+	GAtServer *server;
+
+	if (!io || !modem_path)
+		return NULL;
+
+	server = g_try_new0(GAtServer, 1);
+	if (!server)
+		return NULL;
+
+	server->ref_count = 1;
+	server->v250 = v250_settings_create();
+	server->server_io = io;
+	server->modem_path = g_strdup(modem_path);
+	server->user_disconnect = NULL;
+	server->user_disconnect_data = NULL;
+	server->debugf = NULL;
+	server->debug_data = NULL;
+	server->buf = ring_buffer_new(4096);
+
+	if (!server->v250)
+		goto error;
+
+	if (!server->buf)
+		goto error;
+
+	if (!g_at_util_set_io(server->server_io))
+		goto error;
+
+	server->server_watch = g_io_add_watch_full(io,
+				G_PRIORITY_DEFAULT,
+				G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+				received_data, server, NULL);
+
+	return server;
+
+error:
+	if (server->buf)
+		ring_buffer_free(server->buf);
+
+	if (server->modem_path)
+		g_free(server->modem_path);
+
+	if (server->v250)
+		g_free(server->v250);
+
+	if (server)
+		g_free(server);
+
+	return NULL;
+}
+
+GAtServer *g_at_server_ref(GAtServer *server)
+{
+	if (server == NULL)
+		return NULL;
+
+	g_atomic_int_inc(&server->ref_count);
+
+	return server;
+}
+
+void g_at_server_unref(GAtServer *server)
+{
+	gboolean is_zero;
+
+	if (server == NULL)
+		return;
+
+	is_zero = g_atomic_int_dec_and_test(&server->ref_count);
+
+	if (is_zero == FALSE)
+		return;
+
+	g_at_server_shutdown(server);
+}
+
+gboolean g_at_server_shutdown(GAtServer *server)
+{
+	if (!server)
+		return FALSE;
+
+	if (server->modem_path)
+		g_free(server->modem_path);
+
+	if (server->v250)
+		g_free(server->v250);
+
+	ring_buffer_free(server->buf);
+	server->buf = NULL;
+
+	if (server->server_watch) {
+		g_source_remove(server->server_watch);
+		server->server_watch = 0;
+	}
+
+	if (server->server_io) {
+		g_io_channel_shutdown(server->server_io, FALSE, NULL);
+		g_io_channel_unref(server->server_io);
+		server->server_io = NULL;
+	}
+
+	if (server->user_disconnect)
+		server->user_disconnect(server->user_disconnect_data);
+
+	g_free(server);
+	server = NULL;
+
+	return TRUE;
+}
+
+gboolean g_at_server_set_disconnect_function(GAtServer *server,
+						GAtDisconnectFunc disconnect,
+						gpointer user)
+{
+	if (server == NULL)
+		return FALSE;
+
+	server->user_disconnect = disconnect;
+	server->user_disconnect_data = user;
+
+	return TRUE;
+}
+
+gboolean g_at_server_set_debug(GAtServer *server, GAtDebugFunc func,
+						gpointer user)
+{
+	if (server == NULL)
+		return FALSE;
+
+	server->debugf = func;
+	server->debug_data = user;
+
+	return TRUE;
+}
diff --git a/gatchat/gatserver.h b/gatchat/gatserver.h
new file mode 100644
index 0000000..39916ec
--- /dev/null
+++ b/gatchat/gatserver.h
@@ -0,0 +1,65 @@
+/*
+ *
+ *  AT Server library with GLib integration
+ *
+ *  Copyright (C) 2008-2010  Intel Corporation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef __GATSERVER_H
+#define __GATSERVER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "gatutil.h"
+
+struct _GAtServer;
+
+typedef struct _GAtServer GAtServer;
+
+/* V.250 Table 1/V.250 Result codes */
+enum _GAtServerResultCodes {
+	G_AT_SERVER_RESULT_OK = 0,
+	G_AT_SERVER_RESULT_CONNECT,
+	G_AT_SERVER_RESULT_RING,
+	G_AT_SERVER_RESULT_NO_CARRIER,
+	G_AT_SERVER_RESULT_ERROR,
+	G_AT_SERVER_RESULT_NO_DIALTONE,
+	G_AT_SERVER_RESULT_BUSY,
+	G_AT_SERVER_RESULT_NO_ANSWER,
+	G_AT_SERVER_RESULT_CONNECT_EXT,
+};
+
+GAtServer *g_at_server_new(GIOChannel *io, const char *modem_path);
+
+GAtServer *g_at_server_ref(GAtServer *server);
+void g_at_server_unref(GAtServer *server);
+gboolean g_at_server_shutdown(GAtServer *server);
+
+gboolean g_at_server_set_disconnect_function(GAtServer *server,
+					GAtDisconnectFunc disconnect,
+					gpointer user_data);
+gboolean g_at_server_set_debug(GAtServer *server,
+					GAtDebugFunc func,
+					gpointer user);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GATSERVER_H */
-- 
1.6.3.3


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 3/4] Add AT command parsing support and interface
  2010-01-11 10:53 ` [PATCH 2/4] Add GAtServer basic parsing support Zhenhua Zhang
@ 2010-01-11 10:53   ` Zhenhua Zhang
  2010-01-11 10:53     ` [PATCH 4/4] Add test-server test application for GAtServer Zhenhua Zhang
  2010-01-14 17:24   ` [PATCH 2/4] Add GAtServer basic parsing support Denis Kenzior
  1 sibling, 1 reply; 10+ messages in thread
From: Zhenhua Zhang @ 2010-01-11 10:53 UTC (permalink / raw)
  To: ofono

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

Add parsing support for server supported AT commands. Also add
APIs to add/remove notification functions.
---
 gatchat/gatserver.c |  225 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 gatchat/gatserver.h |   23 +++++
 2 files changed, 247 insertions(+), 1 deletions(-)

diff --git a/gatchat/gatserver.c b/gatchat/gatserver.c
index e861e25..602e509 100644
--- a/gatchat/gatserver.c
+++ b/gatchat/gatserver.c
@@ -67,12 +67,24 @@ struct v250_settings {
 	unsigned int c108;		/* set by &D<val> */
 };
 
+/* AT command that server supported */
+struct at_command {
+	int id;
+	char *prefix;
+	gboolean expect_pdu;
+	GAtServerNotifyFunc notify;
+	gpointer user_data;
+	GDestroyNotify destroy_notify;
+};
+
 struct _GAtServer {
 	gint ref_count;				/* Ref count */
 	struct v250_settings *v250;		/* V.250 command setting */
 	GIOChannel *server_io;			/* Server IO */
 	int server_watch;			/* Watch for server IO */
 	char *modem_path;			/* Emulated modem path */
+	GHashTable *command_list;		/* Server supported commands */
+	gint next_command_id;			/* Id for next command */
 	GAtDisconnectFunc user_disconnect;	/* User disconnect func */
 	gpointer user_disconnect_data;		/* User disconnect data */
 	GAtDebugFunc debugf;			/* Debugging output function */
@@ -128,6 +140,112 @@ static gsize skip_space(const char *buf, gsize pos)
 	return i;
 }
 
+static inline gboolean is_at_command_prefix(const char c)
+{
+	if (c == '&')
+		return FALSE;
+
+	return g_ascii_ispunct(c);
+}
+
+static gchar *get_at_command_prefix(gchar *command, GAtServerRequestType *type)
+{
+	char c = g_ascii_toupper(*command);
+	gchar *prefix;
+	gchar *equal;
+	gchar *question;
+
+	/* Try to match command in ATA, ATD or ATH */
+	if (c == 'A' || c == 'D' || c == 'H') {
+		*type = G_AT_SERVER_REQUEST_TYPE_ACTION;
+
+		prefix = g_strdup(command);
+	} else if (is_at_command_prefix(c)) {
+		command++;
+
+		equal = strchr(command, '=');
+		question = strchr(command, '?');
+
+		/* Try to match AT+XXX=?, AT+XXX=, AT+XXX? or AT+XXX */
+		if (equal) {
+			if (question)
+				*type = G_AT_SERVER_REQUEST_TYPE_SUPPORT;
+			else
+				*type = G_AT_SERVER_REQUEST_TYPE_SET;
+
+			/* It shouldn't happen but we still check it */
+			if (question != equal + 1)
+				return G_AT_SERVER_REQUEST_TYPE_NONE;
+
+			prefix = g_strndup(command, equal - command);
+		} else if (question) {
+			*type = G_AT_SERVER_REQUEST_TYPE_QUERY;
+
+			prefix = g_strndup(command, question - command);
+		} else {
+			*type = G_AT_SERVER_REQUEST_TYPE_ACTION;
+
+			prefix = g_strdup(command);
+		}
+	}
+
+	return prefix;
+}
+
+static int parse_at_command(GAtServer *server, char *buf)
+{
+	int res = G_AT_SERVER_RESULT_ERROR;
+	GAtServerRequestType type = G_AT_SERVER_REQUEST_TYPE_NONE;
+	gchar t = server->v250->s3;
+	gsize i = 0;
+	gchar *command = NULL;
+	gchar *prefix = NULL;
+	struct at_command *node;
+
+	while (buf[i] != t && buf[i] != ';')
+		i++;
+
+	command = g_strndup(buf, i);
+
+	prefix = get_at_command_prefix(command, &type);
+
+	if (G_AT_SERVER_REQUEST_TYPE_NONE == type)
+		goto out;
+
+	node = g_hash_table_lookup(server->command_list, prefix);
+
+	if (node && node->notify) {
+		if (type == G_AT_SERVER_REQUEST_TYPE_SUPPORT)
+			res = G_AT_SERVER_RESULT_OK;
+		else {
+			GAtResult *result = g_try_new0(GAtResult, 1);
+
+			if (!result)
+				goto out;
+
+			result->lines = g_slist_prepend(NULL, command);
+			result->final_or_pdu = NULL;
+
+			res = node->notify(type, result, node->user_data);
+
+			g_free(result);
+		}
+	}
+
+	/* Compound command */
+	if ((res == G_AT_SERVER_RESULT_OK) && (buf[i] == ';'))
+		res = at_server_parse(server, buf + i);
+
+out:
+	if (prefix)
+		g_free(prefix);
+
+	if (command)
+		g_free(command);
+
+	return res;
+}
+
 static int parse_v250_settings(GAtServer *server, char *buf)
 {
 	int res = G_AT_SERVER_RESULT_ERROR;
@@ -150,7 +268,9 @@ static int at_server_parse(GAtServer *server, char *buf)
 	if (c == ';')
 		c = buf[++i];
 
-	if (g_ascii_isalpha(c) || c == '&')
+	if (is_at_command_prefix(c) || c == 'A' || c == 'D' || c == 'H')
+		res = parse_at_command(server, buf + i);
+	else if (g_ascii_isalpha(c) || c == '&')
 		res = parse_v250_settings(server, buf + i);
 	else if (c == v250->s3)
 		res = G_AT_SERVER_RESULT_OK;
@@ -305,6 +425,8 @@ GAtServer *g_at_server_new(GIOChannel *io, const char *modem_path)
 	server->v250 = v250_settings_create();
 	server->server_io = io;
 	server->modem_path = g_strdup(modem_path);
+	server->command_list = g_hash_table_new(g_str_hash, g_str_equal);
+	server->next_command_id = 1;
 	server->user_disconnect = NULL;
 	server->user_disconnect_data = NULL;
 	server->debugf = NULL;
@@ -331,6 +453,9 @@ error:
 	if (server->buf)
 		ring_buffer_free(server->buf);
 
+	if (server->command_list)
+		g_hash_table_destroy(server->command_list);
+
 	if (server->modem_path)
 		g_free(server->modem_path);
 
@@ -379,6 +504,10 @@ gboolean g_at_server_shutdown(GAtServer *server)
 	if (server->v250)
 		g_free(server->v250);
 
+	g_at_server_remove_all(server);
+
+	g_hash_table_destroy(server->command_list);
+
 	ring_buffer_free(server->buf);
 	server->buf = NULL;
 
@@ -426,3 +555,97 @@ gboolean g_at_server_set_debug(GAtServer *server, GAtDebugFunc func,
 
 	return TRUE;
 }
+
+guint g_at_server_add_command(GAtServer *server, const char *prefix,
+						gboolean expect_pdu,
+						GAtServerNotifyFunc notify,
+						gpointer user_data,
+						GDestroyNotify destroy_notify)
+{
+	struct at_command *node;
+
+	if (server == NULL || server->command_list == NULL)
+		return 0;
+
+	if (notify == NULL)
+		return 0;
+
+	if (prefix == NULL || strlen(prefix) == 0)
+		return 0;
+
+	node = g_hash_table_lookup(server->command_list, prefix);
+
+	if (node) {
+		g_hash_table_remove(server->command_list, prefix);
+
+		if (node->destroy_notify)
+			node->destroy_notify(node->user_data);
+
+		g_free(node->prefix);
+
+		g_free(node);
+	}
+
+	node = g_try_new0(struct at_command, 1);
+
+	if (!node)
+		return 0;
+
+	node->id = server->next_command_id++;
+	node->prefix = g_strdup(prefix);
+	node->expect_pdu = expect_pdu;
+	node->notify = notify;
+	node->user_data = user_data;
+	node->destroy_notify = destroy_notify;
+
+	g_hash_table_insert(server->command_list, node->prefix, node);
+
+	return node->id;
+}
+
+static gboolean at_server_remove_command(gpointer key, gpointer value,
+						gpointer user)
+{
+	struct at_command *node = value;
+
+	if (node->destroy_notify)
+		node->destroy_notify(node->user_data);
+
+	g_free(node->prefix);
+
+	g_free(node);
+
+	return TRUE;
+}
+
+gboolean g_at_server_remove_command(GAtServer *server, char *prefix)
+{
+	struct at_command *node;
+	gpointer key = prefix;
+
+	if (!server || !server->command_list)
+		return FALSE;
+
+	node = g_hash_table_lookup(server->command_list, key);
+
+	if (!node)
+		return FALSE;
+
+	g_hash_table_remove(server->command_list, key);
+
+	at_server_remove_command(prefix, node, node);
+
+	return TRUE;
+}
+
+gboolean g_at_server_remove_all(GAtServer *server)
+{
+	if (!server || !server->command_list)
+		return FALSE;
+
+	g_hash_table_foreach_remove(server->command_list,
+					at_server_remove_command, server);
+
+	return TRUE;
+}
+
diff --git a/gatchat/gatserver.h b/gatchat/gatserver.h
index 39916ec..7b68d8a 100644
--- a/gatchat/gatserver.h
+++ b/gatchat/gatserver.h
@@ -45,6 +45,21 @@ enum _GAtServerResultCodes {
 	G_AT_SERVER_RESULT_CONNECT_EXT,
 };
 
+enum _GAtServerRequestType {
+	G_AT_SERVER_REQUEST_TYPE_NONE = 0,
+	G_AT_SERVER_REQUEST_TYPE_SET,
+	G_AT_SERVER_REQUEST_TYPE_SUPPORT,
+	G_AT_SERVER_REQUEST_TYPE_QUERY,
+	G_AT_SERVER_REQUEST_TYPE_ACTION,
+};
+
+typedef enum _GAtServerRequestType GAtServerRequestType;
+
+typedef int (*GAtServerNotifyFunc)(GAtServerRequestType type,
+					GAtResult *result,
+					gpointer user_data);
+
+
 GAtServer *g_at_server_new(GIOChannel *io, const char *modem_path);
 
 GAtServer *g_at_server_ref(GAtServer *server);
@@ -58,6 +73,14 @@ gboolean g_at_server_set_debug(GAtServer *server,
 					GAtDebugFunc func,
 					gpointer user);
 
+guint g_at_server_add_command(GAtServer *server, const char *prefix,
+					gboolean expect_pdu,
+					GAtServerNotifyFunc notify,
+					gpointer user_data,
+					GDestroyNotify destroy);
+gboolean g_at_server_remove_command(GAtServer *server, char *prefix);
+gboolean g_at_server_remove_all(GAtServer *server);
+
 #ifdef __cplusplus
 }
 #endif
-- 
1.6.3.3


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 4/4] Add test-server test application for GAtServer
  2010-01-11 10:53   ` [PATCH 3/4] Add AT command parsing support and interface Zhenhua Zhang
@ 2010-01-11 10:53     ` Zhenhua Zhang
  0 siblings, 0 replies; 10+ messages in thread
From: Zhenhua Zhang @ 2010-01-11 10:53 UTC (permalink / raw)
  To: ofono

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

Add test-server application to showcase how to use GAtServer. It
supports TTY, tcp, unix socket to talk with client application.
---
 Makefile.am           |    6 +-
 gatchat/test-server.c |  402 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 407 insertions(+), 1 deletions(-)
 create mode 100644 gatchat/test-server.c

diff --git a/Makefile.am b/Makefile.am
index 50dabca..8ab62ca 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -299,12 +299,16 @@ unit_test_idmap_SOURCES = unit/test-idmap.c src/idmap.c
 unit_test_idmap_LDADD = @GLIB_LIBS@
 unit_objects += $(unit_test_idmap_OBJECTS)
 
-noinst_PROGRAMS += gatchat/gsmdial
+noinst_PROGRAMS += gatchat/gsmdial gatchat/test-server
 
 gatchat_gsmdial_SOURCES = gatchat/gsmdial.c $(gatchat_sources)
 
 gatchat_gsmdial_LDADD = @GLIB_LIBS@
 
+gatchat_test_server_SOURCES = gatchat/test-server.c $(gatchat_sources)
+
+gatchat_test_server_LDADD = @GLIB_LIBS@ -lutil
+
 
 DISTCHECK_CONFIGURE_FLAGS = --disable-datafiles
 
diff --git a/gatchat/test-server.c b/gatchat/test-server.c
new file mode 100644
index 0000000..68ddfc4
--- /dev/null
+++ b/gatchat/test-server.c
@@ -0,0 +1,402 @@
+/*
+ *
+ *  oFono - Open Source Telephony
+ *
+ *  Copyright (C) 2008-2010  Intel Corporation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <unistd.h>
+#include <stdio.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <signal.h>
+#include <sys/signalfd.h>
+
+#include <glib.h>
+#include <pty.h>
+
+#include "gatserver.h"
+#include "ringbuffer.h"
+
+#define DEFAULT_TCP_PORT 12346
+#define DEFAULT_SOCK_PATH "./server_sock"
+
+struct sock_server{
+	int server_sock;
+	const char *modem_path;
+};
+
+static GMainLoop *mainloop;
+static GAtServer *server;
+unsigned int server_watch;
+
+static gboolean server_cleanup()
+{
+	if (server_watch)
+		g_source_remove(server_watch);
+
+	g_at_server_unref(server);
+	server = NULL;
+
+	unlink(DEFAULT_SOCK_PATH);
+
+	g_main_loop_quit(mainloop);
+
+	return FALSE;
+}
+
+static void server_debug(const char *str, void *data)
+{
+	g_print("%s: %s\n", (char *) data, str);
+}
+
+static void add_handler(GAtServer *server)
+{
+	g_at_server_set_debug(server, server_debug, "Server");
+}
+
+static void server_destroy(gpointer user)
+{
+	struct sock_server *data = user;
+
+	if (data)
+		g_free(data);
+}
+
+static GAtServer *create_tty(const char *modem_path)
+{
+	int master, slave;
+	char pty_name[256];
+	GIOChannel *io;
+
+	if (!modem_path)
+		return NULL;
+
+	if (openpty(&master, &slave, pty_name, NULL, NULL) < 0)
+		return NULL;
+
+	io = g_io_channel_unix_new(master);
+
+	g_print("new tty is created@%s\n", pty_name);
+
+	server = g_at_server_new(io, modem_path);
+
+	if (!server) {
+		g_io_channel_shutdown(io, FALSE, NULL);
+		g_io_channel_unref(io);
+
+		return NULL;
+	}
+
+	add_handler(server);
+
+	return server;
+}
+
+static gboolean on_socket_connected(GIOChannel *chan, GIOCondition cond,
+							gpointer user)
+{
+	struct sockaddr saddr;
+	unsigned int len = sizeof(saddr);
+	int fd;
+	GIOChannel *client_io = NULL;
+	struct sock_server *data = user;
+
+	if (cond != G_IO_IN)
+		goto error;
+
+	fd = accept(data->server_sock, &saddr, &len);
+	if (fd == -1)
+		goto error;
+
+	client_io = g_io_channel_unix_new(fd);
+
+	server = g_at_server_new(client_io, data->modem_path);
+
+	if (!server) {
+		g_io_channel_shutdown(client_io, FALSE, NULL);
+		g_io_channel_unref(client_io);
+
+		goto error;
+	}
+
+	add_handler(server);
+
+	return TRUE;
+
+error:
+	if (data)
+		g_free(data);
+
+	return FALSE;
+}
+
+static struct sock_server *socket_common(int sk, struct sockaddr *addr,
+						const char *modem_path)
+{
+	struct sock_server *sock;
+
+	if (bind(sk, addr, sizeof(struct sockaddr)) < 0) {
+		g_print("Can't bind socket: %s (%d)", strerror(errno), errno);
+
+		close(sk);
+
+		return NULL;
+	}
+
+	if (listen(sk, 1) < 0) {
+		g_print("Can't listen on socket: %s (%d)",
+						strerror(errno), errno);
+
+		close(sk);
+
+		return NULL;
+	}
+
+	sock = g_try_new0(struct sock_server, 1);
+	if (!sock)
+		return FALSE;
+
+	sock->server_sock = sk;
+	sock->modem_path = g_strdup(modem_path);
+
+	return sock;
+}
+
+static gboolean create_tcp(const char *modem_path, int port)
+{
+	struct sockaddr_in addr;
+	int sk;
+	struct sock_server *server;
+	GIOChannel *server_io;
+
+	if (!modem_path)
+		return FALSE;
+
+	sk = socket(PF_INET, SOCK_STREAM, 0);
+	if (sk < 0) {
+		g_print("Can't create tcp/ip socket: %s (%d)",
+						strerror(errno), errno);
+		return FALSE;
+	}
+
+	memset(&addr, 0, sizeof(addr));
+
+	addr.sin_family = AF_INET;
+	addr.sin_addr.s_addr = INADDR_ANY;
+	addr.sin_port = htons(port);
+
+	server = socket_common(sk, (struct sockaddr *) &addr, modem_path);
+	if (!server)
+		return FALSE;
+
+	g_print("new tcp is created at tcp port %d\n", port);
+
+	server_io = g_io_channel_unix_new(sk);
+
+	g_io_channel_set_close_on_unref(server_io, TRUE);
+
+	server_watch = g_io_add_watch_full(server_io,
+				G_PRIORITY_DEFAULT,
+				G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+				on_socket_connected, server, server_destroy);
+
+	g_io_channel_unref(server_io);
+
+	return TRUE;
+}
+
+static gboolean create_unix(const char *modem_path, const char *sock_path)
+{
+	struct sockaddr_un addr;
+	int sk;
+	struct sock_server *server;
+	GIOChannel *server_io;
+
+	if (!modem_path)
+		return FALSE;
+
+	sk = socket(AF_UNIX, SOCK_STREAM, 0);
+	if (sk < 0) {
+		g_print("Can't create unix socket: %s (%d)",
+						strerror(errno), errno);
+
+		return FALSE;
+	}
+
+	memset(&addr, 0, sizeof(addr));
+
+	addr.sun_family = AF_UNIX;
+	strncpy(addr.sun_path, sock_path, sizeof(addr.sun_path) - 1);
+
+	/* Unlink any existing socket for this session */
+	unlink(addr.sun_path);
+
+	server = socket_common(sk, (struct sockaddr *) &addr, modem_path);
+	if (!server)
+		return FALSE;
+
+	g_print("new unix socket is created at %s\n", sock_path);
+
+	server_io = g_io_channel_unix_new(sk);
+
+	g_io_channel_set_close_on_unref(server_io, TRUE);
+
+	server_watch = g_io_add_watch_full(server_io,
+				G_PRIORITY_DEFAULT,
+				G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+				on_socket_connected, server, server_destroy);
+
+	g_io_channel_unref(server_io);
+
+	return TRUE;
+}
+
+static void test_server(int type)
+{
+	switch (type) {
+	case 0:
+		server = create_tty("/phonesim1");
+
+		add_handler(server);
+		break;
+	case 1:
+		if (!create_tcp("/phonesim1", DEFAULT_TCP_PORT))
+			exit(-1);
+		break;
+	case 2:
+		if (!create_unix("/phonesim1", DEFAULT_SOCK_PATH))
+			exit(-1);
+		break;
+	}
+}
+
+static gboolean signal_cb(GIOChannel *channel, GIOCondition cond, gpointer data)
+{
+	int signal_fd = GPOINTER_TO_INT(data);
+	struct signalfd_siginfo si;
+	ssize_t res;
+
+	if (cond & (G_IO_NVAL | G_IO_ERR))
+		return FALSE;
+
+	res = read(signal_fd, &si, sizeof(si));
+	if (res != sizeof(si))
+		return FALSE;
+
+	switch (si.ssi_signo) {
+	case SIGINT:
+		server_cleanup();
+		break;
+	case SIGTERM:
+		server_cleanup();
+		break;
+	default:
+		break;
+	}
+
+	return TRUE;
+}
+
+static int create_signal_io()
+{
+	sigset_t mask;
+	GIOChannel *signal_io;
+	int signal_fd, signal_source;
+
+	sigemptyset(&mask);
+	sigaddset(&mask, SIGTERM);
+	sigaddset(&mask, SIGINT);
+
+	if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) {
+		g_error("Can't set signal mask");
+		return 1;
+	}
+
+	signal_fd = signalfd(-1, &mask, 0);
+	if (signal_fd < 0) {
+		g_error("Can't create signal filedescriptor");
+		return 1;
+	}
+
+	signal_io = g_io_channel_unix_new(signal_fd);
+
+	g_io_channel_set_close_on_unref(signal_io, TRUE);
+
+	signal_source = g_io_add_watch(signal_io,
+			G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+			signal_cb, GINT_TO_POINTER(signal_fd));
+
+	g_io_channel_unref(signal_io);
+
+	return signal_source;
+}
+
+static void usage(void)
+{
+	g_print("test-server - AT Server testing\n"
+		"Usage:\n");
+	g_print("\ttest-server [-t type]\n");
+	g_print("Types:\n"
+		"\t0: Pseudo TTY port (default)\n"
+		"\t1: TCP sock at port 12346)\n"
+		"\t2: Unix sock@./server_sock\n");
+}
+
+int main(int argc, char **argv)
+{
+	int opt, signal_source;
+	int type = 0;
+
+	while ((opt = getopt(argc, argv, "ht:")) != EOF) {
+		switch (opt) {
+		case 't':
+			type = atoi(optarg);
+			break;
+		case 'h':
+			usage();
+			exit(1);
+			break;
+		default:
+			break;
+		}
+	}
+
+	test_server(type);
+
+	signal_source = create_signal_io();
+
+	mainloop = g_main_loop_new(NULL, FALSE);
+
+	g_main_loop_run(mainloop);
+
+	g_main_loop_unref(mainloop);
+
+	g_source_remove(signal_source);
+
+	return 0;
+}
-- 
1.6.3.3


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/4] Add gatutil.c to share common APIs with GAtServer
  2010-01-11 10:53 [PATCH 1/4] Add gatutil.c to share common APIs with GAtServer Zhenhua Zhang
  2010-01-11 10:53 ` [PATCH 2/4] Add GAtServer basic parsing support Zhenhua Zhang
@ 2010-01-14 15:49 ` Denis Kenzior
  2010-01-15  1:24   ` Zhang, Zhenhua
  1 sibling, 1 reply; 10+ messages in thread
From: Denis Kenzior @ 2010-01-14 15:49 UTC (permalink / raw)
  To: ofono

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

Hi Zhenhua,

> +gboolean g_at_util_set_io(GIOChannel *io)

Rename this g_at_util_setup_io

> +{
> +	GIOFlags io_flags;
> +
> +	if (g_io_channel_set_encoding(io, NULL, NULL) !=
> +			G_IO_STATUS_NORMAL)
> +		return FALSE;
> +
> +	io_flags = g_io_channel_get_flags(io);
> +
> +	io_flags |= G_IO_FLAG_NONBLOCK;
> +	io_flags |= G_IO_FLAG_IS_READABLE;
> +	io_flags |= G_IO_FLAG_IS_WRITEABLE;

According to GLib docs the READABLE and WRITEABLE flags are not settable.  
Don't see the point in setting them anyway, please get rid of this.

> +
> +	if (g_io_channel_set_flags(io, io_flags, NULL) !=
> +			G_IO_STATUS_NORMAL)
> +		return FALSE;
> +
> +	g_io_channel_set_close_on_unref(io, TRUE);
> +
> +	return TRUE;
> +}
> +
> diff --git a/gatchat/gatutil.h b/gatchat/gatutil.h
> new file mode 100644
> index 0000000..63bbfff
> --- /dev/null
> +++ b/gatchat/gatutil.h
> @@ -0,0 +1,46 @@
> +/*
> + *
> + *  AT chat library with GLib integration
> + *
> + *  Copyright (C) 2008-2010  Intel Corporation. All rights reserved.
> + *
> + *  This program is free software; you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License version 2 as
> + *  published by the Free Software Foundation.
> + *
> + *  This program is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *  GNU General Public License for more details.
> + *
> + *  You should have received a copy of the GNU General Public License
> + *  along with this program; if not, write to the Free Software
> + *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 
>  USA + *
> + */
> +
> +#ifndef __GATUTIL_H
> +#define __GATUTIL_H
> +
> +#ifdef __cplusplus
> +extern "C" {
> +#endif
> +
> +#include "gatresult.h"

Get rid of this include

> +
> +typedef void (*GAtResultFunc)(gboolean success, GAtResult *result,
> +				gpointer user_data);
> +typedef void (*GAtNotifyFunc)(GAtResult *result, gpointer user_data);

The GAtNotify and GAtResultFunc should stay in gatchat.h

> +typedef void (*GAtDisconnectFunc)(gpointer user_data);
> +typedef void (*GAtDebugFunc)(const char *str, gpointer user_data);

These don't belong here, create a new file called gat.h and put them there.

Regards,
-Denis

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 2/4] Add GAtServer basic parsing support
  2010-01-11 10:53 ` [PATCH 2/4] Add GAtServer basic parsing support Zhenhua Zhang
  2010-01-11 10:53   ` [PATCH 3/4] Add AT command parsing support and interface Zhenhua Zhang
@ 2010-01-14 17:24   ` Denis Kenzior
  2010-01-14 21:53     ` Marcel Holtmann
  1 sibling, 1 reply; 10+ messages in thread
From: Denis Kenzior @ 2010-01-14 17:24 UTC (permalink / raw)
  To: ofono

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

Hi Zhenhua,

> +
> +#include <glib.h>
> +
> +#include "ringbuffer.h"
> +#include "gatresult.h"

Is this include really necessary?

> +#include "gatserver.h"
> +
> +#define DBG(fmt, arg...) g_print("%s:%s() " fmt, __FILE__, __FUNCTION__ ,
>  ## arg) +

Move this to gat.h

> +struct _GAtServer {
> +	gint ref_count;				/* Ref count */
> +	struct v250_settings *v250;		/* V.250 command setting */

This one doesn't need to be a pointer.

> +	GIOChannel *server_io;			/* Server IO */
> +	int server_watch;			/* Watch for server IO */
> +	char *modem_path;			/* Emulated modem path */

Get rid of this, there's no purpose for it.

> +static int at_server_parse(GAtServer *server, char *buf)
> +{
> +	int res = G_AT_SERVER_RESULT_ERROR;
> +	struct v250_settings *v250 = server->v250;
> +	gsize i = 0;
> +	char c;
> +
> +	/* skip space after "AT" or previous command */
> +	i = skip_space(buf, i);
> +
> +	c = buf[i];
> +	/* skip semicolon */
> +	if (c == ';')
> +		c = buf[++i];
> +
> +	if (g_ascii_isalpha(c) || c == '&')
> +		res = parse_v250_settings(server, buf + i);

This part makes no sense

> +	else if (c == v250->s3)
> +		res = G_AT_SERVER_RESULT_OK;
> +
> +	return res;
> +}
> +
> +static void parse_buffer(GAtServer *server, unsigned int len)
> +{
> +	int res = G_AT_SERVER_RESULT_ERROR;
> +	gsize i = 0;
> +	char *buf = NULL;
> +
> +	g_at_server_ref(server);

Lets get rid of this part for now.  It was a necessary evil inside GAtChat 
since the client can close the channel in the command result callback.  I 
don't think this is relevant for GAtServer.  If it ever becomes relevant we 
can add this back in.

> +
> +	buf = g_try_new0(char, len+1);

You're leaking the buf memory in this function.

> +
> +	if (!buf)
> +		goto out;
> +
> +	if (-1 == ring_buffer_read(server->buf, buf, len))
> +		goto out;
> +
> +	buf[len] = '\0';
> +
> +	DBG("received %s\n", buf);
> +
> +	/* skip header space */
> +	buf += skip_space(buf, i);
> +
> +	/* Make sure the command line prefix is "AT" or "at" */
> +	if (g_str_has_prefix(buf, "AT") ||
> +				g_str_has_prefix(buf, "at"))
> +		res = at_server_parse(server, (char *) buf + 2);
> +
> +	g_at_server_send_result_code(server, res);
> +
> +out:
> +	/* We're overflowing the buffer, shutdown the socket */
> +	if (server->buf && ring_buffer_avail(server->buf) == 0)
> +		g_at_server_shutdown(server);
> +
> +	g_at_server_unref(server);

Same here, see above.

> +}
> +
> +static gboolean received_data(GIOChannel *chan, GIOCondition cond,
> +				gpointer data)
> +{
> +	GAtServer *server = data;
> +	struct v250_settings *v250 = server->v250;
> +	GIOError err;
> +	gsize rbytes;
> +	gsize total_read = 0;
> +	unsigned char *total_buf = ring_buffer_write_ptr(server->buf);

You're totally abusing the ring buffer concept here, the fact that this works 
is pure luck.

> +	static gsize total_len;
> +
> +	if (cond & G_IO_NVAL)
> +		return FALSE;
> +
> +	if (cond & (G_IO_HUP | G_IO_ERR)) {
> +		g_at_server_shutdown(server);
> +
> +		return FALSE;
> +	}
> +
> +	/* Regardless of condition, try to read all the data available */
> +	do {
> +		unsigned char *buf;
> +		gsize toread;
> +
> +		rbytes = 0;
> +
> +		toread = ring_buffer_avail_no_wrap(server->buf);
> +
> +		if (toread == 0)
> +			break;
> +
> +		buf = ring_buffer_write_ptr(server->buf);
> +
> +		err = g_io_channel_read(chan, (char *) buf, toread, &rbytes);
> +
> +		total_read += rbytes;
> +
> +		if (rbytes > 0)
> +			ring_buffer_write_advance(server->buf, rbytes);
> +
> +	} while (err == G_IO_ERROR_NONE && rbytes > 0);
> +
> +	g_at_util_debug_chat(server->debugf, TRUE, (char *) total_buf,
> +						total_read, server->debug_data);
> +
> +	if (total_read == 0) {
> +		g_at_server_shutdown(server);

You should be checking rbytes == 0 && err != EAGAIN here.  Your check below is 
also redundant.

> +
> +		return FALSE;
> +	}
> +
> +	total_len += total_read;
> +
> +	/* Add '\0' to perform strchr */
> +	total_buf[total_read] = '\0';
> +
> +	/* Parse buffer until we meet the terminator so that
> +	 * all preceding characters will be processed
> +	 */
> +	if (strchr((char *) total_buf, v250->s3)) {
> +		parse_buffer(server, total_len);
> +
> +		total_len = 0;
> +	}

Should this be inside a while loop? Several commands can come in at once.

> +
> +	if (err != G_IO_ERROR_NONE && err != G_IO_ERROR_AGAIN)
> +		return FALSE;
> +
> +	return TRUE;
> +}
> +

> +GAtServer *g_at_server_new(GIOChannel *io, const char *modem_path)

Get rid of modem_path

> +{
> +	GAtServer *server;
> +
> +	if (!io || !modem_path)
> +		return NULL;
> +
> +	server = g_try_new0(GAtServer, 1);
> +	if (!server)
> +		return NULL;
> +
> +	server->ref_count = 1;
> +	server->v250 = v250_settings_create();
> +	server->server_io = io;
> +	server->modem_path = g_strdup(modem_path);

And here

> +	server->user_disconnect = NULL;
> +	server->user_disconnect_data = NULL;
> +	server->debugf = NULL;
> +	server->debug_data = NULL;
> +	server->buf = ring_buffer_new(4096);
> +
> +	if (!server->v250)
> +		goto error;
> +
> +	if (!server->buf)
> +		goto error;
> +
> +	if (!g_at_util_set_io(server->server_io))
> +		goto error;
> +
> +	server->server_watch = g_io_add_watch_full(io,
> +				G_PRIORITY_DEFAULT,
> +				G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
> +				received_data, server, NULL);
> +
> +	return server;
> +
> +error:
> +	if (server->buf)
> +		ring_buffer_free(server->buf);
> +
> +	if (server->modem_path)
> +		g_free(server->modem_path);

And here

> +
> +	if (server->v250)
> +		g_free(server->v250);
> +
> +	if (server)
> +		g_free(server);
> +
> +	return NULL;
> +}
> +
> +gboolean g_at_server_shutdown(GAtServer *server)
> +{
> +	if (!server)
> +		return FALSE;
> +
> +	if (server->modem_path)
> +		g_free(server->modem_path);
> +
> +	if (server->v250)
> +		g_free(server->v250);
> +
> +	ring_buffer_free(server->buf);
> +	server->buf = NULL;
> +
> +	if (server->server_watch) {
> +		g_source_remove(server->server_watch);
> +		server->server_watch = 0;
> +	}
> +
> +	if (server->server_io) {
> +		g_io_channel_shutdown(server->server_io, FALSE, NULL);
> +		g_io_channel_unref(server->server_io);
> +		server->server_io = NULL;
> +	}
> +
> +	if (server->user_disconnect)
> +		server->user_disconnect(server->user_disconnect_data);

We should not trigger a user_disconnect if we're shutting down normally.  The 
purpose is to detect when the remote side has disconnected the connection.

Regards,
-Denis

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 2/4] Add GAtServer basic parsing support
  2010-01-14 21:53     ` Marcel Holtmann
@ 2010-01-14 20:57       ` Denis Kenzior
  0 siblings, 0 replies; 10+ messages in thread
From: Denis Kenzior @ 2010-01-14 20:57 UTC (permalink / raw)
  To: ofono

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

Hi Marcel,

> Hi Denis,
> 
> > > +#include "gatserver.h"
> > > +
> > > +#define DBG(fmt, arg...) g_print("%s:%s() " fmt, __FILE__,
> > > __FUNCTION__ , ## arg) +
> >
> > Move this to gat.h
> 
> can we actually not be using DBG inside gatchat. Why is that suddenly
> needed?

Actually good point. I agree this should be removed.

Regards,
-Denis

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 2/4] Add GAtServer basic parsing support
  2010-01-14 17:24   ` [PATCH 2/4] Add GAtServer basic parsing support Denis Kenzior
@ 2010-01-14 21:53     ` Marcel Holtmann
  2010-01-14 20:57       ` Denis Kenzior
  0 siblings, 1 reply; 10+ messages in thread
From: Marcel Holtmann @ 2010-01-14 21:53 UTC (permalink / raw)
  To: ofono

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

Hi Denis,

> > +#include "gatserver.h"
> > +
> > +#define DBG(fmt, arg...) g_print("%s:%s() " fmt, __FILE__, __FUNCTION__ ,
> >  ## arg) +
> 
> Move this to gat.h

can we actually not be using DBG inside gatchat. Why is that suddenly
needed?

Regards

Marcel



^ permalink raw reply	[flat|nested] 10+ messages in thread

* RE: [PATCH 1/4] Add gatutil.c to share common APIs with GAtServer
  2010-01-14 15:49 ` [PATCH 1/4] Add gatutil.c to share common APIs with GAtServer Denis Kenzior
@ 2010-01-15  1:24   ` Zhang, Zhenhua
  2010-01-20 20:23     ` Denis Kenzior
  0 siblings, 1 reply; 10+ messages in thread
From: Zhang, Zhenhua @ 2010-01-15  1:24 UTC (permalink / raw)
  To: ofono

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

Hi Denis,

Denis Kenzior wrote:
> Hi Zhenhua,
> 
>> +gboolean g_at_util_set_io(GIOChannel *io)
> 
> Rename this g_at_util_setup_io
> 
>> +typedef void (*GAtDisconnectFunc)(gpointer user_data); typedef void
>> +(*GAtDebugFunc)(const char *str, gpointer user_data);
> 
> These don't belong here, create a new file called gat.h and put them
> there. 
> 
> Regards,
> -Denis

Thanks for your comments. Updated patch is attached.

Regards,
Zhenhua

[-- Attachment #2: 0001-Add-gatutil.c-to-share-common-APIs-with-GAtServer.patch --]
[-- Type: application/octet-stream, Size: 11673 bytes --]

From 05f4611e5a3f0353fc79a341ef4be07e515a48eb Mon Sep 17 00:00:00 2001
From: Zhenhua Zhang <zhenhua.zhang@intel.com>
Date: Fri, 15 Jan 2010 09:15:38 +0800
Subject: [PATCH 1/4] Add gatutil.c to share common APIs with GAtServer

Add gatutil.c/h gat.h and move shared typedef and APIs into it.
So that they can be shared by GAtServer and GAtChat.
---
 Makefile.am       |    4 +-
 gatchat/gat.h     |   36 +++++++++++++++
 gatchat/gatchat.c |   98 +++-------------------------------------
 gatchat/gatchat.h |    3 +-
 gatchat/gatutil.c |  129 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 gatchat/gatutil.h |   40 ++++++++++++++++
 6 files changed, 215 insertions(+), 95 deletions(-)
 create mode 100644 gatchat/gat.h
 create mode 100644 gatchat/gatutil.c
 create mode 100644 gatchat/gatutil.h

diff --git a/Makefile.am b/Makefile.am
index 276b478..b6776bd 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -51,7 +51,9 @@ gatchat_sources = gatchat/gatchat.h gatchat/gatchat.c \
 				gatchat/ringbuffer.h gatchat/ringbuffer.c \
 				gatchat/gatmux.h gatchat/gatmux.c \
 				gatchat/gsm0710.h gatchat/gsm0710.c \
-				gatchat/gattty.h gatchat/gattty.c
+				gatchat/gattty.h gatchat/gattty.c \
+				gatchat/gatutil.h gatchat/gatutil.c \
+				gatchat/gat.h
 
 udev_files = plugins/ofono.rules
 
diff --git a/gatchat/gat.h b/gatchat/gat.h
new file mode 100644
index 0000000..6696e7d
--- /dev/null
+++ b/gatchat/gat.h
@@ -0,0 +1,36 @@
+/*
+ *
+ *  AT chat library with GLib integration
+ *
+ *  Copyright (C) 2008-2010  Intel Corporation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef __GAT_H
+#define __GAT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void (*GAtDisconnectFunc)(gpointer user_data);
+typedef void (*GAtDebugFunc)(const char *str, gpointer user_data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GAT_H */
diff --git a/gatchat/gatchat.c b/gatchat/gatchat.c
index 8af927e..b5627b3 100644
--- a/gatchat/gatchat.c
+++ b/gatchat/gatchat.c
@@ -40,7 +40,6 @@
 static const char *none_prefix[] = { NULL };
 
 static void g_at_chat_wakeup_writer(GAtChat *chat);
-static void debug_chat(GAtChat *chat, gboolean in, const char *str, gsize len);
 
 struct at_command {
 	char *cmd;
@@ -686,81 +685,6 @@ static void new_bytes(GAtChat *p)
 	g_at_chat_unref(p);
 }
 
-static void debug_chat(GAtChat *chat, gboolean in, const char *str, gsize len)
-{
-	char type = in ? '<' : '>';
-	gsize escaped = 2; /* Enough for '<', ' ' */
-	char *escaped_str;
-	const char *esc = "<ESC>";
-	gsize esc_size = strlen(esc);
-	const char *ctrlz = "<CtrlZ>";
-	gsize ctrlz_size = strlen(ctrlz);
-	gsize i;
-
-	if (!chat->debugf || !len)
-		return;
-
-	for (i = 0; i < len; i++) {
-		char c = str[i];
-
-		if (isprint(c))
-			escaped += 1;
-		else if (c == '\r' || c == '\t' || c == '\n')
-			escaped += 2;
-		else if (c == 26)
-			escaped += ctrlz_size;
-		else if (c == 25)
-			escaped += esc_size;
-		else
-			escaped += 4;
-	}
-
-	escaped_str = g_malloc(escaped + 1);
-	escaped_str[0] = type;
-	escaped_str[1] = ' ';
-	escaped_str[2] = '\0';
-	escaped_str[escaped] = '\0';
-
-	for (escaped = 2, i = 0; i < len; i++) {
-		char c = str[i];
-
-		switch (c) {
-		case '\r':
-			escaped_str[escaped++] = '\\';
-			escaped_str[escaped++] = 'r';
-			break;
-		case '\t':
-			escaped_str[escaped++] = '\\';
-			escaped_str[escaped++] = 't';
-			break;
-		case '\n':
-			escaped_str[escaped++] = '\\';
-			escaped_str[escaped++] = 'n';
-			break;
-		case 26:
-			strncpy(&escaped_str[escaped], ctrlz, ctrlz_size);
-			escaped += ctrlz_size;
-			break;
-		case 25:
-			strncpy(&escaped_str[escaped], esc, esc_size);
-			escaped += esc_size;
-			break;
-		default:
-			if (isprint(c))
-				escaped_str[escaped++] = c;
-			else {
-				escaped_str[escaped++] = '\\';
-				escaped_str[escaped++] = '0' + ((c >> 6) & 07);
-				escaped_str[escaped++] = '0' + ((c >> 3) & 07);
-				escaped_str[escaped++] = '0' + (c & 07);
-			}
-		}
-	}
-
-	chat->debugf(escaped_str, chat->debug_data);
-	g_free(escaped_str);
-}
-
 static gboolean received_data(GIOChannel *channel, GIOCondition cond,
 				gpointer data)
 {
@@ -786,7 +710,8 @@ static gboolean received_data(GIOChannel *channel, GIOCondition cond,
 		buf = ring_buffer_write_ptr(chat->buf);
 
 		err = g_io_channel_read(channel, (char *) buf, toread, &rbytes);
-		debug_chat(chat, TRUE, (char *)buf, rbytes);
+		g_at_util_debug_chat(chat->debugf, TRUE, (char *)buf, rbytes,
+							chat->debug_data);
 
 		total_read += rbytes;
 
@@ -932,8 +857,9 @@ static gboolean can_write_data(GIOChannel *channel, GIOCondition cond,
 		return FALSE;
 	}
 
-	debug_chat(chat, FALSE, cmd->cmd + chat->cmd_bytes_written,
-			bytes_written);
+	g_at_util_debug_chat(chat->debugf, FALSE,
+					cmd->cmd + chat->cmd_bytes_written,
+					bytes_written, chat->debug_data);
 	chat->cmd_bytes_written += bytes_written;
 
 	if (bytes_written < towrite)
@@ -961,7 +887,6 @@ static void g_at_chat_wakeup_writer(GAtChat *chat)
 GAtChat *g_at_chat_new(GIOChannel *channel, GAtSyntax *syntax)
 {
 	GAtChat *chat;
-	GIOFlags io_flags;
 
 	if (!channel)
 		return NULL;
@@ -992,20 +917,9 @@ GAtChat *g_at_chat_new(GIOChannel *channel, GAtSyntax *syntax)
 	chat->notify_list = g_hash_table_new_full(g_str_hash, g_str_equal,
 				g_free, (GDestroyNotify)at_notify_destroy);
 
-	if (g_io_channel_set_encoding(channel, NULL, NULL) !=
-			G_IO_STATUS_NORMAL)
-		goto error;
-
-	io_flags = g_io_channel_get_flags(channel);
-
-	io_flags |= G_IO_FLAG_NONBLOCK;
-
-	if (g_io_channel_set_flags(channel, io_flags, NULL) !=
-			G_IO_STATUS_NORMAL)
+	if (!g_at_util_setup_io(channel))
 		goto error;
 
-	g_io_channel_set_close_on_unref(channel, TRUE);
-
 	chat->channel = channel;
 	chat->read_watch = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT,
 				G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
diff --git a/gatchat/gatchat.h b/gatchat/gatchat.h
index 999b92d..f76fc42 100644
--- a/gatchat/gatchat.h
+++ b/gatchat/gatchat.h
@@ -28,6 +28,7 @@ extern "C" {
 
 #include "gatresult.h"
 #include "gatsyntax.h"
+#include "gatutil.h"
 
 struct _GAtChat;
 
@@ -36,8 +37,6 @@ typedef struct _GAtChat GAtChat;
 typedef void (*GAtResultFunc)(gboolean success, GAtResult *result,
 				gpointer user_data);
 typedef void (*GAtNotifyFunc)(GAtResult *result, gpointer user_data);
-typedef void (*GAtDisconnectFunc)(gpointer user_data);
-typedef void (*GAtDebugFunc)(const char *str, gpointer user_data);
 
 GAtChat *g_at_chat_new(GIOChannel *channel, GAtSyntax *syntax);
 
diff --git a/gatchat/gatutil.c b/gatchat/gatutil.c
new file mode 100644
index 0000000..6bc5dcb
--- /dev/null
+++ b/gatchat/gatutil.c
@@ -0,0 +1,129 @@
+/*
+ *
+ *  AT chat library with GLib integration
+ *
+ *  Copyright (C) 2008-2010  Intel Corporation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <ctype.h>
+
+#include <glib.h>
+
+#include "gatutil.h"
+
+void g_at_util_debug_chat(GAtDebugFunc debugf, gboolean in, const char *str,
+						gsize len, gpointer user_data)
+{
+	char type = in ? '<' : '>';
+	gsize escaped = 2; /* Enough for '<', ' ' */
+	char *escaped_str;
+	const char *esc = "<ESC>";
+	gsize esc_size = strlen(esc);
+	const char *ctrlz = "<CtrlZ>";
+	gsize ctrlz_size = strlen(ctrlz);
+	gsize i;
+
+	if (!debugf || !len)
+		return;
+
+	for (i = 0; i < len; i++) {
+		char c = str[i];
+
+		if (isprint(c))
+			escaped += 1;
+		else if (c == '\r' || c == '\t' || c == '\n')
+			escaped += 2;
+		else if (c == 26)
+			escaped += ctrlz_size;
+		else if (c == 25)
+			escaped += esc_size;
+		else
+			escaped += 4;
+	}
+
+	escaped_str = g_malloc(escaped + 1);
+	escaped_str[0] = type;
+	escaped_str[1] = ' ';
+	escaped_str[2] = '\0';
+	escaped_str[escaped] = '\0';
+
+	for (escaped = 2, i = 0; i < len; i++) {
+		char c = str[i];
+
+		switch (c) {
+		case '\r':
+			escaped_str[escaped++] = '\\';
+			escaped_str[escaped++] = 'r';
+			break;
+		case '\t':
+			escaped_str[escaped++] = '\\';
+			escaped_str[escaped++] = 't';
+			break;
+		case '\n':
+			escaped_str[escaped++] = '\\';
+			escaped_str[escaped++] = 'n';
+			break;
+		case 26:
+			strncpy(&escaped_str[escaped], ctrlz, ctrlz_size);
+			escaped += ctrlz_size;
+			break;
+		case 25:
+			strncpy(&escaped_str[escaped], esc, esc_size);
+			escaped += esc_size;
+			break;
+		default:
+			if (isprint(c))
+				escaped_str[escaped++] = c;
+			else {
+				escaped_str[escaped++] = '\\';
+				escaped_str[escaped++] = '0' + ((c >> 6) & 07);
+				escaped_str[escaped++] = '0' + ((c >> 3) & 07);
+				escaped_str[escaped++] = '0' + (c & 07);
+			}
+		}
+	}
+
+	debugf(escaped_str, user_data);
+	g_free(escaped_str);
+}
+
+gboolean g_at_util_setup_io(GIOChannel *io)
+{
+	GIOFlags io_flags;
+
+	if (g_io_channel_set_encoding(io, NULL, NULL) !=
+			G_IO_STATUS_NORMAL)
+		return FALSE;
+
+	io_flags = g_io_channel_get_flags(io);
+
+	io_flags |= G_IO_FLAG_NONBLOCK;
+
+	if (g_io_channel_set_flags(io, io_flags, NULL) !=
+			G_IO_STATUS_NORMAL)
+		return FALSE;
+
+	g_io_channel_set_close_on_unref(io, TRUE);
+
+	return TRUE;
+}
+
diff --git a/gatchat/gatutil.h b/gatchat/gatutil.h
new file mode 100644
index 0000000..b17dad4
--- /dev/null
+++ b/gatchat/gatutil.h
@@ -0,0 +1,40 @@
+/*
+ *
+ *  AT chat library with GLib integration
+ *
+ *  Copyright (C) 2008-2010  Intel Corporation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef __GATUTIL_H
+#define __GATUTIL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "gat.h"
+
+void g_at_util_debug_chat(GAtDebugFunc debugf, gboolean in, const char *str,
+						gsize len, gpointer user_data);
+
+gboolean g_at_util_setup_io(GIOChannel *io);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GATUTIL_H */
-- 
1.6.3.3


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/4] Add gatutil.c to share common APIs with GAtServer
  2010-01-15  1:24   ` Zhang, Zhenhua
@ 2010-01-20 20:23     ` Denis Kenzior
  0 siblings, 0 replies; 10+ messages in thread
From: Denis Kenzior @ 2010-01-20 20:23 UTC (permalink / raw)
  To: ofono

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

Hi Zhenhua,

> Hi Denis,
> 
> Denis Kenzior wrote:
> > Hi Zhenhua,
> >
> >> +gboolean g_at_util_set_io(GIOChannel *io)
> >
> > Rename this g_at_util_setup_io
> >
> >> +typedef void (*GAtDisconnectFunc)(gpointer user_data); typedef void
> >> +(*GAtDebugFunc)(const char *str, gpointer user_data);
> >
> > These don't belong here, create a new file called gat.h and put them
> > there.
> >
> > Regards,
> > -Denis
> 
> Thanks for your comments. Updated patch is attached.
> 

Patch has been applied.  Thanks.

Regards,
-Denis

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2010-01-20 20:23 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-01-11 10:53 [PATCH 1/4] Add gatutil.c to share common APIs with GAtServer Zhenhua Zhang
2010-01-11 10:53 ` [PATCH 2/4] Add GAtServer basic parsing support Zhenhua Zhang
2010-01-11 10:53   ` [PATCH 3/4] Add AT command parsing support and interface Zhenhua Zhang
2010-01-11 10:53     ` [PATCH 4/4] Add test-server test application for GAtServer Zhenhua Zhang
2010-01-14 17:24   ` [PATCH 2/4] Add GAtServer basic parsing support Denis Kenzior
2010-01-14 21:53     ` Marcel Holtmann
2010-01-14 20:57       ` Denis Kenzior
2010-01-14 15:49 ` [PATCH 1/4] Add gatutil.c to share common APIs with GAtServer Denis Kenzior
2010-01-15  1:24   ` Zhang, Zhenhua
2010-01-20 20:23     ` Denis Kenzior

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.