00001
00012 #include "includes.h"
00013 #include <assert.h>
00014
00015 #include "common.h"
00016 #include "eloop.h"
00017 #include "uuid.h"
00018 #include "http_client.h"
00019 #include "wps_defs.h"
00020 #include "wps_upnp.h"
00021 #include "wps_upnp_i.h"
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #define MAX_EVENTS_QUEUED 20
00035 #define EVENT_TIMEOUT_SEC 30
00036
00037
00038 #define EVENT_DELAY_SECONDS 0
00039 #define EVENT_DELAY_MSEC 0
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049 struct wps_event_ {
00050 struct wps_event_ *next;
00051 struct wps_event_ *prev;
00052 struct subscription *s;
00053 unsigned subscriber_sequence;
00054 int retry;
00055 struct subscr_addr *addr;
00056 struct wpabuf *data;
00057 struct http_client *http_event;
00058 };
00059
00060
00061
00062
00063
00064 static void event_clean(struct wps_event_ *e)
00065 {
00066 if (e->s->current_event == e)
00067 e->s->current_event = NULL;
00068 http_client_free(e->http_event);
00069 e->http_event = NULL;
00070 }
00071
00072
00073
00074
00075
00076 static void event_delete(struct wps_event_ *e)
00077 {
00078 event_clean(e);
00079 wpabuf_free(e->data);
00080 os_free(e);
00081 }
00082
00083
00084
00085
00086
00087 static struct wps_event_ *event_dequeue(struct subscription *s)
00088 {
00089 struct wps_event_ **event_head = &s->event_queue;
00090 struct wps_event_ *e = *event_head;
00091 if (e == NULL)
00092 return NULL;
00093 e->next->prev = e->prev;
00094 e->prev->next = e->next;
00095 if (*event_head == e) {
00096 if (e == e->next) {
00097
00098 *event_head = NULL;
00099 } else {
00100 *event_head = e->next;
00101 }
00102 }
00103 s->n_queue--;
00104 e->next = e->prev = NULL;
00105
00106 return e;
00107 }
00108
00109
00110
00111 static void event_enqueue_at_end(struct subscription *s, struct wps_event_ *e)
00112 {
00113 struct wps_event_ **event_head = &s->event_queue;
00114 if (*event_head == NULL) {
00115 *event_head = e->next = e->prev = e;
00116 } else {
00117 e->next = *event_head;
00118 e->prev = e->next->prev;
00119 e->prev->next = e;
00120 e->next->prev = e;
00121 }
00122 s->n_queue++;
00123 }
00124
00125
00126
00127
00128
00129 static void event_enqueue_at_begin(struct subscription *s,
00130 struct wps_event_ *e)
00131 {
00132 struct wps_event_ **event_head = &s->event_queue;
00133 if (*event_head == NULL) {
00134 *event_head = e->next = e->prev = e;
00135 } else {
00136 e->prev = *event_head;
00137 e->next = e->prev->next;
00138 e->prev->next = e;
00139 e->next->prev = e;
00140 *event_head = e;
00141 }
00142 s->n_queue++;
00143 }
00144
00145
00146
00147 void event_delete_all(struct subscription *s)
00148 {
00149 struct wps_event_ *e;
00150 while ((e = event_dequeue(s)) != NULL)
00151 event_delete(e);
00152 if (s->current_event) {
00153 event_delete(s->current_event);
00154
00155 }
00156 }
00157
00158
00165 static void event_retry(struct wps_event_ *e, int do_next_address)
00166 {
00167 struct subscription *s = e->s;
00168 struct upnp_wps_device_sm *sm = s->sm;
00169
00170 event_clean(e);
00171
00172
00173 if (do_next_address)
00174 e->retry++;
00175 if (e->retry >= s->n_addr) {
00176 wpa_printf(MSG_DEBUG, "WPS UPnP: Giving up on sending event "
00177 "for %s", e->addr->domain_and_port);
00178 return;
00179 }
00180 event_enqueue_at_begin(s, e);
00181 event_send_all_later(sm);
00182 }
00183
00184
00185 static struct wpabuf * event_build_message(struct wps_event_ *e)
00186 {
00187 struct wpabuf *buf;
00188 char *b;
00189
00190 buf = wpabuf_alloc(1000 + wpabuf_len(e->data));
00191 if (buf == NULL)
00192 return NULL;
00193 wpabuf_printf(buf, "NOTIFY %s HTTP/1.1\r\n", e->addr->path);
00194 wpabuf_put_str(buf, "SERVER: Unspecified, UPnP/1.0, Unspecified\r\n");
00195 wpabuf_printf(buf, "HOST: %s\r\n", e->addr->domain_and_port);
00196 wpabuf_put_str(buf, "CONTENT-TYPE: text/xml; charset=\"utf-8\"\r\n"
00197 "NT: upnp:event\r\n"
00198 "NTS: upnp:propchange\r\n");
00199 wpabuf_put_str(buf, "SID: uuid:");
00200 b = wpabuf_put(buf, 0);
00201 uuid_bin2str(e->s->uuid, b, 80);
00202 wpabuf_put(buf, os_strlen(b));
00203 wpabuf_put_str(buf, "\r\n");
00204 wpabuf_printf(buf, "SEQ: %u\r\n", e->subscriber_sequence);
00205 wpabuf_printf(buf, "CONTENT-LENGTH: %d\r\n",
00206 (int) wpabuf_len(e->data));
00207 wpabuf_put_str(buf, "\r\n");
00208 wpabuf_put_buf(buf, e->data);
00209 return buf;
00210 }
00211
00212
00213 static void event_http_cb(void *ctx, struct http_client *c,
00214 enum http_client_event event)
00215 {
00216 struct wps_event_ *e = ctx;
00217 struct subscription *s = e->s;
00218
00219 switch (event) {
00220 case HTTP_CLIENT_OK:
00221 wpa_printf(MSG_DEBUG,
00222 "WPS UPnP: Got event reply OK from "
00223 "%s", e->addr->domain_and_port);
00224 event_delete(e);
00225
00226
00227 if (s->event_queue)
00228 event_send_all_later(s->sm);
00229 break;
00230 case HTTP_CLIENT_FAILED:
00231 case HTTP_CLIENT_INVALID_REPLY:
00232 wpa_printf(MSG_DEBUG, "WPS UPnP: Failed to send event to %s",
00233 e->addr->domain_and_port);
00234
00235
00236
00237
00238
00239
00240
00241 wpa_printf(MSG_DEBUG, "WPS UPnP: Deleting subscription due to "
00242 "errors");
00243 subscription_unlink(s);
00244 subscription_destroy(s);
00245 break;
00246 case HTTP_CLIENT_TIMEOUT:
00247 wpa_printf(MSG_DEBUG, "WPS UPnP: Event send timeout");
00248 event_retry(e, 1);
00249 }
00250 }
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273 static int event_send_start(struct subscription *s)
00274 {
00275 struct wps_event_ *e;
00276 int itry;
00277 struct wpabuf *buf;
00278
00279
00280
00281
00282
00283 assert(s->addr_list != NULL);
00284 assert(s->current_event == NULL);
00285 assert(s->event_queue != NULL);
00286
00287 s->current_event = e = event_dequeue(s);
00288
00289
00290 e->addr = s->addr_list;
00291 for (itry = 0; itry < e->retry; itry++)
00292 e->addr = e->addr->next;
00293
00294 buf = event_build_message(e);
00295 if (buf == NULL) {
00296 event_retry(e, 0);
00297 return -1;
00298 }
00299
00300 e->http_event = http_client_addr(&e->addr->saddr, buf, 0,
00301 event_http_cb, e);
00302 if (e->http_event == NULL) {
00303 wpabuf_free(buf);
00304 event_retry(e, 0);
00305 return -1;
00306 }
00307
00308 return 0;
00309 }
00310
00311
00312
00313 static void event_send_all_later_handler(void *eloop_data, void *user_ctx)
00314 {
00315 struct upnp_wps_device_sm *sm = user_ctx;
00316 struct subscription *s;
00317 struct subscription *s_old;
00318 int nerrors = 0;
00319
00320 sm->event_send_all_queued = 0;
00321 s = sm->subscriptions;
00322 if (s == NULL)
00323 return;
00324 do {
00325 if (s->addr_list == NULL) {
00326
00327 wpa_printf(MSG_DEBUG, "WPS UPnP: Removing "
00328 "subscription with no addresses");
00329 s_old = s;
00330 s = s_old->next;
00331 subscription_unlink(s_old);
00332 subscription_destroy(s_old);
00333 } else {
00334 if (s->current_event == NULL &&
00335 s->event_queue != NULL ) {
00336 if (event_send_start(s))
00337 nerrors++;
00338 }
00339 s = s->next;
00340 }
00341 } while (sm->subscriptions != NULL && s != sm->subscriptions);
00342
00343 if (nerrors) {
00344
00345 event_send_all_later(sm);
00346 }
00347 }
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357 void event_send_all_later(struct upnp_wps_device_sm *sm)
00358 {
00359
00360
00361
00362
00363 if (sm->event_send_all_queued)
00364 return;
00365 sm->event_send_all_queued = 1;
00366 eloop_register_timeout(EVENT_DELAY_SECONDS, EVENT_DELAY_MSEC,
00367 event_send_all_later_handler, NULL, sm);
00368 }
00369
00370
00371
00372 void event_send_stop_all(struct upnp_wps_device_sm *sm)
00373 {
00374 if (sm->event_send_all_queued)
00375 eloop_cancel_timeout(event_send_all_later_handler, NULL, sm);
00376 sm->event_send_all_queued = 0;
00377 }
00378
00379
00387 int event_add(struct subscription *s, const struct wpabuf *data)
00388 {
00389 struct wps_event_ *e;
00390
00391 if (s->n_queue >= MAX_EVENTS_QUEUED) {
00392 wpa_printf(MSG_DEBUG, "WPS UPnP: Too many events queued for "
00393 "subscriber");
00394 return 1;
00395 }
00396
00397 e = os_zalloc(sizeof(*e));
00398 if (e == NULL)
00399 return 1;
00400 e->s = s;
00401 e->data = wpabuf_dup(data);
00402 if (e->data == NULL) {
00403 os_free(e);
00404 return 1;
00405 }
00406 e->subscriber_sequence = s->next_subscriber_sequence++;
00407 if (s->next_subscriber_sequence == 0)
00408 s->next_subscriber_sequence++;
00409 event_enqueue_at_end(s, e);
00410 event_send_all_later(s->sm);
00411 return 0;
00412 }
00413