changeset 32001:506b77a27a53

This should fix TLV in from and out of the wire.
author Elliott Sales de Andrade <qulogic@pidgin.im>
date Thu, 05 May 2011 21:49:21 +0000
parents 83c5af533082
children dfc2a8e98430
files libpurple/protocols/msn/p2p.c libpurple/protocols/msn/tlv.c libpurple/protocols/msn/tlv.h
diffstat 3 files changed, 76 insertions(+), 69 deletions(-) [+]
line wrap: on
line diff
--- a/libpurple/protocols/msn/p2p.c	Thu May 05 07:21:14 2011 +0000
+++ b/libpurple/protocols/msn/p2p.c	Thu May 05 21:49:21 2011 +0000
@@ -204,41 +204,43 @@
 
 		case MSN_P2P_VERSION_TWO: {
 			MsnP2Pv2Header *header = &info->header.v2;
+			char *header_wire = NULL;
+			char *data_header_wire = NULL;
 
 			if (header->header_tlv != NULL)
-				header->header_len = msn_tlvlist_size(header->header_tlv) + 8;
+				header_wire = msn_tlvlist_write(header->header_tlv, (size_t *)&header->header_len);
 			else
-				header->header_len = 8;
+				header->header_len = 0;
 
 			if (header->data_tlv != NULL)
-				header->data_header_len = msn_tlvlist_size(header->data_tlv) + 8;
+				data_header_wire = msn_tlvlist_write(header->data_tlv, (size_t *)&header->data_header_len);
 			else
-				header->data_header_len = 8;
+				header->data_header_len = 0;
 
-			tmp = wire = g_new(char, header->header_len + header->data_header_len);
+			tmp = wire = g_new(char, 16 + header->header_len + header->data_header_len);
 
-			msn_push8(tmp, header->header_len);
+			msn_push8(tmp, header->header_len + 8);
 			msn_push8(tmp, header->opcode);
-			msn_push16be(tmp, header->data_header_len + header->message_len);
+			msn_push16be(tmp, header->data_header_len + 8 + header->message_len);
 			msn_push32be(tmp, header->base_id);
 
-			if (header->header_tlv != NULL) {
-				msn_tlvlist_write(tmp, header->header_len - 8, header->header_tlv);
-				tmp += header->header_len - 8;
+			if (header_wire != NULL) {
+				memcpy(tmp, header_wire, header->header_len);
+				tmp += header->header_len;
 			}
 
-			msn_push8(tmp, header->data_header_len);
+			msn_push8(tmp, header->data_header_len + 8);
 			msn_push8(tmp, header->data_tf);
 			msn_push16be(tmp, header->package_number);
 			msn_push32be(tmp, header->session_id);
 
-			if (header->data_tlv != NULL) {
-				msn_tlvlist_write(tmp, header->data_header_len - 8, header->data_tlv);
-				tmp += header->data_header_len - 8;
+			if (data_header_wire != NULL) {
+				memcpy(tmp, data_header_wire, header->data_header_len);
+				tmp += header->data_header_len;
 			}
 
 			if (len)
-				*len = header->header_len + header->data_header_len;
+				*len = header->header_len + header->data_header_len + 16;
 
 			break;
 		}
@@ -248,7 +250,6 @@
 	}
 
 	return wire;
-
 }
 
 size_t
--- a/libpurple/protocols/msn/tlv.c	Thu May 05 07:21:14 2011 +0000
+++ b/libpurple/protocols/msn/tlv.c	Thu May 05 21:49:21 2011 +0000
@@ -45,51 +45,50 @@
 	g_free(oldtlv);
 }
 
