/*! * \brief Returns OK message in the case of a subscription request. * * \return UPNP_E_SUCCESS if successful, otherwise the appropriate error code. */ static int respond_ok( /*! [in] Socket connection of request. */ SOCKINFO *info, /*! [in] Accepted duration. */ int time_out, /*! [in] Accepted subscription. */ subscription *sub, /*! [in] Http request. */ http_message_t *request) { int major; int minor; membuffer response; int return_code; char timeout_str[100]; int upnp_timeout = UPNP_TIMEOUT; int rc = 0; http_CalcResponseVersion( request->major_version, request->minor_version, &major, &minor ); if( time_out >= 0 ) { rc = snprintf( timeout_str, sizeof ( timeout_str ), "TIMEOUT: Second-%d", time_out ); } else { memset( timeout_str, 0, sizeof( timeout_str ) ); strncpy( timeout_str, "TIMEOUT: Second-infinite", sizeof ( timeout_str ) - 1); } if (rc < 0 || (unsigned int) rc >= sizeof ( timeout_str ) ) { error_respond( info, HTTP_INTERNAL_SERVER_ERROR, request ); return UPNP_E_OUTOF_MEMORY; } membuffer_init( &response ); response.size_inc = 30; if( http_MakeMessage( &response, major, minor, "R" "D" "S" "N" "Xc" "ssc" "scc", HTTP_OK, (off_t)0, X_USER_AGENT, "SID: ", sub->sid, timeout_str ) != 0 ) { membuffer_destroy( &response ); error_respond( info, HTTP_INTERNAL_SERVER_ERROR, request ); return UPNP_E_OUTOF_MEMORY; } return_code = http_SendMessage( info, &upnp_timeout, "b", response.buf, response.length ); membuffer_destroy( &response ); return return_code; }
/**************************************************************************** * Function : send_var_query_response * * Parameters : * IN SOCKINFO *info : socket info * IN const char* var_value : value of the state variable * IN http_message_t* hmsg : HTTP request * * Description : This function sends response of get var status * * Return : void * * Note : ****************************************************************************/ static UPNP_INLINE void send_var_query_response( IN SOCKINFO * info, IN const char *var_value, IN http_message_t * hmsg ) { off_t content_length; int timeout_secs = SOAP_TIMEOUT; int major; int minor; const char *start_body = "<s:Envelope " "xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" " "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n" "<s:Body>\n" "<u:QueryStateVariableResponse " "xmlns:u=\"urn:schemas-upnp-org:control-1-0\">\n" "<return>"; const char *end_body = "</return>\n" "</u:QueryStateVariableResponse>\n" "</s:Body>\n" "</s:Envelope>\n"; membuffer response; http_CalcResponseVersion( hmsg->major_version, hmsg->minor_version, &major, &minor ); content_length = strlen( start_body ) + strlen( var_value ) + strlen( end_body ); // make headers membuffer_init( &response ); if (http_MakeMessage( &response, major, minor, "RNsDsSXcc" "sss", HTTP_OK, content_length, ContentTypeHeader, "EXT:\r\n", X_USER_AGENT, start_body, var_value, end_body ) != 0 ) { membuffer_destroy( &response ); return; // out of mem } // send msg http_SendMessage( info, &timeout_secs, "b", response.buf, response.length ); membuffer_destroy( &response ); }
/**************************************************************************** * Function : send_error_response * * Parameters : * IN SOCKINFO *info : socket info * IN int error_code : error code * IN const char* err_msg : error message * IN http_message_t* hmsg : HTTP request * * Description : This function sends SOAP error response * * Return : void * * Note : ****************************************************************************/ static void send_error_response( IN SOCKINFO * info, IN int error_code, IN const char *err_msg, IN http_message_t * hmsg ) { int content_length; int timeout_secs = SOAP_TIMEOUT; int major, minor; const char *start_body = "<s:Envelope\n" "xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"\n" "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n" "<s:Body>\n" "<s:Fault>\n" "<faultcode>s:Client</faultcode>\n" "<faultstring>UPnPError</faultstring>\n" "<detail>\n" "<UPnPError xmlns=\"urn:schemas-upnp-org:control-1-0\">\n" "<errorCode>"; const char *mid_body = "</errorCode>\n" "<errorDescription>"; const char *end_body = "</errorDescription>\n" "</UPnPError>\n" "</detail>\n" "</s:Fault>\n" "</s:Body>\n" "</s:Envelope>\n"; char err_code_str[30]; membuffer headers; sprintf( err_code_str, "%d", error_code ); // calc body len content_length = strlen( start_body ) + strlen( err_code_str ) + strlen( mid_body ) + strlen( err_msg ) + strlen( end_body ); http_CalcResponseVersion( hmsg->major_version, hmsg->minor_version, &major, &minor ); // make headers membuffer_init( &headers ); if( http_MakeMessage( &headers, major, minor, "RNsDsSc" "sssss", 500, content_length, ContentTypeHeader, "EXT:\r\n", start_body, err_code_str, mid_body, err_msg, end_body ) != 0 ) { membuffer_destroy( &headers ); return; // out of mem } // send err msg http_SendMessage( info, &timeout_secs, "b", headers.buf, headers.length ); membuffer_destroy( &headers ); }
/*! * \brief Sends the notify message and returns a reply. * * \return on success returns UPNP_E_SUCCESS, otherwise returns a UPNP error. * * \note called by genaNotify */ static UPNP_INLINE int notify_send_and_recv( /*! [in] subscription callback URL (URL of the control point). */ uri_type *destination_url, /*! [in] Common HTTP headers. */ membuffer *mid_msg, /*! [in] The evented XML. */ char *propertySet, /*! [out] The response from the control point. */ http_parser_t *response) { uri_type url; SOCKET conn_fd; membuffer start_msg; int ret_code; int err_code; int timeout; SOCKINFO info; const char *CRLF = "\r\n"; /* connect */ UpnpPrintf(UPNP_ALL, GENA, __FILE__, __LINE__, "gena notify to: %.*s\n", (int)destination_url->hostport.text.size, destination_url->hostport.text.buff); conn_fd = http_Connect(destination_url, &url); if (conn_fd < 0) /* return UPNP error */ return UPNP_E_SOCKET_CONNECT; ret_code = sock_init(&info, conn_fd); if (ret_code) { sock_destroy(&info, SD_BOTH); return ret_code; } /* make start line and HOST header */ membuffer_init(&start_msg); if (http_MakeMessage( &start_msg, 1, 1, "q" "s", HTTPMETHOD_NOTIFY, &url, mid_msg->buf) != 0) { membuffer_destroy(&start_msg); sock_destroy(&info, SD_BOTH); return UPNP_E_OUTOF_MEMORY; } timeout = GENA_NOTIFICATION_SENDING_TIMEOUT; /* send msg (note: end of notification will contain "\r\n" twice) */ ret_code = http_SendMessage(&info, &timeout, "bbb", start_msg.buf, start_msg.length, propertySet, strlen(propertySet), CRLF, strlen(CRLF)); if (ret_code) { membuffer_destroy(&start_msg); sock_destroy(&info, SD_BOTH); return ret_code; } timeout = GENA_NOTIFICATION_ANSWERING_TIMEOUT; ret_code = http_RecvMessage(&info, response, HTTPMETHOD_NOTIFY, &timeout, &err_code); if (ret_code) { membuffer_destroy(&start_msg); sock_destroy(&info, SD_BOTH); httpmsg_destroy(&response->msg); return ret_code; } /* should shutdown completely when closing socket */ sock_destroy(&info, SD_BOTH); membuffer_destroy(&start_msg); return UPNP_E_SUCCESS; }
void web_server_callback(http_parser_t *parser, INOUT http_message_t *req, SOCKINFO *info) { int ret; int timeout = 0; enum resp_type rtype = 0; membuffer headers; membuffer filename; struct xml_alias_t xmldoc; struct SendInstruction RespInstr; /*Initialize instruction header. */ RespInstr.IsVirtualFile = 0; RespInstr.IsChunkActive = 0; RespInstr.IsRangeActive = 0; RespInstr.IsTrailers = 0; memset(RespInstr.AcceptLanguageHeader, 0, sizeof(RespInstr.AcceptLanguageHeader)); /* init */ membuffer_init(&headers); membuffer_init(&filename); /*Process request should create the different kind of header depending on the */ /*the type of request. */ ret = process_request(req, &rtype, &headers, &filename, &xmldoc, &RespInstr); if (ret != HTTP_OK) { /* send error code */ http_SendStatusResponse(info, ret, req->major_version, req->minor_version); } else { /* send response */ switch (rtype) { case RESP_FILEDOC: http_SendMessage(info, &timeout, "Ibf", &RespInstr, headers.buf, headers.length, filename.buf); break; case RESP_XMLDOC: http_SendMessage(info, &timeout, "Ibb", &RespInstr, headers.buf, headers.length, xmldoc.doc.buf, xmldoc.doc.length); alias_release(&xmldoc); break; case RESP_WEBDOC: /*http_SendVirtualDirDoc(info, &timeout, "Ibf", &RespInstr, headers.buf, headers.length, filename.buf);*/ http_SendMessage(info, &timeout, "Ibf", &RespInstr, headers.buf, headers.length, filename.buf); break; case RESP_HEADERS: /* headers only */ http_SendMessage(info, &timeout, "b", headers.buf, headers.length); break; case RESP_POST: /* headers only */ ret = http_RecvPostMessage(parser, info, filename.buf, &RespInstr); /* Send response. */ http_MakeMessage(&headers, 1, 1, "RTLSXcCc", ret, "text/html", &RespInstr, X_USER_AGENT); http_SendMessage(info, &timeout, "b", headers.buf, headers.length); break; default: UpnpPrintf(UPNP_INFO, HTTP, __FILE__, __LINE__, "webserver: Invalid response type received.\n"); assert(0); } } UpnpPrintf(UPNP_INFO, HTTP, __FILE__, __LINE__, "webserver: request processed...\n"); membuffer_destroy(&headers); membuffer_destroy(&filename); }
/*! * \brief Sends the SOAP action response. */ static UPNP_INLINE void send_action_response( /*! [in] Socket info. */ SOCKINFO *info, /*! [in] The response document. */ IXML_Document *action_resp, /*! [in] Action request document. */ http_message_t *request) { char *xml_response = NULL; membuffer headers; int major, minor; int err_code; off_t content_length; int ret_code; int timeout_secs = SOAP_TIMEOUT; static const char *start_body = "<?xml version=\"1.0\"?>" "<s:Envelope xmlns:s=\"http://schemas.xmlsoap." "org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap." "org/soap/encoding/\"><s:Body>\n"; static const char *end_body = "</s:Body> </s:Envelope>"; /* init */ http_CalcResponseVersion(request->major_version, request->minor_version, &major, &minor); membuffer_init(&headers); err_code = UPNP_E_OUTOF_MEMORY; /* one error only */ /* get xml */ xml_response = ixmlPrintNode((IXML_Node *) action_resp); if (!xml_response) goto error_handler; content_length = (off_t)(strlen(start_body) + strlen(xml_response) + strlen(end_body)); /* make headers */ if (http_MakeMessage(&headers, major, minor, "RNsDsSXcc", HTTP_OK, /* status code */ content_length, ContentTypeHeader, "EXT:\r\n", X_USER_AGENT) != 0) { goto error_handler; } /* send whole msg */ ret_code = http_SendMessage( info, &timeout_secs, "bbbb", headers.buf, headers.length, start_body, strlen(start_body), xml_response, strlen(xml_response), end_body, strlen(end_body)); if (ret_code != 0) { UpnpPrintf(UPNP_INFO, SOAP, __FILE__, __LINE__, "Failed to send response: err code = %d\n", ret_code); } err_code = 0; error_handler: ixmlFreeDOMString(xml_response); membuffer_destroy(&headers); if (err_code != 0) { /* only one type of error to worry about - out of mem */ send_error_response(info, SOAP_ACTION_FAILED, "Out of memory", request); } }
/*! * \brief Sends SOAP error response. */ static void send_error_response( /*! [in] Socket info. */ IN SOCKINFO *info, /*! [in] Error code. */ IN int error_code, /*! [in] Error message. */ IN const char *err_msg, /*! [in] HTTP request. */ IN http_message_t *hmsg) { off_t content_length; int timeout_secs = SOAP_TIMEOUT; int major; int minor; const char *start_body = "<?xml version=\"1.0\"?>\n" "<s:Envelope " "xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" " "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n" "<s:Body>\n" "<s:Fault>\n" "<faultcode>s:Client</faultcode>\n" "<faultstring>UPnPError</faultstring>\n" "<detail>\n" "<UPnPError xmlns=\"urn:schemas-upnp-org:control-1-0\">\n" "<errorCode>"; const char *mid_body = "</errorCode>\n" "<errorDescription>"; const char *end_body = "</errorDescription>\n" "</UPnPError>\n" "</detail>\n" "</s:Fault>\n" "</s:Body>\n" "</s:Envelope>\n"; char err_code_str[30]; membuffer headers; memset(err_code_str, 0, sizeof(err_code_str)); snprintf(err_code_str, sizeof(err_code_str), "%d", error_code); /* calc body len */ content_length = (off_t) (strlen(start_body) + strlen(err_code_str) + strlen(mid_body) + strlen(err_msg) + strlen(end_body)); http_CalcResponseVersion(hmsg->major_version, hmsg->minor_version, &major, &minor); /* make headers */ membuffer_init(&headers); if (http_MakeMessage(&headers, major, minor, "RNsDsSXcc" "sssss", 500, content_length, ContentTypeHeader, "EXT:\r\n", X_USER_AGENT, start_body, err_code_str, mid_body, err_msg, end_body) != 0) { membuffer_destroy(&headers); /* out of mem */ return; } /* send err msg */ http_SendMessage(info, &timeout_secs, "b", headers.buf, headers.length); membuffer_destroy(&headers); }
void web_server_callback(http_parser_t *parser, INOUT http_message_t *req, SOCKINFO *info) { int ret; int timeout = 5; enum resp_type rtype = 0; membuffer headers; membuffer filename; struct xml_alias_t xmldoc; #if 0 struct SendInstruction *pRespInstr; struct SendInstruction RespInstr; /*Initialize instruction header. */ RespInstr.IsVirtualFile = 0; RespInstr.IsChunkActive = 0; RespInstr.IsRangeActive = 0; RespInstr.IsTrailers = 0; memset(RespInstr.AcceptLanguageHeader, 0, sizeof(RespInstr.AcceptLanguageHeader)); pRespInstr = &RespInstr; #else struct SendInstruction *pRespInstr = osal_zmalloc( sizeof(struct SendInstruction) ); #endif /* init */ membuffer_init(&headers); membuffer_init(&filename); /*Process request should create the different kind of header depending on the */ /*the type of request. */ ret = process_request(req, &rtype, &headers, &filename, &xmldoc, pRespInstr); if (ret != HTTP_OK) { /* send error code */ http_SendStatusResponse(info, ret, req->major_version, req->minor_version); } else { /* send response */ switch (rtype) { case RESP_FILEDOC: // The timeout need consider as transfer rate is high but consumption is slow and recevie buffer // is small in recevier. It will cause receiver pauses to receive data a while. If timeout is short, // the socket will be closed by timeout!! // HTTP file playback may get a timeout issue when media (bitrate 15Mbits) sent fast (26Mbits or above) // to Android device. timeout = 20; // The value 20 is by experiment,as video is 15Mbits, // tcp has 26Mbits in transfer to NEXUS 7 video player! http_SendMessage(info, &timeout, "Ibf", pRespInstr, headers.buf, headers.length, filename.buf); UpnpPrintf(UPNP_WARN, HTTP, __FILE__, __LINE__,"%d FILEDOC %s\r\n", __LINE__, filename.buf); break; case RESP_XMLDOC: http_SendMessage(info, &timeout, "Ibb", pRespInstr, headers.buf, headers.length, xmldoc.doc.buf, xmldoc.doc.length); alias_release(&xmldoc); UpnpPrintf(UPNP_WARN, HTTP, __FILE__, __LINE__,"%d XMLDOC %s\r\n", __LINE__, xmldoc.doc.buf); break; case RESP_WEBDOC: /*http_SendVirtualDirDoc(info, &timeout, "Ibf", pRespInstr, headers.buf, headers.length, filename.buf);*/ http_SendMessage(info, &timeout, "Ibf", pRespInstr, headers.buf, headers.length, filename.buf); UpnpPrintf(UPNP_WARN, HTTP, __FILE__, __LINE__,"%d WEBDOC %s\r\n", __LINE__, filename.buf); break; case RESP_HEADERS: /* headers only */ http_SendMessage(info, &timeout, "b", headers.buf, headers.length); UpnpPrintf(UPNP_WARN, HTTP, __FILE__, __LINE__,"%d HEADERS %s\r\n", __LINE__, headers.buf); break; case RESP_POST: /* headers only */ ret = http_RecvPostMessage(parser, info, filename.buf, pRespInstr); if (ret != HTTP_OK){ req->status_code = HTTP_BAD_REQUEST; } /* Send response. */ http_MakeMessage(&headers, 1, 1, "RTLSXcCc", ret, "text/html", pRespInstr, X_USER_AGENT, "WebServer by Alpha Imaging Technology Corp."); http_SendMessage(info, &timeout, "b", headers.buf, headers.length); UpnpPrintf(UPNP_WARN, HTTP, __FILE__, __LINE__,"%d POST %s\r\n", __LINE__, headers.buf); break; default: UpnpPrintf(UPNP_INFO, HTTP, __FILE__, __LINE__, "webserver: Invalid response type received.\n"); assert(0); break; } } UpnpPrintf(UPNP_INFO, HTTP, __FILE__, __LINE__, "webserver: request processed...\n"); membuffer_destroy(&headers); membuffer_destroy(&filename); osal_free(pRespInstr) }