/** ** File ......... tracker.cpp ** Published .... 2004-04-20 **/ /* Copyright (C) 2004 grymse@alhem.net This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #if (defined(__unix__) || defined(unix)) && !defined(USG) #include #endif #include #include #include "MyHandler.h" #include "TrackerSock.h" #include "MyMinderSocket.h" #include "MyMinionSocket.h" #define DEB(x) bool quit = false; void top(MyHandler& h) { std::string msg = "Tip_" + Utility::l2string(static_cast(h).GetHostId()); static_cast(h).SendMessage(Utility::base64(msg)); unlink("top_map.dot"); FILE *fil; if ((fil = fopen("top_map.dot","wt")) != NULL) { fprintf(fil,"digraph \"G\" {\n"); fprintf(fil,"\tedge [arrowhead=open]\n"); #ifdef _WIN32 std::string os = "Win32"; #elif defined __FreeBSD__ std::string os = "FreeBSD"; #else std::string os = "Linux"; #endif fprintf(fil,"\t\"%ld\" [label=\"%ld\\n%s\\n%s\" style=filled fillcolor=\"#e0e0e0\"]\n", static_cast(h).GetHostId(), static_cast(h).GetHostId(), h.GetVersion().c_str(), os.c_str()); static_cast(h).Tops(fil); fclose(fil); } } void sigint(int s) /* save+quit */ { fprintf(stderr,"shutting down\n"); quit = true; } void sigpipe(int s) { } void reg_minder(MyHandler& h,const std::string& cmd) { MyMinderSocket *m = new MyMinderSocket(h,h.GetString("server/announce_url") ); m -> Init(); m -> Function(cmd); // Hello / Goodbye m -> SetDeleteByHandler(true); m -> Open(h.GetString("minder/host"),h.GetInt("minder/port")); h.Add(m); m -> SetLocalIpPort(h.GetLocalAddress(),h.GetLocalPort()); if (!m -> Connecting()) // connected { m -> SendHello(); } } void connect(MyHandler& h) { if (h.Count() < h.GetInt("minion/max") ) { ipaddr_t a; port_t p; std::string key; long host_id; if (h.GetHost(a,p,key,host_id)) { MinionSocket *tmp = new MyMinionSocket(h,key,a,p); tmp -> Init(); ipaddr_t my_ip; port_t my_port; h.GetMyIpPort(my_ip, my_port); tmp -> SetMyIpPort(my_ip,my_port); tmp -> SetRemoteHostId(host_id); { std::string t; tmp -> l2ip(a,t); DEB( printf("Connect to: %s:%d\n",t.c_str(),p);) } if (tmp -> Open(a,p)) { tmp -> SetDeleteByHandler(true); h.Add(tmp); // tmp -> SendHello("Hello"); } else if (tmp -> Connecting()) { tmp -> SetDeleteByHandler(true); // check OnConnect h.Add(tmp); } else { delete tmp; } } else { DEB( printf("h.GetHost() failed?\n");) } } } //////// overrides config file /* --port Port to listen on. (defaults to 80) OK --dfile file to store recent downloader info in --bind ip to bind to locally (defaults to '') OK --socket_timeout timeout for closing connections (defaults to 15) --save_dfile_interval seconds between saving dfile (defaults to 300) --timeout_downloaders_interval seconds between expiring downloaders (defaults to 2700) OK --reannounce_interval seconds downloaders should wait between reannouncements (defaults to 1800) OK --response_size number of peers to send in an info message (defaults to 50) OK --timeout_check_interval time to wait between checking if any connections have timed out (defaults to 5) OK --nat_check whether to check back and ban downloaders behind NAT (defaults to 1) --min_time_between_log_flushes minimum time it must have been since the last flush to do another one (defaults to 3.0) --allowed_dir only allow downloads for .torrents in this dir (defaults to '') --parse_allowed_interval minutes between reloading of allowed_dir (defaults to 15) --show_names whether to display names from allowed dir (defaults to 1) --favicon file containing x-icon data to return when browser requests favicon.ico (defaults to '') --only_local_override_ip ignore the ip GET parameter from machines which aren't on local network IPs (defaults to 1) --logfile file to write the tracker logs, use - for stdout (default) (defaults to '') --allow_get use with allowed_dir; adds a /file?hash={hash} url that allows users to download the torrent file (defaults to 0) --keep_dead keep dead torrents after they expire (so they still show up on your /scrape and web page) (defaults to 0) --max_give maximum number of peers to give with any one request (defaults to 200) */ int main(int argc,char *argv[]) { MyHandler h( "config.xml" ); ListenSocket l(h); ListenSocket l3(h); signal(SIGINT, (__sighandler_t)sigint); signal(SIGHUP, (__sighandler_t)sigint); signal(SIGTERM,(__sighandler_t)sigint); signal(SIGPIPE, (__sighandler_t)sigpipe); // http tracker if (h.GetString("server/type") == "normal") { std::string bind = h.GetString("server/bind"); port_t port = h.GetInt("server/port"); int queue_size = h.GetInt("server/queue_size"); { if (l.Bind(bind,port,queue_size)) { return -1; } h.Add(&l); } } else if (h.GetString("server/type") == "ssl") { printf("Tracker type not implemented: 'ssl'\n"); exit(-1); } else { printf("Tracker type not supported: '%s'\n",h.GetString("server/type").c_str()); exit(-1); } // minion { std::string bind = h.GetString("minion/bind"); port_t port = h.GetInt("minion/port"); while (l3.Bind(port)) { port++; } h.Add(&l3); h.SetLocalPort(port); } // main loop { time_t t = time(NULL); // send peer list (update) time_t tc = time(NULL); // connect time_t tm = time(NULL); // reg_minder time_t tt = time(NULL); // top time_t td = time(NULL); // dropped reg_minder(h,"Hello"); h.Select(1,0); while (h.GetCount() && !quit) { h.Select(1,0); time_t t2 = time(NULL); if (t2 - tc > h.GetInt("minion/connect_interval") && h.GetInt("minion/connect_interval") ) { tc = t2; connect(h); } if (t2 - t > h.GetInt("minion/update_interval")) { t = t2; h.SendList(); } if (t2 - tm > 15 * 60) { tm = t2; reg_minder(h,"Hello"); } if (t2 - tt > h.GetInt("minion/top_interval") && h.GetInt("minion/top_interval") ) // var femte minut { tt = t2; top(h); } if (t2 - td > h.GetInt("server/timeout_check_interval") ) { td = t2; h.CheckDropped(); } } } // shutdown { reg_minder(h,"Goodbye"); h.Select(1,0); while (h.MinderSockets()) { h.Select(1,0); } } }