#include "cygwin.h" #include "md4.h" #include "misc.h" #include "donkey.h" #include "protocol.h" #include "sSource.h" #include "sServer.h" #include "sPacket.h" #include "sFile.h" #include "sTag.h" #include "sGui.h" #include "opcodes.h" const int dlTimeout_hello = 60; const int dlTimeout_data = 60; const int dlTimeout_fileinfo = 60; int ulRang = - 5; #define PACKET_LEN_SUB 5 unsigned int sSource::count0 = 0; unsigned int sSource::count1 = 0; unsigned int sSource::count = 0; class sSource *sSource::first_Source = NULL; class c32Key { public: char key[32]; c32Key () { bzero(key, 32); } c32Key (const uint8_t *a, const uint8_t *b) { memcpy(key + 0, a, 16); memcpy(key + 16, b, 16); } c32Key (const class c32Key &b) { memcpy(key, b.key, 32); } class c32Key* operator = (const class c32Key &b) { memcpy(key, b.key, 32); return this; } bool operator < (const class c32Key &B) const { return 0> memcmp(key, B.key, 32); } bool operator > (const class c32Key &B) const { return 0< memcmp(key, B.key, 32); } bool operator <= (const class c32Key &B) const { return 0>=memcmp(key, B.key, 32); } bool operator >= (const class c32Key &B) const { return 0<=memcmp(key, B.key, 32); } bool operator == (const class c32Key &B) const { return 0==memcmp(key, B.key, 32); } bool operator != (const class c32Key &B) const { return 0!=memcmp(key, B.key, 32); } }; class cFileInfo { public: size_t file_size; uint8_t file_info[256]; size_t len; cFileInfo() { file_size = 0; len = 0; } cFileInfo(size_t s, uint8_t *i) { file_size = s; len = (s + PARTSIZE - 1) / PARTSIZE; memcpy(file_info, i, len); } cFileInfo (const class cFileInfo &b) {{{ file_size = b.file_size; len = (file_size + PARTSIZE - 1) / PARTSIZE; if (len == 0) return; memcpy(file_info, b.file_info, len); }}} }; typedef std::map tInfo_File; tInfo_File info_File; void File_info_set (uint8_t *peer_hash, uint8_t *file_hash, size_t file_size, uint8_t *file_info) {{{ return; if (file_info == NULL) return; class c32Key key(peer_hash, file_hash); class cFileInfo *val = new cFileInfo (file_size, file_info); info_File[key] = val; }}} void File_info_del (const uint8_t *peer_hash, const uint8_t *file_hash) {{{ return; class c32Key key(peer_hash, file_hash); tInfo_File::iterator it = info_File.find(key); if (it == info_File.end()) return; delete it->second; it->second = NULL; info_File.erase(it); }}} bool File_info_get (const uint8_t *peer_hash, const uint8_t *file_hash, size_t file_size, uint8_t *file_info) {{{ return false; if (file_info == NULL) return false; class c32Key key(peer_hash, file_hash); tInfo_File::const_iterator it = info_File.find(key); if (it == info_File.end()) return true; if (file_size != it->second->file_size) { File_info_del(peer_hash, file_hash); return false; } memcpy(file_info, it->second->file_info, it->second->len); return true; }}} static int res_sources (sSource *, unsigned char *buf, size_t len) {{{ tHash hash; unsigned count; GET_HASH(&buf, &len, hash); count = GET_U2(&buf, &len); if (len != count * 12) {{{ printf("%s %i len %i count %i USED %i\n", __FILE__, __LINE__, len, count, count*(4+2+4+2)); return 0; }}} for (unsigned i = 0; i < count; i++) {{{ if (len == 0) return 1; in_addr c_ip; uint16_t c_port; in_addr s_ip; uint16_t s_port; c_ip.s_addr = GET_U4(&buf, &len); c_port = GET_U2(&buf, &len); s_ip.s_addr = GET_U4(&buf, &len); s_port = GET_U2(&buf, &len); if (htonl(c_ip.s_addr) > LOW_ID) { if (0 == (c_ip.s_addr & 0x000000FF)) continue; // Who send that damm IP's addSource (c_ip, c_port, 0x01000000, true); insertFiles (hash, c_ip, 0, NULL); } if (s_port == 4665) s_port = 4661; // Kome this from UDP ? if (htonl (s_ip.s_addr)> LOW_ID) saveServer (s_ip, s_port, 0, 0, false); }}} return 1; }}} void sSource::Name (const char *NAME) {{{ if (name != NULL) Free2 (name); name = STRDUP (NAME); }}} void sSource::Init(void){{{ ftp_aktive = false; next_slot = 0; ask_info = false; dl_file = NULL; part_len = 0; auto_select = false; next_Source = first_Source; first_Source = this; overnet = true; Type = tSource; dl_slot = -1; version = 0; dl_select = false; name = NULL; last_code = 0; extra_status = 0; have_slot = false; compress = false; eMule = false; ask_sources = true; zip = NULL; recvData = false; ul_rang = 1000; dl_rang = 0; dl_von[0] = dl_von[1] = dl_von[2] = 0; dl_bis[0] = dl_bis[1] = dl_bis[2] = 0; logged = false ; // one time printf of sSource stats ? ratio = getSources_ratio (peer_ip); if (ratio < -10240 || ratio > 10240) log (1, "%15s init ratio %li\n", inet_ntoa(peer_ip), ratio); count++; dl_next_event = currentTime + 0; ul_next_event = currentTime + 0; bzero (dl_hash, HASH_LEN); bzero (ul_hash, HASH_LEN); }}} sSource::sSource (class cSocket *Fd) : sSocket(Fd) {{{ sort = 0; count0++; status = WAIT_HELLO; Init(); if (mask != 0) doWork(mask); }}} sSource::sSource (struct in_addr Ip, uint16_t PORT) : sSocket (Ip, PORT) {{{ addSource (Ip, PORT, 0x00000000, true); sort = 1; count1++; Init(); if(!IP_is_OK(Ip)) { Close(); return; } status = SEND_HELLO; setSources_aktive (peer_ip); struct eSources *info = Source_ip(peer_ip); if (info != NULL) version = info->version & 0xFFFFFF; else { version = 1044; overnet = true; } if (info != NULL) { if (info->version & 0x02000000) overnet = true; if ( overnet && version == 0) version = 61; if (!overnet && version == 0) version = 1661; } if (mask != 0) doWork(mask); }}} sSource::~sSource (void) {{{ if(sort == 0) count0--; else count1--; if (ul_rang <= 0) ulRang--; tHash hash; bzero (hash, 16); dlFile(hash); SOURCE_LIST if (akt->ul_rang > 0 && akt->ul_rang < 1000) akt->ul_rang--; if (zip != NULL) zip = ende_Infalte (zip); if (connected == 1 && status != 2 && status != 9) { // printf("Close Aktive source\n"); endSources_aktive (peer_ip); setSource_timeout (peer_ip, currentTime + 6 * 60); long ratio_ende = dlCount - ulCount; if (ratio_ende != 0) { chgSources_ratio (peer_ip, ratio_ende); if (ratio_ende < -10240 || ratio_ende > 10240) log (1, "%15s ende ratio %li\n", inet_ntoa(peer_ip), ratio_ende); } } else Delete_src(peer_ip); if (status > 5) log (4, "del [%15s]\n", inet_ntoa (peer_ip)); if (name != NULL) Free2 (name); count--; // remove me from the file_list if (first_Source == this) { first_Source = next_Source; return; } class sSource *prev_file = first_Source; while (prev_file->next_Source != this && prev_file->next_Source != NULL) prev_file = prev_file->next_Source; ASSERT (prev_file != NULL); ASSERT (prev_file->next_Source == this); prev_file->next_Source = prev_file->next_Source->next_Source; }}} void sSource::setPartOK (const unsigned char *a, size_t LEN) {{{ ASSERT (LEN == dl_file->part_count); if (dl_file == NULL) return; part_len = (LEN + 7) / 8; memcpy (part_ok, a, part_len); for (size_t i = 0; i < LEN; i++) if (partStatus(i)) dl_file->part_sources[i]++; }}} bool sSource::partStatus(uint32_t i) const {{{ ASSERT(dl_file != NULL); if (part_len <= 0) return false; if (i > dl_file->part_count ) return false; uint32_t j = i / 8; uint8_t msk = 1 << (i&7); return (part_ok[j] & msk) == msk; }}} class sFile* sSource::ulFile (void) {{{ return forHash(ul_hash); }}} void sSource::dlFile (const tHash &f ) {{{ if (0 == memcmp(dl_hash, f, 16)) return; // Here there old dl file become unused if (dl_file != NULL) {{{ dl_file->downloads--; if (part_len > 0) for (size_t i = 0; i < dl_file->part_count; i++) if (partStatus(i)) dl_file->part_sources[i]--; bzero(part_ok, part_len); }}} // After this point the the new dl file is valid memcpy (dl_hash, f , HASH_LEN); dl_file = forHash(dl_hash); if (dl_file == NULL) return; dl_file->downloads++; char INFO[256]; uint8_t *info = reinterpret_cast(INFO); if (File_info_get(peer_hash, dl_hash, dl_file->size, info)) setPartOK(info, ((dl_file->size + PARTSIZE - 1) / PARTSIZE)); }}} void sSource::ulFile (const tHash &f ) {{{ memcpy (ul_hash, f, HASH_LEN); }}} void sSource::moreData_recv (uint32_t von, uint32_t bis) {{{ log (4, "%s %i [%9u-%9u],[%9u-%9u],[%9u-%9u]\n",__FILE__,__LINE__, dl_von[0],dl_bis[0], dl_von[1],dl_bis[1], dl_von[2],dl_bis[2]); { for (int j=0; j<3; j++) { if (dl_von[j] == von) dl_von[j] = bis; if (dl_von[j] >= dl_bis[j]) dl_von[j] = dl_bis[j] = 0; } } log (4, "%s %i [%9u-%9u],[%9u-%9u],[%9u-%9u]\n",__FILE__,__LINE__, dl_von[0],dl_bis[0], dl_von[1],dl_bis[1], dl_von[2],dl_bis[2]); int sum = 0; { for (int j=0; j<3; j++) sum += (dl_bis[j]-dl_von[j]); } if (sum == 0) { ftp_aktive = false; log (1, "PART RESQUEST ended !!!\n"); req_part_data (); } }}} bool sSource::calcUpload_block (size_t &von, size_t &bis) {{{ class sFile *ul_file = ulFile(); ASSERT (ul_hash != NULL); von = 0; bis = 0; do { if (ul_bis[0] == 0 || ul_von[0] >= ul_bis[0]) { ul_bis[0] = ul_bis[1]; ul_von[0] = ul_von[1]; ul_bis[1] = ul_bis[2]; ul_von[1] = ul_von[2]; ul_von[2] = 0; ul_bis[2] = 0; } if (ul_bis[0] == 0 || ul_von[0] >= ul_bis[0]) { ul_bis[0] = ul_bis[1]; ul_von[0] = ul_von[1]; ul_bis[1] = 0; ul_von[1] = 0; } if (ul_bis[0] == 0 || ul_von[0] >= ul_bis[0]) return false; const dtype *part = ul_file->firstBlock(); while (part!=NULL && bis== 0) { if (part->stat == BLOCK_VERIFY) { if(ul_bis[0] > part->von && ul_von[0] < part->bis) { von = part->von; bis = part->bis; if(von < ul_von[0]) von = ul_von[0]; if(bis > ul_bis[0]) bis = ul_bis[0]; if(bis+1-von>10240) bis = von + 10240 - 1; if(bis >= ulFile()->Size()) bis = ulFile()->Size() - 1; } } part = ul_file->nextBlock(); } if (bis==0 || von>=bis) ul_bis[0] = ul_von[0]=0; } while (bis==0); if (bis==ul_bis[0]) ul_bis[0]=von-1; if (von==ul_von[0]) ul_von[0]=bis+1; if (!ul_file->partStatus(von/PARTSIZE)) return false; if (!ul_file->partStatus(bis/PARTSIZE)) return false; return true; }}} // send Handling {{{ int sSource::client_info (uint8_t opcode ) {{{ /// 0x01/0x4C temp_buffer(tcp,56 + strlen(client_name) + ((opcode == OP_HELLO)?1:0)); logSend ('>', this, opcode, false); ADD_U1 (&tcp.buf, &tcp.len, OP_EDONKEYHEADER); ADD_U4 (&tcp.buf, &tcp.len, tcp.LEN - PACKET_LEN_SUB); // need to be set later ADD_U1 (&tcp.buf, &tcp.len, opcode); if (opcode == OP_HELLO) ADD_U1(&tcp.buf, &tcp.len, HASH_LEN); // hash-length ADD_HASH (&tcp.buf, &tcp.len, client_hash); // client_hash ADD_U4 (&tcp.buf, &tcp.len, this_ip.s_addr); // User_ID ADD_U2 (&tcp.buf, &tcp.len, pref.ports.client); // Client_Port ADD_U4 (&tcp.buf, &tcp.len, 2); // TAG count add_intTag (&tcp.buf, &tcp.len, CT_VERSION, my_version); add_strTag (&tcp.buf, &tcp.len, CT_NAME , client_name); if (run_server) {{{ ADD_U4 (&tcp.buf, &tcp.len, this_ip.s_addr); ADD_U2 (&tcp.buf, &tcp.len, pref.ports.server); }}} else {{{ ADD_U4 (&tcp.buf, &tcp.len, 0); ADD_U2 (&tcp.buf, &tcp.len, 0); }}} ADD_U4 (&tcp.buf, &tcp.len, 0); // ADD_U2 (&tcp.buf, &tcp.len, 0); if(tcp.len != 0) { printf("tcp.len = %u\n", tcp.len); ASSERT(tcp.len == 0); } Write(tcp.BUF, tcp.LEN); return 1; }}} int sSource::C5_client_info (bool start ) {{{ // (0x01/0x02) logSend ('>', this, (start)?0xC501:0xC502, false); temp_buffer(tcp, 79); ADD_U1 (&tcp.buf, &tcp.len, OP_EMULEPROT); ADD_U4 (&tcp.buf, &tcp.len, tcp.LEN - PACKET_LEN_SUB); ADD_U1 (&tcp.buf, &tcp.len, (start)?0x01:0x02); ADD_U1 (&tcp.buf, &tcp.len, CURRENT_VERSION_SHORT); // 1 Bytes ADD_U1 (&tcp.buf, &tcp.len, EMULE_PROTOCOL); // 1 Bytes ADD_U4 (&tcp.buf, &tcp.len, 8); // 4 Bytes add_intTag (&tcp.buf, &tcp.len, ET_COMPRESSION , 1); // 8 Bytes add_intTag (&tcp.buf, &tcp.len, ET_UDPPORT , pref.ports.emule); // 8 Bytes add_intTag (&tcp.buf, &tcp.len, ET_UDPVER , 1); // 8 Bytes (udp protocol version) add_intTag (&tcp.buf, &tcp.len, ET_SOURCEEXCHANGE , 1); // 8 Bytes (source-exchange) add_intTag (&tcp.buf, &tcp.len, ET_COMMENTS , 2); // 8 Bytes (comment an file) add_intTag (&tcp.buf, &tcp.len, ET_EXTENDEDREQUEST , 1); // 8 Bytes (extended requests) add_intTag (&tcp.buf, &tcp.len, ET_COMPATABLECLIENT , 1); // 8 Bytes (Compatibler Client 1=cDonkey) add_intTag (&tcp.buf, &tcp.len, "HASH" , 1); assert(tcp.len == 0); Write (tcp.BUF, tcp.LEN); return 1; }}} int sSource::res_part_data (void ) {{{ // (0x46) sFile *file = ulFile(); if (file == NULL) { if (logSend ('>', this, OP_SENDINGPART, true)) printf("invalid file\n"); printf(">257<(null)\n"); return 0; } size_t von = 0; size_t bis = 0; if (!calcUpload_block(von, bis)) { if (logSend ('>', this, OP_SENDINGPART, true)) printf("%32s no_blocks\n", hash_bin2hex(file->hash)); return 0; } unsigned int cnt = bis - von + 1; if (bis < von) {{{ printf("ERROR %s %i\n", __FILE__, __LINE__); return 0; }}} if (file->fd_in < 0) {{{ printf("ERROR %s %i\n", __FILE__, __LINE__); return 0; }}} FD_LSEEK(file->fd_in, von, SEEK_SET); if (von + cnt > file->size) { printf("Request wrig sieze\n"); return 0; } size_t len, LEN = len = 6 + HASH_LEN + 4 + 4 + cnt; unsigned char *buf, *BUF = buf = reinterpret_cast(alloca(LEN)); ADD_U1 (&buf, &len, OP_EDONKEYHEADER); ADD_U4 (&buf, &len, LEN - PACKET_LEN_SUB); ADD_U1 (&buf, &len, OP_HASHSETANSWER); ADD_HASH (&buf, &len, file->hash); ADD_U4 (&buf, &len, von); ADD_U4 (&buf, &len, bis); Bytef *file_pos = reinterpret_cast(buf); if (!FD_READ2 (file->fd_in, buf, cnt)) { return 0; } len -= cnt; ASSERT(len == 0); if (compress && file->compress_failed < 10) {{{ size_t len1, LEN1 = len1 = 6 + HASH_LEN + 4 + 4 + cnt + 320; unsigned char *buf1, *BUF1 = buf1 = reinterpret_cast(alloca(LEN1)); ADD_U1 (&buf1, &len1, OP_EMULEPROT); ADD_U4 (&buf1, &len1, LEN - PACKET_LEN_SUB); ADD_U1 (&buf1, &len1, OP_COMPRESSEDPART); ADD_HASH (&buf1, &len1, file->hash); ADD_U4 (&buf1, &len1, von); ADD_U4 (&buf1, &len1, bis); uLong pack_len = len1; Bytef *pack = reinterpret_cast(buf1); int err = compress2 (reinterpret_cast(pack), &pack_len, reinterpret_cast(file_pos), cnt, 9); if (err == Z_OK && pack_len < cnt) { if ((pack_len * 100) / cnt < 5) {{{ // safety check return 1; }}} if (logSend ('>', this, 0xC540, true)) printf("%32s (0x40) (%9u-%9lu) %3lu\n", hash_bin2hex(file->hash), von, pack_len, (pack_len*100)/cnt); size_t len_real = 6 + HASH_LEN + 4 + 4 + pack_len; ADD_U1 (&buf1, &len1, OP_EMULEPROT); ADD_U4 (&buf1, &len1, len_real - PACKET_LEN_SUB); ADD_U1 (&buf1, &len1, OP_COMPRESSEDPART); ADD_HASH (&buf1, &len1, file->hash); ADD_U4 (&buf1, &len1, von); ADD_U4 (&buf1, &len1, pack_len); file->ulCount (pack_len); Write (BUF1, len_real); return 1; } file->compress_failed ++; }}} // Not Compressed Handling if (logSend ('>', this, OP_SENDINGPART, true)) printf("%32s (%9i-%9i)\n", hash_bin2hex(file->hash), von, bis-von); file->ulCount (cnt); Write (BUF, LEN); return 1; }}} int sSource::req_part_data (void ) {{{ // (0x47) if (dl_file == NULL) return 0; if (dl_file->get_Completed()) return 0; if (!PartInfo()) { printf("ALERT: req_part_data source->PartInfo() == NULL\n"); return 0; } bool proto_log = logSend ('>', this, OP_REQUESTPARTS, true); if (proto_log) {{{ char *info = reinterpret_cast(alloca (dl_file->partCount() + 1)); info[dl_file->partCount()]=0; char c = '0'; for(uint32_t i=0; ipartCount(); i++) { c='0'; if (c == '0' && dl_file->partStatus (i)) c = '1'; if (c == '0' && partStatus (i)) c = '+'; if (c == '1' && partStatus (i)) c = '2'; info[i] = c; } printf("%32s -> %s ", hash_bin2hex(dl_file->hash), info); }}} // 1. Make an Map of all useable blocks of size BLOCKSIZE // 2. The key of each block is the (source_count + request_count) // 3. Take 3 Blocks with the smallest key dl_von[0] = dl_bis[0] = 0; dl_von[1] = dl_bis[1] = 0; dl_von[2] = dl_bis[2] = 0; size_t dl_key[3] = { 0, 0, 0}; size_t dl_use[3] = {40000,40000,40000}; size_t dl_idx = 0; const dtype *part = NULL; size_t max_size = dl_file->Size(); bool done = false; for (part = dl_file->firstBlock(); part != NULL && !done; part = dl_file->nextBlock()) { // printf("\nBLOK %9u - %9u - %9u\n", part->von, part->bis, part->stat); if (part->stat == BLOCK_RECIVE) continue; if (part->stat == BLOCK_VERIFY) continue; size_t von = part->von; size_t bis = part->bis; ASSERT(von <= bis); do { if (bis - von + 1 > BLOCKSIZE) bis = von + BLOCKSIZE - 1; if (bis > max_size) bis = max_size - 1; if (partStatus (von/PARTSIZE)) { size_t key = part->stat*20 + dl_file->part_sources[von/PARTSIZE]; if (key < dl_use[dl_idx]) { dl_use[dl_idx] = key; dl_von[dl_idx] = von; dl_bis[dl_idx] = bis; dl_key[dl_idx] = part->stat; dl_idx++; if (dl_idx == 3) dl_idx = 0; } } von = bis + 1; bis = part->bis; if (dl_use[0] == 0 && dl_use[1] == 0 && dl_use[2] == 0) done = true; } while (von < part->bis && !done && von < max_size); } for (dl_idx = 0; dl_idx < 3; dl_idx++) { if (dl_use[dl_idx] == 40000) { dl_von[dl_idx] = dl_bis[dl_idx] = 0; continue; } dtype changed; changed.von = dl_von[dl_idx]; changed.bis = dl_bis[dl_idx]; changed.stat = dl_key[dl_idx] + 1; changed.since = currentTime; dl_file->Change_range (&changed); dl_bis[dl_idx]++; } if (dl_bis[0] == 0) { File_info_del (reinterpret_cast(peer_hash), reinterpret_cast(dl_hash)); deleteFiles_ip (peer_ip); Close (); printf(" no-need\n"); return 0; // if first is always set } if (proto_log) printf("[%9i-%9i][%9i-%9i][%9i-%9i]\n", dl_von[0], dl_bis[0], dl_von[1], dl_bis[1], dl_von[2], dl_bis[2]); size_t len, LEN = len = 46; unsigned char *buf, *BUF = buf = reinterpret_cast(alloca(LEN)); ADD_U1 (&buf, &len, OP_EDONKEYHEADER); ADD_U4 (&buf, &len, LEN - PACKET_LEN_SUB); ADD_U1 (&buf, &len, OP_REQUESTPARTS); ADD_HASH(&buf, &len, dl_hash); ADD_U4 (&buf, &len, dl_von[0]); ADD_U4 (&buf, &len, dl_von[1]); ADD_U4 (&buf, &len, dl_von[2]); ADD_U4 (&buf, &len, dl_bis[0]); ADD_U4 (&buf, &len, dl_bis[1]); ADD_U4 (&buf, &len, dl_bis[2]); ASSERT(len == 0); Write (BUF, LEN); dl_next_event = currentTime + dlTimeout_data * 10; status = FTP_AKTIVE; return 1; }}} int sSource::no_such_file (const tHash &hash ) {{{ // (0x48) logSend ('>', this, OP_FILEREQANSNOFIL, false); size_t LEN , len = LEN = 22; unsigned char *buf, *BUF = buf = reinterpret_cast(alloca(LEN)); ADD_U1 (&buf, &len, OP_EDONKEYHEADER); ADD_U4 (&buf, &len, LEN - PACKET_LEN_SUB); ADD_U1 (&buf, &len, OP_FILEREQANSNOFIL); ADD_HASH(&buf, &len, hash); ASSERT(len == 0); Write(BUF, LEN); return 1; }}} int sSource::end_of_download (void ) {{{ // (0x49) o.p. logSend ('>', this, OP_END_OF_DOWNLOAD, false); size_t LEN , len = LEN = 22; unsigned char *buf, *BUF = buf = reinterpret_cast(alloca(LEN)); ADD_U1 (&buf, &len, OP_EDONKEYHEADER); ADD_U4 (&buf, &len, LEN - PACKET_LEN_SUB); ADD_U1 (&buf, &len, OP_END_OF_DOWNLOAD); ADD_HASH(&buf, &len, dl_hash); ASSERT(len == 0); Write(BUF, LEN); tHash hash; bzero (hash, HASH_LEN); dlFile (hash); return 1; }}} int sSource::CMD_req_shared_list (void ) {{{ // (0x4A) Currently unused logSend ('>', this, OP_ASKSHAREDFILES, false); size_t len, LEN = len = 6; unsigned char *buf, *BUF = buf = reinterpret_cast(alloca(LEN)); ADD_U1 (&buf, &len, OP_EDONKEYHEADER); ADD_U4 (&buf, &len, LEN - PACKET_LEN_SUB); ADD_U1 (&buf, &len, OP_ASKSHAREDFILES); logSend ('>', this, OP_ASKSHAREDFILES, false); ASSERT(len == 0); Write(BUF, LEN); return 1; }}} int sSource::res_shared_files (void ) {{{ // (0x4B) Currently unused (maybe never again used) size_t len, LEN = len = 4092; unsigned char *buf, *BUF = buf = reinterpret_cast(alloca(LEN)); size_t cnt = 0; ADD_U1 (&buf, &len, OP_EDONKEYHEADER); ADD_U4 (&buf, &len, LEN - PACKET_LEN_SUB); ADD_U1 (&buf, &len, OP_ASKSHAREDFILESANSWER); ADD_U4 (&buf, &len, cnt); FILE_LIST { ADD_HASH (&buf, &len, akt->hash); ADD_U4 (&buf, &len, this_ip.s_addr); ADD_U2 (&buf, &len, pref.ports.client); ADD_U4 (&buf, &len, 2); add_strTag (&buf, &len, FT_FILENAME, akt->Name()); add_intTag (&buf, &len, FT_FILESIZE, akt->Size()); cnt++; } size_t len_real = LEN - len; buf = BUF; len = LEN; ADD_U4 (&buf, &len, len_real - PACKET_LEN_SUB); ADD_U1 (&buf, &len, OP_ASKSHAREDFILESANSWER); logSend ('>', this, OP_ASKSHAREDFILESANSWER, false); ADD_U4 (&buf, &len, cnt); Write(BUF, LEN); return 1; }}} int sSource::CMD_client_message (const char *msg ) {{{ // (0x4E) Currently unused size_t len, LEN = len = 6 + 2 + strlen(msg); unsigned char *buf, *BUF = buf = reinterpret_cast(alloca(LEN)); ADD_U1 (&buf, &len, OP_EDONKEYHEADER); ADD_U4 (&buf, &len, LEN - PACKET_LEN_SUB); ADD_U1 (&buf, &len, OP_MESSAGE); logSend ('>', this, OP_MESSAGE, false); ADD_S2 (&buf, &len, msg); ASSERT(len == 0); Write(BUF, LEN); return 1; }}} int sSource::req_file_status (const tHash &hash ) {{{ // (0x4F) o.p. if (tcp_server != NULL) { if (tcp_server->peer_ip.s_addr == peer_ip.s_addr) assert(0); } tHash old_dl; memcpy(old_dl, hash, 16); dlFile(hash); if (dl_file == NULL) return 0; if (PartInfo()) { for(uint32_t i=0; ipartCount(); i++) { if (!dl_file ->partStatus (i) && partStatus(i)) { if (!have_slot) req_slot(); else req_part_data(); return 1; } } } dlFile(old_dl); if (logSend('>', this, OP_SETREQFILEID, true)) printf("%32s\n", hash_bin2hex(hash)); size_t LEN , len = LEN = 22; unsigned char *buf, *BUF = buf = reinterpret_cast(alloca(LEN)); ADD_U1 (&buf, &len, OP_EDONKEYHEADER); ADD_U4 (&buf, &len, LEN - PACKET_LEN_SUB); ADD_U1 (&buf, &len, OP_SETREQFILEID); ADD_HASH(&buf, &len, hash); Write(BUF, LEN); return 1; }}} int sSource::res_part_status (tHash &hash ) {{{ // (0x50) const class sFile *file = forHash(hash); if (NULL == file) return 0; if (NULL == File_idx (hash, peer_ip)) { insertFiles(hash, peer_ip, 0, NULL); } if (logSend ('>', this, OP_FILESTATUS, true)) printf("%32s\n", hash_bin2hex(file->hash)); const uint8_t *file_stat = file->listPartStatus(); int cnt = (file->partCount()+7)/8; size_t len, LEN = len = 6 + HASH_LEN + 2 + cnt; unsigned char *buf, *BUF = buf = reinterpret_cast(alloca(LEN)); ADD_U1 (&buf, &len, OP_EDONKEYHEADER); ADD_U4 (&buf, &len, LEN - PACKET_LEN_SUB); ADD_U1 (&buf, &len, OP_FILESTATUS); ADD_HASH (&buf, &len, file->hash); ADD_U2 (&buf, &len, file->partCount()); for (int j=0; j < cnt; j++) ADD_U1 (&buf, &len, file_stat[j]); ASSERT(len == 0); Write (BUF, LEN); log (4, "file : "); for(uint32_t i=0; i < file->partCount(); i++) log (4, "%c", file->partStatus(i)?'1':'0'); log (4, "\n"); return 1; }}} int sSource::req_part_hash (const tHash &hash ) {{{ // (0x51) o.p. if (logSend('>', this, OP_HASHSETREQUEST, true)) printf("%32s\n", hash_bin2hex(hash)); size_t LEN , len = LEN = 22; unsigned char *buf, *BUF = buf = reinterpret_cast(alloca(LEN)); ADD_U1 (&buf, &len, OP_EDONKEYHEADER); ADD_U4 (&buf, &len, LEN - PACKET_LEN_SUB); ADD_U1 (&buf, &len, OP_HASHSETREQUEST); ADD_HASH(&buf, &len, hash); Write(BUF, LEN); return 1; }}} int sSource::res_part_hash (void ) {{{ // (0x52) if (ulFile() == NULL) return 1; // Maybe we deleted this file in the meantime const class sFile *file = ulFile(); if (!file->havePartHash ()) return 1; // No error if we do not have an part hash for that file int cnt = file->partCount(); size_t len, LEN = len = 6 + HASH_LEN + 2 + cnt * HASH_LEN; unsigned char *buf, *BUF = buf = reinterpret_cast(alloca(LEN)); ADD_U1 (&buf, &len, OP_EDONKEYHEADER); ADD_U4 (&buf, &len, LEN - PACKET_LEN_SUB); ADD_U1 (&buf, &len, OP_HASHSETANSWER); logSend ('>', this, OP_HASHSETANSWER, false); ADD_HASH(&buf, &len, file->hash); ADD_U2 (&buf, &len, cnt); for (int i=0; i < cnt; i++) ADD_HASH(&buf, &len, *file->getPartHash (i)); ASSERT (len == 0); Write (BUF, LEN); return 1; }}} int sSource::req_slot (void ) {{{ // (0x54) o.p. (null) if (next_slot >= currentTime) return 1; next_slot = currentTime + 300; logSend('>', this, OP_STARTUPLOADREQ, false); size_t LEN, len = LEN = 22; unsigned char *buf, *BUF = buf = reinterpret_cast(alloca(LEN)); ADD_U1 (&buf, &len, OP_EDONKEYHEADER); ADD_U4 (&buf, &len, LEN - PACKET_LEN_SUB); ADD_U1 (&buf, &len, OP_STARTUPLOADREQ); ADD_HASH(&buf, &len, dl_hash); ASSERT(len == 0); Write(BUF, LEN); return 1; }}} int sSource::CMD_slot_available (void ) {{{ // (0x55) o.p. (null) logSend('>', this, OP_ACCEPTUPLOADREQ, false); size_t LEN, len = LEN = 6; unsigned char *buf, *BUF = buf = reinterpret_cast(alloca(LEN)); ADD_U1(&buf, &len, OP_EDONKEYHEADER); ADD_U4(&buf, &len, LEN - PACKET_LEN_SUB); ADD_U1(&buf, &len, OP_ACCEPTUPLOADREQ); Write(BUF, LEN); return 1; }}} int sSource::res_slot_close (void ) {{{ // (0x57) o.p. (null) logSend('>', this, OP_OUTOFPARTREQS, false); size_t LEN, len = LEN = 6; unsigned char *buf, *BUF = buf = reinterpret_cast(alloca(LEN)); ADD_U1(&buf, &len, OP_EDONKEYHEADER); ADD_U4(&buf, &len, LEN - PACKET_LEN_SUB); ADD_U1(&buf, &len, OP_OUTOFPARTREQS); Write(BUF, LEN); return 1; }}} int sSource::req_fileName (const tHash &hash ) {{{ // (0x58) o.p. tHash old_dl; memcpy(old_dl, hash, 16); dlFile(hash); if (dl_file == NULL) return 0; if (PartInfo()) { for(uint32_t i=0; ipartCount(); i++) { if (!dl_file ->partStatus (i) && partStatus(i)) { if (!have_slot) req_slot(); else req_part_data(); return 1; } } } dlFile(old_dl); if (logSend('>', this, OP_FILEREQUEST, true)) printf("%32s\n", hash_bin2hex(hash)); size_t LEN , len = LEN = 22; unsigned char *buf, *BUF = buf = reinterpret_cast(alloca(LEN)); ADD_U1 (&buf, &len, OP_EDONKEYHEADER); ADD_U4 (&buf, &len, LEN - PACKET_LEN_SUB); ADD_U1 (&buf, &len, OP_FILEREQUEST); ADD_HASH(&buf, &len, hash); ASSERT(len == 0); Write(BUF, LEN); return 1; }}} int sSource::res_offer_file (const sFile *file ) {{{ // (0x59) if (logSend('>', this, OP_FILEREQANSWER, true)) printf("%32s\n", hash_bin2hex(file->hash)); const char *f_name = file->Name(); f_name = ""; size_t len, LEN = len = 6 + HASH_LEN + 2 + strlen (f_name); unsigned char *buf, *BUF = buf = reinterpret_cast(alloca(LEN)); ADD_U1 (&buf, &len, OP_EDONKEYHEADER); ADD_U4 (&buf, &len, LEN - PACKET_LEN_SUB); ADD_U1 (&buf, &len, OP_FILEREQANSWER); ADD_HASH(&buf, &len, file->hash); ADD_S2 (&buf, &len, f_name); ASSERT(len == 0); Write(BUF, LEN); return 0; }}} int sSource::C5_res_rang (uint8_t rang ) {{{ // (0x60) o.p. if (logSend ('>', this,0xC560, true)) printf("%hi\n", rang); size_t LEN , len = LEN = 18; unsigned char *buf, *BUF = buf = reinterpret_cast(alloca(LEN)); ADD_U1 (&buf, &len, OP_EMULEPROT); ADD_U4 (&buf, &len, LEN - PACKET_LEN_SUB); ADD_U1 (&buf, &len, OP_QUEUERANKING); ADD_U2 (&buf, &len, rang); ADD_U4 (&buf, &len, 0); ADD_U4 (&buf, &len, 0); ADD_U2 (&buf, &len, 0); ASSERT(len == 0); Write(BUF, LEN); return 1; }}} int sSource::C5_req_sources (const tHash &hash ) {{{ // (0x81) o.p. tHash Hash; memcpy(Hash,hash,HASH_LEN); nextFile (hash, true); // <- set cursor_count if (cursor_count > 512) return 1; if(logSend ('>', this , 0xC581, true)) printf("%32s\n", hash_bin2hex(hash)); size_t LEN , len = LEN = 22; unsigned char *buf, *BUF = buf = reinterpret_cast(alloca(LEN)); ADD_U1 (&buf, &len, OP_EMULEPROT); ADD_U4 (&buf, &len, LEN - PACKET_LEN_SUB); ADD_U1 (&buf, &len, OP_REQUESTSOURCES); ADD_HASH(&buf, &len, hash); ASSERT(len == 0); Write(BUF, LEN); return 1; }}} // }}} // recv Handling {{{ int sSource::REQ_client_info (sPacket *packet) {{{ // (0x01) bool log = logSend ('<', this, OP_HELLO, true); unsigned char hash_len = packet->GET_U1 (); // hash länge if (hash_len != HASH_LEN) { if (log) printf("Wrong hash len\n"); return -1; } Code(OP_HELLO); packet->GET_HASH(peer_hash); setSources_hash(peer_ip, peer_hash); packet->GET_U4 (); // user->idx_old uint16_t client_port = packet->GET_U2 (); // user->port addSource (peer_ip, client_port, 0x00000000, true); class sTag *tag = parseTag (packet); bool added = false; if (tag != NULL) { if (tag->port > 0) { added = true; addSource (peer_ip, tag->port, 0x00000000, true); } if (tag->version != 0) version = tag->version; version = tag->version; overnet = false; if (tag->version == 43) overnet = true; if (tag->version == 1044) overnet = true; if (tag->name != NULL) Name (tag->name); delete tag; } if (name == NULL) Name ("(null)"); if (log) printf("v.%4u NAME: %s e:%i", version, name, eMule); if (log) printf(" LEN: %i\n", packet->Unused()); if (status == WAIT_HELLO) { client_info(0x4C); status = WAIT_INFO; Code(0x4C); if (peer_hash[5]==14 && peer_hash[14]==111) C5_client_info (true); } return 0; }}} int sSource::RES_part_data (sPacket *packet) {{{ // (0x46) unsigned int off_start,off_ende; // Maybe changed download file (late response) tHash hash; packet->GET_HASH (hash); sFile *file = forHash(hash); if (file == NULL) return 0; if (file != dl_file) { printf("WARNING 584 (%s !=", hash_bin2hex(hash)); printf("%s)\n", hash_bin2hex(dl_hash)); } if (file == NULL) return 0; off_start = packet->GET_U4 (); off_ende = packet->GET_U4 (); if(logSend ('<', this, OP_SENDINGPART, true)) printf("%32s (%9i-%9i)\n", hash_bin2hex (hash), off_start, off_ende - off_start); if ( !logged ) {{{ // debug log char logbuf[256]; snprintf(logbuf, 255, "New Download from %15s (E3:edonkey) Ratio: %li Emule: %d Overnet: %d\n", inet_ntoa(peer_ip), ratio, is_eMule(), is_Overnet() ); log(1, logbuf); GUI_LIST akt->GUI_statusMessage(logbuf); logged = true; }}} recvData = true; // printf("RECV %15s - %32s - %9u - %9u\n", inet_ntoa(peer_ip), hash_bin2hex(dl_hash), off_start, off_ende); int ret = file->recvPart (off_start,off_ende, packet->DATA ()); this->dl_count += (off_ende - off_start) ; // update dl_count if (ret == -9) { // block already exists // cancel request other block req_part_data (); Code(OP_SENDINGPART); return 1; } moreData_recv (off_start, off_ende); Code(OP_SENDINGPART); return 1; }}} int sSource::REQ_part_data (sPacket *packet) {{{ // (0x47) tHash hash; packet->GET_HASH (hash); ulFile (hash); if (ulFile() == NULL) return 0; ul_von[0] = packet->GET_U4 (); ul_von[1] = packet->GET_U4 (); ul_von[2] = packet->GET_U4 (); ul_bis[0] = packet->GET_U4 (); ul_bis[1] = packet->GET_U4 (); ul_bis[2] = packet->GET_U4 (); if(logSend ('<', this, OP_REQUESTPARTS, true)) printf("%32s [%9u-%9u][%9u-%9u][%9u-%9u]\n", hash_bin2hex(ul_hash),ul_von[0],ul_bis[0],ul_von[1],ul_bis[1],ul_von[2],ul_bis[2]); extraSend (OP_SENDINGPART); ul_next_event = currentTime + 0; return 1; }}} int sSource::RES_no_such_file (sPacket *packet) {{{ // (0x48) tHash hash; packet->GET_HASH(hash); if (logSend ('<', this, OP_FILEREQANSNOFIL, true)) printf("%32s\n", hash_bin2hex(hash)); deleteFiles_ip(peer_ip); last_send = last_read = 0; return 1; }}} int sSource::RES_dl_ende (sPacket *packet) {{{ // (0x49) if (packet == NULL) return 0; tHash hash; packet->GET_HASH (hash); extraSend (0); return 1; }}} int sSource::REQ_shared_files (sPacket * ) {{{ // (0x4A) extraSend (OP_ASKSHAREDFILESANSWER); return 1; }}} int sSource::RES_shared_files (sPacket *packet) {{{ // (0x4B) int cnt = packet->GET_U4(); Code(-1); // maybe we got an defekt answer while(--cnt>=0) { tHash hash; packet->GET_HASH(hash); // HASH packet->GET_U4 (); // IP packet->GET_U2 (); // Port class sTag *tag = parseTag (packet); if (tag == NULL) return 0; if (tag->name != NULL) { char buffer[512]; int l = snprintf(buffer,511, "%16s %s %u\n", hash_bin2hex (hash), inet_ntoa(peer_ip),peer_port); buffer[l] = 0; printf("%s", buffer); } delete tag; } Code(OP_ASKSHAREDFILESANSWER); return 1; }}} int sSource::RES_client_login (sPacket *packet) {{{ // (0x4C) bool log = logSend ('<', this, OP_HELLOANSWER, true); if (packet->Unused() < 16 + 4 + 2) { if(log) printf("DEFEKT\n"); Close(); return 0; } tHash hash; struct in_addr new_ip; packet->GET_HASH(hash); setSources_hash(peer_ip, peer_hash); packet->GET_U4 (); uint16_t new_port = packet->GET_U2 (); class sTag *tag = parseTag (packet); if (tag != NULL) { if (tag->port > 0) addSource (peer_ip, tag->port, 0x00000000, true); if (new_port == 0) new_port = tag->port; version = tag->version; if (tag->version == 43) overnet = true; if (tag->version == 1044) overnet = true; if (tag->name != NULL) Name (tag->name); if (log) printf("v.%4u NAME %s LEN: %i\n", tag->version, tag->name, packet->Unused()); delete tag; } else printf("(noTag)\n"); new_ip.s_addr = packet->GET_U4 (); new_port = packet->GET_U2 (); if (new_port == 4665) new_port = 4661; // Client got me via UDP i think if(new_ip.s_addr != 0) { if (htonl(new_ip.s_addr) > LOW_ID) { if ((new_ip.s_addr & 0xFF000000) != 0 && (new_ip.s_addr & 0x000000FF) != 0) saveServer (new_ip, new_port, 0, 0, false); } } Code(OP_HELLOANSWER); return 0; }}} int sSource::RES_changed_server (sPacket * ) {{{ // (0x4D) return 1; // Heist vermutlich Changed IDX (von low auf heigh); /* struct in_addr new_ip; uint32_t new_idx = packet->GET_U4 (); new_ip.s_addr = packet->GET_U4 (); return 0; */ }}} int sSource::RES_source_message (sPacket *packet) {{{ // (0x4E) (log.info) if (packet == NULL) return 0; char *msg = packet->GET_S2 (); printf("SOURCE %15s <- %s\n", inet_ntoa (peer_ip), msg); Free2 (msg); return 1; }}} int sSource::REQ_status (sPacket *packet) {{{ // (0x4F) tHash hash; packet->GET_HASH (hash); class sFile *file = forHash(hash); if (file == NULL) { // if(logSend ('<', this, OP_SETREQFILEID, true)) printf("%32s BAD len:%i\n", hash_bin2hex(hash), packet->Unused()); no_such_file (hash); return 1; } if(logSend ('<', this, OP_SETREQFILEID, true)) printf("%32s OK len:%i\n", hash_bin2hex(hash),packet->Unused()); res_part_status (hash); return 1; }}} int sSource::RES_status (sPacket *packet) {{{ // (0x50) Return file Status if (ftp_aktive) return 1; if (packet->Unused() <= 18) {{{ printf("MALFORMED PACKET 0x50 from %s LEN %u\n", inet_ntoa(peer_ip), packet->Unused()); return 0; }}} tHash hash; if (packet->Unused() < 18) {{{ printf("MALFORMED PACKET 0x50 from %15s LEN %5u VERSION %4u NAME %s\n", inet_ntoa(peer_ip), packet->Unused(), version, name); IP_block (peer_ip); Close(); return 0; }}} packet->GET_HASH(hash); uint16_t cnt = packet->GET_U2(); class sFile *file = forHash(hash); if(file == NULL) {{{ if (logSend ('<', this, OP_FILESTATUS, true)) printf("%32s -> BAD(1)\n", hash_bin2hex(hash)); return 0; }}} size_t file_cnt = (file->Size()+PARTSIZE-1)/PARTSIZE; if (cnt != file_cnt && cnt != 0) {{{ if (logSend ('<', this, OP_FILESTATUS, true)) printf("%32s -> BAD(2)\n", hash_bin2hex(hash)); IP_block (peer_ip); return 0; }}} unsigned bytes = (file->partCount() + 7) / 8; unsigned char *temp_info = reinterpret_cast(alloca (bytes)); char *info = reinterpret_cast(alloca (file->partCount() + 1)); if (cnt == 0) memset (temp_info, 0xff , bytes); else memcpy (temp_info, packet->DATA() , bytes); bool use = false; info[file->partCount()]=0; char c; for(uint32_t i=0; ipartCount(); i++) { c = (file->partStatus(i))?'1':'0'; bool source_have = (0 != ((temp_info[i / 8]) & (1 << (i & 7)))); if (c == '0' && source_have) { c = '+'; use = true; } if (c == '1' && source_have) c = '2'; info[i] = c; } if (!use) {{{ if (logSend ('<', this, OP_FILESTATUS, true)) printf("%32s -> (%2u)%s NO-USE\n", hash_bin2hex(hash), cnt, info); setSource_timeout(peer_ip, currentTime + 3600); // XXX if happens -> we already have all the parts(?) /* ASSERT(cnt != 0); */ return 1; }}} dlFile(hash); setPartOK(temp_info, file->partCount()); File_info_set(peer_hash, hash, file->size, reinterpret_cast(part_ok)); if (logSend ('<', this, OP_FILESTATUS, true)) printf("%32s -> (%2u)%s USE\n", hash_bin2hex(hash), cnt, info); insertFiles (hash, peer_ip, 0, NULL); if (!have_slot) { req_slot(); return 1; } if (!file->havePartHash()) req_part_hash(hash); req_part_data(); return 1; }}} int sSource::REQ_part_hash (sPacket *packet) {{{ // (0x51) tHash hash; packet->GET_HASH(hash); ulFile (hash); if (ulFile() != NULL) extraSend (OP_HASHSETREQUEST); return 1; }}} int sSource::RES_part_hash (sPacket *packet) {{{ // (0x52) Return partial hashes unsigned short cnt; tHash hash_file; tHash hash_test; MD4_CTX ctx; MD4Init (&ctx); packet->GET_HASH(hash_file); cnt = packet->GET_U2(); bool log = logSend ('<', this, OP_HASHSETANSWER, true); if (log) printf("%32s\n", hash_bin2hex(hash_file)); if (version == 666) return 0; printf("ORIG_HASH = %s\n", hash_bin2hex (hash_file)); tHash *hash_part = reinterpret_cast(alloca (cnt * sizeof(tHash))); sFile *file = forHash(hash_file); for(unsigned i = 0; i < cnt; i++) { packet->GET_HASH(hash_part[i]); if (version == 666) { printf("%2i - %32s", i, hash_bin2hex(hash_part[i])); if (file != NULL) if (file->havePartHash () && file->partCount() > i) printf(" + %32s => %i\n", hash_bin2hex(*file->getPartHash(i)), memcmp(hash_part[i], *file->getPartHash(i), HASH_LEN)); if (log) printf("\n"); } MD4Update (&ctx, hash_part[i], sizeof(tHash)); } MD4Final (hash_test, &ctx); if (version == 666) printf("++ - %32s\n", hash_bin2hex(hash_test)); if (file == NULL) { return 0; // We do not need this part hash } if (file->havePartHash ()) { return 1; // We have yet now an valid set } if (file->partCount() != cnt) { version = 666; return 1; } if (0 != memcmp (hash_file, hash_test, HASH_LEN)) { version = 666; Code(-1); return 0; } file->savePartHash (hash_part); return 1; }}} int sSource::REQ_slot (sPacket *packet) {{{ // (0x54) if (logSend('<', this, OP_STARTUPLOADREQ, true)) printf("len %i\n", packet->Unused()); extraSend (OP_ACCEPTUPLOADREQ); return 1; }}} int sSource::RES_slot_avail (sPacket * ) {{{ // (0x55) logSend('<', this, OP_ACCEPTUPLOADREQ, false); Code(OP_ACCEPTUPLOADREQ); have_slot = true; // If more than 2 packet's come if (NULL != dl_file && part_len > 0) req_part_data (); // This is safer that it is not missed return 1; }}} int sSource::RES_slot_release (sPacket * ) {{{ // (0x56) Code(OP_CANCELTRANSFER); return 1; }}} int sSource::RES_slot_close (sPacket * ) {{{ // (0x57) Code(OP_OUTOFPARTREQS); return 1; }}} int sSource::REQ_fileName (sPacket *packet) {{{ // (0x58) tHash hash; packet->GET_HASH(hash); const sFile *file = forHash(hash); if (file == NULL) { // if(logSend ('<', this, OP_FILEREQUEST, true)) printf("%32s BAD\n", hash_bin2hex(hash)); return 0; } if(logSend ('<', this, OP_FILEREQUEST, true)) printf("%32s OK\n", hash_bin2hex(hash)); if (eMule) { res_offer_file (file); // <- Safe UL traffic is only information, but brake eMule res_part_status(hash); } return 1; }}} int sSource::RES_fileName (sPacket *packet) {{{ // (0x59) tHash hash; packet->GET_HASH(hash); const sFile *file = forHash(hash); if (file == NULL) return 1; char *filename = packet->GET_S2 (); // printf("%32s => %s\n", hash_bin2hex(hash), file->Name()); Free2 (filename); if(logSend ('<', this, OP_FILEREQANSWER, true)) printf("%32s OK\n", hash_bin2hex(hash)); file = nextFile_search (); if (file != NULL && eMule) C5_req_sources (file->hash); return 1; }}} int sSource::RES_5b_unknown (sPacket *packet) {{{ // (0x5B) tHash hash; packet->GET_HASH(hash); if (logSend ('<', this, OP_CHANGE_SLOT, true)) printf("%32s\n", hash_bin2hex(hash)); return 1; }}} int sSource::RES_5c_unknown (sPacket *packet) {{{ // (0x5C) uint32_t idx = packet->GET_U4 (); if(logSend ('<', this, OP_QUEUERANK, true)) printf("%4u\n", idx); return 1; }}} int sSource::C5_client_info (sPacket *packet) {{{ // (0x01/0x02) unsigned short_ver = packet->GET_U1 (); unsigned emule_ver = packet->GET_U1 (); if (logSend ('<', this, 0xC501, true)) printf("%u - %u\n", short_ver, emule_ver); setSources_version(peer_ip, 0x01000000 | short_ver); eMule = true; if (packet == NULL) {{{ printf("ERROR %s %i\n", __FILE__, __LINE__); return 0; }}} class sTag *tag = parseTag (packet); if (tag != NULL) { Compress (tag->compress==1); setSources_udp(peer_ip, tag->client_udp); delete tag; } if (eMule && packet->Command() == OP_EMULEINFO) C5_client_info (false); return 1; }}} int sSource::C5_compressed_data (sPacket *packet) {{{ // (0x40) #define OUT_CNT 10240 bool proto_log = logSend ('<', this, 0xC540, true); if (NULL == zip) zip = init_Infalte (); if (zip == NULL) {{{ printf("ERROR %s %i\n", __FILE__, __LINE__); return 0; }}} tHash hash; packet->GET_HASH (hash); if (proto_log) printf ("%32s ", hash_bin2hex (hash)); sFile *file = forHash(hash); if (file == NULL) return 1; ASSERT(dl_file == forHash(dl_hash)); if (file != dl_file) { ende_Infalte(zip); zip = NULL; printf("WARNING: RECV file.hash %32s WAIT file.hash %32s\n", hash_bin2hex(hash), hash_bin2hex(dl_hash)); end_of_download (); return 0; } uint32_t off_start = packet->GET_U4 (); uint32_t PACKED_SIZE = packet->GET_U4 (); int in_cnt = packet->Unused (); char *in = reinterpret_cast(packet->DATA ()); while (in_cnt > 0) { int out_cnt = OUT_CNT; unsigned char out [OUT_CNT]; int worked = Infalte (zip, in, in_cnt, reinterpret_cast(out), &out_cnt); if (worked <= 0) { if (proto_log) printf("FAILED Infalte\n"); ende_Infalte(zip); zip = NULL; Close(); return 0; } if (out_cnt > 0) { uint32_t start = off_start + zip->total_out - out_cnt; uint32_t ende = start + out_cnt; if (proto_log) { unsigned long S = start; unsigned long E = ende; printf("[%9lu-%9lu] \n", S, E - S); } if ( !logged ) { char logbuf[256]; snprintf(logbuf, 255, "New Download from %15s (C5:emule) Ratio: %li\n", inet_ntoa(peer_ip), ratio); log(1, logbuf); GUI_LIST akt->GUI_statusMessage(logbuf); logged = true; } moreData_recv (start, ende); int ret = file->recvPart (start, ende, out); this->dl_count += (ende - start); // update dl_count if (ret == -9) { // block already exists // cancel request other block ende_Infalte(zip); zip = NULL; req_part_data (); Code(OP_SENDINGPART); return 1; } } in += worked; in_cnt -= worked; } Code(OP_SENDINGPART); if (zip->total_in == PACKED_SIZE) zip = ende_Infalte (zip); if(proto_log) printf("\n"); return 1; }}} int sSource::C5_res_rang (sPacket *packet) {{{ // (0x60) unsigned rang = packet->GET_U2 (); dl_slot = rang; setSource_timeout (peer_ip, currentTime + 10 * 30); if (logSend ('<', this,0xC560, true)) printf("%4u\n", rang); setSources_hash_dl(peer_ip, dl_hash); Code(OP_QUEUERANK); return 1; }}} int sSource::C5_rating (sPacket *packet) {{{ // (0x61) uint8_t rate = packet->GET_U1 (); uint32_t size = packet->GET_U4 (); if(size != packet->Unused()) { printf("%s %i WARNING size mismatch\n", __FILE__, __LINE__); if (size > packet->Unused()) size = packet->Unused(); } char *data = reinterpret_cast(packet->DATA()); if (logSend ('<', this,0xC561, true)) printf("%u -> %.*s\n", rate, size, data); return 1; }}} int sSource::C5_req_sources (sPacket *packet) {{{ // (0x81) tHash hash; packet->GET_HASH (hash); if (logSend ('>', this,0xC581, true)) printf("%32s\n", hash_bin2hex(hash)); const struct eFiles *files = nextFile(hash, true); // cursor_count is now set if (cursor_count == 0) return 1; uint16_t cnt = cursor_count; if (cnt > 100) cnt = 100; if (logSend ('>', this,0xC581, true)) printf("%32s\n", hash_bin2hex(hash)); size_t len, LEN = len = 6 + 18 + cnt * 12; unsigned char *buf, *BUF = buf = reinterpret_cast(alloca (LEN)); ADD_U1 (&buf, &len, OP_EMULEPROT); ADD_U4 (&buf, &len, LEN - 5); ADD_U1 (&buf, &len, OP_ANSWERSOURCES); ADD_HASH(&buf, &len, hash); ADD_U2 (&buf, &len, cnt); do { const struct eSources *s = Source_ip (files->ip); uint16_t new_port = 4662; if (s != NULL) new_port = s->port; ADD_U4(&buf, &len, files->ip.s_addr); ADD_U2(&buf, &len, new_port ); ADD_U4(&buf, &len, this_ip.s_addr); ADD_U2(&buf, &len, pref.ports.server); files = nextFile(hash, false); cnt--; if (files == NULL && cnt != 0) { printf("rest count %i\n", cnt); ASSERT(files != NULL || cnt == 0); } } while (cnt > 0); Write (BUF, LEN); if(logSend ('>', this,0xC582, true)) printf("%32s\n", hash_bin2hex(hash)); return 1; }}} int sSource::D4_res_sources (sPacket *packet) {{{ // (0x82) unsigned long cnt = packet->Unused(); unsigned long size = cnt * 10 + 300; unsigned char *buf = reinterpret_cast(alloca (size)); Bytef* in = reinterpret_cast(packet->DATA()); int ret = uncompress (reinterpret_cast(buf), &size, in, cnt); ASSERT (size <= cnt * 10 + 300); if (cnt != size) { printf("WARNING 1041 (%lu , %lu)\n", size, cnt); return 0; } if (ret != Z_OK) {{{ switch(ret) { case Z_MEM_ERROR: printf("%s %i Z_MEM_ERROR\n", __FILE__, __LINE__); ASSERT(0); return 0; case Z_BUF_ERROR: // Zu wenig buffer printf("%s %i Z_BUF_ERROR\n", __FILE__, __LINE__); return 0; case Z_DATA_ERROR: // Falsche daten printf("%s %i Z_DATA_ERROR\n", __FILE__, __LINE__); return 0; case Z_NEED_DICT: printf("%s %i Z_NEED_DICT\n", __FILE__, __LINE__); return 0; default : printf("%s %i %i\n", __FILE__, __LINE__, ret); ASSERT(0); return 0; } }}} logSend ('<', this,0xD482, false); res_sources (this, buf, size); return 1; }}} int sSource::C5_res_sources (sPacket *packet) {{{ // (0x82) int cnt = packet->Unused(); unsigned char *buf = reinterpret_cast(alloca (cnt)); memcpy(buf, packet->DATA(), cnt); res_sources (this, buf, cnt); return 1; }}} int sSource::Donkey_emule_packed (sPacket *packet) {{{ // 0xD4 if (packet == NULL) {{{ printf("ERROR %s %i\n", __FILE__, __LINE__); return 0; }}} if (packet->Proto() != 0xD4) {{{ printf("ERROR %s %i\n", __FILE__, __LINE__); return 0; }}} switch (packet->Command ()) { case 0x82 : return D4_res_sources (packet); default : break; } packet->Dump (); return 0; }}} int sSource::Donkey_emule (sPacket *packet) {{{ // 0xC5 if (packet == NULL) {{{ printf("ERROR %s %i\n", __FILE__, __LINE__); return 0; }}} if (packet->Proto() != OP_EMULEPROT) {{{ printf("ERROR %s %i\n", __FILE__, __LINE__); return 0; }}} switch (packet->Command ()) { case 0x01 : return C5_client_info (packet); case 0x02 : return C5_client_info (packet); case 0x40 : return C5_compressed_data (packet); case 0x60 : return C5_res_rang (packet); case 0x61 : return C5_rating (packet); case 0x81 : return C5_req_sources (packet); case 0x82 : return C5_res_sources (packet); default : break; } packet->Dump (); return 0; }}} int sSource::Donkey_client (sPacket *packet) {{{ // OP_EDONKEYHEADER if (packet == NULL) {{{ printf("ERROR %s %i\n", __FILE__, __LINE__); return 0; }}} if (packet->Proto() != OP_EDONKEYHEADER) {{{ printf("ERROR %s %i\n", __FILE__, __LINE__); return 0; }}} switch (packet->Command ()) { case 0x01 : return REQ_client_info (packet); case 0x1D : return 1; // Chat it deprecated case 0x46 : return RES_part_data (packet); case 0x47 : return REQ_part_data (packet); case 0x48 : return RES_no_such_file (packet); case 0x49 : return RES_dl_ende (packet); case 0x4A : return REQ_shared_files (packet); case 0x4B : return RES_shared_files (packet); case 0x4C : return RES_client_login (packet); case 0x4D : return RES_changed_server(packet); case 0x4E : return RES_source_message(packet); case 0x4F : return REQ_status (packet); case 0x50 : return RES_status (packet); case 0x51 : return REQ_part_hash (packet); case 0x52 : return RES_part_hash (packet); case 0x54 : return REQ_slot (packet); case 0x55 : return RES_slot_avail (packet); case 0x56 : return RES_slot_release (packet); case 0x57 : return RES_slot_close (packet); case 0x58 : return REQ_fileName (packet); case 0x59 : return RES_fileName (packet); case 0x5B : return RES_5b_unknown (packet); case 0x5C : return RES_5c_unknown (packet); default : break; } packet->Dump (); return 0; }}} // }}} void sSource::readWork (void) {{{ switch (READ->Proto()) { case 0xE3: Donkey_client (READ); break; // OP_EDONKEYHEADER case 0xC5: Donkey_emule (READ); break; case 0xD4: Donkey_emule_packed (READ); break; default : printf("Client %15s:%5u\n", inet_ntoa(peer_ip), peer_port); READ->Dump (); break; } READ->readReset(); if (last_code != 0) Work(); }}} void sSource::Work (void) {{{ // Only Called if fd!=INVALID_SOCKET if (16 == (16 & mask)) return; if (connected == 0) { if (currentTime - since > 60) Close(); return; } if (dl_next_event < currentTime && last_code == 0) {{{ if (last_send + 60 > currentTime) goto no_timeout; if (last_read + 60 > currentTime) goto no_timeout; if (status == WAIT_HELLO && currentTime - last_conn < 20 ) goto no_timeout; if (status == WAIT_HELLO && currentTime - last_read < 20 ) goto no_timeout; if (status == WAIT_INFO ) { Close(); return; } if (status == WAIT_HELLO) { Close(); return; } if (status == REQ_SLOT ) { Close(); return; } if (status == WAIT_OFFER_FILE ) { Close(); return; } // if (status == WAIT_HELLO) { status = UNUSED; printf("Hello %15s\n", inet_ntoa(peer_ip)); return; } // if (status == WAIT_INFO ) { status = UNUSED; printf("info %15s\n", inet_ntoa(peer_ip)); return; } // if (status != 12) // if (status != 8) if (status == FTP_AKTIVE ) { dl_next_event = currentTime + 10; goto no_timeout; } if (status == WAIT_SLOT ) { Close(); return; } if (status == 8) { Close(); return; } printf("TIMEOUT %15s source timeout=> status %3i since connect %li\n", inet_ntoa(peer_ip), status, currentTime - last_conn); // dl_next_event = currentTime + 10; }}} no_timeout: if (status == 2 && last_code == 0) return; // Wait for info but got nothing bool use_all = true; int next_extra = 0; if (status == UNUSED) { printf("Close source %15s because of unused\n", inet_ntoa(peer_ip)); Close(); return; } if (0 > last_code) {{{ printf("UNUSE 1 sSource %15s %s %i\n",inet_ntoa(peer_ip),__FILE__,__LINE__); status = UNUSED; return; }}} // DL handling {{{ if (OP_ACCEPTUPLOADREQ == last_code) { last_code = 0; have_slot = true; } if (OP_CANCELTRANSFER == last_code) { last_code = 0; extra_status = 0; } if (OP_OUTOFPARTREQS == last_code) { last_code = 0; req_slot (); } if (status == P_C5060 && have_slot) status = WAIT_SLOT; // if (have_slot && status != 13 && status != 7 && status!=6) printf("%15s STATUS with slot %i\n", inet_ntoa(peer_ip), status); // if (last_code==1) printf("%15s status on code 1 => %i\n", inet_ntoa(peer_ip), status); switch (status) { case P_C5060 : if (last_code == OP_QUEUERANK) last_code = 0; status = WAIT_SLOT; break; // Wait for 0x55 case SEND_HELLO : client_info(0x01); status = WAIT_INFO; dl_next_event = currentTime + dlTimeout_hello; break; case WAIT_HELLO : if (0x01 != last_code) break; last_code=0; status = WAIT_INFO; client_info(0x4C); goto get_info; case FTP_AKTIVE : // wait for file blocks if (OP_SENDINGPART == last_code) {{{ dl_next_event = currentTime + dlTimeout_data; last_code = 0; }}} if (OP_QUEUERANK == last_code) {{{ last_code = 0; status = P_C5060; break; }}} break; case WAIT_OFFER_FILE: if (OP_QUEUERANK == last_code) {{{ last_code = 0; status = P_C5060; break; }}} if (dl_file == NULL) break; last_code = 0; request_file: ASSERT(dl_file != NULL); if (!PartInfo()) { if (ask_info) break; { FILE_LIST { if (akt->status == ALL_DONE || akt->Pause() ) continue; use_all = false; if (eMule) req_fileName (akt->hash); req_file_status (akt->hash); } } ask_info = true; break; } recvData = true; if (!dl_file->havePartHash()) req_part_hash(dl_hash); if (!req_part_data()) {{{ // no more blocks avail tHash new_hash; bzero (new_hash, HASH_LEN); dlFile(new_hash); // We got maybe in the meantime the part // And he maybe have another block we can use goto get_info; }}} dl_next_event = currentTime + dlTimeout_data; break; case WAIT_INFO : if (0x4C != last_code) break; last_code = 0; get_info: use_all = true; if (tcp_server != NULL) if (tcp_server->peer_ip.s_addr == peer_ip.s_addr) break; if (!auto_select) {{{ { FILE_LIST { if (akt->status == ALL_DONE || akt->Pause() ) continue; if (NULL == File_idx (akt->hash, peer_ip)) continue; use_all = false; if (eMule) req_fileName (akt->hash); req_file_status (akt->hash); } } if (use_all) { FILE_LIST { if (akt->status == ALL_DONE || akt->Pause() ) continue; use_all = false; if (eMule) req_fileName (akt->hash); req_file_status (akt->hash); } } ask_info = true; auto_select = use_all; }}} dl_next_event = currentTime + dlTimeout_fileinfo; status = REQ_SLOT; case REQ_SLOT : if (OP_QUEUERANK == last_code && !have_slot) {{{ status = P_C5060; last_code = 0; dl_next_event = currentTime + 60; break; }}} dl_next_event = currentTime + 60; if (dl_file == NULL) { if (have_slot) Close(); break; } if (!have_slot) {{{ req_slot (); dl_next_event = currentTime + 60; status = WAIT_SLOT; break; }}} case WAIT_SLOT : dl_next_event = currentTime + 180; status = WAIT_SLOT; if (0XC540 == last_code) {{{ // resPartData (etwas komisch) last_code = 0; break; }}} if (OP_QUEUERANK == last_code) {{{ // infRank last_code = 0; dl_next_event = currentTime + 60; status = P_C5060; break; }}} if (!have_slot) break; if (dl_file == NULL) goto get_info; dl_next_event = currentTime + dlTimeout_fileinfo; status = WAIT_OFFER_FILE; goto request_file; default : break; } // }}} // ul Status handling {{{ if (0xC550 == last_code && (status == FTP_AKTIVE || status == REQ_SLOT || status == WAIT_HELLO)) last_code = 0; if (last_code != 0) { printf("Last STATUS %i %#X <---------------------------------\n", status, last_code); last_code = 0; } if (extra_status <= 0) return; if (ul_next_event > currentTime) return; switch (extra_status) { case 0x46 : if (ul_rang > 0) return; ul_next_event = currentTime + 10; if (ul_left < 2 * 1024) { next_extra = OP_SENDINGPART; break; } if (dlCount + ratio + 128 * 1024 < ulCount && ul_left < 8 * 1024 && global_ul_count * 10 < global_dl_count) { next_extra = OP_SENDINGPART; break; } if (1 == res_part_data ()) next_extra = OP_SENDINGPART; else next_extra = OP_OUTOFPARTREQS; break; case 0x4B : break; // Shared files not longer supported case 0x52 : if (ulFile() == NULL) break; if (!ulFile()->havePartHash ()) break; res_part_hash(); break; case 0x55 : if (ul_rang == 1000) { ul_rang = ulRang; if (ulRang<990) ulRang++; } if (ul_rang <= 0) { ul_rang = 0; ul_next_event = currentTime + 10; CMD_slot_available (); return; } ul_next_event = currentTime + 60; next_extra = OP_ACCEPTUPLOADREQ; C5_res_rang (ul_rang); break; case 0x57 : res_slot_close (); break; default : break; } extra_status = next_extra; // }}} }}} /* * vim600: fdm=marker */