Implementation of initial exchange of p2pxfer packets that initiates p2p file transfer. Some connection soc.2008.yahoo

Fri, 06 Jun 2008 17:28:37 +0000

author
Sulabh Mahajan <sulabh@pidgin.im>
date
Fri, 06 Jun 2008 17:28:37 +0000
branch
soc.2008.yahoo
changeset 23672
2da6a3bd5b6f
parent 23671
12105746a075
child 23673
b4005ecc8248

Implementation of initial exchange of p2pxfer packets that initiates p2p file transfer. Some connection
and stability issues exists, soon to be looked into.

libpurple/protocols/yahoo/yahoo.c file | annotate | diff | comparison | revisions
libpurple/protocols/yahoo/yahoo.h file | annotate | diff | comparison | revisions
libpurple/protocols/yahoo/yahoo_packet.h file | annotate | diff | comparison | revisions
--- a/libpurple/protocols/yahoo/yahoo.c	Thu May 29 07:57:15 2008 +0000
+++ b/libpurple/protocols/yahoo/yahoo.c	Fri Jun 06 17:28:37 2008 +0000
@@ -2213,6 +2213,153 @@
 	g_free(decoded_group);
 }
 
+static void yahoo_write_p2p_packet(gpointer data, gint source)
+{
+	struct yahoo_p2p_data *user_data;
+	struct yahoo_packet *pkt_to_send;
+	size_t pkt_len;
+	guchar *raw_packet;
+	PurpleAccount *account;
+	int val_13_to_send = 0;
+	
+	if(!(user_data = data))
+		return ;
+
+	account = purple_connection_get_account(user_data->gc);
+
+	/*key_13 appears to be a sort of a counter,yahoo server sends with val_13=0, we send packet to host with val_13=1, receive back with val_13=5, we send with val_13=6, receive back with val_13=7, we send with val_13=7, then break the connection. So we keep the value for 7 and increment for not 7*/
+	
+	if(user_data->val_13 != 7)
+		val_13_to_send = user_data->val_13 + 1;
+	else
+		val_13_to_send = user_data->val_13;	/* haven't ever received values other than 0, 5, 6, 7*/
+		
+	/*Build the yahoo packet*/
+	pkt_to_send = yahoo_packet_new(YAHOO_SERVICE_P2PFILEXFER, YAHOO_STATUS_AVAILABLE, user_data->session_id);
+	yahoo_packet_hash(pkt_to_send, "ssisi",
+		4, purple_normalize(account, purple_account_get_username(account)),
+		5, user_data->host_username,
+		241, 0,		/*Protocol identifier*/
+		49, "PEERTOPEER",
+		13, val_13_to_send);
+
+	/*build the packet and send it to the host*/
+	pkt_len = yahoo_packet_build(pkt_to_send, 0, 0, 0, &raw_packet);
+	if(write(source, raw_packet, pkt_len) != pkt_len)
+		purple_debug_warning("yahoo","p2p: couldn't write to the source\n");
+	yahoo_packet_free(pkt_to_send);
+	g_free(raw_packet);
+
+	/*if written packet has val_13 equal to 7, we dont send any other packet but dont close the connection, connection seems to exist long after the p2p processes are over*/
+	if(val_13_to_send == 7)	{
+		/*cant figure out when to close the connection, not closing connection right now, misbehaves if host logs out, to be fixed soon*/
+		/*free user_data, do we need it now*/
+		g_free(user_data->host_ip);
+		g_free(user_data->host_username);
+		g_free(user_data);
+	}
+}
+
+static void yahoo_p2p_packet_process(gpointer data, gint source, struct yahoo_packet *pkt)
+{
+	struct yahoo_p2p_data *user_data;
+	char *who = NULL;
+	GSList *l = pkt->hash;
+
+	if(!(user_data = data))
+		return ;
+
+	/* lets see whats in the packet */
+	while (l) {
+		struct yahoo_pair *pair = l->data;
+
+		switch (pair->key) {
+		case 4:
+			who = pair->value;
+			if(strncmp(who, user_data->host_username, strlen(user_data->host_username)) != 0) {
+				/* from whom are we receiving the packets ?? */
+				purple_debug_warning("yahoo","p2p: received data from wrong user");
+				return;
+			}
+			break;
+		case 13:
+			user_data->val_13 = strtol(pair->value, NULL, 10);	/*Value should be 5-7*/
+			break;
+		/*case 5, 49 look laters, no use right now*/
+		}
+		l = l->next;
+	}
+	
+	yahoo_write_p2p_packet(data, source);	/*udpated the value of key 13, now write data*/
+}
+
+static void yahoo_read_p2p_pkt_cb(gpointer data, gint source, PurpleInputCondition cond)
+{
+	guchar buf[1024];	/*is it safe to assume a fixed array length of 1024 ??*/
+	int len;
+	int pos = 0;
+	int pktlen;
+	struct yahoo_packet *pkt;
+	guchar *start = NULL;
+
+	if((len = read(source, buf, sizeof(buf))) <= 0 )
+		purple_debug_warning("yahoo","p2p: Error in connection to p2p host\n");
+
+	if(len < YAHOO_PACKET_HDRLEN)
+		return;
+	if(strncmp((char *)buf, "YMSG", MIN(4, len)) != 0) {
+		/* Not a YMSG packet */
+		purple_debug_warning("yahoo","p2p: Got something other than YMSG packet\n");
+
+		start = memchr(buf + 1, 'Y', len - 1);
+		if(start) {
+			g_memmove(buf, start, len - (start - buf));
+			len -= start - buf;
+		} else {
+			g_free(buf);
+			return;
+		}
+	}
+
+	pos += 4;	/* YMSG */
+	pos += 2;
+	pos += 2;
+
+	pktlen = yahoo_get16(buf + pos); pos += 2;
+	purple_debug(PURPLE_DEBUG_MISC, "yahoo", "p2p: %d bytes to read\n", len);
+
+	pkt = yahoo_packet_new(0, 0, 0);
+
+	pkt->service = yahoo_get16(buf + pos); pos += 2;
+	if(pkt->service != YAHOO_SERVICE_P2PFILEXFER)	{
+		/* Shouldn't we be getting p2p filexfer packets only*/
+		/* Should we break connection if this happens ??*/
+		return;
+	}
+	purple_debug_info("yahoo", "p2p: received packet recognized as a p2p, Status: %d\n", pkt->status);
+
+	pkt->status = yahoo_get32(buf + pos); pos += 4;
+	pkt->id = yahoo_get32(buf + pos); pos += 4;
+	
+	yahoo_packet_read(pkt, buf + pos, pktlen);
+
+	yahoo_p2p_packet_process(data, source, pkt);
+	yahoo_packet_free(pkt);
+}
+
+static void yahoo_p2p_init_cb(gpointer data, gint source, const gchar *error_message)
+{
+	if(error_message != NULL)	{
+		purple_debug_warning("yahoo","p2p: %s\n",error_message);
+		return;
+	}
+
+	/*Add an Input Read event to the file descriptor*/
+	purple_input_add(source, PURPLE_INPUT_READ, yahoo_read_p2p_pkt_cb, data);
+
+	yahoo_write_p2p_packet(data, source);	/*create and send packet*/
+}
+
 static void yahoo_process_p2p(PurpleConnection *gc, struct yahoo_packet *pkt)
 {
 	GSList *l = pkt->hash;
@@ -2220,6 +2367,9 @@
 	char *base64 = NULL;
 	guchar *decoded;
 	gsize len;
+	gint val_13 = 0;
+	PurpleAccount *account;
+	struct yahoo_p2p_data *user_data = g_new0(struct yahoo_p2p_data, 1);
 
 	while (l) {
 		struct yahoo_pair *pair = l->data;
@@ -2229,7 +2379,9 @@
 			/* our identity */
 			break;
 		case 4:
-			who = pair->value;
+			who = (char *)g_malloc(strlen(pair->value));
+			strcpy(who, pair->value);
+			user_data->host_username = who;
 			break;
 		case 1:
 			/* who again, the master identity this time? */
@@ -2239,11 +2391,16 @@
 			/* so, this is an ip address. in base64. decoded it's in ascii.
 			   after strtol, it's in reversed byte order. Who thought this up?*/
 			break;
+		case 13:
+			val_13 = strtol(pair->value, NULL, 10);		/*Value always 0*/
+			user_data->val_13 = val_13;
+			break;
+
 		/*
 			TODO: figure these out
 			yahoo: Key: 61          Value: 0
 			yahoo: Key: 2   Value:
-			yahoo: Key: 13          Value: 0
+			yahoo: Key: 13          Value: 0	packet count ??
 			yahoo: Key: 49          Value: PEERTOPEER
 			yahoo: Key: 140         Value: 1
 			yahoo: Key: 11          Value: -1786225828
@@ -2258,6 +2415,7 @@
 		guint32 ip;
 		char *tmp2;
 		YahooFriend *f;
+		char *host_ip;
 
 		decoded = purple_base64_decode(base64, &len);
 		if (len) {
@@ -2270,12 +2428,24 @@
 		ip = strtol(tmp2, NULL, 10);
 		g_free(tmp2);
 		g_free(decoded);
-		tmp2 = g_strdup_printf("%u.%u.%u.%u", ip & 0xff, (ip >> 8) & 0xff, (ip >> 16) & 0xff,
+		host_ip = g_strdup_printf("%u.%u.%u.%u", ip & 0xff, (ip >> 8) & 0xff, (ip >> 16) & 0xff,
 		                       (ip >> 24) & 0xff);
 		f = yahoo_friend_find(gc, who);
 		if (f)
-			yahoo_friend_set_ip(f, tmp2);
-		g_free(tmp2);
+			yahoo_friend_set_ip(f, host_ip);
+		purple_debug_info("yahoo", "IP : %s\n", host_ip);
+
+		account = purple_connection_get_account(gc);
+
+		user_data->host_ip = host_ip;
+		user_data->session_id = pkt->id;
+		user_data->gc = gc;
+
+		/*connect to host*/
+		/*use an handle ??*/		
+		if((purple_proxy_connect(NULL, account, host_ip, YAHOO_PAGER_PORT_P2P, yahoo_p2p_init_cb, user_data))==NULL)
+			purple_debug_info("yahoo","p2p: Connection to %s failed", host_ip);
+
 	}
 }
 
