--- embedaddon/miniupnpd/upnpevents.c 2012/02/21 23:16:02 1.1.1.1 +++ embedaddon/miniupnpd/upnpevents.c 2013/07/22 00:32:35 1.1.1.3 @@ -1,7 +1,7 @@ -/* $Id: upnpevents.c,v 1.1.1.1 2012/02/21 23:16:02 misho Exp $ */ +/* $Id: upnpevents.c,v 1.1.1.3 2013/07/22 00:32:35 misho Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2008-2009 Thomas Bernard + * (c) 2008-2012 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -16,13 +16,13 @@ #include #include #include -#include #include #include "config.h" #include "upnpevents.h" #include "miniupnpdpath.h" #include "upnpglobalvars.h" #include "upnpdescgen.h" +#include "upnputils.h" #ifdef ENABLE_EVENTS /*enum subscriber_service_enum { @@ -37,7 +37,6 @@ struct subscriber { struct upnp_event_notify * notify; time_t timeout; uint32_t seq; - /*enum { EWanCFG = 1, EWanIPC, EL3F } service;*/ enum subscriber_service_enum service; char uuid[42]; char callback[]; @@ -58,7 +57,12 @@ struct upnp_event_notify { int tosend; int sent; const char * path; +#ifdef ENABLE_IPV6 + int ipv6; + char addrstr[48]; +#else char addrstr[16]; +#endif char portstr[8]; }; @@ -80,6 +84,8 @@ newSubscriber(const char * eventurl, const char * call if(!eventurl || !callback || !callbacklen) return NULL; tmp = calloc(1, sizeof(struct subscriber)+callbacklen+1); + if(!tmp) + return NULL; if(strcmp(eventurl, WANCFG_EVENTURL)==0) tmp->service = EWanCFG; else if(strcmp(eventurl, WANIPC_EVENTURL)==0) @@ -88,6 +94,14 @@ newSubscriber(const char * eventurl, const char * call else if(strcmp(eventurl, L3F_EVENTURL)==0) tmp->service = EL3F; #endif +#ifdef ENABLE_6FC_SERVICE + else if(strcmp(eventurl, WANIP6FC_EVENTURL)==0) + tmp->service = E6FC; +#endif +#ifdef ENABLE_DP_SERVICE + else if(strcmp(eventurl, DP_EVENTURL)==0) + tmp->service = EDP; +#endif else { free(tmp); return NULL; @@ -103,7 +117,9 @@ newSubscriber(const char * eventurl, const char * call } /* creates a new subscriber and adds it to the subscriber list - * also initiate 1st notify */ + * also initiate 1st notify + * TODO : add a check on the number of subscriber in order to + * prevent memory overflow... */ const char * upnpevents_addSubscriber(const char * eventurl, const char * callback, int callbacklen, @@ -132,7 +148,7 @@ renewSubscription(const char * sid, int sidlen, int ti { struct subscriber * sub; for(sub = subscriberlist.lh_first; sub != NULL; sub = sub->entries.le_next) { - if(memcmp(sid, sub->uuid, 41) == 0) { + if((sidlen == 41) && (memcmp(sid, sub->uuid, 41) == 0)) { sub->timeout = (timeout ? time(NULL) + timeout : 0); return 0; } @@ -147,7 +163,7 @@ upnpevents_removeSubscriber(const char * sid, int sidl if(!sid) return -1; for(sub = subscriberlist.lh_first; sub != NULL; sub = sub->entries.le_next) { - if(memcmp(sid, sub->uuid, 41) == 0) { + if((sidlen == 41) && (memcmp(sid, sub->uuid, 41) == 0)) { if(sub->notify) { sub->notify->sub = NULL; } @@ -176,7 +192,7 @@ static void upnp_event_create_notify(struct subscriber * sub) { struct upnp_event_notify * obj; - int flags; + obj = calloc(1, sizeof(struct upnp_event_notify)); if(!obj) { syslog(LOG_ERR, "%s: calloc(): %m", "upnp_event_create_notify"); @@ -184,21 +200,21 @@ upnp_event_create_notify(struct subscriber * sub) } obj->sub = sub; obj->state = ECreated; +#ifdef ENABLE_IPV6 + obj->s = socket((obj->sub->callback[7] == '[') ? PF_INET6 : PF_INET, + SOCK_STREAM, 0); +#else obj->s = socket(PF_INET, SOCK_STREAM, 0); +#endif if(obj->s<0) { syslog(LOG_ERR, "%s: socket(): %m", "upnp_event_create_notify"); goto error; } - if((flags = fcntl(obj->s, F_GETFL, 0)) < 0) { - syslog(LOG_ERR, "%s: fcntl(..F_GETFL..): %m", + if(!set_non_blocking(obj->s)) { + syslog(LOG_ERR, "%s: set_non_blocking(): %m", "upnp_event_create_notify"); goto error; } - if(fcntl(obj->s, F_SETFL, flags | O_NONBLOCK) < 0) { - syslog(LOG_ERR, "%s: fcntl(..F_SETFL..): %m", - "upnp_event_create_notify"); - goto error; - } if(sub) sub->notify = obj; LIST_INSERT_HEAD(¬ifylist, obj, entries); @@ -212,10 +228,14 @@ error: static void upnp_event_notify_connect(struct upnp_event_notify * obj) { - int i; + unsigned int i; const char * p; unsigned short port; +#ifdef ENABLE_IPV6 + struct sockaddr_storage addr; +#else struct sockaddr_in addr; +#endif if(!obj) return; memset(&addr, 0, sizeof(addr)); @@ -226,8 +246,21 @@ upnp_event_notify_connect(struct upnp_event_notify * o } p = obj->sub->callback; p += 7; /* http:// */ - while(*p != '/' && *p != ':') - obj->addrstr[i++] = *(p++); +#ifdef ENABLE_IPV6 + if(*p == '[') { /* ip v6 */ + p++; + obj->ipv6 = 1; + while(*p != ']' && i < (sizeof(obj->addrstr)-1)) + obj->addrstr[i++] = *(p++); + if(*p == ']') + p++; + } else { +#endif + while(*p != '/' && *p != ':' && i < (sizeof(obj->addrstr)-1)) + obj->addrstr[i++] = *(p++); +#ifdef ENABLE_IPV6 + } +#endif obj->addrstr[i] = '\0'; if(*p == ':') { obj->portstr[0] = *p; @@ -244,9 +277,23 @@ upnp_event_notify_connect(struct upnp_event_notify * o obj->portstr[0] = '\0'; } obj->path = p; +#ifdef ENABLE_IPV6 + if(obj->ipv6) { + struct sockaddr_in6 * sa = (struct sockaddr_in6 *)&addr; + sa->sin6_family = AF_INET6; + inet_pton(AF_INET6, obj->addrstr, &(sa->sin6_addr)); + sa->sin6_port = htons(port); + } else { + struct sockaddr_in * sa = (struct sockaddr_in *)&addr; + sa->sin_family = AF_INET; + inet_pton(AF_INET, obj->addrstr, &(sa->sin_addr)); + sa->sin_port = htons(port); + } +#else addr.sin_family = AF_INET; inet_aton(obj->addrstr, &addr.sin_addr); addr.sin_port = htons(port); +#endif syslog(LOG_DEBUG, "%s: '%s' %hu '%s'", "upnp_event_notify_connect", obj->addrstr, port, obj->path); obj->state = EConnecting; @@ -260,7 +307,7 @@ upnp_event_notify_connect(struct upnp_event_notify * o static void upnp_event_prepare(struct upnp_event_notify * obj) { - static const char notifymsg[] = + static const char notifymsg[] = "NOTIFY %s HTTP/1.1\r\n" "Host: %s%s\r\n" "Content-Type: text/xml\r\n" @@ -291,14 +338,30 @@ static void upnp_event_prepare(struct upnp_event_notif xml = getVarsL3F(&l); break; #endif +#ifdef ENABLE_6FC_SERVICE + case E6FC: + xml = getVars6FC(&l); + break; +#endif +#ifdef ENABLE_DP_SERVICE + case EDP: + xml = getVarsDP(&l); + break; +#endif default: xml = NULL; l = 0; } obj->buffersize = 1024; obj->buffer = malloc(obj->buffersize); - /*if(!obj->buffer) { - }*/ + if(!obj->buffer) { + syslog(LOG_ERR, "%s: malloc returned NULL", "upnp_event_prepare"); + if(xml) { + free(xml); + } + obj->state = EError; + return; + } obj->tosend = snprintf(obj->buffer, obj->buffersize, notifymsg, obj->path, obj->addrstr, obj->portstr, l+2, obj->sub->uuid, obj->sub->seq, @@ -313,17 +376,23 @@ static void upnp_event_prepare(struct upnp_event_notif static void upnp_event_send(struct upnp_event_notify * obj) { int i; + syslog(LOG_DEBUG, "%s: sending event notify message to %s:%s", "upnp_event_send", obj->addrstr, obj->portstr); syslog(LOG_DEBUG, "%s: msg: %s", "upnp_event_send", obj->buffer + obj->sent); i = send(obj->s, obj->buffer + obj->sent, obj->tosend - obj->sent, 0); if(i<0) { - syslog(LOG_NOTICE, "%s: send(): %m", "upnp_event_send"); - obj->state = EError; - return; + if(errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) { + syslog(LOG_NOTICE, "%s: send(): %m", "upnp_event_send"); + obj->state = EError; + return; + } else { + /* EAGAIN or EWOULDBLOCK or EINTR : no data sent */ + i = 0; + } } - else if(i != (obj->tosend - obj->sent)) + if(i != (obj->tosend - obj->sent)) syslog(LOG_NOTICE, "%s: %d bytes send out of %d", "upnp_event_send", i, obj->tosend - obj->sent); obj->sent += i; @@ -336,12 +405,19 @@ static void upnp_event_recv(struct upnp_event_notify * int n; n = recv(obj->s, obj->buffer, obj->buffersize, 0); if(n<0) { - syslog(LOG_ERR, "%s: recv(): %m", "upnp_event_recv"); - obj->state = EError; + if(errno != EAGAIN && + errno != EWOULDBLOCK && + errno != EINTR) { + syslog(LOG_ERR, "%s: recv(): %m", "upnp_event_recv"); + obj->state = EError; + } return; } syslog(LOG_DEBUG, "%s: (%dbytes) %.*s", "upnp_event_recv", n, n, obj->buffer); + /* TODO : do something with the data recevied ? + * right now, n (number of bytes received) is ignored + * We may need to recv() more bytes. */ obj->state = EFinished; if(obj->sub) obj->sub->seq++; @@ -350,11 +426,26 @@ static void upnp_event_recv(struct upnp_event_notify * static void upnp_event_process_notify(struct upnp_event_notify * obj) { + int err; + socklen_t len; switch(obj->state) { case EConnecting: /* now connected or failed to connect */ + len = sizeof(err); + if(getsockopt(obj->s, SOL_SOCKET, SO_ERROR, &err, &len) < 0) { + syslog(LOG_ERR, "%s: getsockopt: %m", "upnp_event_process_notify"); + obj->state = EError; + break; + } + if(err != 0) { + errno = err; + syslog(LOG_WARNING, "%s: connect failed: %m", "upnp_event_process_notify"); + obj->state = EError; + break; + } upnp_event_prepare(obj); - upnp_event_send(obj); + if(obj->state == ESending) + upnp_event_send(obj); break; case ESending: upnp_event_send(obj); @@ -367,7 +458,7 @@ upnp_event_process_notify(struct upnp_event_notify * o obj->s = -1; break; default: - syslog(LOG_ERR, "upnp_event_process_notify: unknown state"); + syslog(LOG_ERR, "%s: unknown state", "upnp_event_process_notify"); } } @@ -394,6 +485,8 @@ void upnpevents_selectfds(fd_set *readset, fd_set *wri if(obj->s > *max_fd) *max_fd = obj->s; break; + default: + ; } } } @@ -464,7 +557,7 @@ void write_events_details(int s) { write(s, "Subscribers :\n", 14); for(sub = subscriberlist.lh_first; sub != NULL; sub = sub->entries.le_next) { n = snprintf(buff, sizeof(buff), " %p timeout=%d seq=%u service=%d\n", - sub, sub->timeout, sub->seq, sub->service); + sub, (int)sub->timeout, sub->seq, sub->service); write(s, buff, n); n = snprintf(buff, sizeof(buff), " notify=%p %s\n", sub->notify, sub->uuid);