comparison libpurple/protocols/yahoo/yahoo.c @ 25568: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 5ec08738906c
children 9b16249bfbe6
comparison
equal deleted inserted replaced
25567:185bd4679ad1 25568:afb1b5f1dc84
2211 purple_notify_error(gc, NULL, _("Could not add buddy to server list"), buf); 2211 purple_notify_error(gc, NULL, _("Could not add buddy to server list"), buf);
2212 g_free(buf); 2212 g_free(buf);
2213 g_free(decoded_group); 2213 g_free(decoded_group);
2214 } 2214 }
2215 2215
2216 static void yahoo_write_p2p_packet(gpointer data, gint source)
2217 {
2218 struct yahoo_p2p_data *user_data;
2219 struct yahoo_packet *pkt_to_send;
2220 size_t pkt_len;
2221 guchar *raw_packet;
2222 PurpleAccount *account;
2223 int val_13_to_send = 0;
2224
2225 if(!(user_data = data))
2226 return ;
2227
2228 account = purple_connection_get_account(user_data->gc);
2229
2230 /*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*/
2231
2232 if(user_data->val_13 != 7)
2233 val_13_to_send = user_data->val_13 + 1;
2234 else
2235 val_13_to_send = user_data->val_13; /* haven't ever received values other than 0, 5, 6, 7*/
2236
2237 /*Build the yahoo packet*/
2238 pkt_to_send = yahoo_packet_new(YAHOO_SERVICE_P2PFILEXFER, YAHOO_STATUS_AVAILABLE, user_data->session_id);
2239 yahoo_packet_hash(pkt_to_send, "ssisi",
2240 4, purple_normalize(account, purple_account_get_username(account)),
2241 5, user_data->host_username,
2242 241, 0, /*Protocol identifier*/
2243 49, "PEERTOPEER",
2244 13, val_13_to_send);
2245
2246 /*build the packet and send it to the host*/
2247 pkt_len = yahoo_packet_build(pkt_to_send, 0, 0, 0, &raw_packet);
2248 if(write(source, raw_packet, pkt_len) != pkt_len)
2249 purple_debug_warning("yahoo","p2p: couldn't write to the source\n");
2250 yahoo_packet_free(pkt_to_send);
2251 g_free(raw_packet);
2252
2253 /*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*/
2254 if(val_13_to_send == 7) {
2255 /*cant figure out when to close the connection, not closing connection right now, misbehaves if host logs out, to be fixed soon*/
2256 /*free user_data, do we need it now*/
2257 g_free(user_data->host_ip);
2258 g_free(user_data->host_username);
2259 g_free(user_data);
2260 }
2261 }
2262
2263 static void yahoo_p2p_packet_process(gpointer data, gint source, struct yahoo_packet *pkt)
2264 {
2265 struct yahoo_p2p_data *user_data;
2266 char *who = NULL;
2267 GSList *l = pkt->hash;
2268
2269 if(!(user_data = data))
2270 return ;
2271
2272 /* lets see whats in the packet */
2273 while (l) {
2274 struct yahoo_pair *pair = l->data;
2275
2276 switch (pair->key) {
2277 case 4:
2278 who = pair->value;
2279 if(strncmp(who, user_data->host_username, strlen(user_data->host_username)) != 0) {
2280 /* from whom are we receiving the packets ?? */
2281 purple_debug_warning("yahoo","p2p: received data from wrong user");
2282 return;
2283 }
2284 break;
2285 case 13:
2286 user_data->val_13 = strtol(pair->value, NULL, 10); /*Value should be 5-7*/
2287 break;
2288 /*case 5, 49 look laters, no use right now*/
2289 }
2290 l = l->next;
2291 }
2292
2293 yahoo_write_p2p_packet(data, source); /*udpated the value of key 13, now write data*/
2294 }
2295
2296 static void yahoo_read_p2p_pkt_cb(gpointer data, gint source, PurpleInputCondition cond)
2297 {
2298 guchar buf[1024]; /*is it safe to assume a fixed array length of 1024 ??*/
2299 int len;
2300 int pos = 0;
2301 int pktlen;
2302 struct yahoo_packet *pkt;
2303 guchar *start = NULL;
2304
2305 if((len = read(source, buf, sizeof(buf))) <= 0 )
2306 purple_debug_warning("yahoo","p2p: Error in connection to p2p host\n");
2307
2308 if(len < YAHOO_PACKET_HDRLEN)
2309 return;
2310 if(strncmp((char *)buf, "YMSG", MIN(4, len)) != 0) {
2311 /* Not a YMSG packet */
2312 purple_debug_warning("yahoo","p2p: Got something other than YMSG packet\n");
2313
2314 start = memchr(buf + 1, 'Y', len - 1);
2315 if(start) {
2316 g_memmove(buf, start, len - (start - buf));
2317 len -= start - buf;
2318 } else {
2319 g_free(buf);
2320 return;
2321 }
2322 }
2323
2324 pos += 4; /* YMSG */
2325 pos += 2;
2326 pos += 2;
2327
2328 pktlen = yahoo_get16(buf + pos); pos += 2;
2329 purple_debug(PURPLE_DEBUG_MISC, "yahoo", "p2p: %d bytes to read\n", len);
2330
2331 pkt = yahoo_packet_new(0, 0, 0);
2332
2333 pkt->service = yahoo_get16(buf + pos); pos += 2;
2334 if(pkt->service != YAHOO_SERVICE_P2PFILEXFER) {
2335 /* Shouldn't we be getting p2p filexfer packets only*/
2336 /* Should we break connection if this happens ??*/
2337 return;
2338 }
2339 purple_debug_info("yahoo", "p2p: received packet recognized as a p2p, Status: %d\n", pkt->status);
2340
2341 pkt->status = yahoo_get32(buf + pos); pos += 4;
2342 pkt->id = yahoo_get32(buf + pos); pos += 4;
2343
2344 yahoo_packet_read(pkt, buf + pos, pktlen);
2345
2346 yahoo_p2p_packet_process(data, source, pkt);
2347 yahoo_packet_free(pkt);
2348 }
2349
2350 static void yahoo_p2p_init_cb(gpointer data, gint source, const gchar *error_message)
2351 {
2352 if(error_message != NULL) {
2353 purple_debug_warning("yahoo","p2p: %s\n",error_message);
2354 return;
2355 }
2356
2357 /*Add an Input Read event to the file descriptor*/
2358 purple_input_add(source, PURPLE_INPUT_READ, yahoo_read_p2p_pkt_cb, data);
2359
2360 yahoo_write_p2p_packet(data, source); /*create and send packet*/
2361 }
2362
2216 static void yahoo_process_p2p(PurpleConnection *gc, struct yahoo_packet *pkt) 2363 static void yahoo_process_p2p(PurpleConnection *gc, struct yahoo_packet *pkt)
2217 { 2364 {
2218 GSList *l = pkt->hash; 2365 GSList *l = pkt->hash;
2219 char *who = NULL; 2366 char *who = NULL;
2220 char *base64 = NULL; 2367 char *base64 = NULL;
2221 guchar *decoded; 2368 guchar *decoded;
2222 gsize len; 2369 gsize len;
2370 gint val_13 = 0;
2371 PurpleAccount *account;
2372 struct yahoo_p2p_data *user_data = g_new0(struct yahoo_p2p_data, 1);
2223 2373
2224 while (l) { 2374 while (l) {
2225 struct yahoo_pair *pair = l->data; 2375 struct yahoo_pair *pair = l->data;
2226 2376
2227 switch (pair->key) { 2377 switch (pair->key) {
2228 case 5: 2378 case 5:
2229 /* our identity */ 2379 /* our identity */
2230 break; 2380 break;
2231 case 4: 2381 case 4:
2232 who = pair->value; 2382 who = (char *)g_malloc(strlen(pair->value));
2383 strcpy(who, pair->value);
2384 user_data->host_username = who;
2233 break; 2385 break;
2234 case 1: 2386 case 1:
2235 /* who again, the master identity this time? */ 2387 /* who again, the master identity this time? */
2236 break; 2388 break;
2237 case 12: 2389 case 12:
2238 base64 = pair->value; 2390 base64 = pair->value;
2239 /* so, this is an ip address. in base64. decoded it's in ascii. 2391 /* so, this is an ip address. in base64. decoded it's in ascii.
2240 after strtol, it's in reversed byte order. Who thought this up?*/ 2392 after strtol, it's in reversed byte order. Who thought this up?*/
2241 break; 2393 break;
2394 case 13:
2395 val_13 = strtol(pair->value, NULL, 10); /*Value always 0*/
2396 user_data->val_13 = val_13;
2397 break;
2398
2242 /* 2399 /*
2243 TODO: figure these out 2400 TODO: figure these out
2244 yahoo: Key: 61 Value: 0 2401 yahoo: Key: 61 Value: 0
2245 yahoo: Key: 2 Value: 2402 yahoo: Key: 2 Value:
2246 yahoo: Key: 13 Value: 0 2403 yahoo: Key: 13 Value: 0 packet count ??
2247 yahoo: Key: 49 Value: PEERTOPEER 2404 yahoo: Key: 49 Value: PEERTOPEER
2248 yahoo: Key: 140 Value: 1 2405 yahoo: Key: 140 Value: 1
2249 yahoo: Key: 11 Value: -1786225828 2406 yahoo: Key: 11 Value: -1786225828
2250 */ 2407 */
2251 2408
2256 2413
2257 if (base64) { 2414 if (base64) {
2258 guint32 ip; 2415 guint32 ip;
2259 char *tmp2; 2416 char *tmp2;
2260 YahooFriend *f; 2417 YahooFriend *f;
2418 char *host_ip;
2261 2419
2262 decoded = purple_base64_decode(base64, &len); 2420 decoded = purple_base64_decode(base64, &len);
2263 if (len) { 2421 if (len) {
2264 char *tmp = purple_str_binary_to_ascii(decoded, len); 2422 char *tmp = purple_str_binary_to_ascii(decoded, len);
2265 purple_debug_info("yahoo", "Got P2P service packet (from server): who = %s, ip = %s\n", who, tmp); 2423 purple_debug_info("yahoo", "Got P2P service packet (from server): who = %s, ip = %s\n", who, tmp);
2268 2426
2269 tmp2 = g_strndup((const gchar *)decoded, len); /* so its \0 terminated...*/ 2427 tmp2 = g_strndup((const gchar *)decoded, len); /* so its \0 terminated...*/
2270 ip = strtol(tmp2, NULL, 10); 2428 ip = strtol(tmp2, NULL, 10);
2271 g_free(tmp2); 2429 g_free(tmp2);
2272 g_free(decoded); 2430 g_free(decoded);
2273 tmp2 = g_strdup_printf("%u.%u.%u.%u", ip & 0xff, (ip >> 8) & 0xff, (ip >> 16) & 0xff, 2431 host_ip = g_strdup_printf("%u.%u.%u.%u", ip & 0xff, (ip >> 8) & 0xff, (ip >> 16) & 0xff,
2274 (ip >> 24) & 0xff); 2432 (ip >> 24) & 0xff);
2275 f = yahoo_friend_find(gc, who); 2433 f = yahoo_friend_find(gc, who);
2276 if (f) 2434 if (f)
2277 yahoo_friend_set_ip(f, tmp2); 2435 yahoo_friend_set_ip(f, host_ip);
2278 g_free(tmp2); 2436 purple_debug_info("yahoo", "IP : %s\n", host_ip);
2437
2438 account = purple_connection_get_account(gc);
2439
2440 user_data->host_ip = host_ip;
2441 user_data->session_id = pkt->id;
2442 user_data->gc = gc;
2443
2444 /*connect to host*/
2445 /*use an handle ??*/
2446 if((purple_proxy_connect(NULL, account, host_ip, YAHOO_PAGER_PORT_P2P, yahoo_p2p_init_cb, user_data))==NULL)
2447 purple_debug_info("yahoo","p2p: Connection to %s failed", host_ip);
2448
2279 } 2449 }
2280 } 2450 }
2281 2451
2282 static void yahoo_process_audible(PurpleConnection *gc, struct yahoo_packet *pkt) 2452 static void yahoo_process_audible(PurpleConnection *gc, struct yahoo_packet *pkt)
2283 { 2453 {