--- a/libpurple/protocols/yahoo/yahoo.h	Thu May 29 07:57:15 2008 +0000
+++ b/libpurple/protocols/yahoo/yahoo.h	Fri Jun 06 17:28:37 2008 +0000
@@ -30,6 +30,7 @@
 
 #define YAHOO_PAGER_HOST "scs.msg.yahoo.com"
 #define YAHOO_PAGER_PORT 5050
+#define YAHOO_PAGER_PORT_P2P 5101
 #define YAHOO_PROFILE_URL "http://profiles.yahoo.com/"
 #define YAHOO_MAIL_URL "https://login.yahoo.com/config/login?.src=ym"
 #define YAHOO_XFER_HOST "filetransfer.msg.yahoo.com"
@@ -113,6 +114,14 @@
 	guint watcher;
 };
 
+struct yahoo_p2p_data	{
+	PurpleConnection *gc;
+	char *host_ip;		/*also we use it as a handle*/
+	int session_id;
+	char *host_username;
+	int val_13;
+};
+
 struct _YchtConn;
 
 struct yahoo_data {
--- a/libpurple/protocols/yahoo/yahoo_packet.h	Thu May 29 07:57:15 2008 +0000
+++ b/libpurple/protocols/yahoo/yahoo_packet.h	Fri Jun 06 17:28:37 2008 +0000
@@ -100,12 +100,13 @@
 	YAHOO_SERVICE_AUDIBLE = 0xd0,
 	/*YAHOO_SERVICE_CHAT_SESSION = 0xd4,?? Reports start of chat session, gets an id from server*/
 	YAHOO_SERVICE_AUTH_REQ_15 = 0xd6,
+	YAHOO_SERVICE_FILETRANS_15 = 0xdc,
+	YAHOO_SERVICE_FILETRANS_INFO_15 = 0xdd,
+	YAHOO_SERVICE_FILETRANS_ACC_15 = 0xde,
+	/*photo sharing services ?? - 0xd2, 0xd7, 0xd8, 0xda*/
 	YAHOO_SERVICE_CHGRP_15 = 0xe7,
 	YAHOO_SERVICE_STATUS_15 = 0xf0,
 	YAHOO_SERVICE_LIST_15 = 0xf1,
-	YAHOO_SERVICE_FILETRANS_15 = 0xdc,
-	YAHOO_SERVICE_FILETRANS_INFO_15 = 0xdd,
-	YAHOO_SERVICE_FILETRANS_ACC_15 = 0xde,
 	YAHOO_SERVICE_WEBLOGIN = 0x0226,
 	YAHOO_SERVICE_SMS_MSG = 0x02ea
 };

mercurial