2 * UPnP WPS Device - Event processing
3 * Copyright (c) 2000-2003 Intel Corporation
4 * Copyright (c) 2006-2007 Sony Corporation
5 * Copyright (c) 2008-2009 Atheros Communications
6 * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
8 * See wps_upnp.c for more details on licensing and code history.
17 #include "http_client.h"
20 #include "wps_upnp_i.h"
23 * Event message generation (to subscribers)
25 * We make a separate copy for each message for each subscriber. This memory
26 * wasted could be limited (adding code complexity) by sharing copies, keeping
27 * a usage count and freeing when zero.
29 * Sending a message requires using a HTTP over TCP NOTIFY
30 * (like a PUT) which requires a number of states..
33 #define MAX_EVENTS_QUEUED 20 /* How far behind queued events */
34 #define EVENT_TIMEOUT_SEC 30 /* Drop sending event after timeout */
36 /* How long to wait before sending event */
37 #define EVENT_DELAY_SECONDS 0
38 #define EVENT_DELAY_MSEC 0
41 * Event information that we send to each subscriber is remembered in this
42 * struct. The event cannot be sent by simple UDP; it has to be sent by a HTTP
43 * over TCP transaction which requires various states.. It may also need to be
44 * retried at a different address (if more than one is available).
46 * TODO: As an optimization we could share data between subscribers.
50 struct subscription
*s
; /* parent */
51 unsigned subscriber_sequence
; /* which event for this subscription*/
52 unsigned int retry
; /* which retry */
53 struct subscr_addr
*addr
; /* address to connect to */
54 struct wpabuf
*data
; /* event data to send */
55 struct http_client
*http_event
;
59 /* event_clean -- clean sockets etc. of event
60 * Leaves data, retry count etc. alone.
62 static void event_clean(struct wps_event_
*e
)
64 if (e
->s
->current_event
== e
)
65 e
->s
->current_event
= NULL
;
66 http_client_free(e
->http_event
);
71 /* event_delete -- delete single unqueued event
72 * (be sure to dequeue first if need be)
74 static void event_delete(struct wps_event_
*e
)
82 /* event_dequeue -- get next event from the queue
83 * Returns NULL if empty.
85 static struct wps_event_
*event_dequeue(struct subscription
*s
)
88 e
= dl_list_first(&s
->event_queue
, struct wps_event_
, list
);
90 dl_list_del(&e
->list
);
95 /* event_delete_all -- delete entire event queue and current event */
96 void event_delete_all(struct subscription
*s
)
99 while ((e
= event_dequeue(s
)) != NULL
)
101 if (s
->current_event
) {
102 event_delete(s
->current_event
);
103 /* will set: s->current_event = NULL; */
109 * event_retry - Called when we had a failure delivering event msg
111 * @do_next_address: skip address e.g. on connect fail
113 static void event_retry(struct wps_event_
*e
, int do_next_address
)
115 struct subscription
*s
= e
->s
;
116 struct upnp_wps_device_sm
*sm
= s
->sm
;
119 /* will set: s->current_event = NULL; */
123 if (e
->retry
>= dl_list_len(&s
->addr_list
)) {
124 wpa_printf(MSG_DEBUG
, "WPS UPnP: Giving up on sending event "
125 "for %s", e
->addr
->domain_and_port
);
128 dl_list_add(&s
->event_queue
, &e
->list
);
129 event_send_all_later(sm
);
133 static struct wpabuf
* event_build_message(struct wps_event_
*e
)
138 buf
= wpabuf_alloc(1000 + wpabuf_len(e
->data
));
141 wpabuf_printf(buf
, "NOTIFY %s HTTP/1.1\r\n", e
->addr
->path
);
142 wpabuf_put_str(buf
, "SERVER: Unspecified, UPnP/1.0, Unspecified\r\n");
143 wpabuf_printf(buf
, "HOST: %s\r\n", e
->addr
->domain_and_port
);
144 wpabuf_put_str(buf
, "CONTENT-TYPE: text/xml; charset=\"utf-8\"\r\n"
146 "NTS: upnp:propchange\r\n");
147 wpabuf_put_str(buf
, "SID: uuid:");
148 b
= wpabuf_put(buf
, 0);
149 uuid_bin2str(e
->s
->uuid
, b
, 80);
150 wpabuf_put(buf
, os_strlen(b
));
151 wpabuf_put_str(buf
, "\r\n");
152 wpabuf_printf(buf
, "SEQ: %u\r\n", e
->subscriber_sequence
);
153 wpabuf_printf(buf
, "CONTENT-LENGTH: %d\r\n",
154 (int) wpabuf_len(e
->data
));
155 wpabuf_put_str(buf
, "\r\n"); /* terminating empty line */
156 wpabuf_put_buf(buf
, e
->data
);
161 static void event_http_cb(void *ctx
, struct http_client
*c
,
162 enum http_client_event event
)
164 struct wps_event_
*e
= ctx
;
165 struct subscription
*s
= e
->s
;
169 wpa_printf(MSG_DEBUG
,
170 "WPS UPnP: Got event reply OK from "
171 "%s", e
->addr
->domain_and_port
);
174 /* Schedule sending more if there is more to send */
175 if (!dl_list_empty(&s
->event_queue
))
176 event_send_all_later(s
->sm
);
178 case HTTP_CLIENT_FAILED
:
179 case HTTP_CLIENT_INVALID_REPLY
:
180 wpa_printf(MSG_DEBUG
, "WPS UPnP: Failed to send event to %s",
181 e
->addr
->domain_and_port
);
184 * If other side doesn't like what we say, forget about them.
185 * (There is no way to tell other side that we are dropping
187 * Alternately, we could just do event_delete(e)
189 wpa_printf(MSG_DEBUG
, "WPS UPnP: Deleting subscription due to "
191 dl_list_del(&s
->list
);
192 subscription_destroy(s
);
194 case HTTP_CLIENT_TIMEOUT
:
195 wpa_printf(MSG_DEBUG
, "WPS UPnP: Event send timeout");
201 /* event_send_start -- prepare to send a event message to subscriber
203 * This gets complicated because:
204 * -- The message is sent via TCP and we have to keep the stream open
205 * for 30 seconds to get a response... then close it.
206 * -- But we might have other event happen in the meantime...
207 * we have to queue them, if we lose them then the subscriber will
208 * be forced to unsubscribe and subscribe again.
209 * -- If multiple URLs are provided then we are supposed to try successive
210 * ones after 30 second timeout.
211 * -- The URLs might use domain names instead of dotted decimal addresses,
212 * and resolution of those may cause unwanted sleeping.
213 * -- Doing the initial TCP connect can take a while, so we have to come
214 * back after connection and then send the data.
216 * Returns nonzero on error;
218 * Prerequisite: No current event send (s->current_event == NULL)
219 * and non-empty queue.
221 static int event_send_start(struct subscription
*s
)
223 struct wps_event_
*e
;
228 * Assume we are called ONLY with no current event and ONLY with
229 * nonempty event queue and ONLY with at least one address to send to.
231 assert(!dl_list_empty(&s
->addr_list
));
232 assert(s
->current_event
== NULL
);
233 assert(!dl_list_empty(&s
->event_queue
));
235 s
->current_event
= e
= event_dequeue(s
);
237 /* Use address according to number of retries */
239 dl_list_for_each(e
->addr
, &s
->addr_list
, struct subscr_addr
, list
)
240 if (itry
++ == e
->retry
)
245 buf
= event_build_message(e
);
251 e
->http_event
= http_client_addr(&e
->addr
->saddr
, buf
, 0,
253 if (e
->http_event
== NULL
) {
263 /* event_send_all_later_handler -- actually send events as needed */
264 static void event_send_all_later_handler(void *eloop_data
, void *user_ctx
)
266 struct upnp_wps_device_sm
*sm
= user_ctx
;
267 struct subscription
*s
, *tmp
;
270 sm
->event_send_all_queued
= 0;
271 dl_list_for_each_safe(s
, tmp
, &sm
->subscriptions
, struct subscription
,
273 if (dl_list_empty(&s
->addr_list
)) {
274 /* if we've given up on all addresses */
275 wpa_printf(MSG_DEBUG
, "WPS UPnP: Removing "
276 "subscription with no addresses");
277 dl_list_del(&s
->list
);
278 subscription_destroy(s
);
280 if (s
->current_event
== NULL
/* not busy */ &&
281 !dl_list_empty(&s
->event_queue
) /* more to do */) {
282 if (event_send_start(s
))
289 /* Try again later */
290 event_send_all_later(sm
);
295 /* event_send_all_later -- schedule sending events to all subscribers
297 * This avoids two problems:
298 * -- After getting a subscription, we should not send the first event
299 * until after our reply is fully queued to be sent back,
300 * -- Possible stack depth or infinite recursion issues.
302 void event_send_all_later(struct upnp_wps_device_sm
*sm
)
305 * The exact time in the future isn't too important. Waiting a bit
306 * might let us do several together.
308 if (sm
->event_send_all_queued
)
310 sm
->event_send_all_queued
= 1;
311 eloop_register_timeout(EVENT_DELAY_SECONDS
, EVENT_DELAY_MSEC
,
312 event_send_all_later_handler
, NULL
, sm
);
316 /* event_send_stop_all -- cleanup */
317 void event_send_stop_all(struct upnp_wps_device_sm
*sm
)
319 if (sm
->event_send_all_queued
)
320 eloop_cancel_timeout(event_send_all_later_handler
, NULL
, sm
);
321 sm
->event_send_all_queued
= 0;
326 * event_add - Add a new event to a queue
328 * @data: Event data (is copied; caller retains ownership)
329 * Returns: 0 on success, 1 on error
331 int event_add(struct subscription
*s
, const struct wpabuf
*data
)
333 struct wps_event_
*e
;
335 if (dl_list_len(&s
->event_queue
) >= MAX_EVENTS_QUEUED
) {
336 wpa_printf(MSG_DEBUG
, "WPS UPnP: Too many events queued for "
341 e
= os_zalloc(sizeof(*e
));
344 dl_list_init(&e
->list
);
346 e
->data
= wpabuf_dup(data
);
347 if (e
->data
== NULL
) {
351 e
->subscriber_sequence
= s
->next_subscriber_sequence
++;
352 if (s
->next_subscriber_sequence
== 0)
353 s
->next_subscriber_sequence
++;
354 dl_list_add_tail(&s
->event_queue
, &e
->list
);
355 event_send_all_later(s
->sm
);