1 #include "./def.h"
2 #include <sys/types.h>
3 
4 #ifdef WINDOWS
5 #include <windows.h>
6 #else
7 #include <unistd.h>
8 #include <signal.h>
9 #endif
10 
11 #include <sys/time.h>
12 #include <time.h>
13 #include <string.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 
17 #include "btconfig.h"
18 #include "btcontent.h"
19 #include "downloader.h"
20 #include "peerlist.h"
21 #include "tracker.h"
22 #include "ctcs.h"
23 #include "console.h"
24 
25 #include "./config.h"
26 
27 #ifndef HAVE_RANDOM
28 #include "compat.h"
29 #endif
30 
31 #ifndef WINDOWS
32 #include "sigint.h"
33 #endif
34 
35 void usage();
36 int param_check(int argc, char **argv);
37 
38 #ifdef WINDOWS
39 
WinMain(HINSTANCE hInstance,HINSTANCE hPrzevInstance,LPSTR lpCmdLine,int nCmdShow)40 int APIENTRY WinMain(HINSTANCE hInstance,
41                      HINSTANCE hPrzevInstance,
42                      LPSTR     lpCmdLine,
43                      int       nCmdShow)
44 {
45 }
46 
47 #else
48 
Random_init()49 void Random_init()
50 {
51   unsigned long seed;
52 #ifdef HAVE_GETTIMEOFDAY
53   struct timeval tv;
54   gettimeofday(&tv,(struct timezone*) 0);
55   seed = tv.tv_usec + tv.tv_sec + getpid();
56 #else
57   seed = (unsigned long)time((time_t *)0);
58 #endif
59   srandom(seed);
60 }
61 
main(int argc,char ** argv)62 int main(int argc, char **argv)
63 {
64   char *s;
65 
66   Random_init();
67   arg_user_agent = new char[MAX_PF_LEN+1];
68   strcpy(arg_user_agent,PEER_PFX);
69 
70   cfg_user_agent = new char[strlen(PACKAGE_NAME)+strlen(PACKAGE_VERSION)+2];
71 #ifndef WINDOWS
72   if( !cfg_user_agent ) return -1;
73 #endif
74   sprintf(cfg_user_agent, "%s/%s", PACKAGE_NAME, PACKAGE_VERSION);
75   while(s = strchr(cfg_user_agent, ' ')) *s = '-';
76 
77   if( argc < 2 ){
78     usage();
79     exit(1);
80   } else if( param_check(argc,argv) < 0 ) exit(1);
81 
82   if( arg_flg_make_torrent ){
83     if( !arg_announce ){
84       CONSOLE.Warning(1, "Please use -u to specify an announce URL!");
85       exit(1);
86     }
87     if( !arg_save_as ){
88       CONSOLE.Warning(1, "Please use -s to specify a metainfo file name!");
89       exit(1);
90     }
91     if( BTCONTENT.InitialFromFS(arg_metainfo_file, arg_announce,
92                                 arg_piece_length) < 0 ||
93         BTCONTENT.CreateMetainfoFile(arg_save_as) < 0 ){
94       CONSOLE.Warning(1, "create metainfo failed.");
95       exit(1);
96     }
97     CONSOLE.Print("Create metainfo file %s successful.", arg_save_as);
98     exit(0);
99   }
100 
101   if( !arg_flg_exam_only && (!arg_flg_check_only || arg_flg_force_seed_mode) )
102     if( arg_ctcs ) CTCS.Initial();
103 
104   if( arg_daemon ) CONSOLE.Daemonize();
105 
106   if( BTCONTENT.InitialFromMI(arg_metainfo_file, arg_save_as) < 0){
107     CONSOLE.Warning(1, "error, initial meta info failed.");
108     exit(1);
109   }
110 
111   if( !arg_flg_exam_only && (!arg_flg_check_only || arg_flg_force_seed_mode) ){
112     if(WORLD.Initial_ListenPort() < 0){
113       CONSOLE.Warning(2, "warn, you can't accept connections.");
114     }
115 
116     if( Tracker.Initial() < 0 ){
117       CONSOLE.Warning(1, "error, tracker setup failed.");
118       exit(1);
119     }
120 
121     sig_setup();  // setup signal handling
122     CONSOLE.Interact(
123       "Press 'h' or '?' for help (display/control client options)." );
124     Downloader();
125     if( cfg_cache_size ) BTCONTENT.FlushCache();
126   }
127   if( !arg_flg_exam_only ) BTCONTENT.SaveBitfield();
128   WORLD.CloseAll();
129 
130   if(arg_verbose) CONSOLE.cpu();
131   exit(0);
132 }
133 
134 #endif
135 
param_check(int argc,char ** argv)136 int param_check(int argc, char **argv)
137 {
138   const char *opts;
139   int c, l;
140   char *s;
141 
142   if( 0==strncmp(argv[1], "-t", 2) )
143     opts = "tc:l:ps:u:";
144   else opts = "aA:b:cC:dD:e:E:fi:I:M:m:n:P:p:s:S:Tu:U:vxX:z:hH";
145 
146   while( (c=getopt(argc, argv, opts)) != -1 )
147     switch( c ){
148     case 'a':
149       arg_allocate = 1;
150       break;
151 
152     case 'b':
153       arg_bitfield_file = new char[strlen(optarg) + 1];
154 #ifndef WINDOWS
155       if( !arg_bitfield_file ) return -1;
156 #endif
157       strcpy(arg_bitfield_file, optarg);
158       break;
159 
160     case 'i':			// listen on ip XXXX
161       cfg_listen_ip = inet_addr(optarg);
162       break;
163 
164     case 'I':			// set public ip XXXX
165       cfg_public_ip = new char[strlen(optarg) + 1];
166       if( !cfg_public_ip ) return -1;
167       strcpy(cfg_public_ip, optarg);
168       break;
169 
170     case 'p':			// listen on Port XXXX
171       if( arg_flg_make_torrent ) arg_flg_private = 1;
172       else cfg_listen_port = atoi(optarg);
173       break;
174 
175     case 's':			// Save as FILE/DIR NAME
176       if( arg_save_as ) return -1;  // specified twice
177       arg_save_as = new char[strlen(optarg) + 1];
178 #ifndef WINDOWS
179       if( !arg_save_as ) return -1;
180 #endif
181       strcpy(arg_save_as,optarg);
182       break;
183 
184     case 'e':			// Exit while complete
185       cfg_seed_hours = (time_t)strtoul(optarg, NULL, 10);
186       break;
187 
188     case 'E':			// target seed ratio
189       cfg_seed_ratio = atof(optarg);
190       break;
191 
192     case 'c':			// Check exist only
193       if( arg_flg_make_torrent ){
194         arg_comment = new char[strlen(optarg) + 1];
195         if( !arg_comment ) return -1;
196         strcpy(arg_comment, optarg);
197       }else arg_flg_check_only = 1;
198       break;
199 
200     case 'C':			// Max cache size
201       cfg_cache_size = atoi(optarg);
202       break;
203 
204     case 'M':			// Max peers
205       cfg_max_peers = atoi(optarg);
206       if( cfg_max_peers > 1000 || cfg_max_peers < 20 ){
207         CONSOLE.Warning(1, "-%c argument must be between 20 and 1000", c);
208         return -1;
209       }
210       break;
211 
212     case 'm':			// Min peers
213       cfg_min_peers = atoi(optarg);
214       if( cfg_min_peers > 1000 || cfg_min_peers < 1 ){
215         CONSOLE.Warning(1, "-%c argument must be between 1 and 1000", c);
216         return -1;
217       }
218       break;
219 
220     case 'z':			// slice size
221       cfg_req_slice_size = atoi(optarg) * 1024;
222       if(cfg_req_slice_size < 1024 || cfg_req_slice_size > cfg_max_slice_size){
223         CONSOLE.Warning(1, "-%c argument must be between 1 and %d",
224           c, cfg_max_slice_size / 1024);
225         return -1;
226       }
227       break;
228 
229     case 'n':			// Which file download
230       if( arg_file_to_download ) return -1;  // specified twice
231       arg_file_to_download = new char[strlen(optarg) + 1];
232 #ifndef WINDOWS
233       if( !arg_file_to_download ) return -1;
234 #endif
235       strcpy(arg_file_to_download,optarg);
236       break;
237 
238     case 'f':			// force seed mode, skip sha1 check when startup.
239       arg_flg_force_seed_mode = 1;
240       break;
241 
242     case 'D':			// download bandwidth limit
243       cfg_max_bandwidth_down = (int)(strtod(optarg, NULL) * 1024);
244       break;
245 
246     case 'U':			// upload bandwidth limit
247       cfg_max_bandwidth_up = (int)(strtod(optarg, NULL) * 1024);
248       break;
249 
250     case 'P':			// peer ID prefix
251       l = strlen(optarg);
252       if (l > MAX_PF_LEN) {
253         CONSOLE.Warning(1, "-P arg must be %d or less characters", MAX_PF_LEN);
254         return -1;
255       }
256       if (l == 1 && *optarg == '-') *arg_user_agent = (char) 0;
257       else strcpy(arg_user_agent,optarg);
258       break;
259 
260     case 'A':			// HTTP user-agent header string
261       if( cfg_user_agent ) delete []cfg_user_agent;
262       cfg_user_agent = new char[strlen(optarg) + 1];
263 #ifndef WINDOWS
264       if( !cfg_user_agent ) return -1;
265 #endif
266       strcpy(cfg_user_agent, optarg);
267       break;
268 
269     case 'T':			// convert foreign filenames to printable text
270       arg_flg_convert_filenames = 1;
271       break;
272 
273      // BELOW OPTIONS USED FOR CREATE TORRENT.
274     case 'u':			// Announce URL
275       if( arg_announce ) return -1;  // specified twice
276       arg_announce = new char[strlen(optarg) + 1];
277 #ifndef WINDOWS
278       if( !arg_announce ) return -1;
279 #endif
280       strcpy(arg_announce, optarg);
281       break;
282 
283     case 't':			// make Torrent
284       arg_flg_make_torrent = 1;
285       CONSOLE.ChangeChannel(O_INPUT, "off", 0);
286       break;
287 
288     case 'l':			// piece Length (default 262144)
289       arg_piece_length = atoi(optarg);
290       if( arg_piece_length < 65536 || arg_piece_length > 4096*1024 ){
291         CONSOLE.Warning(1, "-%c argument must be between 65536 and %d",
292           c, 4096*1024);
293         return -1;
294       }
295       break;
296      // ABOVE OPTIONS USED FOR CREATE TORRENT.
297 
298     case 'x':			// print torrent information only
299       arg_flg_exam_only = 1;
300       CONSOLE.ChangeChannel(O_INPUT, "off", 0);
301       break;
302 
303     case 'S':			// CTCS server
304       if( arg_ctcs ) return -1;  // specified twice
305       arg_ctcs = new char[strlen(optarg) + 1];
306 #ifndef WINDOWS
307       if( !arg_ctcs ) return -1;
308 #endif
309       if( !strchr(optarg, ':') ){
310         CONSOLE.Warning(1, "-%c argument requires a port number", c);
311         return -1;
312       }
313       strcpy(arg_ctcs, optarg);
314       break;
315 
316     case 'X':			// "user exit" on download completion
317       if( arg_completion_exit ) return -1;  // specified twice
318       arg_completion_exit = new char[strlen(optarg) + 1];
319 #ifndef WINDOWS
320       if( !arg_completion_exit ) return -1;
321 #endif
322 #ifndef HAVE_SYSTEM
323       CONSOLE.Warning(1, "-X is not supported on your system");
324       return -1;
325 #endif
326 #ifndef HAVE_WORKING_FORK
327       CONSOLE.Warning(2,
328         "No working fork function; be sure the -X command is brief!");
329 #endif
330       strcpy(arg_completion_exit, optarg);
331       break;
332 
333     case 'v':			// verbose output
334       arg_verbose = 1;
335       break;
336 
337     case 'd':			// daemon mode (fork to background)
338       arg_daemon++;
339       break;
340 
341     case 'h':
342     case 'H':			// help
343       usage();
344       return -1;
345 
346     default:
347       //unknown option.
348       CONSOLE.Warning(1, "Use -h for help/usage.");
349       return -1;
350     }
351 
352   argc -= optind; argv += optind;
353   if( cfg_min_peers >= cfg_max_peers ) cfg_min_peers = cfg_max_peers - 1;
354   if( argc != 1 ){
355     if( arg_flg_make_torrent )
356       CONSOLE.Warning(1,
357         "Must specify torrent contents (one file or directory)");
358     else CONSOLE.Warning(1, "Must specify one torrent file");
359     return -1;
360   }
361   arg_metainfo_file = new char[strlen(*argv) + 1];
362 #ifndef WINDOWS
363   if( !arg_metainfo_file ) return -1;
364 #endif
365   strcpy(arg_metainfo_file, *argv);
366 
367   if( !arg_bitfield_file ){
368     arg_bitfield_file = new char[strlen(arg_metainfo_file) + 4];
369 #ifndef WINDOWS
370     if( !arg_bitfield_file ) return -1;
371 #endif
372     strcpy(arg_bitfield_file, arg_metainfo_file);
373     strcat(arg_bitfield_file, ".bf");
374   }
375   return 0;
376 }
377 
usage()378 void usage()
379 {
380   CONSOLE.ChangeChannel(O_INPUT, "off", 0);
381   fprintf(stderr,"%s   Original code Copyright: YuHong(992126018601033)\n",
382     PACKAGE_STRING);
383   fprintf(stderr,"WARNING: THERE IS NO WARRANTY FOR CTorrent. USE AT YOUR OWN RISK!!!\n");
384   fprintf(stderr,"\nGeneral Options:\n");
385   fprintf(stderr, "%-15s %s\n", "-h/-H", "Show this message");
386   fprintf(stderr, "%-15s %s\n", "-x",
387     "Decode metainfo (torrent) file only, don't download");
388   fprintf(stderr, "%-15s %s\n", "-c", "Check pieces only, don't download");
389   fprintf(stderr, "%-15s %s\n", "-v", "Verbose output (for debugging)");
390 
391   fprintf(stderr,"\nDownload Options:\n");
392   fprintf(stderr, "%-15s %s\n", "-e int",
393     "Exit while seed <int> hours later (default 72 hours)");
394   fprintf(stderr, "%-15s %s\n", "-E num",
395     "Exit after seeding to <num> ratio (UL:DL)");
396   fprintf(stderr, "%-15s %s\n", "-i ip",
397     "Listen for connections on specific IP address (default all/any)");
398   fprintf(stderr, "%-15s %s\n", "-p port",
399     "Listen port (default 2706 -> 2106)");
400   fprintf(stderr, "%-15s %s\n", "-I ip",
401     "Specify public/external IP address for peer connections");
402   fprintf(stderr, "%-15s %s\n", "-u num or URL",
403     "Use an alternate announce (tracker) URL");
404   fprintf(stderr, "%-15s %s\n", "-s filename",
405     "Download (\"save as\") to a different file or directory");
406   fprintf(stderr, "%-15s %s\n", "-C cache_size",
407     "Cache size, unit MB (default 16MB)");
408   fprintf(stderr, "%-15s %s\n", "-f",
409     "Force saved bitfield or seed mode (skip initial hash check)");
410   fprintf(stderr, "%-15s %s\n", "-b filename",
411     "Specify bitfield save file (default is torrent+\".bf\")");
412   fprintf(stderr, "%-15s %s\n", "-M max_peers",
413     "Max peers count (default 100)");
414   fprintf(stderr, "%-15s %s\n", "-m min_peers", "Min peers count (default 1)");
415   fprintf(stderr, "%-15s %s\n", "-z slice_size",
416     "Download slice/block size, unit KB (default 16, max 128)");
417   fprintf(stderr, "%-15s %s\n", "-n file_list",
418     "Specify file number(s) to download");
419   fprintf(stderr, "%-15s %s\n", "-D rate", "Max bandwidth down (unit KB/s)");
420   fprintf(stderr, "%-15s %s\n", "-U rate", "Max bandwidth up (unit KB/s)");
421   fprintf(stderr, "%-15s %s%s\")\n", "-P peer_id",
422     "Set Peer ID prefix (default \"", PEER_PFX);
423   fprintf(stderr, "%-15s %s%s\")\n", "-A user_agent",
424     "Set User-Agent header (default \"", cfg_user_agent);
425   fprintf(stderr, "%-15s %s\n", "-S host:port",
426     "Use CTCS server at host:port");
427   fprintf(stderr, "%-15s %s\n", "-a", "Preallocate files on disk");
428   fprintf(stderr, "%-15s %s\n", "-T",
429     "Convert foreign filenames to printable text");
430   fprintf(stderr, "%-15s %s\n", "-X command",
431     "Run command upon download completion (\"user exit\")");
432   fprintf(stderr, "%-15s %s\n", "-d", "Daemon mode (fork to background)");
433   fprintf(stderr, "%-15s %s\n", "-dd", "Daemon mode with I/O redirection");
434 
435   fprintf(stderr,"\nMake metainfo (torrent) file options:\n");
436   fprintf(stderr, "%-15s %s\n", "-t", "Create a new torrent file");
437   fprintf(stderr, "%-15s %s\n", "-u URL", "Tracker's URL");
438   fprintf(stderr, "%-15s %s\n", "-l piece_len",
439     "Piece length (default 262144)");
440   fprintf(stderr, "%-15s %s\n", "-s filename", "Specify metainfo file name");
441   fprintf(stderr, "%-15s %s\n", "-p", "Private (disable peer exchange)");
442   fprintf(stderr, "%-15s %s\n", "-c comment", "Include a comment/description");
443 
444   fprintf(stderr,"\nExample:\n");
445   fprintf(stderr,"ctorrent -s new_filename -e 12 -C 32 -p 6881 example.torrent\n");
446   fprintf(stderr,"\nhome page: http://ctorrent.sourceforge.net/\n");
447   fprintf(stderr,"see also: http://www.rahul.net/dholmes/ctorrent/\n");
448   fprintf(stderr,"bug report: %s\n",PACKAGE_BUGREPORT);
449   fprintf(stderr,"original author: bsdi@sina.com\n\n");
450 }
451 
452