//----------------------------------------------------------------------------- /// SendHTTPErrorResponse /// /// Sends an error page back /// /// \param requestID An ID for a particular request; the plugin will get this /// id as a parameter to the ProcessRequest( ) function /// \param nErrorCode numeric identifier of the error to return /// /// \return true if the response could be sent; false otherwise //----------------------------------------------------------------------------- bool SendHTTPErrorResponse(CommunicationID& requestID, int nErrorCode) { // see if the response is streaming and rate limited if (ShouldResponseBeSent(requestID, true) == true) { // the message shouldn't be sent because of the rate limiting // return true though so the server thinks it was sent successfully return true; } Response* pResponse = NULL; if (MakeResponse(requestID, &pResponse) == false) { return false; } if (OutputHTTPError(pResponse->client_socket, nErrorCode) == false) { DestroyResponse(requestID, &pResponse); return false; } if (pResponse->m_bStreamingEnabled == false) { DestroyResponse(requestID, &pResponse); } return true; }
//----------------------------------------------------------------------------- /// SendRedirectResponse /// /// Redirects the browser to a different URL than the one requested /// /// \param requestID An ID for a particular request; the plugin will get this /// id as a parameter to the ProcessRequest( ) function /// \param pNewURL The url that the browser is being redirected to /// /// \return true if the response could be sent; false otherwise //----------------------------------------------------------------------------- bool SendRedirectResponse(CommunicationID& requestID, const char* pNewURL) { if (pNewURL == NULL) { return false; } // see if the response is streaming and rate limited if (ShouldResponseBeSent(requestID, true) == true) { // the message shouldn't be sent because of the rate limiting // return true though so the server thinks it was sent successfully return true; } Response* pResponse = NULL; if (MakeResponse(requestID, &pResponse) == false) { return false; } // generate the redirect html static char headerBuffer[COMM_BUFFER_SIZE]; static char htmlBuffer[COMM_BUFFER_SIZE]; sprintf_s(htmlBuffer, COMM_BUFFER_SIZE, "<html><body><a href=\"%s\">%s</a></body></html>", pNewURL, pNewURL); sprintf_s(headerBuffer, COMM_BUFFER_SIZE, "HTTP/1.0 301\r\nContent-Type: text/html\r\nContent-Length: %zd\r\nLocation: %s\r\n\r\n", strlen(htmlBuffer), pNewURL); bool nRes1; bool nRes2; nRes1 = pResponse->client_socket->Send(headerBuffer, (DWORD)strlen(headerBuffer)); nRes2 = pResponse->client_socket->Send(htmlBuffer, (DWORD)strlen(htmlBuffer)); pResponse->client_socket->close(); if ((nRes1 == false) || (nRes2 == false)) { DestroyResponse(requestID, &pResponse); return false; } if (pResponse->m_bStreamingEnabled == false) { DestroyResponse(requestID, &pResponse); } return true; }
//----------------------------------------------------------------------------- /// SendMimeResponse /// /// Sends a single buffer of raw data as the response which should be /// interpreted by the recipient as being of the indicated MIME type /// /// \param requestID An ID for a particular request; the plugin will get this /// id as a parameter to the ProcessRequest( ) function /// \param cpMimeType A string identifying which MIME type to use for /// interpreting the data /// \param cpData pointer to the data that should be sent as a response /// \param uSizeInBytes number of bytes of data pointed to by cpData /// /// \return true if the response could be sent; false otherwise //----------------------------------------------------------------------------- bool SendMimeResponse(CommunicationID& requestID, const char* cpMimeType, const char* cpData, unsigned int uSizeInBytes) { if (cpMimeType == NULL) { Log(logERROR, "Failed to send %s response because data is NULL\n", cpMimeType); return false; } // see if the response is streaming and rate limited if (ShouldResponseBeSent(requestID, true) == true) { // the message shouldn't be sent because of the rate limiting // return true though so the server thinks it was sent successfully return true; } Response* pResponse = NULL; if (MakeResponse(requestID, &pResponse) == false) { return false; } // if Data is NULL then close streaming connection if (pResponse->m_bStreamingEnabled == true) { if (cpData == NULL) { const char* pstr = "--BoundaryString\r\n"; pResponse->client_socket->Send(pstr, (unsigned int)strlen(pstr)); CloseConnection(*pResponse); DestroyResponse(requestID, &pResponse); return true; } } if (Send(*pResponse, cpMimeType, cpData, uSizeInBytes) == false) { DestroyResponse(requestID, &pResponse); return false; } if (pResponse->m_bStreamingEnabled == false) { DestroyResponse(requestID, &pResponse); } return true; }
//----------------------------------------------------------------------------- /// SendFormattedTextResponse /// /// Send a formatted string to be interpreted as text by the recipient. /// /// \param requestID An ID for a particular request; the plugin will get this /// id as a parameter to the ProcessRequest( ) function /// \param cpFormat pointer to a character format that should be send as a /// response; it is expected that this format consumes the remaining /// parameters to this function /// /// \return true if the response could be sent; false otherwise //----------------------------------------------------------------------------- bool SendFormattedTextResponse(CommunicationID& requestID, const char* cpFormat, ...) { if (cpFormat == NULL) { Log(logERROR, "Failed to send formatted response because data is NULL\n"); return false; } // see if the response is streaming and rate limited if (ShouldResponseBeSent(requestID, true) == true) { // the message shouldn't be sent because of the rate limiting // return true though so the server thinks it was sent successfully return true; } Response* pResponse = NULL; if (MakeResponse(requestID, &pResponse) == false) { Log(logERROR, "Failed to make a response for requestID %d\n", requestID); return false; } static char string[ 10240 ]; va_list arg_ptr; va_start(arg_ptr, cpFormat); vsprintf_s(string, 10240, cpFormat, arg_ptr); va_end(arg_ptr); if (Send(*pResponse, "text/plain", string, (unsigned long)strlen(string)) == false) { Log(logERROR, "Failed to 'Send' response for requestID %d\n", requestID); DestroyResponse(requestID, &pResponse); return false; } if (pResponse->m_bStreamingEnabled == false) { DestroyResponse(requestID, &pResponse); } return true; }
//----------------------------------------------------------------------------- /// SendTextResponse /// /// Sends a character string to be interpreted as text by the recipient. /// /// \param requestID An ID for a particular request; the plugin will get this /// id as a parameter to the ProcessRequest( ) function /// \param cpData pointer to the text that should be sent as a response /// /// \return true if the response could be sent; false otherwise //----------------------------------------------------------------------------- bool SendTextResponse(CommunicationID& requestID, const char* cpData) { if (cpData == NULL) { Log(logERROR, "Failed to send text response because data is NULL\n"); return false; } // see if the response is streaming and rate limited if (ShouldResponseBeSent(requestID, true) == true) { // the message shouldn't be sent because of the rate limiting // return true though so the server thinks it was sent successfully return true; } Response* pResponse = NULL; if (MakeResponse(requestID, &pResponse) == false) { Log(logERROR, "Failed to make a response for requestID %d to send content: %s\n", requestID, cpData); return false; } if (Send(*pResponse, "text/plain", cpData, (unsigned long)strlen(cpData)) == false) { Log(logERROR, "Failed to 'Send' response for requestID %d with content: %s\n", requestID, cpData); DestroyResponse(requestID, &pResponse); return false; } if (pResponse->m_bStreamingEnabled == false) { DestroyResponse(requestID, &pResponse); } return true; }
//----------------------------------------------------------------------------- /// SendBinaryResponse /// /// Sends a single buffer of raw data as the response. /// /// \param requestID An ID for a particular request; the plugin will get this /// id as a parameter to the ProcessRequest( ) function /// \param cpData pointer to the data that should be sent as a response /// \param uSizeInBytes number of bytes of data pointed to by cpData /// /// \return true if the response could be sent; false otherwise //----------------------------------------------------------------------------- bool SendBinaryResponse(CommunicationID& requestID, const char* cpData, unsigned int uSizeInBytes) { if (cpData == NULL) { Log(logERROR, "Failed to send binary response because data is NULL\n"); return false; } // see if the response is streaming and rate limited if (ShouldResponseBeSent(requestID, true) == true) { // the message shouldn't be sent because of the rate limiting // return true though so the server thinks it was sent successfully return true; } Response* pResponse = NULL; if (MakeResponse(requestID, &pResponse) == false) { Log(logERROR, "Failed to make a response for requestID %d\n", requestID); return false; } if (Send(*pResponse, "application/octet-stream", cpData, uSizeInBytes) == false) { Log(logERROR, "Failed to 'Send' response for requestID %d\n", requestID); if (pResponse->m_bStreamingEnabled == false) { DestroyResponse(requestID, &pResponse); } return false; } return true; }
//----------------------------------------------------------------------------- /// SendFileResponse /// /// Sends the binary contents of a file to be interpreted by the recipient as /// the type of file indicated by the file's extension. /// /// \param requestID An ID for a particular request; the plugin will get this /// id as a parameter to the ProcessRequest( ) function /// \param cpData pointer to the filename that should be sent as a response /// /// \return true if the response could be sent; false otherwise //----------------------------------------------------------------------------- bool SendFileResponse(CommunicationID& requestID, const char* cpFile) { if (cpFile == NULL) { Log(logERROR, "Failed to send file response because filename is NULL\n"); return false; } // see if the response is streaming and rate limited if (ShouldResponseBeSent(requestID, true) == true) { // the message shouldn't be sent because of the rate limiting // return true though so the server thinks it was sent successfully return true; } Response* pResponse = NULL; if (MakeResponse(requestID, &pResponse) == false) { Log(logERROR, "Failed to make a response for requestID %d to send file: %s\n", requestID, cpFile); return false; } // collect file data and generate response FILE* in; long fileSize; char* fileBuffer; fopen_s(&in, cpFile, "rb"); // read binary if (!in) { // file error, not found? OutputHTTPError(pResponse->client_socket, 404); // 404 - not found return false; } // determine file size fseek(in, 0, SEEK_END); fileSize = ftell(in); fseek(in, 0, SEEK_SET); // allocate Buffer_ and read in file contents fileBuffer = new char[fileSize]; fread(fileBuffer, sizeof(char), fileSize, in); fclose(in); bool bRes = Send(*pResponse, mimetypes[ FindMimeType(cpFile)].mime, fileBuffer, fileSize); if (bRes == false) { Log(logERROR, "Failed to 'Send' response for requestID %d\n", requestID); DestroyResponse(requestID, &pResponse); } delete [] fileBuffer; if (pResponse->m_bStreamingEnabled == false) { DestroyResponse(requestID, &pResponse); } return bRes; }
int main(void) { char inputBuffer[1024]; InitializeRandomness(); InitializeSimulation(); while (1) { int bytesReceived = ReceiveUntil(inputBuffer, sizeof(inputBuffer), '\n'); if (bytesReceived < 0) { break; } if (bytesReceived == 0) { continue; } query *pCurrentQuery = ParseQuery(inputBuffer); response *pCurrentResponse = GenerateBlankResponse(); switch (pCurrentQuery->type) { case QUERY_ALL: { printf("Query All\n"); // List all servers in network link *listItem = serverList->root; while (listItem != NULL) { serverInfo *server = listItem->object; if (server == NULL) { continue; } AddToResponse(pCurrentResponse, "server:"); AddToResponse(pCurrentResponse, server->name); AddToResponse(pCurrentResponse, ":"); listItem = listItem->next; } break; } case QUERY_SERVER: { printf("Query Server\n"); // List all instances on a server char *name = (char *)pCurrentQuery->data; serverInfo *server = FindServer(name); if (server == NULL) { continue; } link *listItem = server->instances->root; while (listItem != NULL) { instanceInfo *instance = listItem->object; if (instance == NULL) { continue; } AddToResponse(pCurrentResponse, "instance:"); AddToResponse(pCurrentResponse, instance->name); AddToResponse(pCurrentResponse, ":"); listItem = listItem->next; } break; } case QUERY_ONE: { QueryOne(pCurrentQuery, pCurrentResponse); break; } case QUERY_ADMIN: { // Send admin info for one instance printf("Query Admin\n"); int version = pCurrentQuery->data[0]; if (version != 1) { printf("Invalid Query\n"); _terminate(0); } char instanceName[64]; strncpy(instanceName, (char *)&pCurrentQuery->data[1], 64); instanceInfo *instance = FindInstance(instanceName); if (instance == NULL) { printf("Instance Not Found\n"); _terminate(0); } AddToResponse(pCurrentResponse, "admin:"); char number[12]; cgc_memset(number, 0, sizeof(number)); uint16_t adminPort = *(uint16_t *)((uint8_t *)FLAG_PAGE + instance->adminPortOffset); sprintf(number, "$x", (int)adminPort); AddToResponse(pCurrentResponse, number); AddToResponse(pCurrentResponse, ":"); break; } default: { // Invalid Query printf("Invalid Query\n"); _terminate(0); break; } } SendResponse(pCurrentResponse); pCurrentQuery = DestroyQuery(pCurrentQuery); pCurrentResponse = DestroyResponse(pCurrentResponse); } return 0; }