void WebProcessor::Dispatch() { if (*m_szUrl != '/') { SendErrorResponse(ERR_HTTP_BAD_REQUEST); return; } if (XmlRpcProcessor::IsRpcRequest(m_szUrl)) { XmlRpcProcessor processor; processor.SetRequest(m_szRequest); processor.SetHttpMethod(m_eHttpMethod == hmGet ? XmlRpcProcessor::hmGet : XmlRpcProcessor::hmPost); processor.SetUserAccess((XmlRpcProcessor::EUserAccess)m_eUserAccess); processor.SetUrl(m_szUrl); processor.Execute(); SendBodyResponse(processor.GetResponse(), strlen(processor.GetResponse()), processor.GetContentType()); return; } if (Util::EmptyStr(g_pOptions->GetWebDir())) { SendErrorResponse(ERR_HTTP_SERVICE_UNAVAILABLE); return; } if (m_eHttpMethod != hmGet) { SendErrorResponse(ERR_HTTP_BAD_REQUEST); return; } // for security reasons we allow only characters "0..9 A..Z a..z . - _ /" in the URLs // we also don't allow ".." in the URLs for (char *p = m_szUrl; *p; p++) { if (!((*p >= '0' && *p <= '9') || (*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '.' || *p == '-' || *p == '_' || *p == '/') || (*p == '.' && p[1] == '.')) { SendErrorResponse(ERR_HTTP_NOT_FOUND); return; } } const char *szDefRes = ""; if (m_szUrl[strlen(m_szUrl)-1] == '/') { // default file in directory (if not specified) is "index.html" szDefRes = "index.html"; } char disk_filename[1024]; snprintf(disk_filename, sizeof(disk_filename), "%s%s%s", g_pOptions->GetWebDir(), m_szUrl + 1, szDefRes); disk_filename[sizeof(disk_filename)-1] = '\0'; SendFileResponse(disk_filename); }
int CWebServer::CreateMemoryDownloadResponse(IHTTPRequestHandler *handler, struct MHD_Response *&response) { if (handler == NULL) return MHD_NO; const HTTPRequest &request = handler->GetRequest(); const HTTPResponseDetails &responseDetails = handler->GetResponseDetails(); HttpResponseRanges responseRanges = handler->GetResponseData(); // check if the response is completely empty if (responseRanges.empty()) return CreateMemoryDownloadResponse(request.connection, NULL, 0, false, false, response); // check if the response contains more ranges than the request asked for if ((request.ranges.IsEmpty() && responseRanges.size() > 1) || (!request.ranges.IsEmpty() && responseRanges.size() > request.ranges.Size())) { CLog::Log(LOGWARNING, "CWebServer: response contains more ranges (%d) than the request asked for (%d)", (int)responseRanges.size(), (int)request.ranges.Size()); return SendErrorResponse(request.connection, MHD_HTTP_INTERNAL_SERVER_ERROR, request.method); } // if the request asked for no or only one range we can simply use MHDs memory download handler // we MUST NOT send a multipart response if (request.ranges.Size() <= 1) { CHttpResponseRange responseRange = responseRanges.front(); // check if the range is valid if (!responseRange.IsValid()) { CLog::Log(LOGWARNING, "CWebServer: invalid response data with range start at %" PRId64 " and end at %" PRId64, responseRange.GetFirstPosition(), responseRange.GetLastPosition()); return SendErrorResponse(request.connection, MHD_HTTP_INTERNAL_SERVER_ERROR, request.method); } const void* responseData = responseRange.GetData(); size_t responseDataLength = static_cast<size_t>(responseRange.GetLength()); switch (responseDetails.type) { case HTTPMemoryDownloadNoFreeNoCopy: return CreateMemoryDownloadResponse(request.connection, responseData, responseDataLength, false, false, response); case HTTPMemoryDownloadNoFreeCopy: return CreateMemoryDownloadResponse(request.connection, responseData, responseDataLength, false, true, response); case HTTPMemoryDownloadFreeNoCopy: return CreateMemoryDownloadResponse(request.connection, responseData, responseDataLength, true, false, response); case HTTPMemoryDownloadFreeCopy: return CreateMemoryDownloadResponse(request.connection, responseData, responseDataLength, true, true, response); default: return SendErrorResponse(request.connection, MHD_HTTP_INTERNAL_SERVER_ERROR, request.method); } } return CreateRangedMemoryDownloadResponse(handler, response); }
int CWebServer::HandleRequest(IHTTPRequestHandler *handler) { if (handler == NULL) return MHD_NO; HTTPRequest request = handler->GetRequest(); int ret = handler->HandleRequest(); if (ret == MHD_NO) { CLog::Log(LOGERROR, "CWebServer: failed to handle HTTP request for %s", request.pathUrl.c_str()); delete handler; return SendErrorResponse(request.connection, MHD_HTTP_INTERNAL_SERVER_ERROR, request.method); } const HTTPResponseDetails &responseDetails = handler->GetResponseDetails(); struct MHD_Response *response = NULL; switch (responseDetails.type) { case HTTPNone: CLog::Log(LOGERROR, "CWebServer: HTTP request handler didn't process %s", request.pathUrl.c_str()); delete handler; return MHD_NO; case HTTPRedirect: ret = CreateRedirect(request.connection, handler->GetRedirectUrl(), response); break; case HTTPFileDownload: ret = CreateFileDownloadResponse(handler, response); break; case HTTPMemoryDownloadNoFreeNoCopy: case HTTPMemoryDownloadNoFreeCopy: case HTTPMemoryDownloadFreeNoCopy: case HTTPMemoryDownloadFreeCopy: ret = CreateMemoryDownloadResponse(handler, response); break; case HTTPError: ret = CreateErrorResponse(request.connection, responseDetails.status, request.method, response); break; default: CLog::Log(LOGERROR, "CWebServer: internal error while HTTP request handler processed %s", request.pathUrl.c_str()); delete handler; return SendErrorResponse(request.connection, MHD_HTTP_INTERNAL_SERVER_ERROR, request.method); } if (ret == MHD_NO) { CLog::Log(LOGERROR, "CWebServer: failed to create HTTP response for %s", request.pathUrl.c_str()); delete handler; return SendErrorResponse(request.connection, MHD_HTTP_INTERNAL_SERVER_ERROR, request.method); } return FinalizeRequest(handler, responseDetails.status, response); }
/* * Stream contains open file descriptors that could not be completed. * If stream has only pending open file descriptors close file * descriptors. */ static void closeStream() { FileInfo_t *file; int id; id = Stream->first; while (id > EOS) { PthreadMutexLock(&Stream->mutex); file = GetFile(id); PthreadMutexLock(&file->mutex); if (GET_FLAG(file->flags, FI_DCACHE_CLOSE)) { if (close(file->dcache) == -1) { WarnSyscallError(HERE, "close", ""); } CLEAR_FLAG(file->flags, FI_DCACHE); NumOpenFiles--; } else if (GET_FLAG(file->flags, FI_DCACHE)) { SendErrorResponse(file); } id = file->next; PthreadMutexUnlock(&Stream->mutex); PthreadMutexUnlock(&file->mutex); } if (GET_FLAG(Stream->flags, SR_UNAVAIL)) { rejectRequest(ENODEV, B_TRUE); } else { rejectRequest(0, B_TRUE); } }
/* * Remove file with dcache opened from stream. * Caller must have the stream lock held. */ static void removeDcachedFile( StreamInfo_t *stream, int error) { int id; FileInfo_t *file, *prev = NULL; id = stream->first; while (id > EOS) { boolean_t removed = B_FALSE; file = GetFile(id); PthreadMutexLock(&file->mutex); if (prev != NULL) { PthreadMutexLock(&prev->mutex); } if (GET_FLAG(file->flags, FI_DCACHE)) { /* * Remove file from stream. * If multivolume and not section 0, set ECOMM to not * retry from another copy. */ if (file->ar[file->copy].ext_ord != 0 || file->se_ord != 0) { file->error = ECOMM; } else { file->error = error; } SendErrorResponse(file); if (prev != NULL) { prev->next = file->next; } else { stream->first = file->next; } stream->count--; if (stream->first == EOS) { stream->last = EOS; } else if (file->sort == stream->last) { ASSERT(prev != NULL); stream->last = prev->sort; } removed = B_TRUE; } if (prev != NULL) { PthreadMutexUnlock(&prev->mutex); } PthreadMutexUnlock(&file->mutex); id = file->next; if (removed) { SetStageDone(file); } else { prev = file; } } }
void CTcTestRunner::BearerCompletion( MTcBearerObserver::TOperation aOp, TInt aStatus ) { // If we get an error from the bearer, "recommend" disconnect to the AppUi :-) // (usually the only error is KErrDisconnected) if( aStatus != KErrNone ) { iObserver.NotifyDisconnect(); return; } switch( aOp ) { case MTcBearerObserver::ESend: { // Clear buffers iResponse.Zero(); iRequest.Zero(); // Start receiving data again Start(); break; } case MTcBearerObserver::EReceive: { // Update request data length (add new data). iRequest.SetLength( iRequest.Length() + iFreeRequest.Length() ); // Do we have a complete request in iRequest? if( !iCodec.IsComplete() ) { // No, read more Start(); } else { // Yes, try to execute the request TRAPD( err, ExecuteL() ); // Report any errors if( err ) { SendErrorResponse( err ); } iCurrentRequest.Zero(); iObserver.NotifyStatusChange(); } break; } default: { // does not happen, ignored break; } } }
EXPORT_C void CTcTestRunner::Start() { // Is there still room in the receive buffer? if( iRequest.Length() < iRequest.MaxLength() ) { // Construct a pointer descriptor for the free data area of iRequest // This is done to accomplish "appending" socket read. TInt dataLen( iRequest.Length() ); iFreeRequest.Set( const_cast< TUint8* >( iRequest.Ptr() ) + dataLen, 0, iRequest.MaxLength() - dataLen ); iBearer.ReceiveOneOrMore( iFreeRequest ); } else { SendErrorResponse( KTcErrReceiveOverflow ); } }
void WebProcessor::SendFileResponse(const char* filename) { debug("serving file: %s", filename); CharBuffer body; if (!FileSystem::LoadFileIntoBuffer(filename, body, false)) { // do not print warnings "404 not found" for certain files bool ignorable = !strcmp(filename, "package-info.json") || !strcmp(filename, "favicon.ico") || !strncmp(filename, "apple-touch-icon", 16); SendErrorResponse(ERR_HTTP_NOT_FOUND, ignorable); return; } SendBodyResponse(body, body.Size(), DetectContentType(filename)); }
void WebProcessor::SendFileResponse(const char* szFilename) { debug("serving file: %s", szFilename); char *szBody; int iBodyLen; if (!Util::LoadFileIntoBuffer(szFilename, &szBody, &iBodyLen)) { SendErrorResponse(ERR_HTTP_NOT_FOUND); return; } // "LoadFileIntoBuffer" adds a trailing NULL, which we don't need here iBodyLen--; SendBodyResponse(szBody, iBodyLen, DetectContentType(szFilename)); free(szBody); }
int CWebServer::CreateFileDownloadResponse(IHTTPRequestHandler *handler, struct MHD_Response *&response) { if (handler == NULL) return MHD_NO; const HTTPRequest &request = handler->GetRequest(); const HTTPResponseDetails &responseDetails = handler->GetResponseDetails(); HttpResponseRanges responseRanges = handler->GetResponseData(); std::shared_ptr<XFILE::CFile> file = std::make_shared<XFILE::CFile>(); std::string filePath = handler->GetResponseFile(); if (!file->Open(filePath, READ_NO_CACHE)) { CLog::Log(LOGERROR, "WebServer: Failed to open %s", filePath.c_str()); return SendErrorResponse(request.connection, MHD_HTTP_NOT_FOUND, request.method); } bool ranged = false; uint64_t fileLength = static_cast<uint64_t>(file->GetLength()); // get the MIME type for the Content-Type header std::string mimeType = responseDetails.contentType; if (mimeType.empty()) { std::string ext = URIUtils::GetExtension(filePath); StringUtils::ToLower(ext); mimeType = CreateMimeTypeFromExtension(ext.c_str()); } if (request.method != HEAD) { uint64_t totalLength = 0; std::unique_ptr<HttpFileDownloadContext> context(new HttpFileDownloadContext()); context->file = file; context->contentType = mimeType; context->boundaryWritten = false; context->writePosition = 0; if (handler->IsRequestRanged()) { if (!request.ranges.IsEmpty()) context->ranges = request.ranges; else GetRequestedRanges(request.connection, fileLength, context->ranges); } uint64_t firstPosition = 0; uint64_t lastPosition = 0; // if there are no ranges, add the whole range if (context->ranges.IsEmpty()) context->ranges.Add(CHttpRange(0, fileLength - 1)); else { handler->SetResponseStatus(MHD_HTTP_PARTIAL_CONTENT); // we need to remember that we are ranged because the range length might change and won't be reliable anymore for length comparisons ranged = true; context->ranges.GetFirstPosition(firstPosition); context->ranges.GetLastPosition(lastPosition); } // remember the total number of ranges context->rangeCountTotal = context->ranges.Size(); // remember the total length totalLength = context->ranges.GetLength(); // adjust the MIME type and range length in case of multiple ranges which requires multipart boundaries if (context->rangeCountTotal > 1) { context->boundary = HttpRangeUtils::GenerateMultipartBoundary(); mimeType = HttpRangeUtils::GenerateMultipartBoundaryContentType(context->boundary); // build part of the boundary with the optional Content-Type header // "--<boundary>\r\nContent-Type: <content-type>\r\n context->boundaryWithHeader = HttpRangeUtils::GenerateMultipartBoundaryWithHeader(context->boundary, context->contentType); context->boundaryEnd = HttpRangeUtils::GenerateMultipartBoundaryEnd(context->boundary); // for every range, we need to add a boundary with header for (HttpRanges::const_iterator range = context->ranges.Begin(); range != context->ranges.End(); ++range) { // we need to temporarily add the Content-Range header to the boundary to be able to determine the length std::string completeBoundaryWithHeader = HttpRangeUtils::GenerateMultipartBoundaryWithHeader(context->boundaryWithHeader, &*range); totalLength += completeBoundaryWithHeader.size(); // add a newline before any new multipart boundary if (range != context->ranges.Begin()) totalLength += strlen(HEADER_NEWLINE); } // and at the very end a special end-boundary "\r\n--<boundary>--" totalLength += context->boundaryEnd.size(); } // set the initial write position context->ranges.GetFirstPosition(context->writePosition); // create the response object response = MHD_create_response_from_callback(totalLength, 2048, &CWebServer::ContentReaderCallback, context.get(), &CWebServer::ContentReaderFreeCallback); if (response == NULL) { CLog::Log(LOGERROR, "CWebServer: failed to create a HTTP response for %s to be filled from %s", request.pathUrl.c_str(), filePath.c_str()); return MHD_NO; } context.release(); // ownership was passed to mhd // add Content-Range header if (ranged) handler->AddResponseHeader(MHD_HTTP_HEADER_CONTENT_RANGE, HttpRangeUtils::GenerateContentRangeHeaderValue(firstPosition, lastPosition, fileLength)); } else { response = MHD_create_response_from_data(0, NULL, MHD_NO, MHD_NO); if (response == NULL) { CLog::Log(LOGERROR, "CWebServer: failed to create a HTTP HEAD response for %s", request.pathUrl.c_str()); return MHD_NO; } handler->AddResponseHeader(MHD_HTTP_HEADER_CONTENT_LENGTH, StringUtils::Format("%" PRId64, fileLength)); } // set the Content-Type header if (!mimeType.empty()) handler->AddResponseHeader(MHD_HTTP_HEADER_CONTENT_TYPE, mimeType); return MHD_YES; }
int CWebServer::AnswerToConnection(void *cls, struct MHD_Connection *connection, const char *url, const char *method, const char *version, const char *upload_data, unsigned int *upload_data_size, void **con_cls) #endif { if (cls == NULL || con_cls == NULL || *con_cls == NULL) { CLog::Log(LOGERROR, "CWebServer: invalid request received"); return MHD_NO; } CWebServer *server = reinterpret_cast<CWebServer*>(cls); std::auto_ptr<ConnectionHandler> conHandler(reinterpret_cast<ConnectionHandler*>(*con_cls)); HTTPMethod methodType = GetMethod(method); HTTPRequest request = { server, connection, conHandler->fullUri, url, methodType, version }; // remember if the request was new bool isNewRequest = conHandler->isNew; // because now it isn't anymore conHandler->isNew = false; // reset con_cls and set it if still necessary *con_cls = NULL; #ifdef WEBSERVER_DEBUG if (isNewRequest) { std::multimap<std::string, std::string> headerValues; GetRequestHeaderValues(connection, MHD_HEADER_KIND, headerValues); std::multimap<std::string, std::string> getValues; GetRequestHeaderValues(connection, MHD_GET_ARGUMENT_KIND, getValues); CLog::Log(LOGDEBUG, "webserver [IN] %s %s %s", version, method, request.pathUrlFull.c_str()); if (!getValues.empty()) { std::string tmp; for (std::multimap<std::string, std::string>::const_iterator get = getValues.begin(); get != getValues.end(); ++get) { if (get != getValues.begin()) tmp += "; "; tmp += get->first + " = " + get->second; } CLog::Log(LOGDEBUG, "webserver [IN] Query arguments: %s", tmp.c_str()); } for (std::multimap<std::string, std::string>::const_iterator header = headerValues.begin(); header != headerValues.end(); ++header) CLog::Log(LOGDEBUG, "webserver [IN] %s: %s", header->first.c_str(), header->second.c_str()); } #endif if (!IsAuthenticated(server, connection)) return AskForAuthentication(connection); // check if this is the first call to AnswerToConnection for this request if (isNewRequest) { // parse the Range header and store it in the request object CHttpRanges ranges; bool ranged = ranges.Parse(GetRequestHeaderValue(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_RANGE)); // look for a IHTTPRequestHandler which can take care of the current request for (std::vector<IHTTPRequestHandler *>::const_iterator it = m_requestHandlers.begin(); it != m_requestHandlers.end(); ++it) { IHTTPRequestHandler *requestHandler = *it; if (requestHandler->CanHandleRequest(request)) { // we found a matching IHTTPRequestHandler so let's get a new instance for this request IHTTPRequestHandler *handler = requestHandler->Create(request); // if we got a GET request we need to check if it should be cached if (methodType == GET) { if (handler->CanBeCached()) { bool cacheable = true; // handle Cache-Control std::string cacheControl = GetRequestHeaderValue(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_CACHE_CONTROL); if (!cacheControl.empty()) { std::vector<std::string> cacheControls = StringUtils::Split(cacheControl, ","); for (std::vector<std::string>::const_iterator it = cacheControls.begin(); it != cacheControls.end(); ++it) { std::string control = *it; control = StringUtils::Trim(control); // handle no-cache if (control.compare(HEADER_VALUE_NO_CACHE) == 0) cacheable = false; } } if (cacheable) { // handle Pragma (but only if "Cache-Control: no-cache" hasn't been set) std::string pragma = GetRequestHeaderValue(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_PRAGMA); if (pragma.compare(HEADER_VALUE_NO_CACHE) == 0) cacheable = false; } CDateTime lastModified; if (handler->GetLastModifiedDate(lastModified) && lastModified.IsValid()) { // handle If-Modified-Since or If-Unmodified-Since std::string ifModifiedSince = GetRequestHeaderValue(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_IF_MODIFIED_SINCE); std::string ifUnmodifiedSince = GetRequestHeaderValue(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_IF_UNMODIFIED_SINCE); CDateTime ifModifiedSinceDate; CDateTime ifUnmodifiedSinceDate; // handle If-Modified-Since (but only if the response is cacheable) if (cacheable && ifModifiedSinceDate.SetFromRFC1123DateTime(ifModifiedSince) && lastModified.GetAsUTCDateTime() <= ifModifiedSinceDate) { struct MHD_Response *response = MHD_create_response_from_data(0, NULL, MHD_NO, MHD_NO); if (response == NULL) { CLog::Log(LOGERROR, "CWebServer: failed to create a HTTP 304 response"); return MHD_NO; } return FinalizeRequest(handler, MHD_HTTP_NOT_MODIFIED, response); } // handle If-Unmodified-Since else if (ifUnmodifiedSinceDate.SetFromRFC1123DateTime(ifUnmodifiedSince) && lastModified.GetAsUTCDateTime() > ifUnmodifiedSinceDate) return SendErrorResponse(connection, MHD_HTTP_PRECONDITION_FAILED, methodType); } // handle If-Range header but only if the Range header is present if (ranged && lastModified.IsValid()) { std::string ifRange = GetRequestHeaderValue(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_IF_RANGE); if (!ifRange.empty() && lastModified.IsValid()) { CDateTime ifRangeDate; ifRangeDate.SetFromRFC1123DateTime(ifRange); // check if the last modification is newer than the If-Range date // if so we have to server the whole file instead if (lastModified.GetAsUTCDateTime() > ifRangeDate) ranges.Clear(); } } // pass the requested ranges on to the request handler handler->SetRequestRanged(!ranges.IsEmpty()); } } // if we got a POST request we need to take care of the POST data else if (methodType == POST) { conHandler->requestHandler = handler; // get the content-type of the POST data std::string contentType = GetRequestHeaderValue(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_CONTENT_TYPE); if (!contentType.empty()) { // if the content-type is application/x-ww-form-urlencoded or multipart/form-data we can use MHD's POST processor if (StringUtils::EqualsNoCase(contentType, MHD_HTTP_POST_ENCODING_FORM_URLENCODED) || StringUtils::EqualsNoCase(contentType, MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA)) { // Get a new MHD_PostProcessor conHandler->postprocessor = MHD_create_post_processor(connection, MAX_POST_BUFFER_SIZE, &CWebServer::HandlePostField, (void*)conHandler.get()); // MHD doesn't seem to be able to handle this post request if (conHandler->postprocessor == NULL) { CLog::Log(LOGERROR, "CWebServer: unable to create HTTP POST processor for %s", url); delete conHandler->requestHandler; return SendErrorResponse(connection, MHD_HTTP_INTERNAL_SERVER_ERROR, methodType); } } } // otherwise we need to handle the POST data ourselves which is done in the next call to AnswerToConnection // as ownership of the connection handler is passed to libmicrohttpd we must not destroy it *con_cls = conHandler.release(); return MHD_YES; } return HandleRequest(handler); } } } // this is a subsequent call to AnswerToConnection for this request else { // again we need to take special care of the POST data if (methodType == POST) { if (conHandler->requestHandler == NULL) { CLog::Log(LOGERROR, "CWebServer: cannot handle partial HTTP POST for %s request because there is no valid request handler available", url); return SendErrorResponse(connection, MHD_HTTP_INTERNAL_SERVER_ERROR, methodType); } // we only need to handle POST data if there actually is data left to handle if (*upload_data_size > 0) { // either use MHD's POST processor if (conHandler->postprocessor != NULL) MHD_post_process(conHandler->postprocessor, upload_data, *upload_data_size); // or simply copy the data to the handler else conHandler->requestHandler->AddPostData(upload_data, *upload_data_size); // signal that we have handled the data *upload_data_size = 0; // we may need to handle more POST data which is done in the next call to AnswerToConnection // as ownership of the connection handler is passed to libmicrohttpd we must not destroy it *con_cls = conHandler.release(); return MHD_YES; } // we have handled all POST data so it's time to invoke the IHTTPRequestHandler else { if (conHandler->postprocessor != NULL) MHD_destroy_post_processor(conHandler->postprocessor); return HandleRequest(conHandler->requestHandler); } } // it's unusual to get more than one call to AnswerToConnection for none-POST requests, but let's handle it anyway else { for (std::vector<IHTTPRequestHandler *>::const_iterator it = m_requestHandlers.begin(); it != m_requestHandlers.end(); ++it) { IHTTPRequestHandler *requestHandler = *it; if (requestHandler->CanHandleRequest(request)) return HandleRequest(requestHandler->Create(request)); } } } CLog::Log(LOGERROR, "CWebServer: couldn't find any request handler for %s", url); return SendErrorResponse(connection, MHD_HTTP_NOT_FOUND, methodType); }
// Read a command from the CRS uint8_t ReadCmd(void) { Command Cmd; uint32_t *NewNodeNames; pEdgeArray NewEdges; uint32_t i; pNode NewNode; pEdge NewEdge; pEdge ExistingEdge; uint8_t NodeCount; uint32_t *SPT; // read in the basic command header if (ReadBytes((unsigned char *)&Cmd, sizeof(Command)) != sizeof(Command)) { return(0); } if (Cmd.Action == CMD_SEND_NODES) { // read in the indicated number of Nodes #ifdef PATCHED_1 if ((Cmd.NumElements + NumNodes) > MAX_NODES) { #else if (Cmd.NumElements > MAX_NODES) { #endif ReadNull(sizeof(uint32_t)*Cmd.NumElements); SendErrorResponse(RESP_ERROR_TOO_MANY_NODES); return(0); } if ((NewNodeNames = (uint32_t *)calloc(sizeof(uint32_t)*Cmd.NumElements)) == NULL) { DestroyNodes(); DestroyEdges(); _terminate(1); } if (ReadBytes((unsigned char *)NewNodeNames, sizeof(uint32_t)*Cmd.NumElements) != sizeof(uint32_t)*Cmd.NumElements) { free(NewNodeNames); return(0); } // make sure none of the new node names exist already for (i = 0; i < Cmd.NumElements; i++) { if (FindNode(NewNodeNames[i]) != NULL) { free(NewNodeNames); SendErrorResponse(RESP_ERROR_DUPLICATE_NODE); return(0); } } // Create the new nodes for (i = 0; i < Cmd.NumElements; i++) { // create a new node if ((NewNode = (pNode)calloc(sizeof(Node))) == NULL) { free(NewNodeNames); DestroyNodes(); DestroyEdges(); _terminate(1); } NewNode->Name = NewNodeNames[i]; NewNode->Distance = SIZE_MAX; // Add it to the graph if (!AddNode(NewNode)) { free(NewNodeNames); DestroyNodes(); DestroyEdges(); _terminate(1); } } // done creating new nodes free(NewNodeNames); } else if (Cmd.Action == CMD_SEND_EDGES) { // read in the indicated number of Edges if ((Cmd.NumElements + NumEdges) > MAX_EDGES) { ReadNull(sizeof(EdgeArray)*Cmd.NumElements); SendErrorResponse(RESP_ERROR_TOO_MANY_EDGES); return(0); } if ((NewEdges = (pEdgeArray)calloc(sizeof(EdgeArray)*Cmd.NumElements)) == NULL) { DestroyNodes(); DestroyEdges(); _terminate(1); } if (ReadBytes((unsigned char *)NewEdges, sizeof(EdgeArray)*Cmd.NumElements) != sizeof(EdgeArray)*Cmd.NumElements) { free(NewEdges); return(0); } // Create the new edges for (i = 0; i < Cmd.NumElements; i++) { // create a new Edge if ((NewEdge = (pEdge)calloc(sizeof(Edge))) == NULL) { free(NewEdges); DestroyNodes(); DestroyEdges(); _terminate(1); } // make sure the starting and ending nodes exist if ((NewEdge->NodeA = FindNode(NewEdges[i].NodeA)) == NULL) { SendErrorResponse(RESP_ERROR_INVALID_NODE); free(NewEdge); free(NewEdges); DestroyNodes(); DestroyEdges(); _terminate(1); } if ((NewEdge->NodeZ = FindNode(NewEdges[i].NodeZ)) == NULL) { SendErrorResponse(RESP_ERROR_INVALID_NODE); free(NewEdge); free(NewEdges); DestroyNodes(); DestroyEdges(); _terminate(1); } // offset the weight by a fixed magic_page-based value NewEdge->Weight = NewEdges[i].Weight + rand_page[NumNodes]; // see if one already exists if ((ExistingEdge = FindEdge(NewEdge->NodeA, NewEdge->NodeZ)) != NULL) { if (ExistingEdge->Weight > NewEdge->Weight) { ExistingEdge->Weight = NewEdge->Weight; } // keep the existing edge free(NewEdge); continue; } // Add it to the graph if (!AddEdge(NewEdge)) { free(NewEdge); free(NewEdges); DestroyNodes(); DestroyEdges(); _terminate(1); } } } else if (Cmd.Action == CMD_RUN_SPT) { if ((SPT = FindSpt(Cmd.StartingNode, Cmd.EndingNode, &NodeCount)) == NULL) { // unable to find SPT SendErrorResponse(RESP_ERROR_SPT_FAIL); return(0); } SendResponse(RESP_NODE_SET, NodeCount, SPT); free(SPT); } else { SendErrorResponse(RESP_ERROR_INVALID_CMD); return(0); } return(1); }
/******************************************************************************* * Function Name: ProcessWriteReq ******************************************************************************** * * Summary: * Process all GATT level write requests and responds with appropriate status * * Parameters: * CYBLE_GATTS_WRITE_CMD_REQ_PARAM_T: GATT write command request prameter * * Return: * None * *******************************************************************************/ void ProcessWriteReq(CYBLE_GATTS_WRITE_CMD_REQ_PARAM_T writeCmdReq) { bool value_val; uint8 status = LOCKED, key_buf[LOCK_CODE_LENGTH]; uint16 beaconPeriod = 0; CYBLE_GATT_HANDLE_VALUE_PAIR_T valuePairT; /* Reset error send flag */ errorSent = false; /* Retrieve the LOCK status from the GATT DB */ valuePairT.attrHandle = CYBLE_EDDYSTONE_CONFIGURATION_LOCK_STATE_CHAR_HANDLE; valuePairT.value.val = (uint8 *)&value_val; valuePairT.value.len = sizeof(bool); CyBle_GattsReadAttributeValue( &valuePairT, &cyBle_connHandle, CYBLE_GATT_DB_LOCALLY_INITIATED ); /* Check the LOCK status */ if(valuePairT.value.val[0] == UNLOCKED) { /*URL Data*/ if(writeCmdReq.handleValPair.attrHandle == CYBLE_EDDYSTONE_CONFIGURATION_URI_DATA_CHAR_HANDLE) { /* First byte should be scheme prefix and length should be less than * or equal to MAX_URL_LENGTH */ if( (writeCmdReq.handleValPair.value.len <= MAX_URL_LENGTH) && (writeCmdReq.handleValPair.value.val[0] < URL_PREFIX_MAX) ) { uint8 TempURL[MAX_URL_LENGTH]; memset(TempURL, 0, MAX_URL_LENGTH); memcpy( TempURL, writeCmdReq.handleValPair.value.val, writeCmdReq.handleValPair.value.len ); if( CYBLE_GATT_ERR_NONE == WriteAttributeValue ( CYBLE_EDDYSTONE_CONFIGURATION_URI_DATA_CHAR_HANDLE, writeCmdReq.handleValPair.value.len, writeCmdReq.handleValPair.value.val, CYBLE_GATT_DB_PEER_INITIATED ) ) { /* Update the length as per the new URL data */ URLLength = writeCmdReq.handleValPair.value.len; cyBle_attValuesLen[16].actualLength = URLLength; /* Update the URL data */ memcpy(CurrentURL, TempURL, MAX_URL_LENGTH); } } else if (writeCmdReq.handleValPair.value.len > MAX_URL_LENGTH) { /* Invalid length. Send error response */ SendErrorResponse ( CYBLE_EDDYSTONE_CONFIGURATION_URI_DATA_CHAR_HANDLE, CYBLE_GATT_ERR_INVALID_ATTRIBUTE_LEN ); } } /* Lock Characteristic */ else if(writeCmdReq.handleValPair.attrHandle == CYBLE_EDDYSTONE_CONFIGURATION_LOCK_CHAR_HANDLE) { if(writeCmdReq.handleValPair.value.len == LOCK_CODE_LENGTH) { WriteAttributeValue ( CYBLE_EDDYSTONE_CONFIGURATION_LOCK_CHAR_HANDLE, writeCmdReq.handleValPair.value.len, writeCmdReq.handleValPair.value.val, CYBLE_GATT_DB_PEER_INITIATED ); /* Update the LOCK characteristic */ status = LOCKED; WriteAttributeValue ( CYBLE_EDDYSTONE_CONFIGURATION_LOCK_STATE_CHAR_HANDLE, sizeof(bool), &status, CYBLE_GATT_DB_LOCALLY_INITIATED ); } else { /* Invalid length. Send error response */ SendErrorResponse(CYBLE_EDDYSTONE_CONFIGURATION_LOCK_CHAR_HANDLE, CYBLE_GATT_ERR_INVALID_ATTRIBUTE_LEN); } } /* Advertised Tx power level */ else if(writeCmdReq.handleValPair.attrHandle == CYBLE_EDDYSTONE_CONFIGURATION_ADVERTISED_TX_POWER_LEVELS_CHAR_HANDLE) { if (writeCmdReq.handleValPair.value.len == MAX_NUM_PWR_LVL) { WriteAttributeValue ( CYBLE_EDDYSTONE_CONFIGURATION_ADVERTISED_TX_POWER_LEVELS_CHAR_HANDLE, writeCmdReq.handleValPair.value.len, writeCmdReq.handleValPair.value.val, CYBLE_GATT_DB_PEER_INITIATED ); if (writeCmdReq.handleValPair.value.len == MAX_NUM_PWR_LVL) { /* Update Tx Power levels */ memcpy ( currentTxPowerLevels, writeCmdReq.handleValPair.value.val, MAX_NUM_PWR_LVL ); } else { SendErrorResponse ( CYBLE_EDDYSTONE_CONFIGURATION_ADVERTISED_TX_POWER_LEVELS_CHAR_HANDLE, CYBLE_GATT_ERR_INVALID_ATTRIBUTE_LEN ); } } else { /* Invalid length. Send error response */ SendErrorResponse ( CYBLE_EDDYSTONE_CONFIGURATION_ADVERTISED_TX_POWER_LEVELS_CHAR_HANDLE, CYBLE_GATT_ERR_INVALID_ATTRIBUTE_LEN ); } } /* Tx Power Mode */ else if(writeCmdReq.handleValPair.attrHandle == CYBLE_EDDYSTONE_CONFIGURATION_TX_POWER_MODE_CHAR_HANDLE) { if(writeCmdReq.handleValPair.value.val[0] <= 0x03) { WriteAttributeValue ( CYBLE_EDDYSTONE_CONFIGURATION_TX_POWER_MODE_CHAR_HANDLE, writeCmdReq.handleValPair.value.len, writeCmdReq.handleValPair.value.val, CYBLE_GATT_DB_PEER_INITIATED ); currentTxmode = writeCmdReq.handleValPair.value.val[0]; UpdateTxPower(currentTxmode); } else /* Invalid value. Write not permitted. */ { SendErrorResponse ( CYBLE_EDDYSTONE_CONFIGURATION_TX_POWER_MODE_CHAR_HANDLE, CYBLE_GATT_ERR_WRITE_NOT_PERMITTED ); } } /* Beacon Period */ else if(writeCmdReq.handleValPair.attrHandle == CYBLE_EDDYSTONE_CONFIGURATION_BEACON_PERIOD_CHAR_HANDLE) { beaconPeriod = CyBle_Get16ByPtr(writeCmdReq.handleValPair.value.val); /* Disable URL FRAMES */ if(beaconPeriod == 0) { eddystoneImplenmentation = EDDYSTONE_UID; WriteAttributeValue ( CYBLE_EDDYSTONE_CONFIGURATION_BEACON_PERIOD_CHAR_HANDLE, writeCmdReq.handleValPair.value.len, writeCmdReq.handleValPair.value.val, CYBLE_GATT_DB_PEER_INITIATED ); } /* Values in valid range */ else if((beaconPeriod >= MIN_BEACON_PERIOD) && (beaconPeriod <= MAX_BEACON_PERIOD)) { WriteAttributeValue ( CYBLE_EDDYSTONE_CONFIGURATION_BEACON_PERIOD_CHAR_HANDLE, writeCmdReq.handleValPair.value.len, writeCmdReq.handleValPair.value.val, CYBLE_GATT_DB_PEER_INITIATED ); CurrentAdvPeriod = beaconPeriod / 0.625; eddystoneImplenmentation = EDDYSTONE_URL; } else { uint16 temp = MIN_BEACON_PERIOD; /* Values not supportes. Write default values */ WriteAttributeValue( CYBLE_EDDYSTONE_CONFIGURATION_BEACON_PERIOD_CHAR_HANDLE, sizeof(temp), (uint8 *)&temp, CYBLE_GATT_DB_PEER_INITIATED); CurrentAdvPeriod = CYBLE_GAP_ADV_ADVERT_INTERVAL_NONCON_MIN; eddystoneImplenmentation = EDDYSTONE_URL; } } /* Reset the Configurations to default */ else if((writeCmdReq.handleValPair.attrHandle == CYBLE_EDDYSTONE_CONFIGURATION_RESET_CHAR_HANDLE) && (writeCmdReq.handleValPair.value.val[0] != 0)) { ResetGattDb(); } } else if(valuePairT.value.val[0] == LOCKED) { if(writeCmdReq.handleValPair.attrHandle == CYBLE_EDDYSTONE_CONFIGURATION_LOCK_CHAR_HANDLE) { /* Accesing the lock in LOCKED state */ SendErrorResponse(writeCmdReq.handleValPair.attrHandle, CYBLE_GATT_ERR_INSUFFICIENT_AUTHORIZATION); } } if(writeCmdReq.handleValPair.attrHandle == CYBLE_EDDYSTONE_CONFIGURATION_UNLOCK_CHAR_HANDLE) { if(writeCmdReq.handleValPair.value.len == LOCK_CODE_LENGTH) { if(valuePairT.value.val[0] == LOCKED) { int compareResult; valuePairT.attrHandle = CYBLE_EDDYSTONE_CONFIGURATION_LOCK_CHAR_HANDLE; valuePairT.value.val = key_buf; valuePairT.value.len = sizeof(LOCK); CyBle_GattsReadAttributeValue(&valuePairT, &cyBle_connHandle, CYBLE_GATT_DB_LOCALLY_INITIATED); compareResult = memcmp ( valuePairT.value.val, writeCmdReq.handleValPair.value.val, LOCK_CODE_LENGTH ); if(compareResult == 0) { status = UNLOCKED; /* Update the LOCK STATE */ WriteAttributeValue ( CYBLE_EDDYSTONE_CONFIGURATION_LOCK_STATE_CHAR_HANDLE, sizeof(bool), &status, CYBLE_GATT_DB_LOCALLY_INITIATED ); /* Reset the LOCK */ WriteAttributeValue ( CYBLE_EDDYSTONE_CONFIGURATION_LOCK_CHAR_HANDLE, sizeof(LOCK), (uint8 *)LOCK, CYBLE_GATT_DB_LOCALLY_INITIATED ); } else /* LOCK not matched */ { SendErrorResponse(writeCmdReq.handleValPair.attrHandle, CYBLE_GATT_ERR_INSUFFICIENT_AUTHORIZATION); } } } else /* Invalid length */ { SendErrorResponse(writeCmdReq.handleValPair.attrHandle, CYBLE_GATT_ERR_INVALID_ATTRIBUTE_LEN); } } if (errorSent == false) { CyBle_GattsWriteRsp(cyBle_connHandle); } }
int CWebServer::HandlePartialRequest(struct MHD_Connection *connection, ConnectionHandler* connectionHandler, const HTTPRequest& request, const char *upload_data, size_t *upload_data_size, void **con_cls) { std::unique_ptr<ConnectionHandler> conHandler(connectionHandler); // remember if the request was new bool isNewRequest = conHandler->isNew; // because now it isn't anymore conHandler->isNew = false; // reset con_cls and set it if still necessary *con_cls = nullptr; if (!IsAuthenticated(request)) return AskForAuthentication(request); // check if this is the first call to AnswerToConnection for this request if (isNewRequest) { // look for a IHTTPRequestHandler which can take care of the current request auto handler = FindRequestHandler(request); if (handler != nullptr) { // if we got a GET request we need to check if it should be cached if (request.method == GET) { if (handler->CanBeCached()) { bool cacheable = IsRequestCacheable(request); CDateTime lastModified; if (handler->GetLastModifiedDate(lastModified) && lastModified.IsValid()) { // handle If-Modified-Since or If-Unmodified-Since std::string ifModifiedSince = HTTPRequestHandlerUtils::GetRequestHeaderValue(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_IF_MODIFIED_SINCE); std::string ifUnmodifiedSince = HTTPRequestHandlerUtils::GetRequestHeaderValue(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_IF_UNMODIFIED_SINCE); CDateTime ifModifiedSinceDate; CDateTime ifUnmodifiedSinceDate; // handle If-Modified-Since (but only if the response is cacheable) if (cacheable && ifModifiedSinceDate.SetFromRFC1123DateTime(ifModifiedSince) && lastModified.GetAsUTCDateTime() <= ifModifiedSinceDate) { struct MHD_Response *response = create_response(0, nullptr, MHD_NO, MHD_NO); if (response == nullptr) { CLog::Log(LOGERROR, "CWebServer[%hu]: failed to create a HTTP 304 response", m_port); return MHD_NO; } return FinalizeRequest(handler, MHD_HTTP_NOT_MODIFIED, response); } // handle If-Unmodified-Since else if (ifUnmodifiedSinceDate.SetFromRFC1123DateTime(ifUnmodifiedSince) && lastModified.GetAsUTCDateTime() > ifUnmodifiedSinceDate) return SendErrorResponse(request, MHD_HTTP_PRECONDITION_FAILED, request.method); } // pass the requested ranges on to the request handler handler->SetRequestRanged(IsRequestRanged(request, lastModified)); } } // if we got a POST request we need to take care of the POST data else if (request.method == POST) { // as ownership of the connection handler is passed to libmicrohttpd we must not destroy it SetupPostDataProcessing(request, conHandler.get(), handler, con_cls); // as ownership of the connection handler has been passed to libmicrohttpd we must not destroy it conHandler.release(); return MHD_YES; } return HandleRequest(handler); } } // this is a subsequent call to AnswerToConnection for this request else { // again we need to take special care of the POST data if (request.method == POST) { // process additional / remaining POST data if (ProcessPostData(request, conHandler.get(), upload_data, upload_data_size, con_cls)) { // as ownership of the connection handler has been passed to libmicrohttpd we must not destroy it conHandler.release(); return MHD_YES; } // finalize POST data processing FinalizePostDataProcessing(conHandler.get()); // check if something went wrong while handling the POST data if (conHandler->errorStatus != MHD_HTTP_OK) return SendErrorResponse(request, conHandler->errorStatus, request.method); // we have handled all POST data so it's time to invoke the IHTTPRequestHandler return HandleRequest(conHandler->requestHandler); } // it's unusual to get more than one call to AnswerToConnection for none-POST requests, but let's handle it anyway auto requestHandler = FindRequestHandler(request); if (requestHandler != nullptr) return HandleRequest(requestHandler); } CLog::Log(LOGERROR, "CWebServer[%hu]: couldn't find any request handler for %s", m_port, request.pathUrl.c_str()); return SendErrorResponse(request, MHD_HTTP_NOT_FOUND, request.method); }
void CStunThreadMessageHandler::ProcessRequest(StunMessageEnvelope& message) { CStunMessageReader reader; CStunMessageReader::ReaderParseState state; uint16_t responsePort = 0; HRESULT hr = S_OK; ChkIfA(_spStunResponder == NULL, E_FAIL); _spReaderBuffer->SetSize(0); _spResponseBuffer->SetSize(0); _message = message; _addrResponse = message.remoteAddr; _socketOutput = message.localSocket; _fRequestHasResponsePort = false; // zero out _error without the overhead of zero'ing out every byte in the strings _error.errorcode = 0; _error.szNonce[0] = 0; _error.szRealm[0] = 0; _error.attribUnknown = 0; _integrity.fSendWithIntegrity = false; _integrity.szUser[0] = '\0'; _integrity.szRealm[0] = '\0'; _integrity.szPassword[0] = '\0'; // attach the temp buffer to reader reader.GetStream().Attach(_spReaderBuffer, true); reader.SetAllowLegacyFormat(true); // parse the request state = reader.AddBytes(message.spBuffer->GetData(), message.spBuffer->GetSize()); // If we get something that can't be validated as a stun message, don't send back a response // STUN RFC may suggest sending back a "500", but I think that's the wrong approach. ChkIf (state != CStunMessageReader::BodyValidated, E_FAIL); // Regardless of what we send back, let's always attempt to honor a response port request // Fix the destination port if the client asked for us to send back to another port if (SUCCEEDED(reader.GetResponsePort(&responsePort))) { _addrResponse.SetPort(responsePort); _fRequestHasResponsePort = true; } reader.GetTransactionId(&_transid); // ignore anything that is not a request (with no response) ChkIf(reader.GetMessageClass() != StunMsgClassRequest, E_FAIL); // pre-prep the error message in case we wind up needing to send it _error.msgtype = reader.GetMessageType(); _error.msgclass = StunMsgClassFailureResponse; if (reader.GetMessageType() != StunMsgTypeBinding) { // we're going to send back an error response _error.errorcode = STUN_ERROR_BADREQUEST; // invalid request } else { // handle authentication - but only if an auth provider has been set hr = ValidateAuth(reader); // if auth succeeded, then carry on to handling the request if (SUCCEEDED(hr) && (_error.errorcode==0)) { // handle the binding request hr = ProcessBindingRequest(reader); } // catch all for any case where an error occurred if (FAILED(hr) && (_error.errorcode==0)) { _error.errorcode = STUN_ERROR_BADREQUEST; } } if (_error.errorcode != 0) { // if either ValidateAuth or ProcessBindingRequest set an errorcode, or a fatal error occurred SendErrorResponse(); } else { SendResponse(); } Cleanup: return; }
// The Simple Query Protocol // Fix mis-split bug: Previously, this function assumes there are multiple // queries in the string and split it by ';', which would cause one containing // ';' being split into multiple queries. // However, the multi-statement queries has been split by the psql client and // there is no need to split the query again. void PacketManager::ExecQueryMessage(InputPacket *pkt, const size_t thread_id) { std::string query; PacketGetString(pkt, pkt->len, query); // pop out the last character if it is ';' if (query.back() == ';') { query.pop_back(); } boost::trim(query); if (!query.empty()) { std::vector<StatementResult> result; std::vector<FieldInfo> tuple_descriptor; std::string error_message; int rows_affected = 0; std::string query_type_string_; Statement::ParseQueryTypeString(query, query_type_string_); QueryType query_type; Statement::MapToQueryType(query_type_string_, query_type); std::stringstream stream(query_type_string_); switch (query_type) { case QueryType::QUERY_PREPARE: { std::string statement_name; stream >> statement_name; std::size_t pos = query.find("AS"); std::string statement_query = query.substr(pos + 3); boost::trim(statement_query); // Prepare statement std::shared_ptr<Statement> statement(nullptr); LOG_DEBUG("PrepareStatement[%s] => %s", statement_name.c_str(), statement_query.c_str()); statement = traffic_cop_->PrepareStatement(statement_name, statement_query, error_message); if (statement.get() == nullptr) { skipped_stmt_ = true; SendErrorResponse( {{NetworkMessageType::HUMAN_READABLE_ERROR, error_message}}); LOG_TRACE("ExecQuery Error"); return; } auto entry = std::make_pair(statement_name, statement); statement_cache_.insert(entry); for (auto table_id : statement->GetReferencedTables()) { table_statement_cache_[table_id].push_back(statement.get()); } break; } case QueryType::QUERY_EXECUTE: { std::string statement_name; std::shared_ptr<Statement> statement; std::vector<type::Value> param_values; bool unnamed = false; std::vector<std::string> tokens; boost::split(tokens, query, boost::is_any_of("(), ")); statement_name = tokens.at(1); auto statement_cache_itr = statement_cache_.find(statement_name); if (statement_cache_itr != statement_cache_.end()) { statement = *statement_cache_itr; } // Did not find statement with same name else { std::string error_message = "The prepared statement does not exist"; LOG_ERROR("%s", error_message.c_str()); SendErrorResponse( {{NetworkMessageType::HUMAN_READABLE_ERROR, error_message}}); SendReadyForQuery(NetworkTransactionStateType::IDLE); return; } std::vector<int> result_format(statement->GetTupleDescriptor().size(), 0); for (std::size_t idx = 2; idx < tokens.size(); idx++) { std::string param_str = tokens.at(idx); boost::trim(param_str); if (param_str.empty()) { continue; } param_values.push_back(type::ValueFactory::GetVarcharValue(param_str)); } if (param_values.size() > 0) { statement->GetPlanTree()->SetParameterValues(¶m_values); } auto status = traffic_cop_->ExecuteStatement(statement, param_values, unnamed, nullptr, result_format, result, rows_affected, error_message, thread_id); if (status == ResultType::SUCCESS) { tuple_descriptor = statement->GetTupleDescriptor(); } else { SendErrorResponse( {{NetworkMessageType::HUMAN_READABLE_ERROR, error_message}}); SendReadyForQuery(NetworkTransactionStateType::IDLE); return; } break; } default: { // execute the query using tcop auto status = traffic_cop_->ExecuteStatement( query, result, tuple_descriptor, rows_affected, error_message, thread_id); // check status if (status == ResultType::FAILURE) { SendErrorResponse( {{NetworkMessageType::HUMAN_READABLE_ERROR, error_message}}); SendReadyForQuery(NetworkTransactionStateType::IDLE); return; } } } // send the attribute names PutTupleDescriptor(tuple_descriptor); // send the result rows SendDataRows(result, tuple_descriptor.size(), rows_affected); // The response to the SimpleQueryCommand is the query string. CompleteCommand(query, query_type, rows_affected); } else {
/* * Stage all files in the stream. */ static void copyStream() { int rval; FileInfo_t *file; int dcache; boolean_t reject; StageInit(Stream->vsn); /* Set loading flag for this stream. */ PthreadMutexLock(&Stream->mutex); SET_FLAG(Stream->flags, SR_LOADING); PthreadMutexUnlock(&Stream->mutex); rval = LoadVolume(); /* Reject if mount/open failed. */ if (rval != 0) { PthreadMutexLock(&Stream->mutex); removeDcachedFile(Stream, rval); if (rval == ENODEV) { Stream->context = 0; PthreadMutexUnlock(&Stream->mutex); rejectRequest(0, B_TRUE); SET_FLAG(Instance->ci_flags, CI_shutdown); } else { PthreadMutexUnlock(&Stream->mutex); SendCustMsg(HERE, 19017, Stream->vsn); rejectRequest(rval, B_TRUE); } StageEnd(); return; } /* VSN load has completed. */ checkBuffers(Stream->vsn); PthreadMutexLock(&Stream->mutex); CLEAR_FLAG(Stream->flags, SR_LOADING); Instance->ci_seqnum = Stream->seqnum; reject = B_FALSE; /* * Copy all files in stage stream request. The files have * been ordered to eliminate backward media positioning. */ while (STREAM_IS_VALID() && reject == B_FALSE) { /* Stop staging if parent died. */ if (getppid() == 1) { SetErrno = 0; /* set for trace */ Trace(TR_ERR, "Detected stager daemon exit"); Stream->first = EOS; SET_FLAG(Instance->ci_flags, CI_shutdown); break; } file = GetFile(Stream->first); PthreadMutexLock(&file->mutex); PthreadMutexUnlock(&Stream->mutex); /* * If the first vsn, clear bytes read count. * And if multivolume and stage -n set, initialize * residual length. */ if (file->vsn_cnt == 0) { file->read = 0; if (GET_FLAG(file->flags, FI_MULTIVOL) && GET_FLAG(file->flags, FI_STAGE_NEVER)) { file->residlen = file->len; } else { file->residlen = 0; } } SET_FLAG(file->flags, FI_ACTIVE); PthreadMutexUnlock(&file->mutex); /* Set file in io control structure for archive read thread. */ setIoThread(file); /* Log stage start. */ file->eq = IoThread->io_drive; LogIt(LOG_STAGE_START, file); /* * Check if last request was canceled. If the last request * was canceled, invalidate i/o buffers and clear cancel * flag in the control structure. */ if (GET_FLAG(IoThread->io_flags, IO_cancel)) { ResetBuffers(); CLEAR_FLAG(IoThread->io_flags, IO_cancel); } /* * Next archive file. If disk archive, we may be opening * a disk archive tarball. */ if ((rval = NextArchiveFile()) == 0) { /* Prepare filesystem to receive staged file. */ dcache = DiskCacheOpen(file); } else { /* Unable to open disk archive. Error request. */ Trace(TR_ERR, "Unable to open disk archive " "copy: %d inode: %d.%d errno: %d", file->copy + 1, file->id.ino, file->id.gen, errno); dcache = -1; file->error = errno; SendErrorResponse(file); } if (dcache >= 0 && rval == 0) { /* * Notify reader thread that next file in stream * is ready to be staged. */ ThreadStatePost(&IoThread->io_readReady); /* Write data to disk cache. */ rval = DiskCacheWrite(file, dcache); if (rval != 0) { SendErrorResponse(file); /* Check if number of stream errors exceeded. */ reject = ifMaxStreamErrors(file); } ThreadStateWait(&IoThread->io_readDone); } else if (rval != 0 && dcache >= 0) { /* Setup for error handling. */ SetFileError(file, dcache, 0, EIO); SendErrorResponse(file); } EndArchiveFile(); /* Remove file from stream before marking it as done. */ PthreadMutexLock(&Stream->mutex); Stream->first = file->next; /* Device not available. */ if (file->error == ENODEV) { SetErrno = 0; /* set for trace */ Trace(TR_ERR, "No device available"); reject = B_TRUE; if (NumOpenFiles <= 0 && Instance->ci_first == NULL) { SET_FLAG(Instance->ci_flags, CI_shutdown); Instance->ci_busy = B_TRUE; } } /* Mark file staging as done. */ SetStageDone(file); Stream->count--; if (Stream->first == EOS) { Stream->last = EOS; } } /* Reject rest of stages in this stream. */ if (reject == B_TRUE) { if (Stream->first > EOS) { removeDcachedFile(Stream, ENODEV); } PthreadMutexUnlock(&Stream->mutex); rejectRequest(ENODEV, B_FALSE); PthreadMutexLock(&Stream->mutex); } /* Remove copy request, no one is waiting on it. */ RemoveMapFile(copyRequestPath, Request, sizeof (CopyRequestInfo_t)); Request = NULL; /* Ready to unload. Mark stream as done. */ SET_FLAG(Stream->flags, SR_DONE); PthreadMutexUnlock(&Stream->mutex); UnloadVolume(); /* * Unmap pages of memory. Stream's memory * mapped file is removed in parent. */ UnMapFile(Stream, sizeof (StreamInfo_t)); Stream = NULL; StageEnd(); }