Ejemplo n.º 1
0
void* doNetWork(struct threadData* td) {
    /*Response Variables*/
    struct http_request request;
    int bytesSent;
    int sendResponse;
    int controller;
    int status;
    char * response;
    /* Request variables */
    int readAmount;
    int totalRead;
    int flags; 
    int j,k;
    int contentLength;
    int contentLengthRecieved;
    int contentLengthPosition;
    char * tempBuff;
    char * raw_message;
    char contentLengthBuff[100];
    bytesSent = 0;
    sendResponse =0;

    response = malloc(sizeof(char)*STARTING_RESPONSE_SIZE);
    if(response == NULL){
        NETWORK_LOG_LEVEL_1("Fatal: Failed to allocate memory for response");
        response = "{}";
        status = 500;
        goto internal_err;
    }
    memset(response,0,sizeof(char)*STARTING_RESPONSE_SIZE);

    raw_message = malloc(1+sizeof(char)*BUFSIZ); /* Just enough space for the first read, to determine content length */
    if(raw_message == NULL){
        /* Internal Problem! */
        NETWORK_LOG_LEVEL_1("Fatal: Failed to allocate memory for first-read temporary buffer");
        response[0]='{'; response[1]='}'; response[2]='\0';
        status = 500;
        goto internal_err;
    }
    memset(raw_message, 0,1+sizeof(char)*BUFSIZ);
    tempBuff = NULL; /* temp buff will be used to realloc */
        

    /* Accept and read incoming request  */
    if(td->clientfd == -1)
        goto bad_client_id;

    readAmount=totalRead=contentLengthRecieved =contentLengthPosition= contentLength = 0;

    NETWORK_LOG_LEVEL_2_NUM("Accepted Client Request on File Descriptor ", td->clientfd);
    readAmount = 1; /* Sentinal */
    flags = fcntl(td->clientfd, F_GETFL, 0);
    fcntl(td->clientfd, F_SETFL, flags | O_NONBLOCK);
    contentLength = -1; /* Sentinal */
    while(readAmount != 0){
        readAmount = read(td->clientfd,raw_message+totalRead,BUFSIZ);    
        if(readAmount == -1){
            if(errno == EAGAIN && totalRead == 0)
                continue;
            else if(contentLengthRecieved != contentLength)
                continue;
            else
                readAmount = 0;
        }else{
            NETWORK_LOG_LEVEL_2_NUM("Reading Data From Socket", td->clientfd);
            /* Since we're here that means we have at least 
             * the beginning of the request itself but we're
             * waiting for more. So determine the content-length
             * and then figure out if we have all of it or not
            */
            contentLengthPosition = strnstr("Content-Length", raw_message, BUFSIZ);                    
            if(contentLengthPosition == -1){
                /* You didn't send us a content length, carry on! 
                 * so no data, so just url, so good bye.
                */
                contentLengthRecieved = contentLength = readAmount = 0;
            }else{
                if(totalRead == 0){                            
                    /* Convert the content length 
                    * reuse this connections buffer.
                    */
                    bzero(contentLengthBuff, sizeof contentLengthBuff); /* Only what we need */
                    contentLength = contentLengthPosition;
                    contentLength+=strlen("Content-Length: "); /* Skip the text */
                     
                    for(k=0; k < (int)sizeof(contentLengthBuff) && *(raw_message + contentLength) != '\0' && *(raw_message + contentLength) != '\r'; ++k, contentLength++)
                        contentLengthBuff[k] = *(raw_message + contentLength);
                    contentLengthBuff[k] = '\0';
                    contentLength = atoi(contentLengthBuff);                            
                    
                    /* Malloc for the content Length 
                     * j is the position of the data, all things prior 
                     * need to be conserved as well
                    */
                    if( contentLength > 0 ){
                        tempBuff = malloc(5+ strlen(raw_message) + contentLength + BUFSIZ);
                        if(tempBuff == NULL){
                            free(raw_message);
                            NETWORK_LOG_LEVEL_1("Could not reallocate memory during request data acquisition");
                            goto internal_err;
                        }else{
                            memset(tempBuff, 0, 5+ strlen(raw_message) + contentLength + BUFSIZ);
                            strcpy(tempBuff, raw_message);
                            swapCharPtr(&tempBuff, &raw_message);
                            free(tempBuff);
                        }
                    }
                }

                /* We've said a content length now, and we need 
                * determine how much we've actually recieved
                * no need to store it, just count it with j. 
                */
                j = strnstr("\r\n\r\n", raw_message, BUFSIZ);
                if(j != -1){
                    j+=4; /* skip newlines */
                    j+= contentLengthRecieved;
                    for(contentLengthRecieved = (contentLengthRecieved==0 ? 0 : contentLengthRecieved); (unsigned int)j < strlen(raw_message); ++j, ++contentLengthRecieved)
                        ;                            
                }else{   
                    /* Could not find content...*/
                    if(contentLength <= 0)
                        readAmount = 0; /* Get out */
                    else
                        contentLengthRecieved = 0; /* Haven't received it yet */
                }
            }
            /* Important to do this last as the totalRead is what
             * determines if we malloc for content or not
            */
            
            fprintf(stderr, "Recieving Data From Socket %d: %d/%d\n", td->clientfd ,contentLengthRecieved, contentLength);    
            
            totalRead += readAmount;                
            if(contentLength == contentLengthRecieved) 
                readAmount = 0;      
        }
    }
    if(totalRead > THREAD_DATA_MAX_SIZE)
        NETWORK_LOG_LEVEL_1("Warning: Total Read Greater than Buffer Length");

    /*Blank JSON response for no control*/
    *(response+1)='{'; *(response+1)='}'; *(response+2)='\0';
    status = 200;
    parseRequest(&request, raw_message);

    /* Pass the request off to a handler */
    controller = determineController(request.url);
    /* Determine method and call. */
    switch(controller){
        case HEARTBEAT_CONTROLLER :
            NETWORK_LOG_LEVEL_2("Heartbeat Controller Processing Request.");
            status = heartbeat_controller(response, STARTING_RESPONSE_SIZE);
            break;
        case COMMENTS_CONTROLLER :
            NETWORK_LOG_LEVEL_2("Comments Controller Processing Request.");
            status = comment_controller(&request, &response,  STARTING_RESPONSE_SIZE);
            break;
        case HEATMAP_CONTROLLER :
            NETWORK_LOG_LEVEL_2("Heatmap Controller Processing Request.");
            status = heatmap_controller(&request, &response,  STARTING_RESPONSE_SIZE);
            break;
        case MARKER_CONTROLLER :
            NETWORK_LOG_LEVEL_2("Marker Controller Processing Request.");
            status = marker_controller(&request, &response,  STARTING_RESPONSE_SIZE);
            break;
        case REPORT_CONTROLLER :
            NETWORK_LOG_LEVEL_2("Report Controller Processing Request.");
            status = report_controller(&request, &response,  STARTING_RESPONSE_SIZE);
            break;
        default:
            NETWORK_LOG_LEVEL_2("Unknown URL. Refusing to process request.");
            /* We have no clue what the client is talking about with their url */
            status = 404;
            break;
    }
    

    /* Log and clean up. */
    NETWORK_LOG_LEVEL_1("Incoming Request:")
    NETWORK_LOG_LEVEL_1(request.url);
    if(request.contentLength > 0){
        NETWORK_LOG_LEVEL_2("Incoming Data:");
        NETWORK_LOG_LEVEL_2_NUM("Content length of Data: ", request.contentLength);
        NETWORK_LOG_LEVEL_2(request.data);
    }
    if(request.contentLength > 0)
        free(request.data);

    internal_err:
    td->msg = malloc(strlen(response) + 256);
    if(td->msg == NULL){
        NETWORK_LOG_LEVEL_2_NUM("Fatal: Not enough memory for HTTP response", (int)strlen(response)+256);
        free(raw_message);
        free(response);
        close(td->clientfd);
        return NULL;
    }
    memset(td->msg,0,strlen(response)+256);
    createResponse(response,td->msg,status);
    td->msg[strlen(td->msg)] = '\0';\



    bad_client_id: 
    if(td->clientfd != -1){
        do{
            sendResponse = send(td->clientfd,(td->msg)+bytesSent,strlen(td->msg)-bytesSent,0);  
            if(sendResponse == -1){
                NETWORK_LOG_LEVEL_2(strerror(errno));    
            }else{
                bytesSent += sendResponse;
            }
            NETWORK_LOG_LEVEL_1("Sending Response:");
            NETWORK_LOG_LEVEL_1( ( td->msg )+bytesSent  ); 
            NETWORK_LOG_LEVEL_2_NUM("Bytes sent to client: ", bytesSent);
            
        } while(bytesSent < (int)strlen(td->msg) -1 );
        close(td->clientfd);
    }else{
        NETWORK_LOG_LEVEL_2("File Descriptor invalid. If shutting down there is no problem.");
        NETWORK_LOG_LEVEL_2("If not shutting down, there was an issue sending data to the client.");
    }
    free(td->msg);
    free(raw_message);
    free(response);
    return NULL;
}
static setStatus        listNormaliseOrDuplicates(set setA, myBool Normalise) {
// spec
//  o IN-PLACE normalisation (or listDuplicates) of a set - ie I will write to *setA !
//  o Either 'normalise' functionality -or- reports duplicates, dependent on myBool Normalise
// spec - Normalise
//   (1) Order, (2) Reduce WS to single char, (3) remove duplicates, 
// spec - Duplicates
//   (1) Order, (2) Reduce WS to single char, (3) report only duplicates ((single) entry *only* for those duplicated)
// Design
//   o Take a temporary copy of the supplied string, into local array.
//   o Create local array of ptrs of posn of each token (member) within the copy of the string.
//   o Sort the array of ptrs; 
//   o Generate new string(normalised or duplicates) at location pointed to by original string (formal param),

	SL64 MAX_MEMBERS_X_2=2 * setImp.setMaxMembers;  
// #define	MAX_MEMBERS_X_2  (2 * setImp.setMaxMembers)

	UC8 *tT[MAX_MEMBERS_X_2]; // token Table of ptrs to start of each token
	int tTindex=-1;                  // Index into tT
	int numTokens;                   // Number of tokens discovered

	UC8 sCopy[setImp.setMaxChars]; // Copy of supplied set. Use of strtok damages the supplied string.
	UC8 *aMember;                   // a token       

	int pass;                        // Multiple passes within the sort function...

	// Deal with some exceptional conditions
	if (!setA)             return setBadSet;  // No set supplied
	if (!*setA)            return setOK;      // Empty set supplied
	if (isBadLength(setA)) return setBadSet;  // Set TOO large
	if (setCardinal(setA) > MAX_MEMBERS_X_2) return setBadSet;  // Set TOO many members

	// Generate tT - Create this table of ptrs 
	(void) strncpy(sCopy, setA, setImp.setMaxChars);        
	do {
		aMember=strtok((tTindex == -1) ? sCopy : NULL, setImp.setWhiteSpaceChars);
		if (aMember) {
			if (tTindex == MAX_MEMBERS_X_2) 
				return setBadSet;
			else 
				tT[++tTindex]=aMember;   // Got one 
			}
	} while (aMember);

	// Really poor sort algorithm - but heh it's not production.
	// Could use stdlib's qsort.....
	numTokens=tTindex;
	for (pass=numTokens; pass >=0; pass--) {
		for (tTindex=numTokens; tTindex; tTindex--) {
			if (myStrCmp(tT[tTindex], tT[tTindex -1]) < 0) {
				swapCharPtr(&(tT[tTindex]), &(tT[tTindex -1]));
			}
		}
	}

	*setA=(UC8)0; // Bang !! - Sometimes you cannot write to here - unless its a TRUE set that I made....
	for (tTindex=0; tTindex <=numTokens; tTindex++) {
			// WHY? Get MISRA slap for side-effect ON RHS of &&
		if (Normalise != (tTindex && !myStrCmp(tT[tTindex], tT[tTindex -1])))  { 
			if (*setA) setA=strcat(setA, " ");  // Only pre-pend space on non-initial members
			setA=strcat(setA, tT[tTindex]); //zzz
		}
	}
	if (setCardinal(setA) > setImp.setMaxMembers) return setBadSet;  // Set TOO many members
	return setOK;
}