From 421b0fa14fefbd13a455c20380fecddda616b41a Mon Sep 17 00:00:00 2001
From: Andrzej Zaborowski <balrog@zabor.org>
Date: Wed, 19 Sep 2007 18:30:36 +0200
Subject: [PATCH] Handle read() and write() return values.

---
 include/libgsmd/libgsmd.h    |    3 +-
 src/gsmd/usock.c             |   38 ++++++++++++++++-----------
 src/libgsmd/lgsm_internals.h |    2 +
 src/libgsmd/libgsmd.c        |   58 ++++++++++++++++++++++++++---------------
 4 files changed, 63 insertions(+), 38 deletions(-)

diff --git a/include/libgsmd/libgsmd.h b/include/libgsmd/libgsmd.h
index fc56890..db15aa9 100644
--- a/include/libgsmd/libgsmd.h
+++ b/include/libgsmd/libgsmd.h
@@ -65,6 +65,7 @@ extern int lgsm_subscriptions(struct lgsm_handle *lh, u_int32_t subscriptions);
 
 extern struct gsmd_msg_hdr *lgsm_gmh_fill(int type, int subtype, int payload_len);
 extern int lgsm_send(struct lgsm_handle *lh, struct gsmd_msg_hdr *gmh);
-extern int lgsm_handle_packet(struct lgsm_handle *lh, char *buf, int len);
+extern int lgsm_handle_packet(struct lgsm_handle *lh,
+		const char *buf, int len);
 
 #endif
diff --git a/src/gsmd/usock.c b/src/gsmd/usock.c
index bac5f0c..2283600 100644
--- a/src/gsmd/usock.c
+++ b/src/gsmd/usock.c
@@ -1569,23 +1569,29 @@ static int gsmd_usock_user_cb(int fd, unsigned int what, void *data)
 		struct gsmd_ucmd *ucmd, *uctmp;
 		llist_for_each_entry_safe(ucmd, uctmp, &gu->finished_ucmds,
 					  list) {
-			int rc;
-
-			rc = write(fd, &ucmd->hdr, sizeof(ucmd->hdr) + ucmd->hdr.len);
-			if (rc < 0) {
-				DEBUGP("write return %d\n", rc);
-				return rc;
-			}
-			if (rc == 0) {
-				DEBUGP("write returns zero!!\n");
-				break;
+			const void *pos = &ucmd->hdr;
+			size_t len = sizeof(ucmd->hdr) + ucmd->hdr.len;
+
+			while (len) {
+				ssize_t rc;
+
+				rc = write(fd, pos, len);
+				if (rc < 0 && errno != EINTR) {
+					DEBUGP("write returned %s\n",
+							strerror(errno));
+					return rc;
+				}
+				if (rc == 0 && pos == &ucmd->hdr) {
+					DEBUGP("write returns zero!!\n");
+					return 0;
+				}
+				if (rc > 0) {
+					len -= rc;
+					pos += rc;
+				}
 			}
-			if (rc != sizeof(ucmd->hdr) + ucmd->hdr.len) {
-				DEBUGP("short write\n");
-				break;
-			}
-
-			DEBUGP("successfully sent cmd %p to user %p, freeing\n", ucmd, gu);
+			DEBUGP("successfully sent cmd %p to user %p, "
+					"freeing\n", ucmd, gu);
 			llist_del(&ucmd->list);
 			talloc_free(ucmd);
 		}
diff --git a/src/libgsmd/lgsm_internals.h b/src/libgsmd/lgsm_internals.h
index c826723..f1b1a23 100644
--- a/src/libgsmd/lgsm_internals.h
+++ b/src/libgsmd/lgsm_internals.h
@@ -8,6 +8,8 @@ struct lgsm_handle {
 	int fd;
 	lgsm_msg_handler *handler[__NUM_GSMD_MSGS];
 	enum lgsm_netreg_state netreg_state;
+	char usock_fifo[1024];
+	int usock_len;
 };
 
 int lgsm_send(struct lgsm_handle *lh, struct gsmd_msg_hdr *gmh);
diff --git a/src/libgsmd/libgsmd.c b/src/libgsmd/libgsmd.c
index 9906ea8..cc804ed 100644
--- a/src/libgsmd/libgsmd.c
+++ b/src/libgsmd/libgsmd.c
@@ -86,34 +86,37 @@ static int lgsm_open_backend(struct lgsm_handle *lh, const char *device)
 }
 
 /* handle a packet that was received on the gsmd socket */
-int lgsm_handle_packet(struct lgsm_handle *lh, char *buf, int len)
+int lgsm_handle_packet(struct lgsm_handle *lh, const char *buf, int len)
 {
 	struct gsmd_msg_hdr *gmh;
 	lgsm_msg_handler *handler; 
 	int rc = 0;
 
-	while (len) {
-		if (len < sizeof(*gmh))
-			return -EINVAL;
-		gmh = (struct gsmd_msg_hdr *) buf;
-
-		if (len - sizeof(*gmh) < gmh->len)
-			return -EINVAL;
-		len -= sizeof(*gmh) + gmh->len;
-		buf += sizeof(*gmh) + gmh->len;
-
-		if (gmh->msg_type >= __NUM_GSMD_MSGS)
-			return -EINVAL;
-
-		handler = lh->handler[gmh->msg_type];
+	if (lh->usock_len + len > sizeof(lh->usock_fifo))
+		return -ENOMEM;
 
-		if (handler)
+	memcpy(lh->usock_fifo + lh->usock_len, buf, len);
+	lh->usock_len += len;
+	gmh = (struct gsmd_msg_hdr *) lh->usock_fifo;
+	while (lh->usock_len >= sizeof(*gmh) &&
+			lh->usock_len >= sizeof(*gmh) + gmh->len) {
+		if (gmh->msg_type < __NUM_GSMD_MSGS &&
+			(handler = lh->handler[gmh->msg_type]))
 			rc |= handler(lh, gmh);
-		else
-			fprintf(stderr, "unable to handle packet type=%u\n",
-					gmh->msg_type);
+		else {
+			fprintf(stderr, "unable to handle packet "
+					"type=%u id=%u\n",
+					gmh->msg_type, gmh->id);
+			rc |= EINVAL;
+		}
+
+		lh->usock_len -= gmh->len + sizeof(*gmh);
+		memmove(lh->usock_fifo,
+				lh->usock_fifo + gmh->len + sizeof(*gmh),
+				lh->usock_len);
 	}
-	return rc;
+
+	return -rc;
 }
 
 int lgsm_register_handler(struct lgsm_handle *lh, int type, lgsm_msg_handler *handler)
@@ -193,8 +196,21 @@ static u_int16_t next_msg_id;
 
 int lgsm_send(struct lgsm_handle *lh, struct gsmd_msg_hdr *gmh)
 {
+	ssize_t rc;
+	size_t len = sizeof(*gmh) + gmh->len;
+	const void *pos = gmh;
+
 	gmh->id = next_msg_id++;
-	return send(lh->fd, (char *) gmh, sizeof(*gmh) + gmh->len, 0);
+	while (len) {
+		rc = send(lh->fd, pos, len, 0);
+		if (rc < 0 && errno != EINTR)
+			return -errno;
+		if (rc > 0) {
+			len -= rc;
+			pos += rc;
+		}
+	}
+	return 0;
 }
 
 struct gsmd_msg_hdr *lgsm_gmh_fill(int type, int subtype, int payload_len)
-- 
1.5.2.1

