Diff for /embedaddon/miniupnpd/upnpevents.c between versions 1.1 and 1.1.1.3

version 1.1, 2012/02/21 23:16:02 version 1.1.1.3, 2013/07/22 00:32:35
Line 1 Line 1
 /* $Id$ */  /* $Id$ */
 /* MiniUPnP project  /* MiniUPnP project
  * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/   * 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   * This software is subject to the conditions detailed
  * in the LICENCE file provided within the distribution */   * in the LICENCE file provided within the distribution */
   
Line 16 Line 16
 #include <sys/socket.h>  #include <sys/socket.h>
 #include <netinet/in.h>  #include <netinet/in.h>
 #include <arpa/inet.h>  #include <arpa/inet.h>
 #include <fcntl.h>  
 #include <errno.h>  #include <errno.h>
 #include "config.h"  #include "config.h"
 #include "upnpevents.h"  #include "upnpevents.h"
 #include "miniupnpdpath.h"  #include "miniupnpdpath.h"
 #include "upnpglobalvars.h"  #include "upnpglobalvars.h"
 #include "upnpdescgen.h"  #include "upnpdescgen.h"
   #include "upnputils.h"
   
 #ifdef ENABLE_EVENTS  #ifdef ENABLE_EVENTS
 /*enum subscriber_service_enum {  /*enum subscriber_service_enum {
Line 37  struct subscriber { Line 37  struct subscriber {
         struct upnp_event_notify * notify;          struct upnp_event_notify * notify;
         time_t timeout;          time_t timeout;
         uint32_t seq;          uint32_t seq;
         /*enum { EWanCFG = 1, EWanIPC, EL3F } service;*/  
         enum subscriber_service_enum service;          enum subscriber_service_enum service;
         char uuid[42];          char uuid[42];
         char callback[];          char callback[];
Line 58  struct upnp_event_notify { Line 57  struct upnp_event_notify {
         int tosend;          int tosend;
     int sent;      int sent;
         const char * path;          const char * path;
   #ifdef ENABLE_IPV6
           int ipv6;
           char addrstr[48];
   #else
         char addrstr[16];          char addrstr[16];
   #endif
         char portstr[8];          char portstr[8];
 };  };
   
