changeset 25010:afb1b5f1dc84

Implementation of initial exchange of p2pxfer packets that initiates p2p file transfer. Some connection and stability issues exists, soon to be looked into.
author Sulabh Mahajan <sulabh@soc.pidgin.im>
date Fri, 06 Jun 2008 17:28:37 +0000
parents 185bd4679ad1
children 9b16249bfbe6
files libpurple/protocols/yahoo/yahoo.c libpurple/protocols/yahoo/yahoo.h libpurple/protocols/yahoo/yahoo_packet.h
diffstat 3 files changed, 188 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- 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
 };