wps_upnp_web.c
来自「最新的Host AP 新添加了许多pcmcia 的驱动」· C语言 代码 · 共 1,965 行 · 第 1/4 页
C
1,965 行
h = end + 1; end = os_strchr(h, '\n'); if (end == NULL) break; /* no unterminated lines allowed */ /* NT assures that it is our type of subscription; * not used for a renewl. **/ match = "NT:"; match_len = os_strlen(match); if (os_strncasecmp(h, match, match_len) == 0) { h += match_len; while (*h == ' ' || *h == '\t') h++; match = "upnp:event"; match_len = os_strlen(match); if (os_strncasecmp(h, match, match_len) != 0) { ret = HTTP_BAD_REQUEST; goto error; } got_nt = 1; continue; } /* HOST should refer to us */#if 0 match = "HOST:"; match_len = os_strlen(match); if (os_strncasecmp(h, match, match_len) == 0) { h += match_len; while (*h == ' ' || *h == '\t') h++; ..... }#endif /* CALLBACK gives one or more URLs for NOTIFYs * to be sent as a result of the subscription. * Each URL is enclosed in angle brackets. */ match = "CALLBACK:"; match_len = os_strlen(match); if (os_strncasecmp(h, match, match_len) == 0) { h += match_len; while (*h == ' ' || *h == '\t') h++; len = end - h; os_free(callback_urls); callback_urls = os_malloc(len + 1); if (callback_urls == NULL) { ret = HTTP_INTERNAL_SERVER_ERROR; goto error; } os_memcpy(callback_urls, h, len); callback_urls[len] = 0; continue; } /* SID is only for renewal */ match = "SID:"; match_len = os_strlen(match); if (os_strncasecmp(h, match, match_len) == 0) { h += match_len; while (*h == ' ' || *h == '\t') h++; match = "uuid:"; match_len = os_strlen(match); if (os_strncasecmp(h, match, match_len) != 0) { ret = HTTP_BAD_REQUEST; goto error; } h += match_len; while (*h == ' ' || *h == '\t') h++; if (uuid_str2bin(h, uuid)) { ret = HTTP_BAD_REQUEST; goto error; } got_uuid = 1; continue; } /* TIMEOUT is requested timeout, but apparently we can * just ignore this. */ } if (got_uuid) { /* renewal */ if (callback_urls) { ret = HTTP_BAD_REQUEST; goto error; } s = subscription_renew(sm, uuid); if (s == NULL) { ret = HTTP_PRECONDITION_FAILED; goto error; } } else if (callback_urls) { if (!got_nt) { ret = HTTP_PRECONDITION_FAILED; goto error; } s = subscription_start(sm, callback_urls); if (s == NULL) { ret = HTTP_INTERNAL_SERVER_ERROR; goto error; } callback_urls = NULL; /* is now owned by subscription */ } else { ret = HTTP_PRECONDITION_FAILED; goto error; } /* success */ http_put_reply_code(buf, HTTP_OK); wpabuf_put_str(buf, http_server_hdr); wpabuf_put_str(buf, http_connection_close); wpabuf_put_str(buf, "Content-Length: 0\r\n"); wpabuf_put_str(buf, "SID: uuid:"); /* subscription id */ b = wpabuf_put(buf, 0); uuid_bin2str(s->uuid, b, 80); wpabuf_put(buf, os_strlen(b)); wpabuf_put_str(buf, "\r\n"); wpabuf_printf(buf, "Timeout: Second-%d\r\n", UPNP_SUBSCRIBE_SEC); http_put_date(buf); /* And empty line to terminate header: */ wpabuf_put_str(buf, "\r\n"); send_wpabuf(c->sd, buf); wpabuf_free(buf); os_free(callback_urls); return;error: /* Per UPnP spec: * Errors * Incompatible headers * 400 Bad Request. If SID header and one of NT or CALLBACK headers * are present, the publisher must respond with HTTP error * 400 Bad Request. * 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. * Invalid NT * 412 Precondition Failed. If NT header does not equal upnp:event, * the publisher must respond with HTTP error 412 Precondition * Failed. * [For resubscription, use 412 if unknown uuid]. * Unable to accept subscription * 5xx. If a publisher is not able to accept a subscription (such as * due to insufficient resources), it must respond with a * HTTP 500-series error code. * 599 Too many subscriptions (not a standard HTTP error) */ http_put_empty(buf, ret); send_wpabuf(c->sd, buf); wpabuf_free(buf);}/* Given that we have received a header w/ UNSUBSCRIBE, act upon it * * Format of UNSUBSCRIBE (case-insensitive): * * First line must be: * UNSUBSCRIBE /wps_event HTTP/1.1 * * Our response (if no error) which includes only required lines is: * HTTP/1.1 200 OK * Content-Length: 0 * * Header lines must end with \r\n * Per RFC 2616, content-length: is not required but connection:close * would appear to be required (given that we will be closing it!). */static void web_connection_parse_unsubscribe(struct web_connection *c, const char *filename){ struct upnp_wps_device_sm *sm = c->sm; struct wpabuf *buf; char *hdr = httpread_hdr_get(c->hread); char *h; char *match; int match_len; char *end; u8 uuid[UUID_LEN]; int got_uuid = 0; struct subscription *s = NULL; enum http_reply_code ret = HTTP_INTERNAL_SERVER_ERROR; /* Parse/validate headers */ h = hdr; /* First line: UNSUBSCRIBE /wps_event HTTP/1.1 * has already been parsed. */ if (os_strcasecmp(filename, UPNP_WPS_DEVICE_EVENT_FILE) != 0) { ret = HTTP_PRECONDITION_FAILED; goto send_msg; } wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP UNSUBSCRIBE for event"); end = os_strchr(h, '\n'); for (; end != NULL; h = end + 1) { /* Option line by option line */ h = end + 1; end = os_strchr(h, '\n'); if (end == NULL) break; /* no unterminated lines allowed */ /* HOST should refer to us */#if 0 match = "HOST:"; match_len = os_strlen(match); if (os_strncasecmp(h, match, match_len) == 0) { h += match_len; while (*h == ' ' || *h == '\t') h++; ..... }#endif /* SID is only for renewal */ match = "SID:"; match_len = os_strlen(match); if (os_strncasecmp(h, match, match_len) == 0) { h += match_len; while (*h == ' ' || *h == '\t') h++; match = "uuid:"; match_len = os_strlen(match); if (os_strncasecmp(h, match, match_len) != 0) { ret = HTTP_BAD_REQUEST; goto send_msg; } h += match_len; while (*h == ' ' || *h == '\t') h++; if (uuid_str2bin(h, uuid)) { ret = HTTP_BAD_REQUEST; goto send_msg; } got_uuid = 1; continue; } } if (got_uuid) { s = subscription_find(sm, uuid); if (s) { wpa_printf(MSG_DEBUG, "WPS UPnP: Unsubscribing %p %s", s, (s && s->addr_list && s->addr_list->domain_and_port) ? s->addr_list->domain_and_port : "-null-"); subscription_unlink(s); subscription_destroy(s); } } else { wpa_printf(MSG_INFO, "WPS UPnP: Unsubscribe fails (not " "found)"); ret = HTTP_PRECONDITION_FAILED; goto send_msg; } ret = HTTP_OK;send_msg: buf = wpabuf_alloc(200); if (buf == NULL) return; http_put_empty(buf, ret); send_wpabuf(c->sd, buf); wpabuf_free(buf);}/* Send error in response to unknown requests */static void web_connection_unimplemented(struct web_connection *c){ struct wpabuf *buf; buf = wpabuf_alloc(200); if (buf == NULL) return; http_put_empty(buf, HTTP_UNIMPLEMENTED); send_wpabuf(c->sd, buf); wpabuf_free(buf);}/* Called when we have gotten an apparently valid http request. */static void web_connection_check_data(struct web_connection *c){ struct httpread *hread = c->hread; enum httpread_hdr_type htype = httpread_hdr_type_get(hread); /* char *data = httpread_data_get(hread); */ char *filename = httpread_uri_get(hread); c->done = 1; if (!filename) { wpa_printf(MSG_INFO, "WPS UPnP: Could not get HTTP URI"); return; } /* Trim leading slashes from filename */ while (*filename == '/') filename++; wpa_printf(MSG_DEBUG, "WPS UPnP: Got HTTP request type %d from %s:%d", htype, inet_ntoa(c->cli_addr.sin_addr), htons(c->cli_addr.sin_port)); switch (htype) { case HTTPREAD_HDR_TYPE_GET: web_connection_parse_get(c, filename); break; case HTTPREAD_HDR_TYPE_POST: web_connection_parse_post(c, filename); break; case HTTPREAD_HDR_TYPE_SUBSCRIBE: web_connection_parse_subscribe(c, filename); break; case HTTPREAD_HDR_TYPE_UNSUBSCRIBE: web_connection_parse_unsubscribe(c, filename); break; /* We are not required to support M-POST; just plain * POST is supposed to work, so we only support that. * If for some reason we need to support M-POST, it is * mostly the same as POST, with small differences. */ default: /* Send 501 for anything else */ web_connection_unimplemented(c); break; }}/* called back when we have gotten request */static void web_connection_got_file_handler(struct httpread *handle, void *cookie, enum httpread_event en){ struct web_connection *c = cookie; if (en == HTTPREAD_EVENT_FILE_READY) web_connection_check_data(c); web_connection_stop(c);}/* web_connection_start - Start web connection * @sm: WPS UPnP state machine from upnp_wps_device_init() * @sd: Socket descriptor * @addr: Client address * * The socket descriptor sd is handed over for ownership by the WPS UPnP * state machine. */static void web_connection_start(struct upnp_wps_device_sm *sm, int sd, struct sockaddr_in *addr){ struct web_connection *c = NULL; /* if too many connections, bail */ if (sm->n_web_connections >= MAX_WEB_CONNECTIONS) { close(sd); return; } c = os_zalloc(sizeof(*c)); if (c == NULL) return; os_memcpy(&c->cli_addr, addr, sizeof(c->cli_addr)); c->sm = sm; c->sd = sd;#if 0 /* * Setting non-blocking should not be necessary for read, and can mess * up sending where blocking might be better. */ if (fcntl(sd, F_SETFL, O_NONBLOCK) != 0) break;#endif c->hread = httpread_create(c->sd, web_connection_got_file_handler, c /* cookie */, WEB_CONNECTION_MAX_READ, WEB_CONNECTION_TIMEOUT_SEC); if (c->hread == NULL) goto fail; if (sm->web_connections) { c->next = sm->web_connections; c->prev = c->next->prev; c->prev->next = c; c->next->prev = c; } else { sm->web_connections = c->next = c->prev = c; } sm->n_web_connections++; return;fail: if (c) web_connection_stop(c);}/* * Listening for web connections * We have a single TCP listening port, and hand off connections as we get * them. */void web_listener_stop(struct upnp_wps_device_sm *sm){ if (sm->web_sd_registered) { sm->web_sd_registered = 0; eloop_unregister_sock(sm->web_sd, EVENT_TYPE_READ); } if (sm->web_sd >= 0) close(sm->web_sd); sm->web_sd = -1;}static void web_listener_handler(int sd, void *eloop_ctx, void *sock_ctx){ struct sockaddr_in addr; socklen_t addr_len = sizeof(addr); struct upnp_wps_device_sm *sm = sock_ctx; int new_sd; /* Create state for new connection */ /* Remember so we can cancel if need be */ new_sd = accept(sm->web_sd, (struct sockaddr *) &addr, &addr_len); if (new_sd < 0) { wpa_printf(MSG_ERROR, "WPS UPnP: web listener accept " "errno=%d (%s) web_sd=%d", errno, strerror(errno), sm->web_sd); return; } web_connection_start(sm, new_sd, &addr);}int web_listener_start(struct upnp_wps_device_sm *sm){ struct sockaddr_in addr; int port; sm->web_sd = socket(AF_INET, SOCK_STREAM, 0); if (sm->web_sd < 0) goto fail; if (fcntl(sm->web_sd, F_SETFL, O_NONBLOCK) != 0) goto fail; port = 49152; /* first non-reserved port */ for (;;) { os_memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = sm->ip_addr; addr.sin_port = htons(port); if (bind(sm->web_sd, (struct sockaddr *) &addr, sizeof(addr)) == 0) break; if (errno == EADDRINUSE) { /* search for unused port */ if (++port == 65535) goto fail; continue; } goto fail; } if (listen(sm->web_sd, 10 /* max backlog */) != 0) goto fail; if (fcntl(sm->web_sd, F_SETFL, O_NONBLOCK) != 0) goto fail; if (eloop_register_sock(sm->web_sd, EVENT_TYPE_READ, web_listener_handler, NULL, sm)) goto fail; sm->web_sd_registered = 1; sm->web_port = port; return 0;fail: /* Error */ web_listener_stop(sm); return -1;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?