#include "cygwin.h" #include "donkey.h" #include "sServer.h" #include "sSource.h" #include "sSocket.h" #include "sGui.h" #include "misc.h" #include "protocol.h" #include "sFile.h" #include "sPacket.h" #include "sTag.h" #include "opcodes.h" #include "db_macro.h" #ifdef DIPL_LOG #include "CentralLog.h" extern class ServerLogClass *ServerLog; #endif unsigned int sServer::to_me = 0; unsigned int sServer::count = 0; class sServer *sServer::first_Server = NULL; unsigned int limit_sources = 8; unsigned int limit_server = 8; const char *sServer::Statusname (void) {{{ switch(status) { case NEU : return "NEU"; case NOT_LOGIN : return "NOT_LOGIN"; case INVALID_ID : return "INVALID_ID"; case SEND_FILE_LIST : return "SEND_FILE_LIST"; case REQUEST_NEXT_200 : return "REQUEST_NEXT_200"; case REQ_SERVER : return "REQ_SERVER"; case UNUSED_SERVER : return "UNUSED_SERVER"; case ID_CHANGED : return "ID_CHANGED"; case SEARCH : return "SEARCH"; case READY_SERVER : return "READY_SERVER"; case SERVER_CLOSED : return "SERVER_CLOSED"; case WAIT_SERVER_LIST : return "WAIT_SERVER_LIST"; case WAIT_SOURCES : return "WAIT_SOURCES"; case SEARCH_USER : return "SEARCH_USER"; case SEARCH_FILE : return "SEARCH_FILE"; case WAIT_LOGIN : return "WAIT_LOGIN"; case WAIT_REQUEST : return "WAIT_REQUEST"; default : return "unknown"; } }}} uint32_t client_id = 0; /// cDonkey server part: this constructor is used for creating new connections /// to other clients which connect to this server. sServer:: sServer (class cSocket *FD_new, struct in_addr, uint16_t) : sSocket(FD_new) {{{ next_Server = first_Server; // only add where we are the server first_Server = this; Type = tServer; count++; my_id = peer_ip.s_addr; last_file = NULL; last_code = 0; status = WAIT_LOGIN; to_me++; isServer = true; if (mask != 0) doWork(mask); #ifdef DIPL_LOG SelfLog = new ClientLogClass(ServerLog, this); #else SelfLog = NULL; memcpy(the_others_hash, ZERO, 16); the_others_name = NULL; the_others_version = 0; the_others_listening_port = 0; ASSERT(the_others_listening_port == 0 && the_others_version == 0 && the_others_name == NULL && SelfLog == NULL && 0 == memcmp(the_others_hash, ZERO, 16)); #endif }}} sServer:: sServer (in_addr ip, unsigned short PORT) : sSocket(ip, PORT) {{{ next_Server = NULL; // We only connect to one server next_search = 0; Type = tServer; count++; my_id = 0; isServer = false; last_file = NULL; last_code = 0; status = NOT_LOGIN; if (mask != 0) doWork(mask); SelfLog = NULL; memcpy(the_others_hash, ZERO, 16); the_others_name = NULL; the_others_version = 0; the_others_listening_port = 0; ASSERT(the_others_listening_port == 0 && the_others_version == 0 && the_others_name == NULL && SelfLog == NULL && 0 == memcmp(the_others_hash, ZERO, 16)); }}} sServer::~sServer (void) {{{ #ifdef DIPL_LOG delete SelfLog; if (the_others_name) free(the_others_name); #endif actionServer (peer_ip, 0); // Frühestens nach 10 min Wiederverwenden if (tcp_server == this) tcp_server = NULL; if (last_file != NULL) Free2 (last_file); count--; if (isServer) to_me--; // remove me from the file_list if (first_Server == NULL) return; if (first_Server == this) { first_Server = next_Server; return; } sServer *prev_file = first_Server; while (prev_file->next_Server != this && prev_file->next_Server != NULL) prev_file = prev_file->next_Server; ASSERT (prev_file != NULL); if (prev_file->next_Server != this) return; prev_file->next_Server = prev_file->next_Server->next_Server; }}} // (TM) /// Returns a pointer to the member variable the_others_name, which might be /// "unclean", but works. char *sServer::GetUserName() {{{ return the_others_name; }}} /// Returns a pointer to the member variable the_others_hash, which also might /// be unclean, but - as well - works. void sServer::GetUserHash(tHash *hash) {{{ memcpy(hash, &the_others_hash, 16); }}} /// Returns the client's version int sServer::GetUserVersion() {{{ return the_others_version; }}} /// Returns the port the other listens on for incoming connections. Might (!) be useful. int sServer::GetUserListeningPort() {{{ return the_others_listening_port; }}} bool sServer::searchFile (const char *name) {{{ if (name == NULL) return false; if (last_file != NULL) { if (0 == strcmp (last_file, name)) return false; Free2 (last_file); } last_file = STRDUP (name); return true; }}} unsigned int sServer::getID (void) const { return my_id; } void sServer::setID (unsigned int id) {{{ my_id = id; if (htonl(id) >= LOW_ID) { struct in_addr ip; ip.s_addr = id; cSocket::setLocalExternalIP(ip); } }}} const char *sServer::lastFile (void ) const { return last_file; } int sServer::CMD_client_info_server (void ) {{{ // (0x01) ASSERT (client_name != NULL); logSend ('>', this, OP_LOGINREQUEST, false); size_t len, LEN = len = 46 + strlen(client_name); unsigned char *buf, *BUF = buf = reinterpret_cast(alloca (LEN)); ADD_U1 (&buf, &len, OP_EDONKEYHEADER); ADD_U4 (&buf, &len, LEN - 5); ADD_U1 (&buf, &len, OP_LOGINREQUEST); ADD_HASH (&buf, &len, client_hash); // client_hash ADD_U4 (&buf, &len, 0); // ?? ADD_U2 (&buf, &len, pref.ports.client); // port ADD_U4 (&buf, &len, 2); // into_count // add_intTag (&buf, &len, CT_VERSION , my_version); add_intTag (&buf, &len, CT_VERSION , 61); add_strTag (&buf, &len, ST_SERVERNAME, client_name); // size: 3+1+2+strlen(client_name) // add_intTag (&buf, &len, CT_PORT , pref.ports.client); ASSERT(len == 0); Write (BUF, LEN); return 1; }}} int sServer::CMD_req_server_list (void ) {{{ // (0x14) logSend ('>', this, OP_GETSERVERLIST, 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 - 5); ADD_U1 (&buf, &len, OP_GETSERVERLIST); ASSERT(len == 0); Write (BUF, LEN); return 1; }}} int sServer::CMD_files_offer (void ) {{{ // (0x15) logSend ('>', this, OP_OFFERFILES, false); unsigned int file_count = 0; size_t size = 0; { FILE_LIST { // some stupid compile make the for declaration global file_count ++; const char *name = akt->Name(); size += 40 + strlen (name); } } size_t len, LEN = len = 6 + 4 + size; unsigned char *buf, *BUF = buf = reinterpret_cast(alloca (LEN)); ADD_U1 (&buf, &len, OP_EDONKEYHEADER); ADD_U4 (&buf, &len, LEN - 5); ADD_U1 (&buf, &len, OP_OFFERFILES); ADD_U4 (&buf, &len, file_count); { FILE_LIST { // some stupid compile make the for declaration global ADD_HASH(&buf, &len, akt->hash); ADD_U4 (&buf, &len, 0); ADD_U2 (&buf, &len, 0); ADD_U4 (&buf, &len, 2); add_strTag (&buf, &len, FT_FILENAME, akt->Name()); // size: 3+1+2+strlen(client_name) add_intTag (&buf, &len, FT_FILESIZE, akt->Size()); } } ASSERT(len == 0); Write (BUF, LEN); return 1; }}} int sServer::CMD_search4gui (const class sGui *gui ) {{{ // (0x16) ASSERT (gui!=NULL); logSend ('>', this, OP_SEARCHREQUEST, false); size_t len, LEN = len = 6 + gui->searchLen(); unsigned char *buf, *BUF = buf = reinterpret_cast(alloca (LEN)); ADD_U1 (&buf, &len, OP_EDONKEYHEADER); ADD_U4 (&buf, &len, LEN - 5); ADD_U1 (&buf, &len, OP_SEARCHREQUEST); memcpy (buf, gui->searchTree(), len); Write (BUF, LEN); return 1; }}} int sServer::CMD_suche_filename (const char *name ) {{{ // (0x16) ASSERT (name!=NULL); logSend ('>', this, OP_SEARCHREQUEST, false); size_t len, LEN = len = 6 + 3 + strlen(name); unsigned char *buf, *BUF = buf = reinterpret_cast(alloca (LEN)); ADD_U1 (&buf, &len, OP_EDONKEYHEADER); ADD_U4 (&buf, &len, LEN - 5); ADD_U1 (&buf, &len, OP_SEARCHREQUEST); ADD_U1 (&buf, &len, 1); ADD_S2 (&buf, &len, name); ASSERT(len == 0); Write (BUF, LEN); return 1; }}} int sServer::CMD_suche_download (const tHash &hash ) {{{ // (0x19) ASSERT (hash!=NULL); if (logSend ('>', this, OP_GETSOURCES, true)) printf("%32s\n", hash_bin2hex(hash)); printf("%32s\n", hash_bin2hex(hash)); size_t len, LEN = len = 6 + 16; unsigned char *buf, *BUF = buf = reinterpret_cast(alloca (LEN)); ADD_U1 (&buf, &len, OP_EDONKEYHEADER); ADD_U4 (&buf, &len, LEN - 5); ADD_U1 (&buf, &len, OP_GETSOURCES); ADD_HASH (&buf, &len, hash); ASSERT(len == 0); Write (BUF, LEN); return 1; }}} int sServer::CMD_suche_user (const char *name ) {{{ // (0x1A) unused currently ASSERT (name!=NULL); logSend ('>', this, OP_SEARCH_USER, false); size_t len, LEN = len = 6 + strlen (name) + 3; unsigned char *buf, *BUF = buf = reinterpret_cast(alloca (LEN)); ADD_U1 (&buf, &len, OP_EDONKEYHEADER); ADD_U4 (&buf, &len, LEN - 5); ADD_U1 (&buf, &len, OP_SEARCH_USER); ADD_U1 (&buf, &len, 1); ADD_S2 (&buf, &len, name); ASSERT(len == 0); Write (BUF, LEN); return 1; }}} int sServer::CMD_get_client_info (uint32_t idx ) {{{ // (0x1C) unused currently logSend ('>', this, OP_CALLBACKREQUEST, false); size_t len, LEN = len = 6 + 4; unsigned char *buf, *BUF = buf = reinterpret_cast(alloca (LEN)); ADD_U1 (&buf, &len, OP_EDONKEYHEADER); ADD_U4 (&buf, &len, LEN - 5); ADD_U1 (&buf, &len, OP_CALLBACKREQUEST); ADD_U4 (&buf, &len, idx); ASSERT(len == 0); Write (BUF, LEN); return 0; }}} int sServer::CMD_req_next_200 (void ) {{{ // (0x21) logSend ('>', this, OP_QUERY_MORE_RESULT, 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 - 5); ADD_U1 (&buf, &len, OP_QUERY_MORE_RESULT); ASSERT(len == 0); Write (BUF, LEN); return 1; }}} /// cDonkey server part member function: sends a serverlist to the requesting /// caller. /// DO NOT confuse this with sServer::res_server_list(class sPacket *)! int sServer::res_server_list (void ) {{{ // (0x32) struct in_addr ip; uint16_t port; if (limit_server > 255) limit_server = 255; uint8_t cnt = (limit_server); logSend ('>', this, OP_SERVERLIST, false); size_t len, LEN = len = 6 + 1 + cnt * 6; unsigned char *buf, *BUF = buf = reinterpret_cast(alloca (LEN)); ADD_U1 (&buf, &len, OP_EDONKEYHEADER); ADD_U4 (&buf, &len, LEN - 5); ADD_U1 (&buf, &len, OP_SERVERLIST); ADD_U1 (&buf, &len, cnt); for (;cnt > 0;cnt--) { nextServer (&ip, &port); ADD_U4 (&buf, &len, ip.s_addr); ADD_U2 (&buf, &len, port); } ASSERT(len == 0); #ifdef DIPL_LOG SelfLog->LogTcpOut(OP_SERVERLIST, LEN); #endif Write (BUF, LEN); return 0; }}} int sServer::CMD_callback (in_addr ip, uint16_t port) {{{ // (0x35) logSend ('>', this, OP_CALLBACKREQUESTED, false); size_t len, LEN = len = 6 + 6; unsigned char *buf, *BUF = buf = reinterpret_cast(alloca (LEN)); ADD_U1 (&buf, &len, OP_EDONKEYHEADER); ADD_U4 (&buf, &len, LEN - 5); ADD_U1 (&buf, &len, OP_CALLBACKREQUESTED); ADD_U4 (&buf, &len, ip.s_addr); ADD_U2 (&buf, &len, port); ASSERT(len == 0); Write (BUF, LEN); return 1; }}} int sServer::CMD_callback_failed (void ) {{{ // (0x36) logSend ('>', this, OP_CALLBACK_FAIL, 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 - 5); ADD_U1 (&buf, &len, OP_CALLBACK_FAIL); ASSERT(len == 0); Write (BUF, LEN); return 1; }}} /// cDonkey server part function: sends new ID to the new client. /// DO NOT confuse this with sServer::res_change_id(class sPacket *)! int sServer::res_change_id (void ) {{{ // (0x40) logSend ('>', this, OP_IDCHANGE, false); size_t len, LEN = len = 6 + 4; unsigned char *buf, *BUF = buf = reinterpret_cast(alloca (LEN)); ADD_U1 (&buf, &len, OP_EDONKEYHEADER); ADD_U4 (&buf, &len, LEN - 5); ADD_U1 (&buf, &len, OP_IDCHANGE); ADD_U4 (&buf, &len, getID ()); ASSERT(len == 0); Write (BUF, LEN); #ifdef DIPL_LOG SelfLog->LogTcpOut(OP_IDCHANGE, LEN); #endif return 1; }}} /// cDonkey server part member function: searches for a given hash value in the server's /// file database and sends the results back to the caller. /// @param hash the hash value to be searched int sServer::CMD_res_sources (const tHash &hash ) {{{ // (0x42) const struct eFiles *files = nextFile(hash, true); // cursor_count is now set #ifdef DIPL_LOG SelfLog->LogSrcSearch(hash, cursor_count); #endif if (cursor_count == 0) return 1; uint32_t cnt = cursor_count; if (cnt > limit_sources ) cnt = limit_sources; if (cnt > 255 ) cnt = 255; if(logSend ('>', this, OP_FOUNDSOURCES, true)) printf("%32s (%i)\n", hash_bin2hex(hash), cnt); size_t len, LEN = len = 6 + 16 + 1 + cnt * 6; unsigned char *buf, *BUF = buf = reinterpret_cast(alloca (LEN)); ADD_U1 (&buf, &len, OP_EDONKEYHEADER); ADD_U4 (&buf, &len, LEN - 5); ADD_U1 (&buf, &len, OP_FOUNDSOURCES); ADD_HASH (&buf, &len, hash); ADD_U1 (&buf, &len, (cnt)); do { const struct eSources *s = Source_ip (files->ip); uint16_t port = 4662; if (s != NULL) port = s->port; cnt--; ADD_U4(&buf, &len, files->ip.s_addr); ADD_U2(&buf, &len, port); files = nextFile(hash, false); ASSERT(files != NULL || cnt == 0); } while(cnt>0); ASSERT(len == 0); Write (BUF, LEN); return 1; }}} /// cDonkey server part member function: handler for hello messages (0x01) int sServer::REQ_server_info (sPacket *packet) {{{ // (0x01) logSend ('<', this, OP_LOGINREQUEST, false); unsigned int old_id; uint16_t port; Code(OP_LOGINREQUEST); #ifndef DIPL_LOG tHash hash; packet->GET_HASH(hash); #else packet->GET_HASH(the_others_hash); #endif old_id = packet->GET_U4 (); // user->idx_old port = packet->GET_U2 (); // user->port class sTag *tag = parseTag (packet); if (tag == NULL) return 0; #ifdef DIPL_LOG if (tag->name != NULL) the_others_name = strdup(tag->name); if (tag->version != 0) the_others_version = tag->version; if (tag->port != 0) the_others_listening_port = tag->port; #endif delete tag; res_change_id (); // old_id = packet->GET_U4 (); return 0; }}} int sServer::RES_unwanted (sPacket * ) {{{ // (0x05) (log.info) logSend ('<', this, OP_REJECT, false); delServer (peer_ip, 0, -4); Close(); return 0; }}} ///cDonkey server part member function: handler for request serverlist messages (0x14) int sServer::REQ_serverList (sPacket *packet) {{{ // (0x14) (log.info) logSend ('<', this, OP_GETSERVERLIST, false); if (packet == NULL) return 0; res_server_list (); return 1; }}} ///cDonkey server part member function: handler for offer files messages (0x15) int sServer::RES_offerFiles (sPacket *packet) {{{ // (0x15) logSend ('<', this, OP_OFFERFILES, false); ASSERT (packet!= NULL); int cnt = packet->GET_U4(); while (--cnt >= 0) { tHash hash; packet->GET_HASH(hash); packet->GET_U4 (); packet->GET_U2 (); unsigned char *start = packet->DATA(); class sTag *tag = parseTag (packet); // tag->name, tag->size holding filename/-size // Name speicher delete tag; unsigned char *ende = packet->DATA(); printf("Got file info_lei = %i\n", ende - start); insertFiles (hash, peer_ip, ende - start, start); } return 1; }}} /// cDonkey server part member function: handler for query sources messages (0x19) int sServer::REQ_sources (sPacket *packet) {{{ // (0x19) logSend ('<', this, OP_GETSOURCES, false); if (!res_server_sources) return 1; ASSERT (packet!= NULL); tHash hash; packet->GET_HASH(hash); printf("search for hash: %32s\n", hash_bin2hex(hash)); CMD_res_sources (hash); return 1; }}} int sServer::RES_server_list (sPacket *packet) {{{ // (0x32) (log.info) logSend ('<', this, OP_SERVERLIST, false); if (packet == NULL) return 0; Code (OP_SERVERLIST); int cnt = packet->GET_U1 (); while (--cnt >= 0) { struct in_addr ip; ip.s_addr = packet->GET_U4 (); uint16_t port = packet->GET_U2 (); if (port == 4665) port = 4661; if (htonl(ip.s_addr) <= 0x00FFFFFF) printf("zero Server at %i\n", cnt); else saveServer (ip, port, 0, 0, false); } return 0; }}} int sServer::RES_search (sPacket *packet) {{{ // (0x33) logSend ('<', this, OP_SEARCHRESULT, false); if (packet == NULL) return 0; struct in_addr ip; GUI_LIST {{{ if (akt->searchLen() > 0) { uint32_t len = packet->Length() - 1; if (len > 0) { char *tree = reinterpret_cast(MALLOC (len)); memcpy (tree, packet->DATA(), len); akt->resultTree (tree, len); akt->TCP_Response (); akt->GUI_result_tcp (); } } }}} int cnt = packet->GET_U4 (); unsigned int COUNT = cnt; Code((COUNT >= 200)?0x0133:0x0033); printf("Count %u\n", cnt); while (cnt-->0) {{{ tHash hash; log (2,"Found file: (%i)\n", (COUNT-cnt)); packet->GET_HASH(hash); ip.s_addr = packet->GET_U4 (); uint16_t port = packet->GET_U2 (); log (2,"Found file: (%3i) - Client: %15s : %5u\n",(COUNT-cnt),inet_ntoa (ip), port); unsigned char *start = packet->DATA(); class sTag *tag = parseTag (packet); if (tag == NULL) return 0; // if (tag->name != NULL && tag->size != 0) // printf ("ed2k://|file|%s|%u|%s|\n", tag->name, tag->size, hash_bin2hex (hash)); delete tag; unsigned char *ende = packet->DATA(); printf("Got file info_len = %i\n", ende - start); insertFiles (hash, peer_ip, ende - start, start); }}} return 1; }}} int sServer::RES_online_stat (sPacket *packet) {{{ // (0x34) (log.statistik) logSend ('<', this, OP_SERVERSTATUS, false); if (packet == NULL) return 0; unsigned int user = packet->GET_U4 (); unsigned int files = packet->GET_U4 (); saveServer (peer_ip, 0, files, user, false); return 0; }}} int sServer::RES_connect_req (sPacket *packet) {{{ // (0x35) // Solte in warteschleife if (packet == NULL) return 0; struct in_addr ip; uint16_t port; ip.s_addr = packet->GET_U4 (); port = packet->GET_U2 (); if (!IP_is_OK (ip)) return true; if(logSend ('<', this, OP_CALLBACKREQUESTED, true)) printf("%15s:%5u\n", inet_ntoa(ip), port); if (ip.s_addr == htonl(0x7F000001) && port == pref.ports.client) return 1; if (htonl(ip.s_addr) < LOW_ID) { printf("LOW ID init callback\n"); return 0; } tHash hash; bzero (hash, 16); new sSource (ip, port); addSource (ip, port, 0x00000000); return 1; }}} int sServer::RES_server_message (sPacket *packet) {{{ // (0x38) (log.info) KEINE STATUS ÄNDERUNG logSend ('<', this, OP_SERVERMESSAGE, false); if (packet == NULL) return 0; char *msg = packet->GET_S2 (); size_t len = 21 + strlen(msg); char *buf = reinterpret_cast(alloca (len)); snprintf(buf, len, "%15s => %s\n", inet_ntoa(peer_ip), msg); bool gui = false; GUI_LIST { gui = true; akt->GUI_statusMessage(buf); } if (!gui) if (logSend ('<', this, OP_SERVERMESSAGE, true)) printf("%s\n", msg); Free2 (msg); return 1; }}} int sServer::RES_change_id (sPacket *packet) {{{ // (0x40) logSend ('<', this, OP_IDCHANGE, false); if (packet == NULL) return 0; setID (packet->GET_U4 ()); Code (OP_IDCHANGE); return 1; }}} int sServer::RES_version (sPacket *packet) {{{ // (0x41) KEINE STATUS ÄNDERUNG logSend ('<', this, OP_SERVERIDENT, false); ASSERT (packet!= NULL); tHash hash; struct in_addr ip; uint16_t port; packet->GET_HASH(hash); ip.s_addr = htonl (packet->GET_U4 ()); port = htons (packet->GET_U2 ()); class sTag *tag = parseTag (packet); if (tag == NULL) { packet->Dump(); return 0; } if (tag->name != NULL) { setServer_name (ip, port, tag->name); GUI_LIST akt->GUI_connected_to (tag->name); printf("Successfull TCP-Server Connection to %s\n", tag->name ); } if (tag->desc != NULL) setServer_desc (ip, port, tag->desc); delete tag; return 1; }}} int sServer::RES_sources (sPacket *packet) {{{ // (0x42) wird in die auptschleife verschoen (sSource) tHash hash; packet->GET_HASH(hash); int cnt = packet->GET_U1 (); if (logSend ('<', this, OP_FOUNDSOURCES, true)) printf ("%32s (%3i)\n", hash_bin2hex(hash), cnt); sFile *akt_file = forHash(hash); // ONLY if the response are for the wrong file !!! while (--cnt >= 0) { unsigned int IDX = packet->GET_U4 (); unsigned short PORT = packet->GET_U2 (); struct in_addr ip; ip.s_addr = IDX; if (htonl(IDX) > LOW_ID) { ip.s_addr = IDX; addSource(ip, PORT, 0x00000000, true); insertFiles (hash, ip, 0, NULL); } else CMD_callback(ip, PORT); } if (akt_file != NULL) if ( akt_file->status != ALL_DONE ) akt_file->Status (SOURCE_KNOWN); return 0; }}} int sServer::RES_search_user (sPacket *packet) {{{ // (0x43) Erzeugt neues sfile Object !!! logSend ('<', this, OP_USERS_LIST, false); ASSERT (packet!= NULL); struct in_addr ip; tHash hash; int cnt = packet->GET_U4 (); unsigned int COUNT = cnt; printf("Count %u\n", cnt); while (--cnt >= 0) { printf("Found file: (%i)\n", (COUNT-cnt)); packet->GET_HASH(hash); printf("- Hash : %s\n", hash_bin2hex (hash)); // Server hash ip.s_addr = packet->GET_U4 (); printf("- Client: %s\n", inet_ntoa (ip)); // server ip printf("- Port: %u\n", packet->GET_U2 () ); // server port class sTag *tag = parseTag (packet); if (tag == NULL) return 0; if (tag->name != NULL) { printf("User %s , Port %5u , Version %4u\n",tag->name, tag->port, tag->version); } delete tag; } Code (OP_USERS_LIST); return 1; }}} class cTreeSearch { public: int op; class cTreeSearch *A; class cTreeSearch *B; char *val_str; int val_int; char *key; cTreeSearch(void); ~cTreeSearch(void); bool Parse (unsigned char *data, size_t len); bool Match (void) { return false; } }; cTreeSearch:: cTreeSearch(void) {{{ op = 0xFF; A = NULL; B = NULL; val_str = NULL; val_int = 0; key = NULL; }}} cTreeSearch::~cTreeSearch(void) {{{ if (A != NULL) delete A; if (B != NULL) delete B; if (val_str != NULL) Free2 (val_str); if (key != NULL) Free2 (key ); }}} bool cTreeSearch::Parse (unsigned char *data, size_t len) {{{ while (len>0) { unsigned new_op = GET_U1 (&data, &len); switch (new_op) { case 0x01: op = new_op; val_str = GET_S2_ (&data, &len); printf("Match String %s\n", val_str); free (val_str); break; default : return false; } } return true; }}} int sServer::REQ_file_search (sPacket *packet) {{{ // (0x16) int MAX_SEARCH = 14000; cTreeSearch *search = new cTreeSearch(); bool OK = search->Parse (packet->DATA(), packet->Unused()); if (!OK) { delete search; packet->Dump (); return 0; } int err = 0; DBT key; DBT val; bzero (&key, sizeof(key)); bzero (&val, sizeof(val)); DBC *cur = NULL; DB_cursor2 (dat_idx, cur); unsigned char *buffer, *BUFFER = buffer = reinterpret_cast(alloca (MAX_SEARCH)); size_t size = MAX_SEARCH; unsigned cnt = 0; while (0 == cur->c_get (cur, &key, &val, DB_NEXT)) {{{ struct eFiles *f = reinterpret_cast(val.data); if (f->info_len == 0) continue; if (buffer + 22 + f->info_len > BUFFER + MAX_SEARCH) break; size_t ilen = f->info_len; class sTag *tag = parse_tag (f->info, &ilen); if (tag == NULL) continue; if (search->op == 1 && tag->name != NULL) if (NULL != strstr(tag->name, search->val_str)) { tHash hash; memcpy (hash, f->hash, 16); printf("MATCH (%3i) for Search %32s - %9u - %s\n", f->info_len, hash_bin2hex(hash), tag->size, tag->name); ADD_HASH(&buffer, &size, hash); ADD_U4 (&buffer, &size, 0); ADD_U2 (&buffer, &size, 0); memcpy (buffer, f->info, f->info_len); buffer += f->info_len; size -= f->info_len; cnt++; } delete tag; }}} size_t len, LEN = len = 6 + MAX_SEARCH - size + 5; unsigned char *buf, *BUF = buf = reinterpret_cast(alloca (LEN)); ADD_U1 (&buf, &len, OP_EDONKEYHEADER); ADD_U4 (&buf, &len, LEN - 5); ADD_U1 (&buf, &len, OP_SEARCHRESULT); ADD_U4 (&buf, &len, cnt); memcpy(buf, BUFFER, MAX_SEARCH - len); buf += (MAX_SEARCH - len); len -= (MAX_SEARCH - len); ADD_U1 (&buf, &len, 0); ASSERT(len == 0); Write (BUF, LEN); delete search; return 1; }}} int sServer::Donkey_server (sPacket *packet) {{{ ASSERT (packet != NULL); ASSERT (packet->Proto() == OP_EDONKEYHEADER); switch (packet->Command ()) { case 0x1D : return 1; // OP_QUERY_CHATS (depricated) case 0x1E : // OP_CHAT_MESSAGE (depricated) case 0x1F : // OP_JOIN_ROOM (depricated) case 0x39 : // OP_CHAT_ROOM_REQUEST (depricated) case 0x3A : // OP_CHAT_BROADCAST (depricated) case 0x3B : // OP_CHAT_USER_JOIN (depricated) case 0x3C : // OP_CHAT_USER_LEAVE (depricated) case 0x3D : // OP_CHAT_USER (depricated) return 1; #ifdef DIPL_LOG } // only log client requests, NOT server commands to cDonkey as a client // further do not log deprecated messages. if (packet->Command() < 0x25) SelfLog->LogTcpIn(packet); switch (packet->Command()) { #endif case 0x01 : return REQ_server_info (packet); case 0x05 : return RES_unwanted (packet); case 0x14 : return REQ_serverList (packet); case 0x15 : return RES_offerFiles (packet); case 0x16 : return REQ_file_search (packet); case 0x19 : return REQ_sources (packet); case 0x32 : return RES_server_list (packet); case 0x33 : return RES_search (packet); case 0x34 : return RES_online_stat (packet); case 0x35 : return RES_connect_req (packet); case 0x38 : return RES_server_message (packet); case 0x40 : return RES_change_id (packet); case 0x41 : return RES_version (packet); case 0x42 : return RES_sources (packet); case 0x43 : return RES_search_user (packet); default : break; } packet->Dump (); return 0; }}} void sServer::readWork (void) {{{ ASSERT(Type == tServer); if (READ->Proto() == OP_EDONKEYHEADER) Donkey_server (READ); else { READ->Dump (); ASSERT(0); } READ->readReset(); if (last_code != 0) Work(); }}} void sServer::Work (void) {{{ // only called if fd != INVALID socket static bool first_connect = true ; static time_t timeout_event = time(NULL) ;// timeout if no packet is received if (!connected) return; if (status == SERVER_CLOSED) return; if (last_code != 0) {{{ switch (status) { case ID_CHANGED : if (0x40 == last_code) last_code = 0; break; case INVALID_ID : if (0x40 == last_code) { last_code = 0; status = ID_CHANGED; } // Warte auf ID Change else { if ( currentTime - timeout_event > 120 ) { // 120 secs last_code = 0; status = SERVER_CLOSED; timeout_event = currentTime; } } break; case WAIT_SERVER_LIST : // Warte auf Server Liste first_connect = true; if (0x32 == last_code) { last_code = 0; status = SEND_FILE_LIST;} break; case WAIT_SOURCES : if (0x42 == last_code) { last_code = 0; status = READY_SERVER; } // Warte auf Source Liste else { if ( currentTime - timeout_event > 50 ) { last_code = 0; status = READY_SERVER; timeout_event = currentTime; } else printf("waiting %ld sec\n", (currentTime - timeout_event ) ); } break; case SEARCH_USER : if (0x43 == last_code) { last_code = 0; status = READY_SERVER; } break; // warte auf User Liste case SEARCH_FILE : printf("Search file last_status %2X\n", last_code); if (0x33 == last_code || 0x133 == last_code ) { last_code = 0; status = READY_SERVER; } else { printf("Waiting for search results\n"); if ( currentTime - timeout_event > 50 ) { printf("XXXX timeout. Perhaps send empty reply to GUI !\n"); last_code = 0; status = READY_SERVER; timeout_event = currentTime; } } break ; case WAIT_LOGIN : if (0x40 == last_code) { last_code = 0; status = WAIT_REQUEST; } break; default : break; } if (last_code != 0) log (1, "1 Server status %i %2X\n", status, last_code); last_code = 0; }}} if ( status != NEU && status != NOT_LOGIN && status != ID_CHANGED && status != SEND_FILE_LIST && status != READY_SERVER && status != REQUEST_NEXT_200 && status != SERVER_CLOSED && currentTime - timeout_event > 90 ) // 90 secs timeout on all status types before we do special handling last_code = 18; // TIMEOUT eServer_status switch (status) { case NEU: case NOT_LOGIN : if (!CMD_client_info_server ()) { status = SERVER_CLOSED; break; } status = INVALID_ID ; timeout_event = currentTime; break; case ID_CHANGED : CMD_files_offer (); if (CMD_req_server_list ()) { timeout_event = currentTime; status = WAIT_SERVER_LIST; } else status = SERVER_CLOSED; break; case SEND_FILE_LIST: status = READY_SERVER; break; case READY_SERVER: #if 0 // work "suche" links if (searchFile (such_file)) {{{ if (CMD_suche_filename (such_file)) status = SEARCH_FILE; else status = SERVER_CLOSED; break; }}} #endif // get tcp_server sourcen for all files if ( first_connect || next_search < currentTime) { if (sFile::count == 0) break; if (first_connect) { first_connect = false; } next_search = currentTime + 60; log (2,"TCP Server suche\n"); FILE_LIST { if (akt->get_Completed() ) continue; // looking for not completed files if (akt->Pause () ) continue; // should we delay here ? (flood) CMD_suche_download(akt->hash); status = WAIT_SOURCES; timeout_event = currentTime; } } // prevent overwrite of status flag if (tcp_search && status == READY_SERVER ) {{{ const sGui *gui = NULL; GUI_LIST if (akt->searchTree()!=NULL && akt->searchLen()>0) { gui = akt; break; } tcp_search = false; if (gui == NULL) break; if (gui->searchLen() > 0) { if (1 == CMD_search4gui (gui)) { status = SEARCH_FILE; timeout_event = currentTime; break; } } }}} break; case REQUEST_NEXT_200: CMD_req_next_200 (); status = SEARCH; break; case SERVER_CLOSED: default : break; } }}} /* * vim600: fdm=marker */