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