#include "cygwin.h" #include "sGui.h" #include "protocol.h" #include "sServer.h" #include "sCommand.h" #include "sFile.h" #include "donkey.h" #include "cSocket.h" #include "cServer_udp.h" #include "kademlia.h" #include "cSearchManager.h" #include "opcodes.h" #include "cHTTP.h" #include "sPacket.h" #include "sTag.h" #include "sSource.h" #ifdef DIPL_LOG #include "CentralLog.h" // object for gathering central logging data. class ServerLogClass *ServerLog; #endif #define AKT_VERSION (((0*256+0)*256+9)*256+0) // listen client {{{ class cListen_client : public cSocket { public: cListen_client(unsigned short PORT) : cSocket(PORT, SOCK_STREAM) { } virtual void Work(void); virtual int doRead_high(void) { printf("cListen_client::doRead\n"); return 0; } }; void cListen_client::Work(void) { // Only caled if fd_new != INVALID_SOCKET if (!IP_is_OK(peer_ip)) { // Do not accept anything from bad IP's resetAccept(); return; } if (tcp_server != NULL) // Accept from server always if (tcp_server->peer_ip.s_addr == peer_ip.s_addr) { new sSource (this); return; } if(sSource::count > (TCP_CLIENT_COUNT * 11) / 10) { // reject if we have to much connections resetAccept(); return; } new sSource (this); } class cListen_client *client_listen = NULL; void Client_listen (unsigned short port) { if (client_listen == NULL) client_listen = new cListen_client(port); if (!client_listen->validSocket()) { delete client_listen; client_listen = new cListen_client(port); } } /* ----------------------------------------------------------------------------------- this part handles incoming connections to the server part (in cListen_server::Work()) and sets up the server (with Server_listen) */ /// cDonkey server Part: class for listening for incoming connections to the server. class cListen_server : public cSocket { public: cListen_server(unsigned short PORT) : cSocket(PORT, SOCK_STREAM) { } virtual void Work(void); int doRead_high(void) { printf("cListen_server::doRead\n"); return 0; } }; /// Work() is called when a new client connects to the server. It creates a new /// sServer object for handling the connection void cListen_server::Work(void) { // Only called if fd_new != INVALID_SOCKET if (!IP_is_OK(peer_ip) || ( (TCP_SERVER_COUNT*13)/10 < sServer::count && peer_ip.s_addr!=tcp_server->peer_ip.s_addr)) { resetAccept(); return; } new sServer (this, peer_ip, peer_port); } class cListen_server *server_listen = NULL; /// Set up the cDonkey server socket listener. void Server_listen (unsigned short port) { #ifdef DIPL_LOG if (!ServerLog) ServerLog = new ServerLogClass(); #endif if (server_listen == NULL) server_listen = new cListen_server(port); if (!server_listen->validSocket()) { delete server_listen; server_listen = new cListen_server(port); } } /* ----------------------------------------------------------------------------------- */ // }}} // listen gui {{{ class cListen_gui : public cSocket { public: cListen_gui(unsigned short PORT) : cSocket(PORT, SOCK_STREAM) { } virtual void Work(void); int doRead_high(void) { printf("cListen_gui ::doRead\n"); return 0; } }; void cListen_gui::Work(void) { // Only caled if fd_new != INVALID_SOCKET if (connected != 2) return; log(1, "donkey.cpp: Establishing Gui connection...\n"); new sGui (this, peer_ip); } class cListen_gui *gui_listen = NULL; void Gui_listen (unsigned short port) { if (gui_listen == NULL) gui_listen = new cListen_gui(port); if (!gui_listen->validSocket()) { delete gui_listen; gui_listen = new cListen_gui(port); } } // }}} // listen command {{{ class cListen_command : public cSocket { public: cListen_command(unsigned short PORT) : cSocket(PORT, SOCK_STREAM) { } virtual void Work(void); int doRead_high(void) { printf("cListen_command:doRead\n"); return 0;} }; void cListen_command::Work(void) { // Only caled if fd_new != INVALID_SOCKET if (connected != 2) return; new sCommand (this, peer_ip, peer_port); } class cListen_command *command_listen = NULL; void Command_listen (unsigned short port) { if (command_listen == NULL) command_listen = new cListen_command(port); if (!command_listen->validSocket()) { delete command_listen; command_listen = new cListen_command(port); } } // }}} // {{{ UDP_Server listen // didn't check whether the other listeners would require constructs like // this, too -hl class cServer_udp *userver_listen = NULL; void uServer_destructed(cSocket *sock) {{{ log(1, "DEBUG: userver callback called from %p!\n", sock); if (sock == userver_listen) userver_listen = NULL; else log(1, "WARN: userver callback called from wrong object (%p).\n", sock); }}} void UServer_listen (unsigned short port) { if (userver_listen == NULL) { userver_listen = new cServer_udp(port); userver_listen->setDestructorCallback(uServer_destructed); } if (!userver_listen->validSocket()) { delete userver_listen; userver_listen = NULL; } } // }}} // {{{ UUKademlia_listen extern class cKademlia *kademlia; // new cKademlia(kademlia_port); void UKademlia_listen (unsigned short port) { if (kademlia == NULL) kademlia = new cKademlia(port); if (!kademlia->validSocket()) { delete kademlia; kademlia = NULL; return; } } // }}} // listen http {{{ class cListen_http : public cSocket { public: cListen_http (unsigned short PORT) : cSocket(PORT, SOCK_STREAM) { } virtual void Work(void); virtual int doRead_high(void) { printf("cListen_httpt::doRead\n"); return 0; } }; void cListen_http::Work(void) { // Only caled if fd_new != INVALID_SOCKET new cHTTP (this, peer_ip, peer_port); } class cListen_http *listen_http = NULL; void HTTP_listen (unsigned short port) { if (listen_http == NULL) listen_http = new cListen_http (port); if (!listen_http->validSocket()) { delete listen_http; listen_http = new cListen_http (port); } } // }}} // Please do not change this values {{{ const int UDP_SEARCH_TIMEOUT = 5; const int UDP_SEARCH_COUNT = 15; unsigned int CLIENT_COUNT = 140; unsigned int TCP_CLIENT_COUNT = 4000; unsigned int TCP_SERVER_COUNT = 200; bool running = true ; bool eMule = true ; bool use_kademlia = true ; // please do not aktivate, i try to clear with Jed #ifdef DIPL_LOG bool run_server = true; // if you JUST WANT TO HAVE A RUNNING SERVER, *please* bool res_server_sources = true; // DO NOT ENABLE LOGGING!! Changing the other values #else // is sufficient! Really :-) bool run_server = false; // <- change this bool res_server_sources = false; // <- and this #endif bool isTerm = false; // }}} void log (unsigned level, const char *msg, ...) {{{ if (0 == (pref.verbose & level)) return; va_list ap; va_start(ap, msg); vprintf(msg, ap); va_end (ap); }}} struct sPref pref; char ZERO[16]; #define PORT_BASE 4660 static void setDefaults_pref (void) {{{ pref.ports.server = PORT_BASE + 1; pref.ports.client = PORT_BASE + 2; pref.ports.gui = PORT_BASE + 3; pref.ports.clc = PORT_BASE + 4; pref.ports.emule = PORT_BASE + 5; pref.ports.kademlia = PORT_BASE + 6; pref.ports.web = PORT_BASE + 7; pref.verbose = 0; pref.ip_trash = 128; }}} unsigned my_version = 1044; long server_hopping = 1200; long server_connect = 5; double akt_rate_weight = 0.25; // 1 == akt_rate_weight + akt_rate_weight^2 + akt_rate_weight^3 int protocol_logLevel = 9; tHash client_hash = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; bool tcp_search = false; int udp_search = 0; time_t currentTime = 0; char currentTime_str [32]; class sServer *tcp_server = NULL; class cHTTP *server_http = NULL; bool go_to_background = false; // onExit free(*) // {{{ String Parameter from config file char *control = NULL; char *incoming = NULL; char *completed = NULL; char *such_file = NULL; char *ctrl_user = NULL; char *bind_ip = NULL; // should we bind to specific adress ? char *ctrl_pass = NULL; char *client_name = NULL; char *db_client = NULL; char *db_server = NULL; // }}} static void CurrentTime (void) {{{ currentTime = time (NULL); // strftime(currentTime_str, 31, "%Y.%m.%d %H:%M.%S", gmtime(¤tTime)); strftime(currentTime_str, 31, "%H:%M.%S", gmtime(¤tTime)); }}} // Windows Only Startup Code #ifdef _WIN32 // Windows Ctrl-C handler BOOL WINAPI ConsoleHandler(DWORD event) {{{ switch(event) { case CTRL_C_EVENT: case CTRL_BREAK_EVENT: case CTRL_CLOSE_EVENT: case CTRL_LOGOFF_EVENT: case CTRL_SHUTDOWN_EVENT: running = false; break; default: printf("donkey.cpp: ConsoleHandler( %X ): Unknown Console Event.\n",event); } return TRUE; }}} class CApp { public: CApp(); } g_App; CApp::CApp() {{{ if( ::SetConsoleCtrlHandler((PHANDLER_ROUTINE)ConsoleHandler,TRUE) == FALSE ) { // unable to install handler... printf("SetConsoleCtrlHandler failed: Unable to install handler!\n"); } }}} #endif // Windows #ifdef HAVE_ATEXIT void exitHandler(void) #else #ifdef HAVE_ON_EXIT void exitHandler(int sig, void*) #else void exitHandler(void) #endif #endif {{{ running = false; printf("Exiting cDonkey...\n"); manager.stopAllSearches(); while (sFile::first_file != NULL) delete sFile::first_file; if (control != NULL) Free2 (control); if (incoming != NULL) Free2 (incoming); if (completed != NULL) Free2 (completed); if (such_file != NULL) Free2 (such_file); if (ctrl_user != NULL) Free2 (ctrl_user); if (bind_ip != NULL) Free2 (bind_ip); if (ctrl_pass != NULL) Free2 (ctrl_pass); if (client_name != NULL) Free2 (client_name); if (db_client != NULL) Free2 (db_client); if (db_server != NULL) Free2 (db_server); close_Sources (); close_Servers (); ende_IP_list (); cSocket::Stop (); printf("sPacket::count => %i\n", sPacket::count); printf("sSocket::count => %i\n", sSocket::count); printf("sSource::count => %i\n", sSource::count); printf("sSource::count0=> %i\n", sSource::count0); printf("sSource::count1=> %i\n", sSource::count1); printf("cSocket::count => %i\n", cSocket::count); printf("sTag ::count => %i\n", sTag::count); }}} void sigTerm (int) {{{ printf("Signal TERM\n"); running = false; }}} void sigInt (int) {{{ printf("Signal INT\n"); exit(0); running = false; }}} void sigHup (int) {{{ printf("Signal HUP\n"); running = false; }}} static int sFile_createParthash (const char *NAME, const char *dir,tHash *hash) {{{ int ret = 0; // static_cast // reinterpret_cast char* = // const_cast char *name = reinterpret_cast(alloca (strlen (dir) + 1 + strlen (NAME) + 1)); sprintf(name, "%s%c%s", dir, dir_delim, NAME); size_t blocks = 0; int rest = 0; int i = 0; int fd = FD_open (name, O_RDONLY|O_BINARY); if (fd == -1) return ret; int size = FD_LSEEK (fd, 0, SEEK_END); FD_LSEEK (fd, 0, SEEK_SET); blocks = (size + PARTSIZE - 1) / PARTSIZE; unsigned char *hash_list = reinterpret_cast(alloca (16 * blocks)); unsigned char *buf = reinterpret_cast(MALLOC (PARTSIZE)); rest = size; while (rest > 0) {{{ // build Part hashlist int work = (rest(buf), work), 16); rest -= work; i++; printf("Part-Hash created\n"); }}} if (buf) { Free2 (buf); } if (blocks > 1) memcpy ( hash, md4(reinterpret_cast(hash_list), blocks * 16), 16 ); else memcpy ( hash, hash_list , 16); char *buf1 = reinterpret_cast(alloca (strlen(control) + 1 + 32 + 5 +1)); sprintf(buf1, "%s%c%32s.hash", control, dir_delim, hash_bin2hex(*hash) ); FD_close (fd); fd = FD_create (reinterpret_cast(buf1), O_WRONLY|O_CREAT|O_BINARY , 0600); if (fd > 0) { FD_WRITE2 (fd, hash_list, blocks * 16); ret = size; } if (fd > 0) FD_close (fd); return ret; }}} // Config File Handling {{{ struct sFileConfig { const char *name; unsigned type; void *var; }; #define unsigned_short_int 1 #define unsigned_int 2 #define char_star 3 #define size_type 4 #define boolean_value 5 struct sFileConfig listConfig[] = { {"server_port" , unsigned_short_int , &pref.ports.server }, {"client_port" , unsigned_short_int , &pref.ports.client }, {"kademlia_port" , unsigned_short_int , &pref.ports.kademlia }, {"gui_port" , unsigned_short_int , &pref.ports.gui }, {"cmd_port" , unsigned_short_int , &pref.ports.clc }, {"my_version" , unsigned_int , &my_version }, {"verbose" , unsigned_int , &pref.verbose }, {"protocol_logLevel" , unsigned_int , &protocol_logLevel }, {"tcp_server_count" , unsigned_int , &TCP_SERVER_COUNT }, {"tcp_client_count" , size_type , &TCP_CLIENT_COUNT }, {"upload_kb" , unsigned_int , &ulSecond }, {"download_kb" , unsigned_int , &dlSecond }, {"client_name" , char_star , &client_name }, {"control" , char_star , &control }, {"incoming" , char_star , &incoming }, {"completed" , char_star , &completed }, {"ctrl_user" , char_star , &ctrl_user }, {"ctrl_pass" , char_star , &ctrl_pass }, {"bind_ip" , char_star , &bind_ip }, {"enable_overnet" , boolean_value , &use_kademlia }, {"background" , boolean_value , &go_to_background }, {NULL , 0 , NULL } }; static void readConfig(char * p_sFilename) { /// Read the cDonkey config file FILE * piCfgFile = NULL; char sCmd [128]; char sValue[128]; int i = 0; // Try to open the file piCfgFile = fopen(p_sFilename, "r"); // Seems like there is a problem if (piCfgFile == NULL) { // Inform the user printf("Cannot read configuration file %s!\n", p_sFilename); printf("The file does not exist or it has the wrong permissions set.\n"); // Try to create the file printf("Trying to create a new configuration file...\n"); piCfgFile = fopen (p_sFilename, "w+"); // Seems to be a permission problem if (piCfgFile == NULL) { printf("Couldn't create config file %s!\n", p_sFilename); printf("Check for wrong file or directory permissions.\n"); #ifndef HAVE_ATEXIT #ifndef HAVE_ON_EXIT exitHandler (); #endif #endif exit(EXIT_FAILURE); } // Print out the client name as well as the random username/password combination fprintf(piCfgFile, "client_name = cDonkey_(http://cdonkey.suche.org)\n"); fprintf(piCfgFile, "ctrl_user = %s\n", ctrl_user); fprintf(piCfgFile, "ctrl_pass = %s\n", ctrl_pass); // Set the file to the right permissions chmod(p_sFilename, 0600); // Jump to the beginning of the file fseek (piCfgFile, 0, SEEK_SET); printf("Configuration file %s created.\n", p_sFilename); } printf("Processing configuration file %s...\n", p_sFilename); // Analyze each line in the file while (fscanf(piCfgFile, "%128s = %128s", sCmd, sValue) == 2) { log (1, "Config: %s = %s\n", sCmd, sValue); // Try to find a matching setting for the current line for (i = 0; listConfig[i].name != NULL; i++) { // If a setting matches, set it to the value of the configuration file if (strcmp(sCmd, listConfig[i].name) == 0) { int tmpValue; switch (listConfig[i].type) { case unsigned_short_int : *(reinterpret_cast(listConfig[i].var)) = atoi(sValue); break; case unsigned_int : *(reinterpret_cast(listConfig[i].var)) = atoi(sValue); break; case size_type : *(reinterpret_cast(listConfig[i].var)) = atoi(sValue); break; case char_star : Free2 (*(reinterpret_cast(listConfig[i].var))); *(reinterpret_cast(listConfig[i].var)) = STRDUP (sValue); break; case boolean_value : tmpValue = atoi(sValue); if (tmpValue == 0) { *(reinterpret_cast(listConfig[i].var)) = false; break; } else if (tmpValue == 1) { *(reinterpret_cast(listConfig[i].var)) = true; break; } else { printf("An error occured while processing the configuration file: invalid boolean value!\n"); #ifndef HAVE_ATEXIT #ifndef HAVE_ON_EXIT exitHandler (); #endif #endif exit(EXIT_FAILURE); } default : printf("An error occured while processing the configuration file!\n"); #ifndef HAVE_ATEXIT #ifndef HAVE_ON_EXIT exitHandler (); #endif #endif exit(EXIT_FAILURE); } // Output control information, but we don't want passwords in logfiles if (strcmp(sCmd, "ctrl_pass") == 0) printf(" >> Setting \"%s\" is now set to some password. :)\n", sCmd); else printf(" >> Setting \"%s\" is now set to \"%s\".\n", sCmd, sValue); // Stop searching break; } } // Print out a message if we couldn't find a setting of that name if (listConfig[i].name != NULL) continue; if (strcmp(sCmd, "") == 0) continue; printf(" !! Unknown setting \"%s\" in configuration file!\n", sCmd); } printf("Processed configuration file.\n"); // Close the configuration file fclose(piCfgFile); } // }}} typedef void (*file_load)(const char *name, const char *dir_ctl, const char *dir_dat); static void sFile_part_met(const char *name, const char *dir, const char *dir_dat) {{{ char dateiname[512]; snprintf(dateiname, 512, "%s%c%s", dir, dir_delim, name); class sFile *file1 = new sFile(dateiname, dir_dat); class sFile *check = forHash(file1->hash); if (file1->size == 0 || file1 != check || file1->fd_in == -1) delete file1; }}} static void loadDir (const char *dir, const char* dir_dat,const char *postfix_val, file_load load_func) {{{ struct dirent *entry; DIR *dir_hdl = opendir (dir); if (dir_hdl == NULL) return; size_t postfix_len = strlen(postfix_val); while (NULL != (entry = readdir (dir_hdl)) && running) { if (entry->d_name == NULL) continue; size_t name_len = strlen (entry->d_name); if (name_len < postfix_len) continue; if (0 != strcmp (entry->d_name + name_len - postfix_len, postfix_val)) continue; load_func (entry->d_name, dir, dir_dat); } closedir (dir_hdl); }}} static int Initialise (void) {{{ struct dirent *entry; DIR *dir; memcpy (client_hash, md4(client_name, strlen(client_name)), 16); if (eMule) {{{ client_hash[ 5] = 14; // 0x0E client_hash[14] =111; // 0x6F Aktual eMule signature !!! }}} mkdir (incoming, 0700); mkdir (completed, 0700); mkdir (control , 0700); loadDir (control, completed, ".part.met", sFile_part_met); loadDir (control, incoming , ".part.met", sFile_part_met); if ( NULL == (dir = opendir (completed)) || !running) return 0; while (NULL != (entry = readdir (dir)) && running ) {{{ if (0 == strcmp (entry->d_name, "." )) continue; if (0 == strcmp (entry->d_name, "..")) continue; bool alt = false; FILE_LIST if (alt || 0 == strcmp(akt->Name(), entry->d_name)) { alt = true; break; } if (alt) continue; tHash hash; int size = sFile_createParthash(entry->d_name, completed, &hash); if (size == 0) continue; printf("\nAdding shared file %s (%i) %32s\n", entry->d_name, size, hash_bin2hex(hash)); class sFile *neu = new sFile (hash, entry->d_name, size, completed); neu->set_Completed() ; }}} closedir (dir); return 0; }}} // Search const class sFile *nextFile_search (void) {{{ sFile *ret = NULL; unsigned int min = 999999; FILE_LIST { if (ALL_DONE == akt->status || akt->Pause() ) continue; nextFile (akt->hash, true); int src_count = cursor_count; if (ret == NULL) { ret = akt; min = src_count; continue; } if (ret->search_count + (min / 100) > akt->search_count) { min = src_count; ret = akt; } } if (ret == NULL) { log (1, "No search\n"); return ret; } ret->search_count ++; return ret; }}} static void fetchSource_UDP(void) {{{ // aktivate UDP search static time_t timeout = 0; if (sFile::count <= 0) return; if (timeout > currentTime) return; timeout = currentTime + UDP_SEARCH_TIMEOUT; for (int i = UDP_SEARCH_COUNT; --i >= 0;) { if (ul_left < 100 || dl_left < 100) break; in_addr ip; uint16_t port; if (!nextServer (&ip, &port)) break; if (tcp_server != NULL) if (tcp_server->peer_ip.s_addr == ip.s_addr) continue; if (port == 0) continue; const sFile *file1 = NULL; do { file1 = nextFile_search(); if (file1 == NULL) break; } while (file1->Pause() || file1->status == ALL_DONE); if (file1 == NULL) break; userver_listen->UDP_req_sources (ip, port, file1->hash); } }}} static void nextSource (void) {{{ // Holt eine verfügbare Quelle oder sucht nach Ihr struct in_addr ip; ip.s_addr = 0; unsigned short port = 0; if (!getSource (&ip, &port)) { // the timeout save unwanted db access here if (userver_listen!=NULL) fetchSource_UDP (); if (kademlia != NULL) { if (kademlia->status == 8) { const sFile *file1 = nextFile_search(); if (file1 != NULL) if (!cSearchManager::alreadySearchingFor(file1->hash)) kademlia->Search(file1->hash); } } return; } struct eSources *info = Source_ip(ip); if (info != NULL && userver_listen != NULL) { if (info->version & 0x01000000 && info->udp_port != 0) { sFile *dl_file = forHash(info->hash_dl); if (dl_file != NULL) { printf("UDP file reask send\n"); userver_listen->req_file_ping (ip, info->udp_port, info->hash_dl); setSources_version (ip, info->version & 0xFEFFFFFF); } // FILE_LIST { // if (File_info_get(info->hash,akt->hash,akt->size, NULL)) { // printf("send file ping %s:%u\n", inet_ntoa(ip), info->udp_port); // userver_listen->req_file_ping (ip, info->udp_port, akt->hash); // setSources_version (ip, info->version & 0xFEFFFFFF); // } } } else new sSource (ip, port); }}} static const char *print_Human(size_t bytes) {{{ static char buf[64]; double b = bytes; if (b<1024.0) { sprintf(buf,"(%10u) %8.3f B ", bytes, b); return buf; } b = b / 1024.0; if (b<1024.0) { sprintf(buf,"(%10u) %8.3f KB", bytes, b); return buf; } b = b / 1024.0; if (b<1024.0) { sprintf(buf,"(%10u) %8.3f MB", bytes, b); return buf; } b = b / 1024.0; if (b<1024.0) { sprintf(buf,"(%10u) %8.3f GB", bytes, b); return buf; } b = b / 1024.0; if (b<1024.0) { sprintf(buf,"(%10u) %8.3f TB", bytes, b); return buf; } sprintf(buf, "(%10u)",bytes); return buf; }}} static void printfTraffic(void) {{{ unsigned long dl_daten = 0; unsigned long ul_daten = 0; FILE_LIST { dl_daten += akt->dlCount(); ul_daten += akt->ulCount(); } printf("DL/UL abs %s/" , print_Human(global_dl_count)); printf( "%s dat " , print_Human(global_ul_count)); printf("%s/" , print_Human(dl_daten)); printf("%s left %7i/%7i\n" , print_Human(ul_daten), dl_left, ul_left); }}} static void info_dump(void) {{{ log (32, "TIMESTAMP %s\n", currentTime_str); if(currentTime % 60 == 0) printfTraffic (); }}} #ifdef DIPL_LOG /// regular log data is written here. static void log_actions() { if (currentTime % 300 != 0) return; ServerLog->write_event_regular(); } #endif static void check_lib (void) {{{ #if defined(_MSC_VER) const char compiler[] = "MS-CPP"; #elif defined(__CYGWIN__) const char compiler[] = "Cygwin"; #else const char compiler[] = "Gcc"; #endif printf("Author : thomas@suche.org\n"); printf("License: GPL 2.0 (with modifications, MD5: 36B241914312DF86A9B68D56682CA44B)\n"); printf("Build : %s %s with %s\n", __DATE__, __TIME__, compiler); #ifdef DIPL_LOG printf("Notice : logging extensions are *enabled* in this build!\n"); #endif cSocket::Start (); int major = 0; int minor = 0; int patch = 0; char *version = db_version (&major, &minor, &patch); if ((major != 4 && (minor != 0 || minor != 1)) && (major != 3 && minor != 3)) {{{ printf ("Wrong Version of Berkley DB\n"); printf ("Used Version => %s\n", version); printf ("DB source can found at http://www.sleepycat.com/\n"); exit(0); }}} if (major != DB_VERSION_MAJOR || minor != DB_VERSION_MINOR) {{{ printf ("Wrong Version of Berkley DB\n"); printf ("Compiled Version is %i.%i.%i\n", DB_VERSION_MAJOR, DB_VERSION_MINOR, DB_VERSION_PATCH); printf ("Linked Version is %i.%i.%i\n", major, minor, patch); printf ("ERROR: Major and/or minor Number changed. Please recompile cDonkey!\n"); exit (0); }}} if (0 != strcmp(zlibVersion(), ZLIB_VERSION)) {{{ printf ("WARNING zlib version changed since last compile.\n"); printf ("Compiled Version is %s\n", ZLIB_VERSION); printf ("Linked Version is %s\n", zlibVersion()); }}} int z0 = atoi (ZLIB_VERSION); int z1 = atoi (zlibVersion()); if (z0 != z1) {{{ printf ("ERROR: zlib is not compatible!\n"); printf ("zlib source can found at http://www.gzip.org/zlib/\n"); exit (0); }}} #ifndef FASTHASH bool uptodate = true; struct in_addr IP; IP.s_addr = htonl(AKT_VERSION); struct in_addr va; va.s_addr = IP4Name("cDonkey-Version.suche.org"); if (va.s_addr != 0) {{{ if (htonl(va.s_addr) <= AKT_VERSION) printf("Version: Your cDonkey is up to date.\n"); else { printf ("Version: There is a newer version of cDonkey!\n"); printf ("- Current: %s\n", inet_ntoa(IP)); printf ("- Newest : %s\n", inet_ntoa(va)); printf ("- Update : http://cDonkey.suche.org\n"); uptodate = false; } }}} va.s_addr = IP4Name("cDonkey-Expired.suche.org"); if (va.s_addr != 0) {{{ if (htonl(va.s_addr) >= AKT_VERSION) { printf ("ERROR: This cDonkey version is disabled.\n"); printf ("Please get a new version of cDonkey!\n"); printf ("- Current : %s\n", inet_ntoa(IP)); printf ("- Expired : %s\n", inet_ntoa(va)); printf ("- Update : http://cDonkey.suche.org\n"); printf ("- Complain: mailto:thomas@suche.org\n"); exit(0); } }}} #endif }}} static void check_ServerCount(void) {{{ if (tcp_server != NULL) return; if (client_listen == NULL) return; // always stay connected (even if line is full) // Make sure we have an TCP_Server connection if (!use_kademlia) GUI_LIST akt->GUI_disconnected(); // Make sure we have an TCP_Server connection struct in_addr ip; uint16_t port; char logbuf[256]; if (!nextServer (&ip, &port)) { log (1, "No nextServer() found !\n"); return; } tcp_server = new sServer (ip, port); snprintf(logbuf,255, "Trying Edonkey Server: %15s\n", inet_ntoa(ip) ); log (1, logbuf); GUI_LIST akt->GUI_statusMessage(logbuf); }}} static void check_ClientCount(void) {{{ static time_t log_time = currentTime; // only needed to not flood logging output if (sSource::count >= TCP_CLIENT_COUNT) return; if (ul_left <= 1024) return; if (dl_left <= 1024) return; // Make sure we have enaught clients Open (only if we have the bandwith for them) int ftp_aktive = 0; bool hit = false ; SOURCE_LIST {{{ // remove current dl sources if (akt->Status() == FTP_AKTIVE) ftp_aktive++; if ( 0 == (pref.verbose & 1)) continue; // debugging output . Change to other verbose lvl if too slow! if ( currentTime - log_time > 40 ) { // every 40sec hit = true; bool slot_info = (akt->Status() == WAIT_SLOT || (akt->dlSlot() != -1 && akt->Status() == P_C5060)); printf("%s Stats: IP %15s ",(slot_info)?"Queue ":"Downloader",inet_ntoa(akt->peer_ip)); printf("Download %s ", print_Human(akt->dl_count)); printf("Upload %s " , print_Human(akt->ul_count)) ; printf("Ratio %li Rank %hi eMule: %d Overnet: %d\n", akt->Ratio(), akt->dlSlot(), akt->is_eMule(), akt->is_Overnet() ); } }}} if ( hit == true ) { log_time = currentTime ; printf(" Stats ---------\n"); } int con_new = (CLIENT_COUNT - ftp_aktive) * 5; log (16, "FTP_AKTIVE %3i NEUE_CON %3i\n", ftp_aktive, con_new); if (con_new <= 0) return; int max1 = TCP_CLIENT_COUNT - sSource::count; if (max1 > 0) { if (max1 < con_new) con_new = max1; if (con_new> 20) con_new = 20; while (con_new-- > 0) nextSource (); // get an constant Amount of Source } }}} void every_sec (void) {{{ ///< this function is called every once a second is gone static time_t next_bind =0; static time_t last_run = 0; CurrentTime (); time_t diff = currentTime - last_run; if (diff == 0) return; last_run = currentTime; if (diff <= 0 || diff > 3) diff = 1; if (!next_bind + 3 < currentTime) {{{ // only as long as not all port are bound pref.ports.emule = pref.ports.server + 4; if (client_listen == NULL) Client_listen (pref.ports.client ); if (gui_listen == NULL) Gui_listen (pref.ports.gui ); if (command_listen == NULL) Command_listen (pref.ports.clc ); if (userver_listen == NULL) UServer_listen (pref.ports.emule ); if (listen_http == NULL) HTTP_listen (pref.ports.web ); if (use_kademlia && kademlia == NULL) UKademlia_listen (pref.ports.kademlia); if (run_server &&server_listen==NULL) Server_listen (pref.ports.server ); next_bind = currentTime; }}} info_dump(); #ifdef DIPL_LOG log_actions(); #endif if (userver_listen!= NULL && userver_listen->validSocket()) { for (int j=3; --j > 0 && ul_left > 1024 && dl_left > 1024;) { userver_listen->UDP_next_ping (); } } size_t ul_max = (ul_left + ulSecond * diff); size_t dl_max = (ul_left + ulSecond * diff); ul_left = ((ulSecondcalcRate (diff); } fflush(stdout); int work_count = 0; static unsigned long count_a = 0; static unsigned long count_b = 0; count_a ++; class cSocket *akt_sock = NULL; while (NULL != (akt_sock = timer_list.peek())) {{{ cDLL::remove(&akt_sock->timer); akt_sock->timer = timer_list.add_back(akt_sock); if (akt_sock->work_last + 1 >= currentTime) break; akt_sock->work_last = currentTime + 1; count_b++; if (16 == (16 & akt_sock->mask)) {{{ // should not realy happen printf("donkey.cpp: deleting1 %p\n", akt_sock); delete akt_sock; continue; }}} if (!akt_sock->connected && currentTime - akt_sock->since > 66) {{{ // destroy after connect timeout printf("donkey.cpp: deleting2 %p\n", akt_sock); delete akt_sock; continue; }}} if (akt_sock->Type == tServer) {{{ // Server Timeout and hopping if (!akt_sock->connected && currentTime - akt_sock->since > server_connect) {{{ // destroy log (2, "1. delete server timeout %15s \n", inet_ntoa (akt_sock->peer_ip)); printf("donkey.cpp: deleting3 %p\n", akt_sock); delete akt_sock; continue; }}} if (akt_sock->connected && currentTime - akt_sock->last_conn > server_hopping) { // destroy log (2, "2. delete server timeout (hopping) %15s \n", inet_ntoa (akt_sock->peer_ip)); printf("donkey.cpp: deleting4 %p\n", akt_sock); delete akt_sock; GUI_LIST akt->GUI_statusMessage("Hopping to new Server\n"); continue; } }}} if (akt_sock->connected != 1 && akt_sock->connected != 3) continue; work_count ++; akt_sock->addEvent (9); }}} // printf("Counter %lu / %lu (%lu)\n", count_a, count_b, count_b/count_a); cSocket::hdlEvent (); check_ServerCount (); check_ClientCount (); }}} void fork_to_background(void); // located below main int main (int argc, char **argv) {{{ bzero (ZERO, 16); struct stat dStatBuf; int j = 0; setDefaults_pref (); // 1.100.292.227 => sec bei 1.1 GHZ printf("WARNING: server.db / files.db / source.db files were changed\n"); CurrentTime (); ASSERT (sizeof (float ) == 4); ASSERT (sizeof (tHash ) == 16); ASSERT (sizeof (uint32_t) == 4); ASSERT (sizeof (uint16_t) == 2); ASSERT (sizeof (uint8_t ) == 1); // {{{ Init Block srand (currentTime); #if !defined(WIN32) && !defined(__CYGWIN__) struct winsize wsz; isTerm = (ioctl (fileno (stdout), TIOCGWINSZ, &wsz) >= 0); #endif #ifdef HAVE_ATEXIT atexit(exitHandler); #else #ifdef HAVE_ON_EXIT on_exit (exitHandler, NULL); #endif #endif signal (SIGTERM, sigTerm); #ifdef HAVE_SIGHUP signal (SIGHUP , sigHup ); #endif #ifdef HAVE_SIGINT signal (SIGINT , sigInt ); #endif // Generate a random client name and password {{{ char sClientRandom[] = "01234567"; char sPasswdRandom[] = "0123456789"; for (j = 0; j < 8; j++) sClientRandom[j] = ('A' + rand() % 24); for (j = 0; j < 10; j++) sPasswdRandom[j] = ('A' + rand() % 24); if (client_name == NULL) client_name = STRDUP (sClientRandom); if (ctrl_pass == NULL) ctrl_pass = STRDUP (sPasswdRandom); // }}} // Set important settings to default values if (control == NULL) control = STRDUP ("control"); if (incoming == NULL) incoming = STRDUP ("incoming"); if (completed == NULL) completed = STRDUP ("completed"); if (ctrl_user == NULL) ctrl_user = STRDUP ("cdonkey"); if (bind_ip == NULL) bind_ip = STRDUP ("0.0.0.0"); // If there is a valid config file in the users home directory, use it instead of the global one const char * sHomeDir = getenv("HOME"); char * sConfigFile = NULL; if (sHomeDir == NULL || sHomeDir == "" || sHomeDir == "/") { // Something is horrible wrong with users home directory, use the global config file sConfigFile = reinterpret_cast(alloca (strlen(GLOBALCONFIG) + 1)); sprintf(sConfigFile, GLOBALCONFIG); } else { // We got a directory, but does it contain a config file? sConfigFile = reinterpret_cast(alloca (strlen(sHomeDir) + strlen(".cdonkey.conf") + 2)); sprintf(sConfigFile, "%s%c.cdonkey.conf", sHomeDir, dir_delim); if (stat(sConfigFile, &dStatBuf) == -1) { // If not, use the global config file sConfigFile = reinterpret_cast(alloca (strlen(GLOBALCONFIG) + 1)); sprintf(sConfigFile, "/usr/local/etc/cdonkey.conf"); } } readConfig(sConfigFile); // Read or create the config file db_client = reinterpret_cast(MALLOC (strlen(control) + 1 + strlen("source.db") + 1)); db_server = reinterpret_cast(MALLOC (strlen(control) + 1 + strlen("server.db") + 1)); sprintf(db_client, "%s%c%s", control, dir_delim, "source.db"); sprintf(db_server, "%s%c%s", control, dir_delim, "server.db"); cSocket::setLocalInternalIP(cSocket::hostIP(bind_ip)); //printf("MYHOSTIP: %s\n", inet_ntoa(cSocket::getLocalInternalIP())); pref.ports.emule = pref.ports.server + 4; printf("Client Name %s\n" , client_name); printf("Server Port %5u\n", pref.ports.server ); printf("Command Port %5u\n", pref.ports.clc ); printf("Gui Port %5u\n", pref.ports.gui ); printf("eMule Port %5u\n", pref.ports.emule ); printf("Overnet Port %5u\n", pref.ports.kademlia); printf("Web Port %5u\n", pref.ports.web ); check_lib (); Initialise (); misc_init (); printf("Login: %s - %s\n", ctrl_user, ctrl_pass); // }}} for (int i0 = 1; i0 < argc; i0++) split_link (argv[i0]); CurrentTime (); cServer_list::Load (); in_addr tmp_ip; tmp_ip.s_addr = 0; // struct in_addr sadr; // sadr.s_addr = inet_addr("217.172.178.34"); // sadr.s_addr = inet_addr("213.158.125.46"); // new sServer (sadr, 4661); /* {{{ struct in_addr sadr; sadr.s_addr = inet_addr("127.0.0.1"); tHash dh; memcpy (dh, hash_hex2bin("f400c95462f8dedfc8e81f79b279ea2b"), 16); insertFiles(dh, sadr, 0, NULL); new sSource (sadr, 4662); }}} */ if (go_to_background) fork_to_background(); time_t nextLeftRefresh = 0; do { every_sec (); nextLeftRefresh = currentTime; do { cSocket::waitEvent(1000000); cSocket::hdlEvent (); CurrentTime (); } while (nextLeftRefresh == currentTime && running); } while (running); // Erst mit timeout raus *g* #ifndef HAVE_ATEXIT #ifndef HAVE_ON_EXIT exitHandler (); #endif #endif return 0; }}} // // Fork a process to background (swiped from wget) // void fork_to_background(void) {{{ pid_t pid; pid = fork (); if (pid < 0) { // parent, error perror("fork"); exit (1); } else if (pid != 0) { // parent, no error printf("Continuing in background, pid %d.\n", (int)pid); exit(0); } // child: give up the privileges and keep running. setsid(); freopen("/dev/null", "r", stdin); freopen("/dev/null", "w", stdout); freopen("/dev/null", "w", stderr); }}} /* * vim600: fdm=marker */