int LoadMyURLDBFile(char * filename) { FILE * pFile; pFile = fopen (filename,"r"); if (pFile!=0) { char longURL[MAX_LONG_URL_SIZE]={0}; char shortURL[MAX_TO_SIZE]={0}; unsigned int i=0; while (!feof(pFile)) { memset(longURL,0,MAX_LONG_URL_SIZE); memset(shortURL,0,MAX_TO_SIZE); int res = fscanf (pFile, "%s\n", longURL); if (res!=1) { AmmServer_Warning("error (?) reading longURL (%s) item line %u of file %s ",longURL,i,filename); } res = fscanf (pFile, "%s\n", shortURL); if (res!=1) { AmmServer_Warning("error (?) reading shortURL (%s) item line %u of file %s ",shortURL,i,filename); } Add_MyURL(longURL,shortURL,0 /*We dont want to reappend it :P*/); ++i; } fclose (pFile); return 1; } return 0; }
//This function adds a Resource Handler for the pages stats.html and formtest.html and associates stats , form and their callback functions void init_dynamic_content() { if (! AmmServer_AddResourceHandler(default_server,&control,"/control.html",webserver_root,4096,0,(void*) &control_callback,SAME_PAGE_FOR_ALL_CLIENTS) ) { AmmServer_Warning("Failed adding stats page\n"); } if (! AmmServer_AddResourceHandler(default_server,&termination,"/terminate.html",webserver_root,4096,0,(void*) &control_callback,SAME_PAGE_FOR_ALL_CLIENTS) ) { AmmServer_Warning("Failed adding stats page\n"); } }
int AmmServer_RegisterTerminationSignal(void * callback) { TerminationCallback = callback; unsigned int failures=0; if (signal(SIGINT, AmmServer_GlobalTerminationHandler) == SIG_ERR) { AmmServer_Warning("AmmarServer cannot handle SIGINT!\n"); ++failures; } if (signal(SIGHUP, AmmServer_GlobalTerminationHandler) == SIG_ERR) { AmmServer_Warning("AmmarServer cannot handle SIGHUP!\n"); ++failures; } if (signal(SIGTERM, AmmServer_GlobalTerminationHandler) == SIG_ERR) { AmmServer_Warning("AmmarServer cannot handle SIGTERM!\n"); ++failures; } if (signal(SIGKILL, AmmServer_GlobalTerminationHandler) == SIG_ERR) { AmmServer_Warning("AmmarServer cannot handle SIGKILL!\n"); ++failures; } return (failures==0); }
//This function adds a Resource Handler for the pages stats.html and formtest.html and associates stats , form and their callback functions void init_dynamic_content() { AmmServer_AddRequestHandler(default_server,&GET_override,"GET",&request_override_callback); unsigned char* buf = prepare_index_prototype("src/Services/MyBlog/res/index.html",&myblog); if (! AmmServer_AddResourceHandler(default_server,&stats,"/index.html",webserver_root,44096,0,&prepare_index,SAME_PAGE_FOR_ALL_CLIENTS) ) { AmmServer_Warning("Failed adding index page\n"); } if (! AmmServer_AddResourceHandler(default_server,&random_chars,"/random.html",webserver_root,4096,0,&prepare_random_content_callback,DIFFERENT_PAGE_FOR_EACH_CLIENT) ) { AmmServer_Warning("Failed adding random testing page\n"); } }
//This function adds a Resource Handler for the pages stats.html and formtest.html and associates stats , form and their callback functions void init_dynamic_content() { if (! AmmServer_AddResourceHandler(default_server,&searchContext,"/search.html",webserver_root,4096,0,&search_callback,SAME_PAGE_FOR_ALL_CLIENTS) ) { AmmServer_Warning("Failed adding stats page\n"); } if (! AmmServer_AddResourceHandler(default_server,&indexContext,"/index.html",webserver_root,4096,0,&prepare_index_content_callback,SAME_PAGE_FOR_ALL_CLIENTS) ) { AmmServer_Warning("Failed adding stats page\n"); } if (! AmmServer_AddResourceHandler(default_server,&logoContext,"/search.png",webserver_root,4096,0,&prepare_logo_content_callback,DIFFERENT_PAGE_FOR_EACH_CLIENT) ) { AmmServer_Warning("Failed adding random testing page\n"); } if (! AmmServer_AddResourceHandler(default_server,&faviconContext,"/favicon.ico",webserver_root,4096,0,&favicon_callback,DIFFERENT_PAGE_FOR_EACH_CLIENT) ) { AmmServer_Warning("Failed adding random testing page\n"); } }
int AmmServer_AddResourceHandler ( struct AmmServer_Instance * instance, struct AmmServer_RH_Context * context, const char * resource_name , const char * web_root, unsigned int allocate_mem_bytes, unsigned int callback_every_x_msec, void * callback, unsigned int scenario ) { if ( context->requestContext.content!=0 ) { AmmServer_Warning("Context in AmmServer_AddResourceHandler for %s appears to have an already initialized memory part\n",resource_name); AmmServer_Warning("Make sure that you are using a seperate context for each AmmServer_AddResourceHandler call you make..\n"); } memset(context,0,sizeof(struct AmmServer_RH_Context)); strncpy(context->web_root_path,web_root,MAX_FILE_PATH); strncpy(context->resource_name,resource_name,MAX_RESOURCE); context->requestContext.instance=instance; // Remember the instance that created this.. context->requestContext.MAXcontentSize=allocate_mem_bytes; context->callback_every_x_msec=callback_every_x_msec; context->last_callback=0; //This is important because a random value here will screw up things with callback_every_x_msec.. context->callback_cooldown=0; context->RH_Scenario = scenario; if ( allocate_mem_bytes>0 ) { context->requestContext.content = (char*) malloc( sizeof(char) * allocate_mem_bytes ); if (context->requestContext.content==0) { AmmServer_Warning("Could not allocate space for request Context"); } } context->dynamicRequestCallbackFunction=callback; if (callback==0) { AmmServer_Warning("No callback passed for a new AmmServer_AddResourceHandler "); } int returnValue = cache_AddMemoryBlock(instance,context); if (!returnValue) { AmmServer_Error("Failed adding new resource handler\n Resource name `%s` will be unavailable\n",resource_name); } return returnValue; }
unsigned long Add_MyURL(char * longURL,char * shortURL,int saveit) { int shortURL_AlreadyExists=0; Find_longURL(shortURL,&shortURL_AlreadyExists); if (shortURL_AlreadyExists) { return 0; } if (loaded_links>=MAX_LINKS) { return 0; } allocateLinksIfNeeded(); unsigned int long_url_length = strlen(longURL); if (long_url_length>=MAX_LONG_URL_SIZE) { return 0; } unsigned int sort_url_length = strlen(shortURL); if (sort_url_length>=MAX_TO_SIZE) { return 0; } pthread_mutex_lock (&db_addIDLock); // LOCK PROTECTED OPERATION ------------------------------------------- //it might not seem like it but here we are doing two seperate operations //first we give our_index the loaded_links value , and then we increment loaded_links //of course this is a potential race condition where two threads assign themselves the same link //and we have an empty record after that , solved using a lock protection unsigned int our_index=loaded_links++; pthread_mutex_unlock (&db_addIDLock); // LOCK PROTECTED OPERATION ------------------------------------------- links[our_index].longURL = ( char * ) malloc (sizeof(char) * (long_url_length+1) ); //+1 for null termination if ( links[our_index].longURL == 0 ) { AmmServer_Warning("Could not allocate space for a new string \n "); return 0; } links[our_index].shortURL = ( char * ) malloc (sizeof(char) * (sort_url_length+1) ); //+1 for null termination if ( links[our_index].shortURL == 0 ) { AmmServer_Warning("Could not allocate space for a new string \n "); return 0; } links[our_index].shortURLHash=hashURL(shortURL); strncpy(links[our_index].longURL,longURL,long_url_length); links[our_index].longURL[long_url_length]=0; // null terminator :P strncpy(links[our_index].shortURL,shortURL,sort_url_length); links[our_index].shortURL[sort_url_length]=0; // null terminator :P if (saveit) { Append2MyURLDBFile(db_file,longURL,shortURL); } if ( REGROUP_AFTER_X_UNSORTED_LINKS <= loaded_links-sorted_links ) { ResortDB(db_file,links,loaded_links); } return 1; }
int closeAmmarServer() { //Delete dynamic content allocations and remove stats.html and formtest.html from the server close_dynamic_content(); //Stop the server and clean state AmmServer_Stop(default_server); AmmServer_Warning("Ammar Server stopped\n"); return 1; }
//This call , calls callback every time a request hits the server.. //The outer layer of the server can do interesting things with it :P //request_type is supposed to be GET , HEAD , POST , CONNECT , etc.. int AmmServer_AddRequestHandler(struct AmmServer_Instance * instance,struct AmmServer_RequestOverride_Context * RequestOverrideContext,const char * request_type,void * callback) { if ( (instance==0)||(RequestOverrideContext==0)||(request_type==0)||(callback==0) ) { return 0; } strncpy( RequestOverrideContext->requestHeader , request_type , 64 /*limit declared on AmmServerlib.h*/) ; RequestOverrideContext->request=0; instance->clientRequestHandlerOverrideContext = RequestOverrideContext; RequestOverrideContext->request_override_callback = callback; AmmServer_Warning("AmmServer_AddRequestHandler could potentially be buggy\n"); return 1; }
int main(int argc, char *argv[]) { printf("\nAmmar Server %s starting up..\n",AmmServer_Version()); //Check binary and header spec AmmServer_CheckIfHeaderBinaryAreTheSame(AMMAR_SERVER_HTTP_HEADER_SPEC); //Register termination signal for when we receive SIGKILL etc AmmServer_RegisterTerminationSignal(&close_dynamic_content); char bindIP[MAX_IP_STRING_SIZE]; strcpy(bindIP,"0.0.0.0"); unsigned int port=DEFAULT_BINDING_PORT; //Kick start AmmarServer , bind the ports , create the threads and get things going..! default_server = AmmServer_StartWithArgs( "MySearch", argc,argv , //The internal server will use the arguments to change settings //If you don't want this look at the AmmServer_Start call bindIP, port, 0, /*This means we don't want a specific configuration file*/ webserver_root, templates_root ); if (!default_server) { AmmServer_Error("Could not start server , shutting down everything.."); exit(1); } //Create dynamic content allocations and associate context to the correct files init_dynamic_content(); //stats.html and formtest.html should be availiable from now on..! while ( (AmmServer_Running(default_server)) ) { //Main thread should just sleep and let the background threads do the hard work..! //In other applications the programmer could use the main thread to do anything he likes.. //The only caveat is that he would takeup more CPU time from the server and that he would have to poll //the AmmServer_Running() call once in a while to make sure everything is in order //usleep(60000); sleep(1); } //Delete dynamic content allocations and remove stats.html and formtest.html from the server close_dynamic_content(); //Stop the server and clean state AmmServer_Stop(default_server); AmmServer_Warning("Ammar Server stopped\n"); return 0; }
int ResortDB(char * db_file,struct URLDB * links,unsigned int loaded_links) { if ( !isURLDBSorted() ) { AmmServer_Warning("URLDB is not sorted Sorting it now..!\n"); qsort(links, loaded_links , sizeof(struct URLDB), struct_cmp_urldb_items); if ( !isURLDBSorted() ) { AmmServer_Warning("Could not sort URLDB ..! :( , exiting \n"); return 0; } else { AmmServer_Success("Sorted URLDB \n"); if ( ReWriteMyURLDBFile(db_file,links,loaded_links) ) { AmmServer_Success("Saved db file \n"); } } } else { AmmServer_Success("Presorted URLDB \n"); } return 1; }
char * getPointerToGETItemValue(struct AmmServer_DynamicRequest * rqst,const char * nameToLookFor,unsigned int * pointerLength) { const struct GETRequestContent * p = getGETItemFromName(rqst,nameToLookFor); if (p!=0) { //AmmServer_Success("getPointerToPOSTItemValue(%s) success => %p \n",nameToLookFor,p->value); *pointerLength = p->valueSize; return p->value; } AmmServer_Warning("getPointerToPOSTItemValue called but could not find name=`%s` \n",nameToLookFor); *pointerLength=0; return 0; }
unsigned int allocateLinksIfNeeded() { unsigned int makeAnAllocation=0; if (allocated_links>=MAX_LINKS) { AmmServer_Warning("Reached constraint on links , will not commit more memory\n"); return 0; } if (loaded_links>=allocated_links) { makeAnAllocation=1; } if (makeAnAllocation) { fprintf(stderr,"Reallocating -> %u records \n",allocated_links+LINK_ALLOCATION_STEP); struct URLDB * newlinks = realloc(links, sizeof(struct URLDB) * (allocated_links+LINK_ALLOCATION_STEP) ); if (newlinks!=0) { links=newlinks; memset(links+allocated_links,0,LINK_ALLOCATION_STEP); allocated_links+=LINK_ALLOCATION_STEP; return 1; } } return 0; }
//Binary Search inline unsigned int Find_longURL(char * shortURL,int * found) { #if USE_BINARY_SEARCH *found = 0; if (shortURL==0) { return 0; } if (loaded_links==0) { return 0; } if (sorted_links!=0) { unsigned long our_hash = hashURL(shortURL); unsigned int binarySearchLastElement = sorted_links; unsigned int beg=0,mid=0,fin=binarySearchLastElement-1; while ( beg <= fin ) { mid=(unsigned int) beg + ( (fin-beg)/2 ); if (mid >= binarySearchLastElement) { AmmServer_Error("Binary Search overflowed ( beg %u mid %u fin %u ) , binarySearchLastElement %u \n",beg,mid,fin,binarySearchLastElement); break; } else if (our_hash<links[mid].shortURLHash) { fin=mid-1; } else if (our_hash>links[mid].shortURLHash) { beg=mid+1; } else { *found = 1; AmmServer_Success("Found %s using binary search\n",shortURL); return mid; } } } //TODO : Remove this message in the future ------------- AmmServer_Warning("Binary Search couldn't find result , extending search to unsorted list\n"); return Find_longURLSerial(shortURL,found); //---------------------------------------- #else // USE_BINARY_SEARCH return Find_longURLSerial(shortURL,found); #endif return 0; }
int finalizeGenericGETField( struct HTTPHeader * output, struct GETRequestContent * target , unsigned int * targetNumber , char * value, unsigned int valueLength ) { //----------------------------------------------------------------------------------- if (value == 0) { AmmServer_Warning("finalizeGenericGETField Value is not set\n"); return 0; } if (valueLength == 0) { AmmServer_Warning("Value Length is not set\n"); return 0; } if (target == 0) { AmmServer_Warning("Target is not set\n"); return 0; } if (output == 0) { AmmServer_Warning("Output is not set\n"); return 0; } if (targetNumber == 0) { AmmServer_Warning("Target Number is not set\n"); return 0; } //----------------------------------------------------------------------------------- *targetNumber=0; char * GETPtr = value; unsigned int GETPtrLength = valueLength; char * GETPtrEnd = GETPtr + GETPtrLength; //AmmServer_Warning("GET Request %s has %u bytes of stuff..\n",GETPtr ,GETPtrLength); char * startOfPTR=GETPtr; unsigned int state = FOUND_NOTHING; while (GETPtr<GETPtrEnd) { if ( (*GETPtr==10) || (*GETPtr==13) || (*GETPtr==0) ) { if (state==FOUND_NOTHING) { //We found no payload.. break; } else if (state==SEEKING_NAME) { //Last Item was a name with no value target[*targetNumber].name=startOfPTR; target[*targetNumber].value=0; *GETPtr=0; //Null Terminate *targetNumber+=1; break; } else if (state==SEEKING_VALUE) { //We reached the end having found a name(which is already set) and a value..! target[*targetNumber].value=startOfPTR; *GETPtr=0; //Null Terminate //fprintf(stderr,"We finished string searching for a value so it is found value %s\n",startOfPTR); *targetNumber+=1; break; } } else { //fprintf(stderr,"GET -> %c \n",*GETPtr); if (state == FOUND_NOTHING) { state=SEEKING_NAME; } if (*GETPtr=='=') { //We found a value if (state==SEEKING_NAME) { target[*targetNumber].name=startOfPTR; target[*targetNumber].value=0; *GETPtr=0; //fprintf(stderr,"We finished a name %s\n",startOfPTR); state=SEEKING_VALUE; startOfPTR=GETPtr+1; } } else if (*GETPtr=='&') { //We found a value if (state==SEEKING_NAME) { target[*targetNumber].name=startOfPTR; target[*targetNumber].value=0; *targetNumber+=1; *GETPtr=0; //Null Terminate startOfPTR=GETPtr+1; } else if (state==SEEKING_VALUE) { target[*targetNumber].value=startOfPTR; *targetNumber+=1; *GETPtr=0; //Null Terminate state=SEEKING_NAME; startOfPTR=GETPtr+1; } } } ++GETPtr; } //Final ( or only value ) if (state==SEEKING_VALUE) { //We reached the end having found a name(which is already set) and a value..! target[*targetNumber].value=startOfPTR; *GETPtr=0; //Null Terminate //fprintf(stderr,"We finished string searching for a value so it is found value %s\n",startOfPTR); *targetNumber+=1; } //Mark that all of the get items here point on RAW and need update on realloc unsigned int i=0; for (i=0; i<*targetNumber; i++) { target[i].reallocateOnHeaderRAWResize=1; //TODO strip HTML characters here.. //StripHTMLCharacters_Inplace(output->GETquery,0 /* 0 = Disregard dangerous bytes , Safety OFF*/); // <- This call converts char sequences like %20 to " " and %00 to \0 disregarding any form of safety , ( since it is a raw var ) target[i].nameSize = strlen(target[i].name); target[i].valueSize = strlen(target[i].value); } /* AmmServer_Success("A total of %u GET Items \n",*targetNumber); for (i=0; i<*targetNumber; i++) { fprintf(stderr,"GET Item %u ------------------ \n",i); fprintf(stderr,"name = %s \n",target[i].name); fprintf(stderr,"value = %s \n",target[i].value); fprintf(stderr,"-------------------------------- \n",i); } */ return 1; }