#include "cygwin.h" #include "kademlia.h" #include "misc.h" #include "sTag.h" #include "protocol.h" #include "opcodes.h" #include "donkey.h" #include "sGui.h" #include "db_macro.h" #include "cZone.h" #include "cSearchManager.h" #define ctol32(x) (x) #define ctol16(x) (x) extern time_t currentTime; extern bool running; extern int protocol_logLevel; uint8_t this_hash[HASH_LEN]; class cZone overnet; class cSearchManager manager; class cKademlia *kademlia = NULL; const char *op2str(unsigned op) {{{ switch(op) { case 0x0A : return "CONNECT "; case 0x0B : return "CONNECT_res"; case 0x0C : return "PUBLIZE "; case 0x0D : return "PUBLIZE_ack"; case 0x0E : return "NEXT "; case 0x0F : return "NEXT_res "; case 0x10 : return "QUERY "; case 0x11 : return "QUERY_res "; case 0x12 : return "QUERY_end "; case 0x13 : return "PUBLISH "; case 0x14 : return "PUBLISH_res"; case 0x15 : return "ident_res "; case 0x16 : return "ident_ack "; case 0x18 : return "FIRE "; case 0x19 : return "FIRE_ack "; case 0x1A : return "FIRE_nack "; case 0x1B : return "CHECK "; case 0x1C : return "CHECK_ack "; case 0x1D : return "CHECK_end "; case 0x1E : return "Identify "; default : break; } return " (unknown) "; }}} unsigned XOR_distance (const uint8_t *a, const uint8_t *b) {{{ uint8_t XOR[KAD_HASH_LEN]; for (unsigned j=0; j < KAD_HASH_LEN; j++) XOR[j] = a[j] ^ b[j]; unsigned idx = 0; uint8_t check = 0x80; unsigned cnt = 0; for(unsigned i = 0; i < KAD_HASH_LEN*8; i++) { if (idx >= KAD_HASH_LEN) return 128; if (check & XOR[idx]) cnt++; check >>= 1; if (check == 0) { check = 0x80; idx ++; } } return cnt; }}} cKademlia:: cKademlia (len2 my_port):cSocket(my_port,SOCK_DGRAM) {{{ Type = tKademlia; boot_file = NULL; boot_done = false; next_ip_query = 0; bzero(last_publish, KAD_HASH_LEN); status = 0; // NEED_BOOTING for (unsigned i = 0; i < KAD_HASH_LEN ; i++) this_hash[i] = rand(); bzero (seek_hash, KAD_HASH_LEN); printf ("my_hash %32s\n", hash_bin2hex(this_hash)); best_publize = 128; last_query = 0; if (mask != 0) doWork(mask); kademlia = this; }}} cKademlia::~cKademlia () {{{ kademlia = NULL; }}} void cKademlia::load_Boot (const char *boot) {{{ if (boot_done) return; size_t cnt = overnet.getNumContacts(); if (cnt > 0) { printf("Read %u from contact.dat\n", cnt); boot_done = true; return; } if (boot_file == NULL) {{{ printf("boot = %s\n", boot); boot_file = fopen (boot, "r"); if (boot_file == NULL) { printf ("errno %i => \n", errno); printf( "cKademlia::load_Boot: failed to open %s\n", boot ); boot_done = true; return; } }}} char BUF[512]; cnt = 10; while (NULL != fgets(BUF, 512, boot_file) && running) {{{ struct in_addr p_ip; unsigned p_port; char Hash[33], *hash=Hash; char IPS[512], *ips=IPS; ips = IPS; if ( ( sscanf(BUF, "ed2k://|kademlia|%32s|%s %u|/\n", hash, ips, &p_port) ) != 3 ) continue; p_ip.s_addr = IP4Name(IPS); uint8_t p_hash[KAD_HASH_LEN]; memcpy (p_hash, hash_hex2bin(Hash), KAD_HASH_LEN); overnet.add(p_hash, p_ip.s_addr, p_port, 0); cnt --; if (cnt <= 0) return; // printf ("bcp://%s|%s|%u|\n", hash_bin2hex(p_hash), inet_ntoa(p_ip), p_port); }}} boot_done = true; fclose(boot_file); boot_file = NULL; }}} void cKademlia::Init_Search (void) {{{ }}} bool cKademlia::Search (const uint8_t *hash) {{{ log (1, "OVERNET search %s\n", hash_bin2hex(hash)); manager.findFile(hash); if (status == 8) memcpy(seek_hash, hash, KAD_HASH_LEN); return true; }}} // send {{{ bool cKademlia::send_Connect (void) {{{ // (0x0A) request boot list if (!IP_is_OK(peer_ip) || peer_port == 0) return false; logSend('>', OVERNET_CONNECT, 24 ); unsigned char BUF[24]; unsigned char *buf = BUF; size_t len = 24; ADD_U1 (&buf, &len, OP_EDONKEYHEADER); ADD_U1 (&buf, &len, OVERNET_CONNECT); ADD_HASH(&buf, &len, seek_hash); ADD_U4 (&buf, &len, this_ip.s_addr); ADD_U2 (&buf, &len, this_port); Write(BUF, 24); return true; }}} bool cKademlia::send_Connect_reply (void) {{{ // (0x0B) return list of other clients cPeerMap map; size_t RET = overnet.getClosestTo (this_hash, OVERNET_BUCKET, &map); RET = map.size(); if(RET == 0) return false; size_t len, LEN = len = 4 + 23 * RET; unsigned char *buf, *BUF = buf = reinterpret_cast(alloca(LEN)); logSend('>', OVERNET_CONNECT_RES, LEN); ADD_U1 (&buf, &len, OP_EDONKEYHEADER); ADD_U1 (&buf, &len, OVERNET_CONNECT_RES); ADD_U2 (&buf, &len, RET); cPeerMap::iterator it; for (size_t i=0; isecond; map.erase(it); ADD_HASH (&buf, &len, c->get_Hash()->hash); ADD_U4 (&buf, &len, c->ip); ADD_U2 (&buf, &len, c->udp); ADD_U1 (&buf, &len, c->type); if (len == 0) break; } ASSERT(len == 0); Write(BUF, LEN); return true; }}} bool cKademlia::send_Publicize (void) {{{ // (0x0C) publize my client logSend('>', OVERNET_HELLO_REQUEST, 25 ); unsigned char BUF[25]; unsigned char *buf = BUF; size_t len, LEN = len = 25; ADD_U1 (&buf, &len, OP_EDONKEYHEADER); ADD_U1 (&buf, &len, OVERNET_HELLO_REQUEST); ADD_HASH(&buf, &len, this_hash); ADD_U4 (&buf, &len, this_ip.s_addr); ADD_U2 (&buf, &len, this_port); ADD_U1 (&buf, &len, 0); ASSERT(len == 0); Write(BUF, LEN); return true; }}} bool cKademlia::send_Publicize_ack (void) {{{ // (0x0D) ack the publize of my client logSend('>', OVERNET_HELLO_ACK, 2 ); unsigned char BUF[2]; unsigned char *buf = BUF; size_t len = 2; ADD_U1 (&buf, &len, OP_EDONKEYHEADER); ADD_U1 (&buf, &len, OVERNET_HELLO_ACK); Write (BUF, 2); return true; }}} bool cKademlia::send_Search (uint8_t for_type, uint8_t *for_hash) {{{ // (0x0E) search after an HASH (user/file) logSend('>', OVERNET_REQUEST, 19 ); unsigned char BUF[19]; unsigned char *buf = BUF; size_t len, LEN = len = 19; ADD_U1 (&buf, &len, OP_EDONKEYHEADER); ADD_U1 (&buf, &len, OVERNET_REQUEST); ADD_U1 (&buf, &len, for_type); ADD_HASH(&buf, &len, for_hash); ASSERT(len == 0); Write (BUF, LEN);; return true; }}} bool cKademlia::send_Search_next (unsigned cnt, const uint8_t *p_hash) {{{ // (0x0F) List of peers to try next time cPeerMap map; size_t RET = overnet.getClosestTo (p_hash, cnt, &map); RET = map.size(); if (RET == 0) return false; size_t len, LEN = len = 20 + 23 * RET; unsigned char *buf, *BUF = buf = reinterpret_cast(alloca(LEN)); logSend('>', OVERNET_REQUEST_RES, LEN); ADD_U1 (&buf, &len, OP_EDONKEYHEADER); ADD_U1 (&buf, &len, OVERNET_REQUEST_RES); ADD_HASH (&buf, &len, p_hash); ADD_U2 (&buf, &len, RET); cPeerMap::iterator it; for (size_t i=0; isecond; map.erase(it); ADD_HASH (&buf, &len, c->get_Hash()->hash); ADD_U4 (&buf, &len, c->ip); ADD_U2 (&buf, &len, c->udp); ADD_U1 (&buf, &len, c->type); if (len == 0) break; } ASSERT(len == 0); Write( BUF, LEN); return true; }}} /* now in cSearch {{{ bool cKademlia::send_Search_info (void ) {{{ // (0x10) req_result logSend('>', OVERNET_SEARCH_REQUEST, 23); char BUF[23]; char *buf = BUF; size_t len = 23; ADD_U1 (&buf, &len, OP_EDONKEYHEADER); ADD_U1 (&buf, &len, OVERNET_SEARCH_REQUEST); ADD_HASH (&buf, &len, seek_hash); ADD_U1 (&buf, &len, 0); ADD_U2 (&buf, &len, 0); ADD_U2 (&buf, &len, 100); ASSERT(len == 0); Write (BUF, 23); return true; }}} }}} */ bool cKademlia::send_Search_result (uint8_t *p_hash, unsigned min, unsigned max) {{{ // (0x11) int err = 0; logSend('>', OVERNET_SEARCH_RESULT, 0); DBC *cur; DB_cursor2 (dat_hash, cur); INIT_DBT(key, p_hash, HASH_LEN); DBT val; bzero(&val, sizeof(val)); log (1, "SEEK %s - %u - %u\n", hash_bin2hex(p_hash), min, max); if (0 != (err = cur->c_get (cur, &key, &val, DB_SET))) {{{ cursor_count = 0; if (err != DB_NOTFOUND) DB_error(); return false; }}} unsigned cnt = 0; do { struct eFiles *file = reinterpret_cast(val.data); if (file->info_len == 0) continue; struct eSources *source = Source_ip(file->ip); if (source == NULL) continue; if (0 == (source->version & 0x02000000)) continue; size_t len, LEN = len = 34 + file->info_len; unsigned char *buf , *BUF = buf = reinterpret_cast(alloca (LEN)); ADD_U1 (&buf, &len, OP_EDONKEYHEADER); ADD_U1 (&buf, &len, OVERNET_SEARCH_RESULT); ADD_HASH (&buf, &len, p_hash); ADD_HASH (&buf, &len, reinterpret_cast(file->hash)); memcpy ( buf, file->info , len); Write (BUF, LEN); cnt ++; if (cnt == max) break; } while (0 == (err = cur->c_get (cur, &key, &val, DB_NEXT_DUP))); DB_c_close(cur); return true; }}} bool cKademlia::send_search_end (uint8_t *p_hash ) {{{ // (0x12) logSend('>', OVERNET_SEARCH_END, 22); unsigned char BUF[22]; unsigned char *buf = BUF; size_t len = 22; ADD_U1 (&buf, &len, OP_EDONKEYHEADER); ADD_U1 (&buf, &len, OVERNET_SEARCH_END); ADD_HASH (&buf, &len, p_hash); ADD_U4 (&buf, &len, 0); Write(BUF, 22); printf("Request result %15s:%5u\n", inet_ntoa(peer_ip), peer_port); return true; }}} bool cKademlia::send_Publish (const uint8_t *key, size_t size, const char* name) {{{ // (0x13) Publish an meta description ASSERT(name != NULL); ASSERT(key != NULL); size_t len, LEN = len = 52+strlen(name); unsigned char *buf, *BUF = buf = reinterpret_cast(alloca(LEN)); logSend('>', OVERNET_PUBLISH_REQ, len); ADD_U1 (&buf, &len, OP_EDONKEYHEADER); ADD_U1 (&buf, &len, OVERNET_PUBLISH_REQ); ADD_HASH (&buf, &len, key); ADD_HASH (&buf, &len, this_hash); ADD_U4 (&buf, &len, 2); add_strTag (&buf, &len, FT_FILENAME, name); add_intTag (&buf, &len, FT_FILESIZE, size); ASSERT(len == 0); Write(BUF, LEN); return true; }}} bool cKademlia::send_Publish_ack (const uint8_t * p_hash ) {{{ // (0x14) acknowlegde the send_Publish size_t len, LEN = len = 18; unsigned char BUF[18], *buf = BUF; ADD_U1 (&buf, &len, OP_EDONKEYHEADER); ADD_U1 (&buf, &len, OVERNET_PUBLISH_ACK); ADD_HASH (&buf, &len, p_hash); ASSERT(len == 0); Write(BUF, LEN); logSend('>', OVERNET_PUBLISH_ACK, 0); return true; }}} bool cKademlia::send_Identify_reply (void) {{{ // (0x15) logSend('>', OVERNET_IDENTIFY_RES, 25); size_t len = 25; unsigned char BUF[25]; unsigned char *buf = BUF; ADD_U1 (&buf, &len, OP_EDONKEYHEADER); ADD_U1 (&buf, &len, OVERNET_IDENTIFY_RES); ADD_HASH(&buf, &len, this_hash); ADD_U4 (&buf, &len, this_ip.s_addr); ADD_U2 (&buf, &len, this_port); Write(BUF, 25); return true; }}} bool cKademlia::send_Identify_ack (void) {{{ // (0x16) logSend('>',OVERNET_IDENTIFY_ACK, 4); size_t len = 4; unsigned char BUF[4]; unsigned char *buf = BUF; ADD_U1 (&buf, &len, OP_EDONKEYHEADER); ADD_U1 (&buf, &len, OVERNET_IDENTIFY_ACK); ADD_U2 (&buf, &len, pref.ports.client); Write(BUF, 4); return true; }}} bool cKademlia::send_FireCon (void) {{{ // (0x18) tODO logSend('>', OVERNET_FIREWALL_REQ, 0); return true; }}} bool cKademlia::send_FireCon_ack (void) {{{ // (0x19) tODO logSend('>', OVERNET_FIREWALL_ACK, 0); return true; }}} bool cKademlia::send_FireCon_nack (void) {{{ // (0x1A) tODO logSend('>', OVERNET_FIREWALL_NACK, 0); return true; }}} bool cKademlia::send_IP_query (void) {{{ // (0x1B) Ask after BOOT what the other see as my ip unsigned char BUF[4]; unsigned char *buf = BUF; size_t len, LEN = len = 4; ADD_U1 (&buf, &len, OP_EDONKEYHEADER); ADD_U1 (&buf, &len, OVERNET_IP_REQ); ADD_U2 (&buf, &len, pref.ports.client); logSend('>', OVERNET_IP_REQ, LEN); Write (BUF, LEN); return true; }}} bool cKademlia::send_IP_answer (void) {{{ // (0x1C) Answer for send_IP_query unsigned char BUF[6]; unsigned char *buf = BUF; size_t len, LEN = len = 6; ADD_U1 (&buf, &len, OP_EDONKEYHEADER); ADD_U1 (&buf, &len, OVERNET_IP_RES); ADD_U4 (&buf, &len, peer_ip.s_addr); logSend('>', OVERNET_IP_RES, LEN); Write(BUF, LEN); return true; }}} bool cKademlia::send_IP_end (void) {{{ // (0x1D) returned after send_IP_answer unsigned char BUF[2]; unsigned char *buf = BUF; size_t len, LEN = len = 2; ADD_U1 (&buf, &len, OP_EDONKEYHEADER); ADD_U1 (&buf, &len, OVERNET_IP_ACK); logSend('>', OVERNET_IP_ACK, LEN); Write(BUF, LEN); return true; }}} bool cKademlia::send_Identify (void) {{{ // (0x1E) unsigned char BUF[2]; unsigned char *buf = BUF; size_t len, LEN = len = 2; ADD_U1 (&buf, &len, OP_EDONKEYHEADER); ADD_U1 (&buf, &len, OVERNET_SEARCH_END); // logSend('>', 0x1E, LEN); Write(BUF, LEN); return true; }}} bool cKademlia::send_Raw(struct in_addr ip, uint16_t port, const unsigned char *data, size_t len) {{{ struct in_addr old_ip = peer_ip; uint16_t old_port = peer_port; peer_ip = ip; peer_port = port; unsigned char cmd = data[1]; if (cmd != 0x0E) if (logSend('>', cmd, len, true)) printf("RAW\n"); Write(data, len); peer_ip = old_ip; peer_port = old_port; return true; }}} // }}} // recv {{{ void cKademlia::parsePeer_lst (unsigned char **buf , size_t *len, unsigned cnt) {{{ for (unsigned i = 0; i < cnt && *len >= 23; i++) { uint8_t p_hash[KAD_HASH_LEN]; GET_HASH (buf, len, p_hash); struct in_addr p_ip; p_ip.s_addr = GET_U4 (buf, len); uint16_t p_port = GET_U2 (buf, len); uint8_t p_kind = GET_U1 (buf, len); overnet.add(p_hash, p_ip.s_addr, p_port, p_kind); } }}} bool cKademlia::recv_Connect (unsigned char *buf, size_t len) {{{ // (0x0A) request boot list uint8_t p_hash[KAD_HASH_LEN]; GET_HASH(&buf, &len, p_hash); uint32_t p_ip = GET_U4(&buf, &len); uint16_t p_udp = GET_U2(&buf, &len); uint8_t p_type = GET_U1(&buf, &len); if (peer_ip.s_addr != p_ip ) printf("WARNING sender ip dos not match %15s:%5u\n", inet_ntoa(peer_ip), peer_port); if (peer_port != p_udp) printf("WARING sender port does not match %15s:%5u\n", inet_ntoa(peer_ip), peer_port); overnet.add(p_hash, peer_ip.s_addr, peer_port, p_type); send_Connect_reply (); return true; }}} bool cKademlia::recv_Connect_reply (unsigned char *buf, size_t len) {{{ // (0x0B) return list of other clients unsigned cnt = GET_U2 (&buf, &len); parsePeer_lst (&buf, &len, cnt); status = 8; return true; }}} bool cKademlia::recv_Publicize (unsigned char *buf, size_t len) {{{ // (0x0C) publize my client uint8_t p_hash [HASH_LEN]; GET_HASH(&buf, &len, p_hash); uint32_t p_ip = GET_U4(&buf, &len); uint16_t p_udp = GET_U2(&buf, &len); uint8_t p_type = GET_U1(&buf, &len); if (pref.verbose & 1) { if (peer_ip.s_addr != p_ip ) printf("467 UGLY %15s:%5u\n", inet_ntoa(peer_ip), peer_port); if (peer_port != p_udp) printf("468 UGLY %15s:%5u\n", inet_ntoa(peer_ip), peer_port); } overnet.add(p_hash, peer_ip.s_addr, peer_port, p_type); send_Publicize_ack(); if (status == 0) status = 1; return true; }}} bool cKademlia::recv_Publicize_ack (unsigned char * , size_t ) {{{ // (0x0D) ack the publize of my client if (status == 5) status = 8; return true; }}} bool cKademlia::recv_Search (unsigned char *buf, size_t len) {{{ // (0x0E) search after an HASH (user/file) uint8_t p_hash[KAD_HASH_LEN]; unsigned cnt = GET_U1(&buf, &len); GET_HASH(&buf, &len, p_hash); if (cnt > OVERNET_BUCKET) cnt = OVERNET_BUCKET; send_Search_next(cnt, p_hash); return true; }}} unsigned cKademlia::recv_Search_next (unsigned char *buf, size_t len) {{{ // (0x0F) List of peers to try next time if (len == 0) return 0; result_countdown--; uint8_t info_hash[KAD_HASH_LEN]; GET_HASH(&buf, &len, info_hash); // <-- Move UP in bucket ? if(logSend('<', 0x0F, len, true)) printf(" %32s\n", hash_bin2hex(info_hash)); unsigned cnt = GET_U1(&buf, &len); cPeerList *results = new cPeerList(); for (unsigned i = 0; i < cnt && len >= 23; i++) { uint8_t p_hash[KAD_HASH_LEN]; GET_HASH (&buf, &len, p_hash); struct in_addr p_ip; p_ip.s_addr = GET_U4 (&buf, &len); uint16_t p_port = GET_U2 (&buf, &len); uint8_t p_kind = GET_U1 (&buf, &len); results->push_back(new cPeer(p_hash, p_ip.s_addr, p_port, p_kind)); } uint8_t *key = info_hash; cSearchManager::processResponse(key, peer_ip.s_addr, peer_port, results); cPeerList::const_iterator itc; for(itc = results->begin(); itc != results->end(); itc++) delete (*itc); results->clear(); delete results; return true; }}} bool cKademlia::recv_Search_info (unsigned char *buf, size_t len) {{{ // (0x10) for what ? uint8_t p_hash[KAD_HASH_LEN]; GET_HASH (&buf, &len, p_hash); unsigned extend = GET_U1(&buf, &len); unsigned min = GET_U2(&buf, &len); unsigned max = GET_U2(&buf, &len); send_Search_result(p_hash, min, max); return (extend == 0); }}} bool cKademlia::recv_Search_result (unsigned char *buf, size_t len) {{{ // (0x11) Query successful return the stored data size_t LEN = len; unsigned char *BUF = buf; result_countdown--; uint8_t info_hash [KAD_HASH_LEN]; uint8_t peer_hash [KAD_HASH_LEN]; GET_HASH (&buf, &len, info_hash); if (cSearchManager::isKeywordSearch(info_hash)) { size_t len_gui, LEN_gui = len_gui = 6 + LEN; unsigned char *buf_gui, *BUF_gui = buf_gui = reinterpret_cast(alloca (LEN_gui)); ADD_U1 (&buf_gui, &len_gui, OP_EDONKEYHEADER); ADD_U4 (&buf_gui, &len_gui, (LEN_gui - 5)); ADD_U1 (&buf_gui, &len_gui, CO_OV_SEARCH_RESULT); ASSERT(len_gui == LEN); memcpy(buf_gui, BUF, LEN); GUI_LIST akt->Write(BUF_gui, LEN_gui); } if(logSend('<', 0x11, len, true)) printf(" %32s\n", hash_bin2hex(info_hash)); GET_HASH (&buf, &len, peer_hash); class sFile *file = forHash(peer_hash); if (file != NULL) { if (file->publish_next < currentTime || file->publish_count > 0) { if (file->publish_next < currentTime) { file->publish_next = currentTime + 3600; file->publish_count = OVERNET_BUCKET; } struct in_addr old_ip = peer_ip; uint16_t old_port = peer_port; send_Publish(file->hash, file->size, file->Name()); peer_ip = old_ip; peer_port = old_port; } } unsigned char *start = buf; class sTag *tag = parse_tag (buf, &len); if (tag == NULL) return false; if (tag->loc != NULL) {{{ insertFiles (info_hash, peer_ip, len, start); if (0 == strncmp("bcp://", tag->loc, strlen("bcp://"))) {{{ char *link1 = tag->loc + strlen("bcp://"); // printf("x bcp:// %s\n", link1); int cnt = 0; char *token[4]; link1 = strtok(link1, ":"); struct in_addr new_ip; uint16_t new_port = 0; while (cnt < 3 && link1 != NULL) {{{ token[cnt++] = STRDUP (link1); link1 = strtok(NULL, ":"); if (NULL == link1) break; }}} switch (cnt) { case 2: // printf("2 bcp:// %s - %s\n", token[0], tocken[1]); new_ip.s_addr = inet_addr (token[0]); new_port = (atol(token[1])); if (new_ip.s_addr != 0 && (new_ip.s_addr & 0xFF000000) != 0) { addSource (new_ip, new_port, 0x02000000, true); insertFiles(info_hash, new_ip, 0 , NULL); } break; case 3: // printf("3 bcp:// %s - %s - %s\n", token[0], tocken[1], tocken[2]); // This is an overnet peer information with UDP port new_ip.s_addr = inet_addr (token[1]); new_port = (atol(token[2])); if ((new_ip.s_addr & 0xFF000000) != 0) if (new_ip.s_addr != 0) overnet.add(hash_hex2bin(token[0]), new_ip.s_addr, new_port, 0); break; default:printf("n bcp:// %s\n", tag->loc + strlen("bcp://")); break; } for (int i = 0; i < cnt ; i++ ) free (token[i]); }}} else printf("LOC : %s\n", tag->loc); delete tag; return true; }}} if (tag->name != NULL) {{{ insertFiles (info_hash, peer_ip, len, start); if (tag->size > 0) { // printf("ed2k://|file|%32s|%u|%s\n", hash_bin2hex(info_hash), tag->size, tag->name); delete tag; return true; } // printf("Name: %s\n", tag->name); // printf("Size: %u\n", tag->size); delete tag; return false; }}} if (tag->ip.s_addr != 0 && tag->port != 0) {{{ // TODO printf("info => IP %15s:%5u\n", inet_ntoa(tag->ip), tag->port); delete tag; return true; }}} dump (BUF, LEN); delete tag; return false; }}} bool cKademlia::recv_search_end (unsigned char *buf, size_t len) {{{ // (0x12) end the Query resonse (no more infos follow) uint8_t p_hash [HASH_LEN]; GET_HASH(&buf, &len, p_hash); return true; }}} bool cKademlia::recv_Publish (unsigned char *buf, size_t len) {{{ // (0x13) Publish an meta description uint8_t file_hash [KAD_HASH_LEN]; uint8_t p_hash[KAD_HASH_LEN]; GET_HASH(&buf, &len, file_hash ); GET_HASH(&buf, &len, p_hash); unsigned char *start = buf; class sTag *tag = parse_tag (buf, &len); if (tag == NULL) return false; delete tag; insertFiles (file_hash, peer_ip, len, start); return true; }}} bool cKademlia::recv_Publish_ack (unsigned char * , size_t ) {{{ // (0x14) acknowlegde the send_Publish return true; }}} bool cKademlia::recv_Identify_reply (unsigned char *buf, size_t len) {{{ // (0x15) parsePeer_lst(&buf, &len, 1); send_Identify_ack (); return true; }}} bool cKademlia::recv_Identify_ack (unsigned char *buf, size_t len) {{{ // (0x16) acknowlegde the send_Publish unsigned p_port = GET_U2(&buf, &len); addSource(peer_ip, p_port, 0x02000000); status = 8; return true; }}} bool cKademlia::recv_FireCon (unsigned char * , size_t ) {{{ // (0x18) i handle the firewalled server return true; }}} bool cKademlia::recv_FireCon_ack (unsigned char * , size_t ) {{{ // (0x19) return true; }}} bool cKademlia::recv_FireCon_nack (unsigned char * , size_t ) {{{ // (0x1A) return true; }}} bool cKademlia::recv_IP_query (unsigned char * , size_t ) {{{ // (0x1B) send_IP_answer (); send_IP_end (); return true; }}} bool cKademlia::recv_IP_answer (unsigned char *buf, size_t len) {{{ // (0x1C) Answer for send_IP_query //static struct in_addr last_ip; struct in_addr tmp_ip; tmp_ip.s_addr = GET_U4( &buf, &len); cSocket::setLocalExternalIP(tmp_ip); this_ip.s_addr = tmp_ip.s_addr; // believe it for this connection // if (my_ip.s_addr != last_ip.s_addr ) { // if (protocol_logLevel == 9) printf("MY IP = %15s\n", inet_ntoa(my_ip)); // last_ip.s_addr = my_ip.s_addr; // } next_ip_query = currentTime + 3600; return true; }}} bool cKademlia::recv_IP_end (unsigned char * , size_t ) {{{ // (0x1D) returned after send_IP_answer next_ip_query = currentTime + 3600; return true; }}} bool cKademlia::recv_Identify (unsigned char * , size_t ) {{{ // 0x1E send_Identify_reply (); return true; }}} // }}} bool cKademlia::logSend(char dir, unsigned cmd, size_t len,bool extra) {{{ if (dir == '<' && cmd == 0x12) return false; if (dir == '<' && cmd == 0x11) return false; if (dir == '<' && cmd == 0x0F) return false; switch (protocol_logLevel) { default : case 8 : return false; case 2 : if (cmd == 0x0E || cmd == 0x1E) return false; case 1 : if (cmd == 0x12 || cmd == 0x10) return false; case 9 : case 0 : break; } printf("%s %c 0x%04X overnet [%15s](%9u) %-15s [%3u]", currentTime_str, dir, cmd, inet_ntoa(peer_ip), peer_port, op2str(cmd), len); if (!extra) printf("\n"); return true; }}} int cKademlia::doRead_high (void) {{{ if (read_len == 0) return 0; IP_is_OK(peer_ip); overnet.setAlive(peer_ip.s_addr, peer_port); if (next_ip_query < currentTime || this_ip.s_addr == 0) send_IP_query (); unsigned char *BUF = read_buf; size_t len, LEN = len = read_len; unsigned proto = GET_U1(&BUF, &LEN); if (proto == OP_EDONKEYHEADER) { unsigned cmd = GET_U1(&BUF, &LEN); if (cmd!=0x0F && cmd!=0x11) logSend('<', cmd, len); switch(cmd) { case 0x0A : recv_Connect (BUF, LEN); break; case 0x0B : recv_Connect_reply (BUF, LEN); break; case 0x0C : recv_Publicize (BUF, LEN); break; case 0x0D : recv_Publicize_ack (BUF, LEN); break; case 0x0E : recv_Search (BUF, LEN); break; case 0x0F : recv_Search_next (BUF, LEN); break; case 0x10 : if (!recv_Search_info(BUF, LEN)) dump(BUF, LEN); break; case 0x11 : recv_Search_result (BUF, LEN); break; case 0x12 : recv_search_end (BUF, LEN); break; case 0x13 : recv_Publish (BUF, LEN); break; case 0x14 : recv_Publish_ack (BUF, LEN); break; case 0x15 : recv_Identify_reply (BUF, LEN); break; case 0x16 : recv_Identify_ack (BUF, LEN); break; case 0x18 : // firewall break; case 0x1B : recv_IP_query (BUF, LEN); break; case 0x1C : recv_IP_answer (BUF, LEN); break; case 0x1D : break; // IP_end case 0x1E : recv_Identify (BUF, LEN); break; case 0x21 : break; // TODO WARNING unclear if this opcode is real or an bug default : printf("Protocol %3u (0x%0X) (overnet) (%15s:%5u)\n", proto , proto, inet_ntoa(peer_ip), peer_port); printf("Command %3u (0x%0X) (overnet)\n", cmd, cmd); printf("len: %u\n", LEN); dump (BUF, LEN); break; } } else printf("Protocol %3u (0x%0X)\n", proto, proto); Read (read_buf, read_len); Work(); return 0; }}} void cKademlia::Work (void) {{{ cSearchManager::jumpStart(); overnet.onSmallTimer(); load_Boot("kademlia.lst"); if (last_query > currentTime) return; last_query = currentTime + 2; switch(status) { case 0 : memcpy (seek_hash, this_hash, KAD_HASH_LEN); Init_Search(); status = 1; case 1 : { cPeerList peers; overnet.getBootstrapContacts (&peers, OVERNET_BUCKET); cPeerList::const_iterator it; for (it = peers.begin(); it != peers.end(); it++) { cPeer *c = *it; peer_port = c->udp; peer_ip.s_addr = c->ip; if(peer_port != 0 && IP_is_OK(peer_ip)) send_Connect (); } } status = 8; case 8 : break; default : printf("status %i\n", status); return; break; } }}}