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; }