Line 80  newSubscriber(const char * eventurl, const char * call Line 84  newSubscriber(const char * eventurl, const char * call
         if(!eventurl || !callback || !callbacklen)          if(!eventurl || !callback || !callbacklen)
                 return NULL;                  return NULL;
         tmp = calloc(1, sizeof(struct subscriber)+callbacklen+1);          tmp = calloc(1, sizeof(struct subscriber)+callbacklen+1);
           if(!tmp)
                   return NULL;
         if(strcmp(eventurl, WANCFG_EVENTURL)==0)          if(strcmp(eventurl, WANCFG_EVENTURL)==0)
                 tmp->service = EWanCFG;                  tmp->service = EWanCFG;
         else if(strcmp(eventurl, WANIPC_EVENTURL)==0)          else if(strcmp(eventurl, WANIPC_EVENTURL)==0)
Line 88  newSubscriber(const char * eventurl, const char * call Line 94  newSubscriber(const char * eventurl, const char * call
         else if(strcmp(eventurl, L3F_EVENTURL)==0)          else if(strcmp(eventurl, L3F_EVENTURL)==0)
                 tmp->service = EL3F;                  tmp->service = EL3F;
 #endif  #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 {          else {
                 free(tmp);                  free(tmp);
                 return NULL;                  return NULL;
Line 103  newSubscriber(const char * eventurl, const char * call Line 117  newSubscriber(const char * eventurl, const char * call
 }  }
   
 /* creates a new subscriber and adds it to the subscriber list  /* 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 *  const char *
 upnpevents_addSubscriber(const char * eventurl,  upnpevents_addSubscriber(const char * eventurl,
                          const char * callback, int callbacklen,                           const char * callback, int callbacklen,
Line 132  renewSubscription(const char * sid, int sidlen, int ti Line 148  renewSubscription(const char * sid, int sidlen, int ti
 {  {
         struct subscriber * sub;          struct subscriber * sub;
         for(sub = subscriberlist.lh_first; sub != NULL; sub = sub->entries.le_next) {          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);                          sub->timeout = (timeout ? time(NULL) + timeout : 0);
                         return 0;                          return 0;
                 }                  }
Line 147  upnpevents_removeSubscriber(const char * sid, int sidl Line 163  upnpevents_removeSubscriber(const char * sid, int sidl
         if(!sid)          if(!sid)
                 return -1;                  return -1;
         for(sub = subscriberlist.lh_first; sub != NULL; sub = sub->entries.le_next) {          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) {                          if(sub->notify) {
                                 sub->notify->sub = NULL;                                  sub->notify->sub = NULL;
                         }                          }
Line 176  static void Line 192  static void
 upnp_event_create_notify(struct subscriber * sub)  upnp_event_create_notify(struct subscriber * sub)
 {  {
         struct upnp_event_notify * obj;          struct upnp_event_notify * obj;
        int flags;
         obj = calloc(1, sizeof(struct upnp_event_notify));          obj = calloc(1, sizeof(struct upnp_event_notify));
         if(!obj) {          if(!obj) {
                 syslog(LOG_ERR, "%s: calloc(): %m", "upnp_event_create_notify");                  syslog(LOG_ERR, "%s: calloc(): %m", "upnp_event_create_notify");
Line 184  upnp_event_create_notify(struct subscriber * sub) Line 200  upnp_event_create_notify(struct subscriber * sub)
         }          }
         obj->sub = sub;          obj->sub = sub;
         obj->state = ECreated;          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);          obj->s = socket(PF_INET, SOCK_STREAM, 0);
   #endif
         if(obj->s<0) {          if(obj->s<0) {
                 syslog(LOG_ERR, "%s: socket(): %m", "upnp_event_create_notify");                  syslog(LOG_ERR, "%s: socket(): %m", "upnp_event_create_notify");
                 goto error;                  goto error;
         }          }
        if((flags = fcntl(obj->s, F_GETFL, 0)) < 0) {        if(!set_non_blocking(obj->s)) {
                syslog(LOG_ERR, "%s: fcntl(..F_GETFL..): %m",                syslog(LOG_ERR, "%s: set_non_blocking(): %m",
                        "upnp_event_create_notify");                         "upnp_event_create_notify");
                 goto error;                  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)          if(sub)
                 sub->notify = obj;                  sub->notify = obj;
         LIST_INSERT_HEAD(&notifylist, obj, entries);          LIST_INSERT_HEAD(&notifylist, obj, entries);
Line 212  error: Line 228  error:
 static void  static void
 upnp_event_notify_connect(struct upnp_event_notify * obj)  upnp_event_notify_connect(struct upnp_event_notify * obj)
 {  {
        int i;        unsigned int i;
         const char * p;          const char * p;
         unsigned short port;          unsigned short port;
   #ifdef ENABLE_IPV6
           struct sockaddr_storage addr;
   #else
         struct sockaddr_in addr;          struct sockaddr_in addr;
   #endif
         if(!obj)          if(!obj)
                 return;                  return;
         memset(&addr, 0, sizeof(addr));          memset(&addr, 0, sizeof(addr));
Line 226  upnp_event_notify_connect(struct upnp_event_notify * o Line 246  upnp_event_notify_connect(struct upnp_event_notify * o
         }          }
         p = obj->sub->callback;          p = obj->sub->callback;
         p += 7; /* http:// */          p += 7; /* http:// */
        while(*p != '/' && *p != ':')#ifdef ENABLE_IPV6
                obj->addrstr[i++] = *(p++);        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';          obj->addrstr[i] = '\0';
         if(*p == ':') {          if(*p == ':') {
                 obj->portstr[0] = *p;                  obj->portstr[0] = *p;
Line 244  upnp_event_notify_connect(struct upnp_event_notify * o Line 277  upnp_event_notify_connect(struct upnp_event_notify * o
                 obj->portstr[0] = '\0';                  obj->portstr[0] = '\0';
         }          }
         obj->path = p;          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;          addr.sin_family = AF_INET;
         inet_aton(obj->addrstr, &addr.sin_addr);          inet_aton(obj->addrstr, &addr.sin_addr);
         addr.sin_port = htons(port);          addr.sin_port = htons(port);
   #endif
         syslog(LOG_DEBUG, "%s: '%s' %hu '%s'", "upnp_event_notify_connect",          syslog(LOG_DEBUG, "%s: '%s' %hu '%s'", "upnp_event_notify_connect",
                obj->addrstr, port, obj->path);                 obj->addrstr, port, obj->path);
         obj->state = EConnecting;          obj->state = EConnecting;
Line 260  upnp_event_notify_connect(struct upnp_event_notify * o Line 307  upnp_event_notify_connect(struct upnp_event_notify * o
   
 static void upnp_event_prepare(struct upnp_event_notify * obj)  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"                  "NOTIFY %s HTTP/1.1\r\n"
                 "Host: %s%s\r\n"                  "Host: %s%s\r\n"
                 "Content-Type: text/xml\r\n"                  "Content-Type: text/xml\r\n"
Line 291  static void upnp_event_prepare(struct upnp_event_notif Line 338  static void upnp_event_prepare(struct upnp_event_notif
                 xml = getVarsL3F(&l);                  xml = getVarsL3F(&l);
                 break;                  break;
 #endif  #endif
   #ifdef ENABLE_6FC_SERVICE
           case E6FC:
                   xml = getVars6FC(&l);
                   break;
   #endif
   #ifdef ENABLE_DP_SERVICE
           case EDP:
                   xml = getVarsDP(&l);
                   break;
   #endif
         default:          default:
                 xml = NULL;                  xml = NULL;
                 l = 0;                  l = 0;
         }          }
         obj->buffersize = 1024;          obj->buffersize = 1024;
         obj->buffer = malloc(obj->buffersize);          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->tosend = snprintf(obj->buffer, obj->buffersize, notifymsg,
                                obj->path, obj->addrstr, obj->portstr, l+2,                                 obj->path, obj->addrstr, obj->portstr, l+2,
                                obj->sub->uuid, obj->sub->seq,                                 obj->sub->uuid, obj->sub->seq,
Line 313  static void upnp_event_prepare(struct upnp_event_notif Line 376  static void upnp_event_prepare(struct upnp_event_notif
 static void upnp_event_send(struct upnp_event_notify * obj)  static void upnp_event_send(struct upnp_event_notify * obj)
 {  {
         int i;          int i;
   
         syslog(LOG_DEBUG, "%s: sending event notify message to %s:%s",          syslog(LOG_DEBUG, "%s: sending event notify message to %s:%s",
                "upnp_event_send", obj->addrstr, obj->portstr);                 "upnp_event_send", obj->addrstr, obj->portstr);
         syslog(LOG_DEBUG, "%s: msg: %s",          syslog(LOG_DEBUG, "%s: msg: %s",
                "upnp_event_send", obj->buffer + obj->sent);                 "upnp_event_send", obj->buffer + obj->sent);
         i = send(obj->s, obj->buffer + obj->sent, obj->tosend - obj->sent, 0);          i = send(obj->s, obj->buffer + obj->sent, obj->tosend - obj->sent, 0);
         if(i<0) {          if(i<0) {
                syslog(LOG_NOTICE, "%s: send(): %m", "upnp_event_send");                if(errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) {
                obj->state = EError;                        syslog(LOG_NOTICE, "%s: send(): %m", "upnp_event_send");
                return;                        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",                  syslog(LOG_NOTICE, "%s: %d bytes send out of %d",
                        "upnp_event_send", i, obj->tosend - obj->sent);                         "upnp_event_send", i, obj->tosend - obj->sent);
         obj->sent += i;          obj->sent += i;
Line 336  static void upnp_event_recv(struct upnp_event_notify * Line 405  static void upnp_event_recv(struct upnp_event_notify *
         int n;          int n;
         n = recv(obj->s, obj->buffer, obj->buffersize, 0);          n = recv(obj->s, obj->buffer, obj->buffersize, 0);
         if(n<0) {          if(n<0) {
                syslog(LOG_ERR, "%s: recv(): %m", "upnp_event_recv");                if(errno != EAGAIN &&
                obj->state = EError;                   errno != EWOULDBLOCK &&
                    errno != EINTR) {
                         syslog(LOG_ERR, "%s: recv(): %m", "upnp_event_recv");
                         obj->state = EError;
                 }
                 return;                  return;
         }          }
         syslog(LOG_DEBUG, "%s: (%dbytes) %.*s", "upnp_event_recv",          syslog(LOG_DEBUG, "%s: (%dbytes) %.*s", "upnp_event_recv",
                n, n, obj->buffer);                 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;          obj->state = EFinished;
         if(obj->sub)          if(obj->sub)
                 obj->sub->seq++;                  obj->sub->seq++;
Line 350  static void upnp_event_recv(struct upnp_event_notify * Line 426  static void upnp_event_recv(struct upnp_event_notify *
 static void  static void
 upnp_event_process_notify(struct upnp_event_notify * obj)  upnp_event_process_notify(struct upnp_event_notify * obj)
 {  {
           int err;
           socklen_t len;
         switch(obj->state) {          switch(obj->state) {
         case EConnecting:          case EConnecting:
                 /* now connected or failed to connect */                  /* 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_prepare(obj);
                upnp_event_send(obj);                if(obj->state == ESending)
                         upnp_event_send(obj);
                 break;                  break;
         case ESending:          case ESending:
                 upnp_event_send(obj);                  upnp_event_send(obj);
Line 367  upnp_event_process_notify(struct upnp_event_notify * o Line 458  upnp_event_process_notify(struct upnp_event_notify * o
                 obj->s = -1;                  obj->s = -1;
                 break;                  break;
         default:          default:
                syslog(LOG_ERR, "upnp_event_process_notify: unknown state");                syslog(LOG_ERR, "%s: unknown state", "upnp_event_process_notify");
         }          }
 }  }
   
Line 394  void upnpevents_selectfds(fd_set *readset, fd_set *wri Line 485  void upnpevents_selectfds(fd_set *readset, fd_set *wri
                                 if(obj->s > *max_fd)                                  if(obj->s > *max_fd)
                                         *max_fd = obj->s;                                          *max_fd = obj->s;
                                 break;                                  break;
                           default:
                                   ;
                         }                          }
                 }                  }
         }          }
Line 464  void write_events_details(int s) { Line 557  void write_events_details(int s) {
         write(s, "Subscribers :\n", 14);          write(s, "Subscribers :\n", 14);
         for(sub = subscriberlist.lh_first; sub != NULL; sub = sub->entries.le_next) {          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",                  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);                  write(s, buff, n);
                 n = snprintf(buff, sizeof(buff), "   notify=%p %s\n",                  n = snprintf(buff, sizeof(buff), "   notify=%p %s\n",
                              sub->notify, sub->uuid);                               sub->notify, sub->uuid);

Removed from v.1.1  
changed lines
  Added in v.1.1.1.3


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>