$search
00001 /* 00002 * UPnP WPS Device - Event processing 00003 * Copyright (c) 2000-2003 Intel Corporation 00004 * Copyright (c) 2006-2007 Sony Corporation 00005 * Copyright (c) 2008-2009 Atheros Communications 00006 * Copyright (c) 2009, Jouni Malinen <j@w1.fi> 00007 * 00008 * See wps_upnp.c for more details on licensing and code history. 00009 */ 00010 00011 #include "includes.h" 00012 #include <assert.h> 00013 00014 #include "common.h" 00015 #include "eloop.h" 00016 #include "uuid.h" 00017 #include "http_client.h" 00018 #include "wps_defs.h" 00019 #include "wps_upnp.h" 00020 #include "wps_upnp_i.h" 00021 00022 /* 00023 * Event message generation (to subscribers) 00024 * 00025 * We make a separate copy for each message for each subscriber. This memory 00026 * wasted could be limited (adding code complexity) by sharing copies, keeping 00027 * a usage count and freeing when zero. 00028 * 00029 * Sending a message requires using a HTTP over TCP NOTIFY 00030 * (like a PUT) which requires a number of states.. 00031 */ 00032 00033 #define MAX_EVENTS_QUEUED 20 /* How far behind queued events */ 00034 #define EVENT_TIMEOUT_SEC 30 /* Drop sending event after timeout */ 00035 00036 /* How long to wait before sending event */ 00037 #define EVENT_DELAY_SECONDS 0 00038 #define EVENT_DELAY_MSEC 0 00039 00040 /* 00041 * Event information that we send to each subscriber is remembered in this 00042 * struct. The event cannot be sent by simple UDP; it has to be sent by a HTTP 00043 * over TCP transaction which requires various states.. It may also need to be 00044 * retried at a different address (if more than one is available). 00045 * 00046 * TODO: As an optimization we could share data between subscribers. 00047 */ 00048 struct wps_event_ { 00049 struct dl_list list; 00050 struct subscription *s; /* parent */ 00051 unsigned subscriber_sequence; /* which event for this subscription*/ 00052 unsigned int retry; /* which retry */ 00053 struct subscr_addr *addr; /* address to connect to */ 00054 struct wpabuf *data; /* event data to send */ 00055 struct http_client *http_event; 00056 }; 00057 00058 00059 /* event_clean -- clean sockets etc. of event 00060 * Leaves data, retry count etc. alone. 00061 */ 00062 static void event_clean(struct wps_event_ *e) 00063 { 00064 if (e->s->current_event == e) 00065 e->s->current_event = NULL; 00066 http_client_free(e->http_event); 00067 e->http_event = NULL; 00068 } 00069 00070 00071 /* event_delete -- delete single unqueued event 00072 * (be sure to dequeue first if need be) 00073 */ 00074 static void event_delete(struct wps_event_ *e) 00075 { 00076 event_clean(e); 00077 wpabuf_free(e->data); 00078 os_free(e); 00079 } 00080 00081 00082 /* event_dequeue -- get next event from the queue 00083 * Returns NULL if empty. 00084 */ 00085 static struct wps_event_ *event_dequeue(struct subscription *s) 00086 { 00087 struct wps_event_ *e; 00088 e = dl_list_first(&s->event_queue, struct wps_event_, list); 00089 if (e) 00090 dl_list_del(&e->list); 00091 return e; 00092 } 00093 00094 00095 /* event_delete_all -- delete entire event queue and current event */ 00096 void event_delete_all(struct subscription *s) 00097 { 00098 struct wps_event_ *e; 00099 while ((e = event_dequeue(s)) != NULL) 00100 event_delete(e); 00101 if (s->current_event) { 00102 event_delete(s->current_event); 00103 /* will set: s->current_event = NULL; */ 00104 } 00105 } 00106 00107 00113 static void event_retry(struct wps_event_ *e, int do_next_address) 00114 { 00115 struct subscription *s = e->s; 00116 struct upnp_wps_device_sm *sm = s->sm; 00117 00118 event_clean(e); 00119 /* will set: s->current_event = NULL; */ 00120 00121 if (do_next_address) 00122 e->retry++; 00123 if (e->retry >= dl_list_len(&s->addr_list)) { 00124 wpa_printf(MSG_DEBUG, "WPS UPnP: Giving up on sending event " 00125 "for %s", e->addr->domain_and_port); 00126 return; 00127 } 00128 dl_list_add(&s->event_queue, &e->list); 00129 event_send_all_later(sm); 00130 } 00131 00132 00133 static struct wpabuf * event_build_message(struct wps_event_ *e) 00134 { 00135 struct wpabuf *buf; 00136 char *b; 00137 00138 buf = wpabuf_alloc(1000 + wpabuf_len(e->data)); 00139 if (buf == NULL) 00140 return NULL; 00141 wpabuf_printf(buf, "NOTIFY %s HTTP/1.1\r\n", e->addr->path); 00142 wpabuf_put_str(buf, "SERVER: Unspecified, UPnP/1.0, Unspecified\r\n"); 00143 wpabuf_printf(buf, "HOST: %s\r\n", e->addr->domain_and_port); 00144 wpabuf_put_str(buf, "CONTENT-TYPE: text/xml; charset=\"utf-8\"\r\n" 00145 "NT: upnp:event\r\n" 00146 "NTS: upnp:propchange\r\n"); 00147 wpabuf_put_str(buf, "SID: uuid:"); 00148 b = wpabuf_put(buf, 0); 00149 uuid_bin2str(e->s->uuid, b, 80); 00150 wpabuf_put(buf, os_strlen(b)); 00151 wpabuf_put_str(buf, "\r\n"); 00152 wpabuf_printf(buf, "SEQ: %u\r\n", e->subscriber_sequence); 00153 wpabuf_printf(buf, "CONTENT-LENGTH: %d\r\n", 00154 (int) wpabuf_len(e->data)); 00155 wpabuf_put_str(buf, "\r\n"); /* terminating empty line */ 00156 wpabuf_put_buf(buf, e->data); 00157 return buf; 00158 } 00159 00160 00161 static void event_http_cb(void *ctx, struct http_client *c, 00162 enum http_client_event event) 00163 { 00164 struct wps_event_ *e = ctx; 00165 struct subscription *s = e->s; 00166 00167 switch (event) { 00168 case HTTP_CLIENT_OK: 00169 wpa_printf(MSG_DEBUG, 00170 "WPS UPnP: Got event reply OK from " 00171 "%s", e->addr->domain_and_port); 00172 event_delete(e); 00173 00174 /* Schedule sending more if there is more to send */ 00175 if (!dl_list_empty(&s->event_queue)) 00176 event_send_all_later(s->sm); 00177 break; 00178 case HTTP_CLIENT_FAILED: 00179 case HTTP_CLIENT_INVALID_REPLY: 00180 wpa_printf(MSG_DEBUG, "WPS UPnP: Failed to send event to %s", 00181 e->addr->domain_and_port); 00182 00183 /* 00184 * If other side doesn't like what we say, forget about them. 00185 * (There is no way to tell other side that we are dropping 00186 * them...). 00187 * Alternately, we could just do event_delete(e) 00188 */ 00189 wpa_printf(MSG_DEBUG, "WPS UPnP: Deleting subscription due to " 00190 "errors"); 00191 dl_list_del(&s->list); 00192 subscription_destroy(s); 00193 break; 00194 case HTTP_CLIENT_TIMEOUT: 00195 wpa_printf(MSG_DEBUG, "WPS UPnP: Event send timeout"); 00196 event_retry(e, 1); 00197 } 00198 } 00199 00200 00201 /* event_send_start -- prepare to send a event message to subscriber 00202 * 00203 * This gets complicated because: 00204 * -- The message is sent via TCP and we have to keep the stream open 00205 * for 30 seconds to get a response... then close it. 00206 * -- But we might have other event happen in the meantime... 00207 * we have to queue them, if we lose them then the subscriber will 00208 * be forced to unsubscribe and subscribe again. 00209 * -- If multiple URLs are provided then we are supposed to try successive 00210 * ones after 30 second timeout. 00211 * -- The URLs might use domain names instead of dotted decimal addresses, 00212 * and resolution of those may cause unwanted sleeping. 00213 * -- Doing the initial TCP connect can take a while, so we have to come 00214 * back after connection and then send the data. 00215 * 00216 * Returns nonzero on error; 00217 * 00218 * Prerequisite: No current event send (s->current_event == NULL) 00219 * and non-empty queue. 00220 */ 00221 static int event_send_start(struct subscription *s) 00222 { 00223 struct wps_event_ *e; 00224 unsigned int itry; 00225 struct wpabuf *buf; 00226 00227 /* 00228 * Assume we are called ONLY with no current event and ONLY with 00229 * nonempty event queue and ONLY with at least one address to send to. 00230 */ 00231 assert(!dl_list_empty(&s->addr_list)); 00232 assert(s->current_event == NULL); 00233 assert(!dl_list_empty(&s->event_queue)); 00234 00235 s->current_event = e = event_dequeue(s); 00236 00237 /* Use address according to number of retries */ 00238 itry = 0; 00239 dl_list_for_each(e->addr, &s->addr_list, struct subscr_addr, list) 00240 if (itry++ == e->retry) 00241 break; 00242 if (itry < e->retry) 00243 return -1; 00244 00245 buf = event_build_message(e); 00246 if (buf == NULL) { 00247 event_retry(e, 0); 00248 return -1; 00249 } 00250 00251 e->http_event = http_client_addr(&e->addr->saddr, buf, 0, 00252 event_http_cb, e); 00253 if (e->http_event == NULL) { 00254 wpabuf_free(buf); 00255 event_retry(e, 0); 00256 return -1; 00257 } 00258 00259 return 0; 00260 } 00261 00262 00263 /* event_send_all_later_handler -- actually send events as needed */ 00264 static void event_send_all_later_handler(void *eloop_data, void *user_ctx) 00265 { 00266 struct upnp_wps_device_sm *sm = user_ctx; 00267 struct subscription *s, *tmp; 00268 int nerrors = 0; 00269 00270 sm->event_send_all_queued = 0; 00271 dl_list_for_each_safe(s, tmp, &sm->subscriptions, struct subscription, 00272 list) { 00273 if (dl_list_empty(&s->addr_list)) { 00274 /* if we've given up on all addresses */ 00275 wpa_printf(MSG_DEBUG, "WPS UPnP: Removing " 00276 "subscription with no addresses"); 00277 dl_list_del(&s->list); 00278 subscription_destroy(s); 00279 } else { 00280 if (s->current_event == NULL /* not busy */ && 00281 !dl_list_empty(&s->event_queue) /* more to do */) { 00282 if (event_send_start(s)) 00283 nerrors++; 00284 } 00285 } 00286 } 00287 00288 if (nerrors) { 00289 /* Try again later */ 00290 event_send_all_later(sm); 00291 } 00292 } 00293 00294 00295 /* event_send_all_later -- schedule sending events to all subscribers 00296 * that need it. 00297 * This avoids two problems: 00298 * -- After getting a subscription, we should not send the first event 00299 * until after our reply is fully queued to be sent back, 00300 * -- Possible stack depth or infinite recursion issues. 00301 */ 00302 void event_send_all_later(struct upnp_wps_device_sm *sm) 00303 { 00304 /* 00305 * The exact time in the future isn't too important. Waiting a bit 00306 * might let us do several together. 00307 */ 00308 if (sm->event_send_all_queued) 00309 return; 00310 sm->event_send_all_queued = 1; 00311 eloop_register_timeout(EVENT_DELAY_SECONDS, EVENT_DELAY_MSEC, 00312 event_send_all_later_handler, NULL, sm); 00313 } 00314 00315 00316 /* event_send_stop_all -- cleanup */ 00317 void event_send_stop_all(struct upnp_wps_device_sm *sm) 00318 { 00319 if (sm->event_send_all_queued) 00320 eloop_cancel_timeout(event_send_all_later_handler, NULL, sm); 00321 sm->event_send_all_queued = 0; 00322 } 00323 00324 00331 int event_add(struct subscription *s, const struct wpabuf *data) 00332 { 00333 struct wps_event_ *e; 00334 00335 if (dl_list_len(&s->event_queue) >= MAX_EVENTS_QUEUED) { 00336 wpa_printf(MSG_DEBUG, "WPS UPnP: Too many events queued for " 00337 "subscriber"); 00338 return 1; 00339 } 00340 00341 e = os_zalloc(sizeof(*e)); 00342 if (e == NULL) 00343 return 1; 00344 dl_list_init(&e->list); 00345 e->s = s; 00346 e->data = wpabuf_dup(data); 00347 if (e->data == NULL) { 00348 os_free(e); 00349 return 1; 00350 } 00351 e->subscriber_sequence = s->next_subscriber_sequence++; 00352 if (s->next_subscriber_sequence == 0) 00353 s->next_subscriber_sequence++; 00354 dl_list_add_tail(&s->event_queue, &e->list); 00355 event_send_all_later(s->sm); 00356 return 0; 00357 }