38
38
"Connection: close\r\n";
41
* Incoming web connections are recorded in this struct.
42
* A web connection is a TCP connection to us, the server;
43
* it is called a "web connection" because we use http and serve
44
* data that looks like web pages.
45
* State information is need to track the connection until we figure
46
* out what they want and what we want to do about it.
48
struct web_connection {
49
/* double linked list */
50
struct web_connection *next;
51
struct web_connection *prev;
52
struct upnp_wps_device_sm *sm; /* parent */
53
int sd; /* socket to read from */
54
struct sockaddr_in cli_addr;
55
int sd_registered; /* nonzero if we must cancel registration */
56
struct httpread *hread; /* state machine for reading socket */
57
int n_rcvd_data; /* how much data read so far */
58
int done; /* internal flag, set when we've finished */
63
* XML parsing and formatting
65
* XML is a markup language based on unicode; usually (and in our case,
66
* always!) based on utf-8. utf-8 uses a variable number of bytes per
67
* character. utf-8 has the advantage that all non-ASCII unicode characters are
68
* represented by sequences of non-ascii (high bit set) bytes, whereas ASCII
69
* characters are single ascii bytes, thus we can use typical text processing.
71
* (One other interesting thing about utf-8 is that it is possible to look at
72
* any random byte and determine if it is the first byte of a character as
73
* versus a continuation byte).
75
* The base syntax of XML uses a few ASCII punctionation characters; any
76
* characters that would appear in the payload data are rewritten using
77
* sequences, e.g., & for ampersand(&) and < for left angle bracket (<).
78
* Five such escapes total (more can be defined but that does not apply to our
79
* case). Thus we can safely parse for angle brackets etc.
81
* XML describes tree structures of tagged data, with each element beginning
82
* with an opening tag <label> and ending with a closing tag </label> with
83
* matching label. (There is also a self-closing tag <label/> which is supposed
84
* to be equivalent to <label></label>, i.e., no payload, but we are unlikely
85
* to see it for our purpose).
87
* Actually the opening tags are a little more complicated because they can
88
* contain "attributes" after the label (delimited by ascii space or tab chars)
89
* of the form attribute_label="value" or attribute_label='value'; as it turns
90
* out we do not have to read any of these attributes, just ignore them.
92
* Labels are any sequence of chars other than space, tab, right angle bracket
93
* (and ?), but may have an inner structure of <namespace><colon><plain_label>.
94
* As it turns out, we can ignore the namespaces, in fact we can ignore the
95
* entire tree hierarchy, because the plain labels we are looking for will be
96
* unique (not in general, but for this application). We do however have to be
97
* careful to skip over the namespaces.
99
* In generating XML we have to be more careful, but that is easy because
100
* everything we do is pretty canned. The only real care to take is to escape
101
* any special chars in our payload.
105
* xml_next_tag - Advance to next tag
107
* @out: OUT: start of tag just after '<'
108
* @out_tagname: OUT: start of name of tag, skipping namespace
109
* @end: OUT: one after tag
110
* Returns: 0 on success, 1 on failure
113
* <left angle bracket><...><right angle bracket>
114
* Within the angle brackets, there is an optional leading forward slash (which
115
* makes the tag an ending tag), then an optional leading label (followed by
116
* colon) and then the tag name itself.
118
* Note that angle brackets present in the original data must have been encoded
119
* as < and > so they will not trouble us.
121
static int xml_next_tag(char *in, char **out, char **out_tagname,
124
while (*in && *in != '<')
131
*out_tagname = in; /* maybe */
132
while (isalnum(*in) || *in == '-')
136
while (*in && *in != '>')
145
/* xml_data_encode -- format data for xml file, escaping special characters.
147
* Note that we assume we are using utf8 both as input and as output!
148
* In utf8, characters may be classed as follows:
149
* 0xxxxxxx(2) -- 1 byte ascii char
150
* 11xxxxxx(2) -- 1st byte of multi-byte char w/ unicode value >= 0x80
151
* 110xxxxx(2) -- 1st byte of 2 byte sequence (5 payload bits here)
152
* 1110xxxx(2) -- 1st byte of 3 byte sequence (4 payload bits here)
153
* 11110xxx(2) -- 1st byte of 4 byte sequence (3 payload bits here)
154
* 10xxxxxx(2) -- extension byte (6 payload bits per byte)
155
* Some values implied by the above are however illegal because they
156
* do not represent unicode chars or are not the shortest encoding.
157
* Actually, we can almost entirely ignore the above and just do
158
* text processing same as for ascii text.
160
* XML is written with arbitrary unicode characters, except that five
161
* characters have special meaning and so must be escaped where they
162
* appear in payload data... which we do here.
164
static void xml_data_encode(struct wpabuf *buf, const char *data, int len)
167
for (i = 0; i < len; i++) {
168
u8 c = ((u8 *) data)[i];
170
wpabuf_put_str(buf, "<");
174
wpabuf_put_str(buf, ">");
178
wpabuf_put_str(buf, "&");
182
wpabuf_put_str(buf, "'");
186
wpabuf_put_str(buf, """);
190
* We could try to represent control characters using the
191
* sequence: &#x; where x is replaced by a hex numeral, but not
192
* clear why we would do this.
194
wpabuf_put_u8(buf, c);
199
/* xml_add_tagged_data -- format tagged data as a new xml line.
201
* tag must not have any special chars.
202
* data may have special chars, which are escaped.
204
static void xml_add_tagged_data(struct wpabuf *buf, const char *tag,
207
wpabuf_printf(buf, "<%s>", tag);
208
xml_data_encode(buf, data, os_strlen(data));
209
wpabuf_printf(buf, "</%s>\n", tag);
213
/* A POST body looks something like (per upnp spec):
214
* <?xml version="1.0"?>
216
* xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
217
* s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
219
* <u:actionName xmlns:u="urn:schemas-upnp-org:service:serviceType:v">
220
* <argumentName>in arg value</argumentName>
221
* other in args and their values go here, if any
227
* s: might be some other namespace name followed by colon
228
* u: might be some other namespace name followed by colon
229
* actionName will be replaced according to action requested
230
* schema following actionName will be WFA scheme instead
231
* argumentName will be actual argument name
232
* (in arg value) will be actual argument value
235
upnp_get_first_document_item(char *doc, const char *item, char **value)
237
const char *match = item;
238
int match_len = os_strlen(item);
243
*value = NULL; /* default, bad */
246
* This is crude: ignore any possible tag name conflicts and go right
247
* to the first tag of this name. This should be ok for the limited
248
* domain of UPnP messages.
251
if (xml_next_tag(doc, &tag, &tagname, &end))
254
if (!os_strncasecmp(tagname, match, match_len) &&
256
(tagname[match_len] == '>' ||
257
!isgraph(tagname[match_len]))) {
262
while (*end && *end != '<')
264
*value = os_zalloc(1 + (end - doc));
267
os_memcpy(*value, doc, end - doc);
273
41
* "Files" that we serve via HTTP. The format of these files is given by
274
42
* WFA WPS specifications. Extra white space has been removed to save space.
305
73
"</argumentList>\n"
308
"<name>GetAPSettings</name>\n"
311
"<name>NewMessage</name>\n"
312
"<direction>in</direction>\n"
313
"<relatedStateVariable>Message</relatedStateVariable>\n"
316
"<name>NewAPSettings</name>\n"
317
"<direction>out</direction>\n"
318
"<relatedStateVariable>APSettings</relatedStateVariable>\n"
323
"<name>SetAPSettings</name>\n"
326
"<name>APSettings</name>\n"
327
"<direction>in</direction>\n"
328
"<relatedStateVariable>APSettings</relatedStateVariable>\n"
333
"<name>DelAPSettings</name>\n"
336
"<name>NewAPSettings</name>\n"
337
"<direction>in</direction>\n"
338
"<relatedStateVariable>APSettings</relatedStateVariable>\n"
343
"<name>GetSTASettings</name>\n"
346
"<name>NewMessage</name>\n"
347
"<direction>in</direction>\n"
348
"<relatedStateVariable>Message</relatedStateVariable>\n"
351
"<name>NewSTASettings</name>\n"
352
"<direction>out</direction>\n"
353
"<relatedStateVariable>STASettings</relatedStateVariable>\n"
358
"<name>SetSTASettings</name>\n"
361
"<name>NewSTASettings</name>\n"
362
"<direction>out</direction>\n"
363
"<relatedStateVariable>STASettings</relatedStateVariable>\n"
368
"<name>DelSTASettings</name>\n"
371
"<name>NewSTASettings</name>\n"
372
"<direction>in</direction>\n"
373
"<relatedStateVariable>STASettings</relatedStateVariable>\n"
378
76
"<name>PutWLANResponse</name>\n"
379
77
"<argumentList>\n"
833
465
* PutWLANResponse which is for proxying.
835
467
wpa_printf(MSG_DEBUG, "WPS UPnP: PutMessage");
836
if (sm->ctx->rx_req_put_message == NULL)
837
return HTTP_INTERNAL_SERVER_ERROR;
838
msg = web_get_item(data, "NewInMessage", &ret);
841
*reply = sm->ctx->rx_req_put_message(sm->priv, &sm->peer, msg);
844
return HTTP_INTERNAL_SERVER_ERROR;
850
static enum http_reply_code
851
web_process_get_ap_settings(struct upnp_wps_device_sm *sm, char *data,
852
struct wpabuf **reply, const char **replyname)
855
static const char *name = "NewAPSettings";
856
enum http_reply_code ret;
858
wpa_printf(MSG_DEBUG, "WPS UPnP: GetAPSettings");
859
if (sm->ctx->rx_req_get_ap_settings == NULL)
860
return HTTP_INTERNAL_SERVER_ERROR;
861
msg = web_get_item(data, "NewMessage", &ret);
864
*reply = sm->ctx->rx_req_get_ap_settings(sm->priv, msg);
867
return HTTP_INTERNAL_SERVER_ERROR;
873
static enum http_reply_code
874
web_process_set_ap_settings(struct upnp_wps_device_sm *sm, char *data,
875
struct wpabuf **reply, const char **replyname)
878
enum http_reply_code ret;
880
wpa_printf(MSG_DEBUG, "WPS UPnP: SetAPSettings");
881
msg = web_get_item(data, "NewAPSettings", &ret);
884
if (!sm->ctx->rx_req_set_ap_settings ||
885
sm->ctx->rx_req_set_ap_settings(sm->priv, msg)) {
887
return HTTP_INTERNAL_SERVER_ERROR;
896
static enum http_reply_code
897
web_process_del_ap_settings(struct upnp_wps_device_sm *sm, char *data,
898
struct wpabuf **reply, const char **replyname)
901
enum http_reply_code ret;
903
wpa_printf(MSG_DEBUG, "WPS UPnP: DelAPSettings");
904
msg = web_get_item(data, "NewAPSettings", &ret);
907
if (!sm->ctx->rx_req_del_ap_settings ||
908
sm->ctx->rx_req_del_ap_settings(sm->priv, msg)) {
910
return HTTP_INTERNAL_SERVER_ERROR;
919
static enum http_reply_code
920
web_process_get_sta_settings(struct upnp_wps_device_sm *sm, char *data,
921
struct wpabuf **reply, const char **replyname)
924
static const char *name = "NewSTASettings";
925
enum http_reply_code ret;
927
wpa_printf(MSG_DEBUG, "WPS UPnP: GetSTASettings");
928
if (sm->ctx->rx_req_get_sta_settings == NULL)
929
return HTTP_INTERNAL_SERVER_ERROR;
930
msg = web_get_item(data, "NewMessage", &ret);
933
*reply = sm->ctx->rx_req_get_sta_settings(sm->priv, msg);
936
return HTTP_INTERNAL_SERVER_ERROR;
942
static enum http_reply_code
943
web_process_set_sta_settings(struct upnp_wps_device_sm *sm, char *data,
944
struct wpabuf **reply, const char **replyname)
947
enum http_reply_code ret;
949
wpa_printf(MSG_DEBUG, "WPS UPnP: SetSTASettings");
950
msg = web_get_item(data, "NewSTASettings", &ret);
953
if (!sm->ctx->rx_req_set_sta_settings ||
954
sm->ctx->rx_req_set_sta_settings(sm->priv, msg)) {
956
return HTTP_INTERNAL_SERVER_ERROR;
965
static enum http_reply_code
966
web_process_del_sta_settings(struct upnp_wps_device_sm *sm, char *data,
967
struct wpabuf **reply, const char **replyname)
970
enum http_reply_code ret;
972
wpa_printf(MSG_DEBUG, "WPS UPnP: DelSTASettings");
973
msg = web_get_item(data, "NewSTASettings", &ret);
976
if (!sm->ctx->rx_req_del_sta_settings ||
977
sm->ctx->rx_req_del_sta_settings(sm->priv, msg)) {
979
return HTTP_INTERNAL_SERVER_ERROR;
468
msg = xml_get_base64_item(data, "NewInMessage", &ret);
471
res = wps_process_msg(sm->peer.wps, WSC_UPnP, msg);
472
if (res == WPS_FAILURE)
475
*reply = wps_get_msg(sm->peer.wps, &op_code);
478
return HTTP_INTERNAL_SERVER_ERROR;
1004
500
wpa_printf(MSG_DEBUG, "WPS UPnP: PutWLANResponse");
1005
msg = web_get_item(data, "NewMessage", &ret);
501
msg = xml_get_base64_item(data, "NewMessage", &ret);
503
wpa_printf(MSG_DEBUG, "WPS UPnP: Could not extract NewMessage "
504
"from PutWLANResponse");
1008
if (upnp_get_first_document_item(data, "NewWLANEventType", &val)) {
507
val = xml_get_first_item(data, "NewWLANEventType");
509
wpa_printf(MSG_DEBUG, "WPS UPnP: No NewWLANEventType in "
1009
511
wpabuf_free(msg);
1010
512
return UPNP_ARG_VALUE_INVALID;
1012
514
ev_type = atol(val);
1015
if (upnp_get_first_document_item(data, "NewWLANEventMAC", &val) ||
1016
hwaddr_aton(val, macaddr)) {
516
val = xml_get_first_item(data, "NewWLANEventMAC");
518
wpa_printf(MSG_DEBUG, "WPS UPnP: No NewWLANEventMAC in "
1017
520
wpabuf_free(msg);
1019
521
return UPNP_ARG_VALUE_INVALID;
523
if (hwaddr_aton(val, macaddr)) {
524
wpa_printf(MSG_DEBUG, "WPS UPnP: Invalid NewWLANEventMAC in "
525
"PutWLANResponse: '%s'", val);
526
if (hwaddr_aton2(val, macaddr) > 0) {
528
* At least some versions of Intel PROset seem to be
529
* using dot-deliminated MAC address format here.
531
wpa_printf(MSG_DEBUG, "WPS UPnP: Workaround - allow "
532
"incorrect MAC address format in "
537
return UPNP_ARG_VALUE_INVALID;
1022
541
if (ev_type == UPNP_WPS_WLANEVENT_TYPE_EAP) {
1023
542
struct wps_parse_attr attr;
566
static int find_er_addr(struct subscription *s, struct sockaddr_in *cli)
568
struct subscr_addr *a;
570
dl_list_for_each(a, &s->addr_list, struct subscr_addr, list) {
571
if (cli->sin_addr.s_addr == a->saddr.sin_addr.s_addr)
578
static struct subscription * find_er(struct upnp_wps_device_sm *sm,
579
struct sockaddr_in *cli)
581
struct subscription *s;
582
dl_list_for_each(s, &sm->subscriptions, struct subscription, list)
583
if (find_er_addr(s, cli))
1047
589
static enum http_reply_code
1048
web_process_set_selected_registrar(struct upnp_wps_device_sm *sm, char *data,
590
web_process_set_selected_registrar(struct upnp_wps_device_sm *sm,
591
struct sockaddr_in *cli, char *data,
1049
592
struct wpabuf **reply,
1050
593
const char **replyname)
1052
595
struct wpabuf *msg;
1053
596
enum http_reply_code ret;
597
struct subscription *s;
1055
599
wpa_printf(MSG_DEBUG, "WPS UPnP: SetSelectedRegistrar");
1056
msg = web_get_item(data, "NewMessage", &ret);
1059
if (!sm->ctx->rx_req_set_selected_registrar ||
1060
sm->ctx->rx_req_set_selected_registrar(sm->priv, msg)) {
1062
return HTTP_INTERNAL_SERVER_ERROR;
1071
static enum http_reply_code
1072
web_process_reboot_ap(struct upnp_wps_device_sm *sm, char *data,
1073
struct wpabuf **reply, const char **replyname)
1076
enum http_reply_code ret;
1078
wpa_printf(MSG_DEBUG, "WPS UPnP: RebootAP");
1079
msg = web_get_item(data, "NewAPSettings", &ret);
1082
if (!sm->ctx->rx_req_reboot_ap ||
1083
sm->ctx->rx_req_reboot_ap(sm->priv, msg)) {
1085
return HTTP_INTERNAL_SERVER_ERROR;
1094
static enum http_reply_code
1095
web_process_reset_ap(struct upnp_wps_device_sm *sm, char *data,
1096
struct wpabuf **reply, const char **replyname)
1099
enum http_reply_code ret;
1101
wpa_printf(MSG_DEBUG, "WPS UPnP: ResetAP");
1102
msg = web_get_item(data, "NewMessage", &ret);
1105
if (!sm->ctx->rx_req_reset_ap ||
1106
sm->ctx->rx_req_reset_ap(sm->priv, msg)) {
1108
return HTTP_INTERNAL_SERVER_ERROR;
1117
static enum http_reply_code
1118
web_process_reboot_sta(struct upnp_wps_device_sm *sm, char *data,
1119
struct wpabuf **reply, const char **replyname)
1122
enum http_reply_code ret;
1124
wpa_printf(MSG_DEBUG, "WPS UPnP: RebootSTA");
1125
msg = web_get_item(data, "NewSTASettings", &ret);
1128
if (!sm->ctx->rx_req_reboot_sta ||
1129
sm->ctx->rx_req_reboot_sta(sm->priv, msg)) {
1131
return HTTP_INTERNAL_SERVER_ERROR;
1140
static enum http_reply_code
1141
web_process_reset_sta(struct upnp_wps_device_sm *sm, char *data,
1142
struct wpabuf **reply, const char **replyname)
1145
enum http_reply_code ret;
1147
wpa_printf(MSG_DEBUG, "WPS UPnP: ResetSTA");
1148
msg = web_get_item(data, "NewMessage", &ret);
1151
if (!sm->ctx->rx_req_reset_sta ||
1152
sm->ctx->rx_req_reset_sta(sm->priv, msg)) {
600
s = find_er(sm, cli);
602
wpa_printf(MSG_DEBUG, "WPS UPnP: Ignore SetSelectedRegistrar "
604
return UPNP_ACTION_FAILED;
606
msg = xml_get_base64_item(data, "NewMessage", &ret);
609
if (upnp_er_set_selected_registrar(sm->wps->registrar, s, msg)) {
1153
610
wpabuf_free(msg);
1154
611
return HTTP_INTERNAL_SERVER_ERROR;
1349
800
* Per RFC 2616, content-length: is not required but connection:close
1350
801
* would appear to be required (given that we will be closing it!).
1352
static void web_connection_parse_post(struct web_connection *c,
803
static void web_connection_parse_post(struct upnp_wps_device_sm *sm,
804
struct sockaddr_in *cli,
805
struct http_request *req,
1353
806
const char *filename)
1355
808
enum http_reply_code ret;
1356
struct upnp_wps_device_sm *sm = c->sm;
1357
char *data = httpread_data_get(c->hread); /* body of http msg */
809
char *data = http_request_get_data(req); /* body of http msg */
810
const char *action = NULL;
811
size_t action_len = 0;
1360
812
const char *replyname = NULL; /* argument name for the reply */
1361
813
struct wpabuf *reply = NULL; /* data for the reply */
815
if (os_strcasecmp(filename, UPNP_WPS_DEVICE_CONTROL_FILE)) {
816
wpa_printf(MSG_INFO, "WPS UPnP: Invalid POST filename %s",
818
ret = HTTP_NOT_FOUND;
1363
822
ret = UPNP_INVALID_ACTION;
1364
action = web_get_action(c, filename, &action_len);
823
action = web_get_action(req, &action_len);
1365
824
if (action == NULL)
1369
* There are quite a few possible actions. Although we appear to
1370
* support them all here, not all of them are necessarily supported by
1371
* callbacks at higher levels.
1373
827
if (!os_strncasecmp("GetDeviceInfo", action, action_len))
1374
828
ret = web_process_get_device_info(sm, &reply, &replyname);
1375
829
else if (!os_strncasecmp("PutMessage", action, action_len))
1376
830
ret = web_process_put_message(sm, data, &reply, &replyname);
1377
else if (!os_strncasecmp("GetAPSettings", action, action_len))
1378
ret = web_process_get_ap_settings(sm, data, &reply,
1380
else if (!os_strncasecmp("SetAPSettings", action, action_len))
1381
ret = web_process_set_ap_settings(sm, data, &reply,
1383
else if (!os_strncasecmp("DelAPSettings", action, action_len))
1384
ret = web_process_del_ap_settings(sm, data, &reply,
1386
else if (!os_strncasecmp("GetSTASettings", action, action_len))
1387
ret = web_process_get_sta_settings(sm, data, &reply,
1389
else if (!os_strncasecmp("SetSTASettings", action, action_len))
1390
ret = web_process_set_sta_settings(sm, data, &reply,
1392
else if (!os_strncasecmp("DelSTASettings", action, action_len))
1393
ret = web_process_del_sta_settings(sm, data, &reply,
1395
831
else if (!os_strncasecmp("PutWLANResponse", action, action_len))
1396
832
ret = web_process_put_wlan_response(sm, data, &reply,
1398
834
else if (!os_strncasecmp("SetSelectedRegistrar", action, action_len))
1399
ret = web_process_set_selected_registrar(sm, data, &reply,
835
ret = web_process_set_selected_registrar(sm, cli, data, &reply,
1401
else if (!os_strncasecmp("RebootAP", action, action_len))
1402
ret = web_process_reboot_ap(sm, data, &reply, &replyname);
1403
else if (!os_strncasecmp("ResetAP", action, action_len))
1404
ret = web_process_reset_ap(sm, data, &reply, &replyname);
1405
else if (!os_strncasecmp("RebootSTA", action, action_len))
1406
ret = web_process_reboot_sta(sm, data, &reply, &replyname);
1407
else if (!os_strncasecmp("ResetSTA", action, action_len))
1408
ret = web_process_reset_sta(sm, data, &reply, &replyname);
1410
838
wpa_printf(MSG_INFO, "WPS UPnP: Unknown POST type");
1413
841
if (ret != HTTP_OK)
1414
842
wpa_printf(MSG_INFO, "WPS UPnP: POST failure ret=%d", ret);
1415
web_connection_send_reply(c, ret, action, action_len, reply,
843
web_connection_send_reply(req, ret, action, action_len, reply,
1417
845
wpabuf_free(reply);
1783
1214
wpa_printf(MSG_DEBUG, "WPS UPnP: Got HTTP request type %d from %s:%d",
1784
htype, inet_ntoa(c->cli_addr.sin_addr),
1785
htons(c->cli_addr.sin_port));
1215
htype, inet_ntoa(cli->sin_addr), htons(cli->sin_port));
1787
1217
switch (htype) {
1788
1218
case HTTPREAD_HDR_TYPE_GET:
1789
web_connection_parse_get(c, filename);
1219
web_connection_parse_get(sm, req, filename);
1791
1221
case HTTPREAD_HDR_TYPE_POST:
1792
web_connection_parse_post(c, filename);
1222
web_connection_parse_post(sm, cli, req, filename);
1794
1224
case HTTPREAD_HDR_TYPE_SUBSCRIBE:
1795
web_connection_parse_subscribe(c, filename);
1225
web_connection_parse_subscribe(sm, req, filename);
1797
1227
case HTTPREAD_HDR_TYPE_UNSUBSCRIBE:
1798
web_connection_parse_unsubscribe(c, filename);
1228
web_connection_parse_unsubscribe(sm, req, filename);
1800
1231
/* We are not required to support M-POST; just plain
1801
1232
* POST is supposed to work, so we only support that.
1802
1233
* If for some reason we need to support M-POST, it is
1806
1237
/* Send 501 for anything else */
1807
web_connection_unimplemented(c);
1814
/* called back when we have gotten request */
1815
static void web_connection_got_file_handler(struct httpread *handle,
1817
enum httpread_event en)
1819
struct web_connection *c = cookie;
1821
if (en == HTTPREAD_EVENT_FILE_READY)
1822
web_connection_check_data(c);
1823
web_connection_stop(c);
1827
/* web_connection_start - Start web connection
1828
* @sm: WPS UPnP state machine from upnp_wps_device_init()
1829
* @sd: Socket descriptor
1830
* @addr: Client address
1832
* The socket descriptor sd is handed over for ownership by the WPS UPnP
1835
static void web_connection_start(struct upnp_wps_device_sm *sm,
1836
int sd, struct sockaddr_in *addr)
1838
struct web_connection *c = NULL;
1840
/* if too many connections, bail */
1841
if (sm->n_web_connections >= MAX_WEB_CONNECTIONS) {
1846
c = os_zalloc(sizeof(*c));
1849
os_memcpy(&c->cli_addr, addr, sizeof(c->cli_addr));
1854
* Setting non-blocking should not be necessary for read, and can mess
1855
* up sending where blocking might be better.
1857
if (fcntl(sd, F_SETFL, O_NONBLOCK) != 0)
1860
c->hread = httpread_create(c->sd, web_connection_got_file_handler,
1862
WEB_CONNECTION_MAX_READ,
1863
WEB_CONNECTION_TIMEOUT_SEC);
1864
if (c->hread == NULL)
1866
if (sm->web_connections) {
1867
c->next = sm->web_connections;
1868
c->prev = c->next->prev;
1872
sm->web_connections = c->next = c->prev = c;
1874
sm->n_web_connections++;
1879
web_connection_stop(c);
1238
web_connection_unimplemented(req);
1889
1250
void web_listener_stop(struct upnp_wps_device_sm *sm)
1891
if (sm->web_sd_registered) {
1892
sm->web_sd_registered = 0;
1893
eloop_unregister_sock(sm->web_sd, EVENT_TYPE_READ);
1895
if (sm->web_sd >= 0)
1901
static void web_listener_handler(int sd, void *eloop_ctx, void *sock_ctx)
1903
struct sockaddr_in addr;
1904
socklen_t addr_len = sizeof(addr);
1905
struct upnp_wps_device_sm *sm = sock_ctx;
1908
/* Create state for new connection */
1909
/* Remember so we can cancel if need be */
1910
new_sd = accept(sm->web_sd, (struct sockaddr *) &addr, &addr_len);
1912
wpa_printf(MSG_ERROR, "WPS UPnP: web listener accept "
1913
"errno=%d (%s) web_sd=%d",
1914
errno, strerror(errno), sm->web_sd);
1917
web_connection_start(sm, new_sd, &addr);
1252
http_server_deinit(sm->web_srv);
1921
1257
int web_listener_start(struct upnp_wps_device_sm *sm)
1923
struct sockaddr_in addr;
1926
sm->web_sd = socket(AF_INET, SOCK_STREAM, 0);
1929
if (fcntl(sm->web_sd, F_SETFL, O_NONBLOCK) != 0)
1931
port = 49152; /* first non-reserved port */
1933
os_memset(&addr, 0, sizeof(addr));
1934
addr.sin_family = AF_INET;
1935
addr.sin_addr.s_addr = sm->ip_addr;
1936
addr.sin_port = htons(port);
1937
if (bind(sm->web_sd, (struct sockaddr *) &addr,
1940
if (errno == EADDRINUSE) {
1941
/* search for unused port */
1942
if (++port == 65535)
1259
struct in_addr addr;
1260
addr.s_addr = sm->ip_addr;
1261
sm->web_srv = http_server_init(&addr, -1, web_connection_check_data,
1263
if (sm->web_srv == NULL) {
1264
web_listener_stop(sm);
1948
if (listen(sm->web_sd, 10 /* max backlog */) != 0)
1950
if (fcntl(sm->web_sd, F_SETFL, O_NONBLOCK) != 0)
1952
if (eloop_register_sock(sm->web_sd, EVENT_TYPE_READ,
1953
web_listener_handler, NULL, sm))
1955
sm->web_sd_registered = 1;
1956
sm->web_port = port;
1267
sm->web_port = http_server_get_port(sm->web_srv);
1962
web_listener_stop(sm);