PageRenderTime 5803ms CodeModel.GetById 1079ms app.highlight 3228ms RepoModel.GetById 840ms app.codeStats 0ms

/Src/Symphony/slurpie_client/context.cpp

https://bitbucket.org/jurgen_kluft/symphony
C++ | 599 lines | 489 code | 66 blank | 44 comment | 81 complexity | 7ddf641890c16d612ba983e00e3cacc0 MD5 | raw file
  1#include <stdio.h>
  2#include <stdlib.h>
  3#include <string.h>
  4#include <assert.h>
  5#include <fcntl.h>
  6#include <time.h>
  7
  8#include "utils.h"
  9#include "connection.h"
 10#include "rem_slurpied.h"
 11#include "protocol.h"
 12#include "context.h"
 13#include "downloads.h"
 14#include "version.h"
 15
 16// Local prototypes. aka helper functions
 17static int parseSlurpieServer(context* c, const char* server_port);
 18static int contextParseURL(context* c, const char* url);
 19static int parseURLMD5SUM(context* c, const char* urlmd5sum);
 20static int generateDestination(context* c);
 21
 22context* contextCreate()
 23{
 24
 25	context* c;
 26
 27	// Allocate the structure
 28	c = (context*) malloc(sizeof(context));
 29	if (c == NULL)
 30		return NULL;
 31	memset(c, 0, sizeof(context));
 32
 33	// Set some default values
 34	c->maxNumOfDownloads = 10;
 35	c->maxUpdateTreeLeaves = 100;
 36	c->maxNumOfNeighbors = MAXNUMNEIGHBORS;
 37	c->desiredNumOfNeighbors = DEFAULTNUMNEIGHBORS;
 38	c->desiredNumOfUpdates=DEFAULT_UPDATES_PER_ROUND;
 39	c->neighborChoice=0;
 40
 41	c->URL= NULL;
 42
 43	// leech server stuff
 44	c->maxNumOfLeeches = 10;
 45	c->numOfLeechThreads = 10;
 46	c->useMTLeechServ = 0;
 47
 48	// Initialize the Block break rule
 49	c->blockRule = 0;
 50	c->blockSize = 256*1024;			// by default, bs=256k
 51	c->blockingPriority = BLOCKSIZEPRIORITY;	// by default, we fix
 52	// the blocksize, and then calculate the number of blocks
 53	// as a function of the size, by default
 54	c->fileSize = -1;	// set later in init
 55	c->numberOfBlocks = -1;
 56	c->fd = 0;
 57	c->dlBitMap = NULL;
 58	c->dlq = NULL;
 59	c->ac = NULL;
 60	c->quiet = 0;		// not quiet by default
 61	c->downloadType=DOWNLOADTYPE_ADAPTIVE;	// download style
 62	c->phase2=0;
 63	c->magicTime=DEFAULT_MAGIC_TIME;
 64	c->pickTwo=0;
 65	c->randomSeed=-1;
 66
 67	// Neighbor Manager: creation moved to contextJoin
 68	c->neighborMgr = NULL;
 69
 70	// Hash stuff
 71	c->hashChecker = NULL;
 72	c->hash_enabled = 0;
 73	c->hash_maxRequestSize = DEFAULT_HASH_MAX_REQ_SIZE;
 74
 75	c->backoffRule=BACKOFFRULE_GOOD;
 76	c->backoffBias=BACKOFFBIASDEFAULT;
 77	c->backOffCommitTime=DEFAULT_BACKOFF_TIME;
 78	c->backoffDidBackOff=0;
 79
 80	c->peerBlocksDld=c-> sourceBlocksDld=0;
 81
 82	// Update Tree
 83	// If you create something thing, don't forget to destroy
 84	// it at contextDestroy
 85	c->updateTree = updateTreeNew(c->maxUpdateTreeLeaves);
 86	c->updateThreadP=NULL;
 87
 88	// Slurpie Server stuff
 89	c->slurpieServerAddress = (char*)(malloc(strlen(SLURPIED_DEFAULT_HOST)+1));
 90	strcpy(c->slurpieServerAddress, SLURPIED_DEFAULT_HOST);
 91	c->slurpieServerPort=SLURPIED_DEFAULT_PORT;
 92
 93	c->localIp = getLocalHostIP();
 94
 95	// Initialize the Synchronization Primitives
 96	c->lock = (boost::mutex*)malloc(sizeof(boost::mutex));
 97	c->flock = (boost::mutex*)malloc(sizeof(boost::mutex));
 98
 99	// Default adaptive downloading parameters
100	c->adl_maxBandwidth = DEFAULT_ADL_MAX_BANDWIDTH;;
101	c->adl_timer =	DEFAULT_ADL_TIMER;
102	c->adl_timer_inc =	DEFAULT_ADL_TIMER_INC;
103	c->adl_maxConnections =	DEFAULT_ADL_MAX_CONNECTIONS;
104	c->adl_bandwidth_inc =	DEFAULT_ADL_BANDWIDTH_INC;
105
106	return c;
107}
108
109int contextParseParameters(context* c, int argc, char** argv)
110{
111	int i;
112	// Lock the mutex
113
114	c->lock->lock();
115	for(i=1;i<argc;i++)
116	{
117		if(!strcmp(argv[i],"-q"))
118		{
119			c->quiet=1;
120			continue;
121		}
122		if(!strcmp(argv[i],"-p"))
123		{
124			c->phase2=1;
125			continue;
126		}
127		if((!strcmp(argv[i],"-s"))&&(i+1<argc))
128		{
129			i++;
130			if(parseSlurpieServer(c,argv[i]))
131				usage(argv[i],": bad server:port");
132			continue;
133		}
134		if((!strcmp(argv[i],"-o"))&&(i+1<argc))
135		{
136			i++;
137			c->destFileName = strdup(argv[i]);
138			assert(c->destFileName!=NULL);
139			continue;
140		}
141		if((!strcmp(argv[i],"-N"))&&(i+1<argc))
142		{
143			i++;
144			c->maxNumOfNeighbors = atoi(argv[i]);
145			assert(c->maxNumOfNeighbors>=0);
146			continue;
147		}
148		if((!strcmp(argv[i],"-m"))&&(i+1<argc))
149		{
150			i++;
151			c->magicTime = atoi(argv[i]);
152			assert(c->magicTime>=0);
153			continue;
154		}
155		if((!strcmp(argv[i],"-n"))&&(i+1<argc))
156		{
157			i++;
158			c->numberOfBlocks = atoi(argv[i]);
159			c->blockingPriority=NUMBLOCKSPRIORITY;
160			assert(c->numberOfBlocks>=0);
161			continue;
162		}
163		if((!strcmp(argv[i],"-b"))&&(i+1<argc))
164		{
165			i++;
166			c->blockSize = atoi(argv[i]);
167			c->blockingPriority=BLOCKSIZEPRIORITY;
168			assert(c->blockSize>=0);
169			continue;
170		}
171		if((!strcmp(argv[i],"-B"))&&(i+1<argc))
172		{
173			i++;
174			c->backoffRule = atoi(argv[i]);
175			continue;
176		}
177		if((!strcmp(argv[i],"-bt"))&&(i+1<argc))
178		{
179			i++;
180			c->backoffTime = atoi(argv[i]);
181			continue;
182		}
183		if((!strcmp(argv[i],"-bb"))&&(i+1<argc))
184		{
185			i++;
186			c->backoffBias = atoi(argv[i]);
187			continue;
188		}
189		if((!strcmp(argv[i],"-d"))&&(i+1<argc))
190		{
191			i++;
192			DEBUGLEVEL = atoi(argv[i]);
193			assert(DEBUGLEVEL>=0);
194			continue;
195		}
196		if((!strcmp(argv[i],"-R"))&&(i+1<argc))
197		{
198			i++;
199			c->randomSeed = atoi(argv[i]);
200			continue;
201		}
202		if((!strcmp(argv[i],"-t"))&&(i+1<argc))
203		{
204			i++;
205			c->maxNumOfDownloads = atoi(argv[i]);
206			assert(c->maxNumOfDownloads>=0);
207			continue;
208		}
209		if(!strncmp(argv[i],"ftp://",strlen("ftp://")))
210		{
211			if(contextParseURL(c,argv[i]))
212				usage(argv[i],": bad URL");
213			continue;
214		}
215		if(!strncmp(argv[i],"http://",strlen("http://")))
216		{
217			if(contextParseURL(c,argv[i]))
218				usage(argv[i],": bad URL");
219			continue;
220		}
221		if(!strcmp(argv[i],"-a"))
222		{
223			c->downloadType=DOWNLOADTYPE_ADAPTIVE;
224			continue;
225		}
226		if(!strcmp(argv[i],"-at"))
227		{
228			i++;
229			c->adl_timer=atoi(argv[i]);
230			assert(c->adl_timer>=0);
231			continue;
232		}
233		if(!strcmp(argv[i], "-P")) 
234		{
235			c->pickTwo = 0;
236			continue;
237		}
238		if(!strcmp(argv[i], "-L"))
239		{
240			c->neighborChoice = 1;
241			continue;
242		}
243		if(!strcmp(argv[i], "-l"))
244		{
245			c->useMTLeechServ = 1;
246			continue;
247		}
248		if(!strcmp(argv[i], "-S"))
249		{
250			c->hash_enabled = 1;
251			continue;
252		}
253		if(!strcmp(argv[i], "-Ssize")) 
254		{
255			// The value specified is in kilobytes, but store it in bytes for
256			// easy comparison later
257			i++;
258			c->hash_maxRequestSize = 1024 * atoi(argv[i]);
259			assert(c->hash_maxRequestSize > 0);
260			continue;
261		}
262		usage(argv[i],": unknown argument");
263	}
264
265	c->lock->unlock();
266	return 0;
267}
268
269void usage(char *s1, char *s2)
270{
271	if(s1)
272		fprintf(stderr,"%s ",s1);
273	if(s2)
274		fprintf(stderr,"%s ",s2);
275	if(s1||s2)
276		fprintf(stderr,"\n");
277
278
279	fprintf(stderr,"Slurpie Client v%d.%d\n"
280		"Usage:\n"
281		"slurpie [options] <http://...|ftp://...>\n"
282		"Options:\n"
283		"\t-a                 - turns on adaptive downloads\n"
284		"\t-s host[:port]     - set slurpie server\n"
285		"\t-t nThreads        - number of concurrent downloads\n"
286		"\t-o outfile         - alternative name for outfile\n"
287		"\t-b blocksize       - sets the size of the blocks\n"
288		"\t-B rule       	- sets the backoff rule [off]\n"
289		"\t-bt secs		- time in secs to backoff [%d]\n"
290		"\t-bb k		- goto the source with P(k/n) [%d]\n"
291		"\t-m secs		- the time to wait after downloads[%d]\n"
292		"\t-n numberofblocks  - sets the number of blocks (overrides blocksize)\n"
293		"\t-N numofneighbors  - sets the number of neighbors[%d]\n"
294		"\t-l                 - use old (multithreaded) threaded leech sever\n"
295		"\t-L                 - sets neighbors to O(ln(n))\n"
296		"\t-p			- disable phase1 of downloads\n"
297		"\t-P			- pick best block of 2\n"
298		"\t-q                 - turns off all screen output\n"
299		"\t-R seed		- seed the PRNG with 'seed' \n"
300		"\t-d level           - sets the debug level[%d]\n"
301		"\t-S                 - turns on secure mode (blocks verified)\n"
302		"\t-------------- Adaptive Download Options -------------\n"
303		"\t-at secs           - initial timer value [%d] \n"
304		"\t----------------- Secure Mode Options ----------------\n"
305		"\t-Ssize kbytes      - sets the maximum size of a hash request [1024]\n",
306		SLURPIE_VERSION.major,
307		SLURPIE_VERSION.minor,
308		DEFAULT_BACKOFF_TIME,
309		BACKOFFBIASDEFAULT,
310		DEFAULT_MAGIC_TIME,
311		DEFAULTNUMNEIGHBORS,
312		DEFAULTDEBUGLEVEL,
313		DEFAULT_ADL_TIMER
314		);
315	exit(1);
316}
317
318void contextDestroy(context* c) 
319{
320	Dprintf("contextDestroy ENTERED\n");
321	// Free The user parameters
322	if (c->slurpieServerAddress) free(c->slurpieServerAddress);
323	if (c->URL) free(c->URL);
324	if (c->URLMD5SUM) free(c->URLMD5SUM);
325	if (c->destFileName) free(c->destFileName);
326
327	// Destroy the NeighborManager
328	if(c->neighborMgr)
329		neighborManagerDestroy(c->neighborMgr);
330
331	// Destroy the Sync Primitives
332	delete c->lock;
333	c->lock = NULL;
334
335	// take out the updateTree
336	c->updateThreadP->detach();
337
338	if(c->updateTree)
339		updateTreeFree(c->updateTree);
340
341	close(c->fd);
342
343	Dprintf("contextDestroy EXIT\n");
344}
345
346int contextJoin(context* c)
347{
348	int rv = 0;
349	char addr[30];
350	connection_t* server;
351	order_cmd* order;
352	get_drinkers_cmd* get_drinkers;
353
354	c->lock->lock();
355
356	// moved from contextCreate: Rob
357	c->neighborMgr= neighborManagerCreate((struct context *)c);
358
359	server = connection_create(PROTO_SLURPIED, SLURPIE_VERSION);
360	order = order_create(c->URL, neighborManagerGetAddr(c->neighborMgr, addr, 30), neighborManagerGetPort(c->neighborMgr));
361	get_drinkers = get_drinkers_create(c->URL, c->neighborMgr->maxNumOfNeighbors);
362
363	rv = server == NULL;
364	rv = (rv) ? rv : connection_connect(server, c->slurpieServerAddress, c->slurpieServerPort);
365	rv = (rv) ? rv : rem_slurpied_get_drinkers(server, &get_drinkers);
366	rv = (rv) ? rv : rem_slurpied_order(server, order);
367
368	if (server)
369		connection_destroy(server);
370
371	if (order) 
372		order_destroy(&order);
373
374	if (get_drinkers) 
375	{
376		int i;
377		if (rv == 0)
378		{
379			if((get_drinkers->num_ip_ports)&&(!c->quiet))
380				printf("Neighbors:");
381
382			for (i = 0; i < get_drinkers->num_ip_ports; i++) 
383			{
384				char ipPortBuf[IP_PORT_BUF_LEN];
385				if(!c->quiet) printf(" %s", ip_port_to_string(get_drinkers->ip_ports[i], ipPortBuf, IP_PORT_BUF_LEN));
386				neighborManagerConnectToPeer(c->neighborMgr, get_drinkers->ip_ports[i]->ip, get_drinkers->ip_ports[i]->port);
387			}
388
389			if ((get_drinkers->num_ip_ports)&&(!c->quiet))
390				printf("\n");
391		}
392
393		get_drinkers_destroy(&get_drinkers);
394	}
395	c->lock->unlock();
396	return rv;
397}
398
399
400/* int contextFileOpen(context *c);
401* 	opens the dst file in the dst dir
402*/
403
404int contextFileOpen(context *c)
405{
406	char buf[BUFLEN];
407	int fd;
408
409	sprintf_s(buf,BUFLEN,"%s",c->destFileName);
410	fd= open(buf,O_RDWR|O_CREAT|O_TRUNC,0644);
411	c->fd=fd;
412	if(fd == -1){
413		perror("contextFileOpen:open");
414		abort();
415	}
416	return fd;
417}
418
419/* char *contextParseFileName(context *c)
420* 	sldkfslk
421*/
422
423char * contextParseFileName(context *c)
424{
425	char * tmp;
426	if(c->destFileName)	// already set on command line
427		return c->destFileName;	
428	tmp = rindex(c->URL,'/');
429	tmp++;
430	c->destFileName = strdup(tmp);
431	return c->destFileName;
432}
433
434
435void do_context_tests()
436{
437	context* c = contextCreate();
438
439	// parseSlurpieServer test
440	{
441		const char* serverPort[] =
442		{ 
443			"envy.sodre.cx", 
444			"lust.sodre.cx:", 
445			"sloth.sodre.cx:33456",
446			":33457", 
447			":", 
448			NULL
449		};
450		const char* expectedAddress[] = 
451		{
452			"envy.sodre.cx",
453			"lust.sodre.cx",
454			"sloth.sodre.cx",
455			SLURPIED_DEFAULT_HOST,
456			SLURPIED_DEFAULT_HOST,
457			NULL
458		};
459		const int expectedPort[] = 
460		{
461			SLURPIED_DEFAULT_PORT,
462			SLURPIED_DEFAULT_PORT,
463			33456,
464			33457,
465			SLURPIED_DEFAULT_PORT,
466			-1
467		};
468		const char** sp = serverPort;
469		const char** ea = expectedAddress;
470		const int* ep = expectedPort;
471		for(; *sp != NULL; sp++, ea++, ep++) 
472		{
473			assert(parseSlurpieServer(c, *sp) == 0);
474			assert(strcmp(c->slurpieServerAddress, *ea) == 0);
475			assert(c->slurpieServerPort == *ep);
476			printf("%s -> %s:%d OK\n", *sp, *ea, *ep);
477			free(c->slurpieServerAddress);
478		}
479
480		assert(parseSlurpieServer(c, *(--sp)) == 0);
481	}
482
483	// Test the contextParseURL
484	{
485		const char* url = "ftp://ftp2.it.debian.org/debian-cd/3.0_r0/i386/debian-30r0-i386-1_NONUS.iso";
486		assert(contextParseURL(c, url) == 0);
487		assert(strcmp(c->URL, url) == 0);
488		printf("%s == %s OK\n", url, c->URL);
489	}
490
491	// Test the parseURLMD5SUM
492	{
493		const char* url = "ftp://ftp2.it.debian.org/debian-cd/3.0_r0/i386/MD5SUMS";
494		assert(parseURLMD5SUM(c, url) == 0);
495		assert(strcmp(c->URLMD5SUM, url) == 0);
496		printf("%s == %s OK\n", url, c->URLMD5SUM);
497	}
498
499	// Test the generateDestinationFilename
500	{
501		const char* destFN = "debian-30r0-i386-1_NONUS.iso";
502		assert(generateDestination(c) == 0);
503		assert(strcmp(c->destFileName, destFN) == 0);
504		printf("%s == %s OK\n", c->destFileName, destFN);
505	}
506
507	contextDestroy(c);
508	return;
509}
510
511// Local Prototypes. aka helper functions {{{2
512static int parseSlurpieServer(context* c, const char* server_port)
513{
514	int rv=0;
515	int i=0;
516	// Find a ':'
517	while(i < strlen(server_port) && server_port[i] != ':')
518		i++;
519
520	// Copy the serverName
521	if (i == 0) {
522		const char* defaultServer = SLURPIED_DEFAULT_HOST;
523		free(c->slurpieServerAddress);
524		c->slurpieServerAddress = (char*)(malloc(strlen(defaultServer)+1));
525		strcpy(c->slurpieServerAddress, defaultServer);
526	}
527	else {
528		c->slurpieServerAddress = (char*)(malloc(i+1));
529		strncpy(c->slurpieServerAddress, server_port, i);
530		c->slurpieServerAddress[i] = '\0';
531	}
532	// Get the Port
533	if ((i+1) >= strlen(server_port)) 
534		c->slurpieServerPort = SLURPIED_DEFAULT_PORT;
535	else {
536		char* endPtr;
537		c->slurpieServerPort = strtoul(&server_port[i+1], &endPtr, 10);
538		if (*endPtr != '\0') {
539			printf("contextParseSlurpieServer error: Invalid <[server]:[port]> %s\n", server_port);
540			rv = -1;
541		}
542	}
543
544	return rv;
545}
546
547static int contextParseURL(context* c, const char* url) 
548{
549	int rv = 0;
550	// ftp://ftp2.it.debian.org/debian-cd/3.0_r0/i386/debian-30r0-i386-1_NONUS.iso;
551	c->URL = (char*)malloc(strlen(url)+1);
552	if (c->URL) 
553		strcpy(c->URL, url);
554	else 
555		rv = -1;
556	return rv;
557}
558
559static int parseURLMD5SUM(context* c, const char* url)
560{
561	// ftp://ftp2.it.debian.org/debian-cd/3.0_r0/i386/MD5SUMS;
562	int rv = 0;
563	c->URLMD5SUM = (char*)malloc(strlen(url)+1);
564	if (c->URLMD5SUM)
565		strcpy(c->URLMD5SUM, url);
566	else
567		rv = -1;
568	return rv;
569}
570
571static int generateDestination(context* c)
572{
573	int rv = 0;
574	// Default value was 
575	// debian-30r0-i386-1_NONUS.iso;
576	int i = strlen(c->URL);
577
578	// Look for the url separator '/'
579	do
580	{
581		i--;
582	} while(i > 0 && c->URL[i] != '/');
583
584	// copy the filename
585	if (i > 0) 
586	{
587		const char* destFN = &c->URL[i+1];
588		c->destFileName = (char*)malloc(strlen(destFN)+1);
589		if (c->destFileName) 
590			strcpy(c->destFileName, destFN);
591		else 
592			rv = -1;
593	}
594	else 
595		rv = -1;
596	return rv;
597}
598
599// 2}}}