-static GSList *
-msn_tlv_read(GSList *list, const char *bs, size_t *bs_len)
-{
-	guint8 type, length;
-	msn_tlv_t *tlv;
-
-	type = msn_read8(bs);
-	length = msn_read8(bs);
-	*bs_len -= 2;
-
-	if (length > *bs_len) {
-		msn_tlvlist_free(list);
-		return NULL;
-	}
-
-	tlv = createtlv(type, length, NULL);
-	if (length > 0) {
-		tlv->value = g_memdup(bs, length);
-		if (!tlv->value) {
-			freetlv(tlv);
-			msn_tlvlist_free(list);
-			return NULL;
-		}
-	}
-
-	*bs_len -= length;
-
-	return g_slist_prepend(list, tlv);
-}
-
 GSList *
 msn_tlvlist_read(const char *bs, size_t bs_len)
 {
 	GSList *list = NULL;
 
 	while (bs_len > 0) {
-		list = msn_tlv_read(list, bs, &bs_len);
-		if (list == NULL)
+		guint8 type, length;
+		msn_tlv_t *tlv;
+
+		if (bs_len < 2) {
+			msn_tlvlist_free(list);
+			return NULL;
+		}
+
+		type = msn_pop8(bs);
+		length = msn_pop8(bs);
+		bs_len -= 2;
+
+		if (length > bs_len) {
+			msn_tlvlist_free(list);
 			return NULL;
+		}
+
+		tlv = createtlv(type, length, NULL);
+		if (length > 0) {
+			tlv->value = g_memdup(bs, length);
+			if (!tlv->value) {
+				freetlv(tlv);
+				msn_tlvlist_free(list);
+				return NULL;
+			}
+		}
+
+		bs_len -= length;
+		bs += length;
+
+		list = g_slist_prepend(list, tlv);
 	}
 
 	return g_slist_reverse(list);
 }
 
-GSList *msn_tlvlist_copy(GSList *orig)
+GSList *
+msn_tlvlist_copy(GSList *orig)
 {
 	GSList *new = NULL;
 	msn_tlv_t *tlv;
@@ -302,31 +301,38 @@
 	}
 }
 
-int
-msn_tlvlist_write(char *bs, size_t bs_len, GSList *list)
+char *
+msn_tlvlist_write(GSList *list, size_t *out_len)
 {
-#if 0
-	int goodbuflen;
-	GSList *cur;
-	msn_tlv_t *tlv;
+	char *buf;
+	char *tmp;
+	size_t bytes_left;
+	size_t total_len;
 
-	/* do an initial run to test total length */
-	goodbuflen = msn_tlvlist_size(*list);
+	tmp = buf = g_malloc(256);
+	bytes_left = total_len = 256;
+
+	for (; list; list = g_slist_next(list)) {
+		msn_tlv_t *tlv = (msn_tlv_t *)list->data;
 
-	if (goodbuflen > byte_stream_bytes_left(bs))
-		return 0; /* not enough buffer */
+		if (G_UNLIKELY(tlv->length + 2 > bytes_left)) {
+			buf = g_realloc(buf, total_len + 256);
+			bytes_left += 256;
+			total_len += 256;
+			tmp = buf + (total_len - bytes_left);
+		}
 
-	/* do the real write-out */
-	for (cur = *list; cur; cur = cur->next) {
-		tlv = cur->data;
-		byte_stream_put16(bs, tlv->type);
-		byte_stream_put16(bs, tlv->length);
-		if (tlv->length > 0)
-			byte_stream_putraw(bs, tlv->value, tlv->length);
+		msn_push8(tmp, tlv->type);
+		msn_push8(tmp, tlv->length);
+		memcpy(tmp, tlv->value, tlv->length);
+		tmp += tlv->length;
+
+		bytes_left -= (tlv->length + 2);
 	}
 
-#endif
-	return 0; /* TODO: This is a nonsensical return */
+	*out_len = total_len - bytes_left;
+
+	return buf;
 }
 
 msn_tlv_t *
--- a/libpurple/protocols/msn/tlv.h	Thu May 05 07:21:14 2011 +0000
+++ b/libpurple/protocols/msn/tlv.h	Thu May 05 21:49:21 2011 +0000
@@ -52,7 +52,7 @@
 int msn_tlvlist_count(GSList *list);
 size_t msn_tlvlist_size(GSList *list);
 gboolean msn_tlvlist_equal(GSList *one, GSList *two);
-int msn_tlvlist_write(char *bs, size_t bs_len, GSList *list);
+char *msn_tlvlist_write(GSList *list, size_t *out_len);
 void msn_tlvlist_free(GSList *list);
 
 int msn_tlvlist_add_raw(GSList **list, const guint16 type, const guint16 length, const char *value);