static void ProcessHTTPSubscribe_upnphttp(struct upnphttp * h, const char * path) { const char * sid; syslog(LOG_DEBUG, "ProcessHTTPSubscribe %s", path); syslog(LOG_DEBUG, "Callback '%.*s' Timeout=%d", h->req_CallbackLen, h->req_Callback, h->req_Timeout); syslog(LOG_DEBUG, "SID '%.*s'", h->req_SIDLen, h->req_SID); if(!h->req_Callback && !h->req_SID) { /* Missing or invalid CALLBACK : 412 Precondition Failed. * If CALLBACK header is missing or does not contain a valid HTTP URL, * the publisher must respond with HTTP error 412 Precondition Failed*/ BuildResp2_upnphttp(h, 412, "Precondition Failed", 0, 0); SendResp_upnphttp(h); CloseSocket_upnphttp(h); } else { /* - add to the subscriber list * - respond HTTP/x.x 200 OK * - Send the initial event message */ /* Server:, SID:; Timeout: Second-(xx|infinite) */ /* Check that the callback URL is on the same IP as * the request, and not on the internet, nor on ourself (DOS attack ?) */ if(h->req_Callback) { if(checkCallbackURL(h)) { sid = upnpevents_addSubscriber(path, h->req_Callback, h->req_CallbackLen, h->req_Timeout); h->respflags = FLAG_TIMEOUT; if(sid) { syslog(LOG_DEBUG, "generated sid=%s", sid); h->respflags |= FLAG_SID; h->req_SID = sid; h->req_SIDLen = strlen(sid); } BuildResp_upnphttp(h, 0, 0); } else { syslog(LOG_WARNING, "Invalid Callback in SUBSCRIBE %.*s", h->req_CallbackLen, h->req_Callback); BuildResp2_upnphttp(h, 412, "Precondition Failed", 0, 0); } } else { /* subscription renew */ /* Invalid SID 412 Precondition Failed. If a SID does not correspond to a known, un-expired subscription, the publisher must respond with HTTP error 412 Precondition Failed. */ if(renewSubscription(h->req_SID, h->req_SIDLen, h->req_Timeout) < 0) { BuildResp2_upnphttp(h, 412, "Precondition Failed", 0, 0); } else { h->respflags = FLAG_TIMEOUT; BuildResp_upnphttp(h, 0, 0); } } SendResp_upnphttp(h); CloseSocket_upnphttp(h); } }
void SendRootContainer(struct upnphttp * h) { char * resp; int len; len = asprintf(&resp, "<?xml version='1.0' encoding='UTF-8' ?>\n" "<TiVoContainer>" "<Details>" "<ContentType>x-container/tivo-server</ContentType>" "<SourceFormat>x-container/folder</SourceFormat>" "<TotalDuration>0</TotalDuration>" "<TotalItems>3</TotalItems>" "<Title>%s</Title>" "</Details>" "<ItemStart>0</ItemStart>" "<ItemCount>2</ItemCount>" "<Item>" "<Details>" "<ContentType>x-container/tivo-photos</ContentType>" "<SourceFormat>x-container/folder</SourceFormat>" "<Title>Pictures on %s</Title>" "</Details>" "<Links>" "<Content>" "<Url>/TiVoConnect?Command=QueryContainer&Container=3</Url>" "</Content>" "</Links>" "</Item>" "<Item>" "<Details>" "<ContentType>x-container/tivo-music</ContentType>" "<SourceFormat>x-container/folder</SourceFormat>" "<Title>Music on %s</Title>" "</Details>" "<Links>" "<Content>" "<Url>/TiVoConnect?Command=QueryContainer&Container=1</Url>" "</Content>" "</Links>" "</Item>" "<Item>" "<Details>" "<ContentType>x-container/tivo-videos</ContentType>" "<SourceFormat>x-container/folder</SourceFormat>" "<Title>Videos on %s</Title>" "</Details>" "<Links>" "<Content>" "<Url>/TiVoConnect?Command=QueryContainer&Container=2</Url>" "<ContentType>x-container/tivo-videos</ContentType>" "</Content>" "</Links>" "</Item>" "</TiVoContainer>", friendly_name, friendly_name, friendly_name, friendly_name); BuildResp_upnphttp(h, resp, len); free(resp); SendResp_upnphttp(h); }
static void ProcessHTTPUnSubscribe_upnphttp(struct upnphttp * h, const char * path) { syslog(LOG_DEBUG, "ProcessHTTPUnSubscribe %s", path); syslog(LOG_DEBUG, "SID '%.*s'", h->req_SIDLen, h->req_SID); /* Remove from the list */ if(upnpevents_removeSubscriber(h->req_SID, h->req_SIDLen) < 0) { BuildResp2_upnphttp(h, 412, "Precondition Failed", 0, 0); } else { BuildResp_upnphttp(h, 0, 0); } SendResp_upnphttp(h); CloseSocket_upnphttp(h); }
static void sendDummyDesc(struct upnphttp * h) { static const char xml_desc[] = "<?xml version=\"1.0\"?>\r\n" "<scpd xmlns=\"urn:schemas-upnp-org:service-1-0\">" " <specVersion>" " <major>1</major>" " <minor>0</minor>" " </specVersion>" " <actionList />" " <serviceStateTable />" "</scpd>\r\n"; BuildResp_upnphttp(h, xml_desc, sizeof(xml_desc)-1); SendRespAndClose_upnphttp(h); }
static void ProcessHTTPUnSubscribe_upnphttp(struct upnphttp * h, const char * path) { syslog(LOG_DEBUG, "ProcessHTTPUnSubscribe %s", path); syslog(LOG_DEBUG, "SID '%.*s'", h->req_SIDLen, h->req_buf + h->req_SIDOff); /* Remove from the list */ #ifdef UPNP_STRICT if(h->req_SIDOff <= 0 || h->req_SIDLen == 0) { /* SID: header missing or empty */ BuildResp2_upnphttp(h, 412, "Precondition Failed", 0, 0); } else if(h->req_CallbackOff > 0 || h->req_NTOff > 0) { /* no NT: or Callback: header must be present */ BuildResp2_upnphttp(h, 400, "Incompatible header fields", 0, 0); } else #endif if(upnpevents_removeSubscriber(h->req_buf + h->req_SIDOff, h->req_SIDLen) < 0) { BuildResp2_upnphttp(h, 412, "Precondition Failed", 0, 0); } else { BuildResp_upnphttp(h, 0, 0); } SendRespAndClose_upnphttp(h); }
/* Sends the description generated by the parameter */ static void sendXMLdesc(struct upnphttp * h, char * (f)(int *)) { char * desc; int len; desc = f(&len); if(!desc) { static const char error500[] = "<HTML><HEAD><TITLE>Error 500</TITLE>" "</HEAD><BODY>Internal Server Error</BODY></HTML>\r\n"; syslog(LOG_ERR, "Failed to generate XML description"); h->respflags = FLAG_HTML; BuildResp2_upnphttp(h, 500, "Internal Server Error", error500, sizeof(error500)-1); } else { BuildResp_upnphttp(h, desc, len); } SendRespAndClose_upnphttp(h); free(desc); }
static void ProcessHTTPSubscribe_upnphttp(struct upnphttp * h, const char * path) { const char * sid; syslog(LOG_DEBUG, "ProcessHTTPSubscribe %s", path); syslog(LOG_DEBUG, "Callback '%.*s' Timeout=%d", h->req_CallbackLen, h->req_buf + h->req_CallbackOff, h->req_Timeout); syslog(LOG_DEBUG, "SID '%.*s'", h->req_SIDLen, h->req_buf + h->req_SIDOff); if((h->req_CallbackOff <= 0) && (h->req_SIDOff <= 0)) { /* Missing or invalid CALLBACK : 412 Precondition Failed. * If CALLBACK header is missing or does not contain a valid HTTP URL, * the publisher must respond with HTTP error 412 Precondition Failed*/ BuildResp2_upnphttp(h, 412, "Precondition Failed", 0, 0); SendRespAndClose_upnphttp(h); } else { /* - add to the subscriber list * - respond HTTP/x.x 200 OK * - Send the initial event message */ /* Server:, SID:; Timeout: Second-(xx|infinite) */ /* Check that the callback URL is on the same IP as * the request, and not on the internet, nor on ourself (DOS attack ?) */ if(h->req_CallbackOff > 0) { #ifdef UPNP_STRICT /* SID: and Callback: are incompatible */ if(h->req_SIDOff > 0) { syslog(LOG_WARNING, "Both Callback: and SID: in SUBSCRIBE"); BuildResp2_upnphttp(h, 400, "Incompatible header fields", 0, 0); /* "NT: upnp:event" header is mandatory */ } else if(h->req_NTOff <= 0 || h->req_NTLen != 10 || 0 != memcmp("upnp:event", h->req_buf + h->req_NTOff, 10)) { syslog(LOG_WARNING, "Invalid NT in SUBSCRIBE %.*s", h->req_NTLen, h->req_buf + h->req_NTOff); BuildResp2_upnphttp(h, 412, "Precondition Failed", 0, 0); } else #endif if(checkCallbackURL(h)) { sid = upnpevents_addSubscriber(path, h->req_buf + h->req_CallbackOff, h->req_CallbackLen, h->req_Timeout); h->respflags = FLAG_TIMEOUT; if(sid) { syslog(LOG_DEBUG, "generated sid=%s", sid); h->respflags |= FLAG_SID; h->res_SID = sid; } BuildResp_upnphttp(h, 0, 0); } else { syslog(LOG_WARNING, "Invalid Callback in SUBSCRIBE %.*s", h->req_CallbackLen, h->req_buf + h->req_CallbackOff); BuildResp2_upnphttp(h, 412, "Precondition Failed", 0, 0); } } else { /* subscription renew */ /* Invalid SID 412 Precondition Failed. If a SID does not correspond to a known, un-expired subscription, the publisher must respond with HTTP error 412 Precondition Failed. */ #ifdef UPNP_STRICT /* SID: and NT: headers are incompatibles */ if(h->req_NTOff > 0) { syslog(LOG_WARNING, "Both NT: and SID: in SUBSCRIBE"); BuildResp2_upnphttp(h, 400, "Incompatible header fields", 0, 0); } else #endif if(renewSubscription(h->req_buf + h->req_SIDOff, h->req_SIDLen, h->req_Timeout) < 0) { BuildResp2_upnphttp(h, 412, "Precondition Failed", 0, 0); } else { h->respflags = FLAG_TIMEOUT; BuildResp_upnphttp(h, 0, 0); } } SendRespAndClose_upnphttp(h); } }
static void ProcessHTTPSubscribe_upnphttp(struct upnphttp * h, const char * path) { const char * sid; syslog(LOG_DEBUG, "ProcessHTTPSubscribe %s", path); syslog(LOG_DEBUG, "Callback '%.*s' Timeout=%d", h->req_CallbackLen, h->req_buf + h->req_CallbackOff, h->req_Timeout); syslog(LOG_DEBUG, "SID '%.*s'", h->req_SIDLen, h->req_buf + h->req_SIDOff); #if defined(UPNP_STRICT) && (UPNP_VERSION_MAJOR > 1) || (UPNP_VERSION_MINOR > 0) /*if(h->req_Timeout < 1800) {*/ if(h->req_Timeout == 0) { /* Second-infinite is forbidden with UDA v1.1 and later : * (UDA 1.1 : 4.1.1 Subscription) * UPnP 1.1 control points MUST NOT subscribe using keyword infinite, * UPnP 1.1 devices MUST NOT set actual subscription durations to * "infinite". The presence of infinite in a request MUST be silently * ignored by a UPnP 1.1 device (the presence of infinite is handled * by the device as if the TIMEOUT header field in a request was not * present) . The keyword infinite MUST NOT be returned by a UPnP 1.1 * device. */ h->req_Timeout = 1800; /* default to 30 minutes */ } #endif /* UPNP_STRICT */ if((h->req_CallbackOff <= 0) && (h->req_SIDOff <= 0)) { /* Missing or invalid CALLBACK : 412 Precondition Failed. * If CALLBACK header is missing or does not contain a valid HTTP URL, * the publisher must respond with HTTP error 412 Precondition Failed*/ BuildResp2_upnphttp(h, 412, "Precondition Failed", 0, 0); SendRespAndClose_upnphttp(h); } else { /* - add to the subscriber list * - respond HTTP/x.x 200 OK * - Send the initial event message */ /* Server:, SID:; Timeout: Second-(xx|infinite) */ /* Check that the callback URL is on the same IP as * the request, and not on the internet, nor on ourself (DOS attack ?) */ if(h->req_CallbackOff > 0) { #ifdef UPNP_STRICT /* SID: and Callback: are incompatible */ if(h->req_SIDOff > 0) { syslog(LOG_WARNING, "Both Callback: and SID: in SUBSCRIBE"); BuildResp2_upnphttp(h, 400, "Incompatible header fields", 0, 0); /* "NT: upnp:event" header is mandatory */ } else if(h->req_NTOff <= 0 || h->req_NTLen != 10 || 0 != memcmp("upnp:event", h->req_buf + h->req_NTOff, 10)) { syslog(LOG_WARNING, "Invalid NT in SUBSCRIBE %.*s", h->req_NTLen, h->req_buf + h->req_NTOff); BuildResp2_upnphttp(h, 412, "Precondition Failed", 0, 0); } else #endif if(checkCallbackURL(h)) { sid = upnpevents_addSubscriber(path, h->req_buf + h->req_CallbackOff, h->req_CallbackLen, h->req_Timeout); h->respflags = FLAG_TIMEOUT; if(sid) { syslog(LOG_DEBUG, "generated sid=%s", sid); h->respflags |= FLAG_SID; h->res_SID = sid; } BuildResp_upnphttp(h, 0, 0); } else { syslog(LOG_WARNING, "Invalid Callback in SUBSCRIBE %.*s", h->req_CallbackLen, h->req_buf + h->req_CallbackOff); BuildResp2_upnphttp(h, 412, "Precondition Failed", 0, 0); } } else { /* subscription renew */ /* Invalid SID 412 Precondition Failed. If a SID does not correspond to a known, un-expired subscription, the publisher must respond with HTTP error 412 Precondition Failed. */ #ifdef UPNP_STRICT /* SID: and NT: headers are incompatibles */ if(h->req_NTOff > 0) { syslog(LOG_WARNING, "Both NT: and SID: in SUBSCRIBE"); BuildResp2_upnphttp(h, 400, "Incompatible header fields", 0, 0); } else { #endif /* UPNP_STRICT */ sid = upnpevents_renewSubscription(h->req_buf + h->req_SIDOff, h->req_SIDLen, h->req_Timeout); if(!sid) { BuildResp2_upnphttp(h, 412, "Precondition Failed", 0, 0); } else { h->respflags = FLAG_TIMEOUT | FLAG_SID; h->res_SID = sid; BuildResp_upnphttp(h, 0, 0); } #ifdef UPNP_STRICT } #endif /* UPNP_STRICT */ } SendRespAndClose_upnphttp(h); } }