"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "upnpevents.c" between
minidlna-1.2.1.tar.gz and minidlna-1.3.0.tar.gz

About: ReadyMedia (formerly known as MiniDLNA) is a simple media server software, with the aim of being fully compliant with DLNA/UPnP-AV clients.

upnpevents.c  (minidlna-1.2.1):upnpevents.c  (minidlna-1.3.0)
skipping to change at line 62 skipping to change at line 62
#include <errno.h> #include <errno.h>
#include <sys/queue.h> #include <sys/queue.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <time.h> #include <time.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/param.h> #include <sys/param.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <assert.h>
#include <fcntl.h> #include <fcntl.h>
#include <errno.h> #include <errno.h>
#include "event.h"
#include "upnpevents.h" #include "upnpevents.h"
#include "minidlnapath.h" #include "minidlnapath.h"
#include "upnpglobalvars.h" #include "upnpglobalvars.h"
#include "upnpdescgen.h" #include "upnpdescgen.h"
#include "uuid.h" #include "uuid.h"
#include "utils.h" #include "utils.h"
#include "log.h" #include "log.h"
/* stuctures definitions */ /* stuctures definitions */
struct subscriber { struct subscriber {
LIST_ENTRY(subscriber) entries; LIST_ENTRY(subscriber) entries;
struct upnp_event_notify * notify; struct upnp_event_notify * notify;
time_t timeout; time_t timeout;
uint32_t seq; uint32_t seq;
enum subscriber_service_enum service; enum subscriber_service_enum service;
char uuid[42]; char uuid[42];
char callback[]; char callback[];
}; };
struct upnp_event_notify { struct upnp_event_notify {
struct event ev;
LIST_ENTRY(upnp_event_notify) entries; LIST_ENTRY(upnp_event_notify) entries;
int s; /* socket */ enum { EConnecting,
enum { ECreated=1,
EConnecting,
ESending, ESending,
EWaitingForResponse, EWaitingForResponse,
EFinished, EFinished,
EError } state; EError } state;
struct subscriber * sub; struct subscriber * sub;
char * buffer; char * buffer;
int buffersize; int buffersize;
int tosend; int tosend;
int sent; int sent;
const char * path; const char * path;
char addrstr[16]; char addrstr[16];
char portstr[8]; char portstr[8];
}; };
/* prototypes */ /* prototypes */
static void static void upnp_event_create_notify(struct subscriber * sub);
upnp_event_create_notify(struct subscriber * sub); static void upnp_event_process_notify(struct event *ev);
/* Subscriber list */ /* Subscriber list */
LIST_HEAD(listhead, subscriber) subscriberlist = { NULL }; LIST_HEAD(listhead, subscriber) subscriberlist = { NULL };
/* notify list */ /* notify list */
LIST_HEAD(listheadnotif, upnp_event_notify) notifylist = { NULL }; LIST_HEAD(listheadnotif, upnp_event_notify) notifylist = { NULL };
#define MAX_SUBSCRIBERS 500 #define MAX_SUBSCRIBERS 500
static uint16_t nsubscribers = 0; static uint16_t nsubscribers = 0;
skipping to change at line 227 skipping to change at line 228
void void
upnp_event_var_change_notify(enum subscriber_service_enum service) upnp_event_var_change_notify(enum subscriber_service_enum service)
{ {
struct subscriber * sub; struct subscriber * sub;
for(sub = subscriberlist.lh_first; sub != NULL; sub = sub->entries.le_nex t) { for(sub = subscriberlist.lh_first; sub != NULL; sub = sub->entries.le_nex t) {
if(sub->service == service && sub->notify == NULL) if(sub->service == service && sub->notify == NULL)
upnp_event_create_notify(sub); upnp_event_create_notify(sub);
} }
} }
/* create and add the notify object to the list */ /* create and add the notify object to the list, start connecting */
static void 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; int flags, s, i;
const char *p;
unsigned short port;
struct sockaddr_in addr;
assert(sub);
obj = calloc(1, sizeof(struct upnp_event_notify)); obj = calloc(1, sizeof(struct upnp_event_notify));
if(!obj) { if(!obj) {
DPRINTF(E_ERROR, L_HTTP, "%s: calloc(): %s\n", "upnp_event_create _notify", strerror(errno)); DPRINTF(E_ERROR, L_HTTP, "%s: calloc(): %s\n", "upnp_event_create _notify", strerror(errno));
return; return;
} }
obj->sub = sub; obj->sub = sub;
obj->state = ECreated; s = socket(PF_INET, SOCK_STREAM, 0);
obj->s = socket(PF_INET, SOCK_STREAM, 0); if(s < 0) {
if(obj->s<0) {
DPRINTF(E_ERROR, L_HTTP, "%s: socket(): %s\n", "upnp_event_create _notify", strerror(errno)); DPRINTF(E_ERROR, L_HTTP, "%s: socket(): %s\n", "upnp_event_create _notify", strerror(errno));
goto error; goto error;
} }
if((flags = fcntl(obj->s, F_GETFL, 0)) < 0) { if((flags = fcntl(s, F_GETFL, 0)) < 0) {
DPRINTF(E_ERROR, L_HTTP, "%s: fcntl(..F_GETFL..): %s\n", DPRINTF(E_ERROR, L_HTTP, "%s: fcntl(..F_GETFL..): %s\n",
"upnp_event_create_notify", strerror(errno)); "upnp_event_create_notify", strerror(errno));
goto error; goto error;
} }
if(fcntl(obj->s, F_SETFL, flags | O_NONBLOCK) < 0) { if(fcntl(s, F_SETFL, flags | O_NONBLOCK) < 0) {
DPRINTF(E_ERROR, L_HTTP, "%s: fcntl(..F_SETFL..): %s\n", DPRINTF(E_ERROR, L_HTTP, "%s: fcntl(..F_SETFL..): %s\n",
"upnp_event_create_notify", strerror(errno)); "upnp_event_create_notify", strerror(errno));
goto error; goto error;
} }
if(sub) if(sub)
sub->notify = obj; sub->notify = obj;
LIST_INSERT_HEAD(&notifylist, obj, entries); LIST_INSERT_HEAD(&notifylist, obj, entries);
return;
error:
if(obj->s >= 0)
close(obj->s);
free(obj);
}
static void
upnp_event_notify_connect(struct upnp_event_notify * obj)
{
int i;
const char * p;
unsigned short port;
struct sockaddr_in addr;
if(!obj)
return;
memset(&addr, 0, sizeof(addr)); memset(&addr, 0, sizeof(addr));
i = 0; i = 0;
if(obj->sub == NULL) {
obj->state = EError;
return;
}
p = obj->sub->callback; p = obj->sub->callback;
p += 7; /* http:// */ p += 7; /* http:// */
while(*p != '/' && *p != ':' && i < (sizeof(obj->addrstr)-1)) while(*p != '/' && *p != ':' && i < (sizeof(obj->addrstr)-1))
obj->addrstr[i++] = *(p++); obj->addrstr[i++] = *(p++);
obj->addrstr[i] = '\0'; obj->addrstr[i] = '\0';
if(*p == ':') { if(*p == ':') {
obj->portstr[0] = *p; obj->portstr[0] = *p;
i = 1; i = 1;
p++; p++;
port = (unsigned short)atoi(p); port = (unsigned short)atoi(p);
skipping to change at line 309 skipping to change at line 296
if( *p ) if( *p )
obj->path = p; obj->path = p;
else else
obj->path = "/"; obj->path = "/";
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);
DPRINTF(E_DEBUG, L_HTTP, "%s: '%s' %hu '%s'\n", "upnp_event_notify_connec t", DPRINTF(E_DEBUG, L_HTTP, "%s: '%s' %hu '%s'\n", "upnp_event_notify_connec t",
obj->addrstr, port, obj->path); obj->addrstr, port, obj->path);
obj->state = EConnecting; obj->state = EConnecting;
if(connect(obj->s, (struct sockaddr *)&addr, sizeof(addr)) < 0) { if(connect(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
if(errno != EINPROGRESS && errno != EWOULDBLOCK) { if(errno != EINPROGRESS && errno != EWOULDBLOCK) {
DPRINTF(E_ERROR, L_HTTP, "%s: connect(): %s\n", "upnp_eve nt_notify_connect", strerror(errno)); DPRINTF(E_ERROR, L_HTTP, "%s: connect(): %s\n", "upnp_eve nt_notify_connect", strerror(errno));
obj->state = EError; obj->state = EError;
} }
} else {
obj->ev = (struct event ){ .fd = s, .rdwr = EVENT_WRITE,
.process = upnp_event_process_notify, .data = obj };
event_module.add(&obj->ev);
} }
return;
error:
if(s >= 0)
close(s);
free(obj);
} }
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; charset=\"utf-8\"\r\n" "Content-Type: text/xml; charset=\"utf-8\"\r\n"
"Content-Length: %d\r\n" "Content-Length: %d\r\n"
"NT: upnp:event\r\n" "NT: upnp:event\r\n"
"NTS: upnp:propchange\r\n" "NTS: upnp:propchange\r\n"
"SID: %s\r\n" "SID: %s\r\n"
"SEQ: %u\r\n" "SEQ: %u\r\n"
"Connection: close\r\n" "Connection: close\r\n"
"Cache-Control: no-cache\r\n" "Cache-Control: no-cache\r\n"
"\r\n" "\r\n"
"%.*s\r\n"; "%.*s\r\n";
char * xml; char * xml;
int l; int l;
if(obj->sub == NULL) {
obj->state = EError; assert(obj->sub);
return;
}
switch(obj->sub->service) { switch(obj->sub->service) {
case EContentDirectory: case EContentDirectory:
xml = getVarsContentDirectory(&l); xml = getVarsContentDirectory(&l);
break; break;
case EConnectionManager: case EConnectionManager:
xml = getVarsConnectionManager(&l); xml = getVarsConnectionManager(&l);
break; break;
case EMSMediaReceiverRegistrar: case EMSMediaReceiverRegistrar:
xml = getVarsX_MS_MediaReceiverRegistrar(&l); xml = getVarsX_MS_MediaReceiverRegistrar(&l);
break; break;
skipping to change at line 367 skipping to change at line 364
free(xml); free(xml);
DPRINTF(E_DEBUG, L_HTTP, "Sending UPnP Event response:\n%s\n", obj->buffe r); DPRINTF(E_DEBUG, L_HTTP, "Sending UPnP Event response:\n%s\n", obj->buffe r);
obj->state = ESending; obj->state = ESending;
} }
static void upnp_event_send(struct upnp_event_notify * obj) static void upnp_event_send(struct upnp_event_notify * obj)
{ {
int i; int i;
//DEBUG DPRINTF(E_DEBUG, L_HTTP, "Sending UPnP Event:\n%s", obj->buffer+o bj->sent); //DEBUG DPRINTF(E_DEBUG, L_HTTP, "Sending UPnP Event:\n%s", obj->buffer+o bj->sent);
while( obj->sent < obj->tosend ) { while( obj->sent < obj->tosend ) {
i = send(obj->s, obj->buffer + obj->sent, obj->tosend - obj->sent , 0); i = send(obj->ev.fd, obj->buffer + obj->sent, obj->tosend - obj-> sent, 0);
if(i<0) { if(i<0) {
DPRINTF(E_WARN, L_HTTP, "%s: send(): %s\n", "upnp_event_s end", strerror(errno)); DPRINTF(E_WARN, L_HTTP, "%s: send(): %s\n", "upnp_event_s end", strerror(errno));
obj->state = EError; obj->state = EError;
event_module.del(&obj->ev, 0);
return; return;
} }
obj->sent += i; obj->sent += i;
} }
if(obj->sent == obj->tosend) if(obj->sent == obj->tosend) {
obj->state = EWaitingForResponse; obj->state = EWaitingForResponse;
event_module.del(&obj->ev, 0);
obj->ev.rdwr = EVENT_READ;
event_module.add(&obj->ev);
}
} }
static void upnp_event_recv(struct upnp_event_notify * obj) static void upnp_event_recv(struct upnp_event_notify * obj)
{ {
int n; int n;
n = recv(obj->s, obj->buffer, obj->buffersize, 0); n = recv(obj->ev.fd, obj->buffer, obj->buffersize, 0);
if(n<0) { if(n<0) {
DPRINTF(E_ERROR, L_HTTP, "%s: recv(): %s\n", "upnp_event_recv", s trerror(errno)); DPRINTF(E_ERROR, L_HTTP, "%s: recv(): %s\n", "upnp_event_recv", s trerror(errno));
obj->state = EError; obj->state = EError;
event_module.del(&obj->ev, 0);
return; return;
} }
DPRINTF(E_DEBUG, L_HTTP, "%s: (%dbytes) %.*s\n", "upnp_event_recv", DPRINTF(E_DEBUG, L_HTTP, "%s: (%dbytes) %.*s\n", "upnp_event_recv",
n, n, obj->buffer); n, n, obj->buffer);
obj->state = EFinished; obj->state = EFinished;
event_module.del(&obj->ev, 0);
if(obj->sub) if(obj->sub)
{ {
obj->sub->seq++; obj->sub->seq++;
if (!obj->sub->seq) if (!obj->sub->seq)
obj->sub->seq++; obj->sub->seq++;
} }
} }
static void static void
upnp_event_process_notify(struct upnp_event_notify * obj) upnp_event_process_notify(struct event *ev)
{ {
struct upnp_event_notify *obj = ev->data;
switch(obj->state) { switch(obj->state) {
case EConnecting: case EConnecting:
/* now connected or failed to connect */ /* now connected or failed to connect */
upnp_event_prepare(obj); upnp_event_prepare(obj);
upnp_event_send(obj); upnp_event_send(obj);
break; break;
case ESending: case ESending:
upnp_event_send(obj); upnp_event_send(obj);
break; break;
case EWaitingForResponse: case EWaitingForResponse:
upnp_event_recv(obj); upnp_event_recv(obj);
break; break;
case EFinished: case EFinished:
close(obj->s); close(obj->ev.fd);
obj->s = -1; obj->ev.fd = -1;
break; break;
default: default:
DPRINTF(E_ERROR, L_HTTP, "upnp_event_process_notify: unknown stat e\n"); DPRINTF(E_ERROR, L_HTTP, "upnp_event_process_notify: unknown stat e\n");
} }
} }
void upnpevents_selectfds(fd_set *readset, fd_set *writeset, int * max_fd) void upnpevents_gc(void)
{
struct upnp_event_notify * obj;
for(obj = notifylist.lh_first; obj != NULL; obj = obj->entries.le_next) {
DPRINTF(E_DEBUG, L_HTTP, "upnpevents_selectfds: %p %d %d\n",
obj, obj->state, obj->s);
if(obj->s >= 0) {
switch(obj->state) {
case ECreated:
upnp_event_notify_connect(obj);
if(obj->state != EConnecting)
break;
case EConnecting:
case ESending:
FD_SET(obj->s, writeset);
if(obj->s > *max_fd)
*max_fd = obj->s;
break;
case EWaitingForResponse:
FD_SET(obj->s, readset);
if(obj->s > *max_fd)
*max_fd = obj->s;
break;
default:
break;
}
}
}
}
void upnpevents_processfds(fd_set *readset, fd_set *writeset)
{ {
struct upnp_event_notify * obj; struct upnp_event_notify * obj;
struct upnp_event_notify * next; struct upnp_event_notify * next;
struct subscriber * sub; struct subscriber * sub;
struct subscriber * subnext; struct subscriber * subnext;
time_t curtime; time_t curtime;
for(obj = notifylist.lh_first; obj != NULL; obj = obj->entries.le_next) {
DPRINTF(E_DEBUG, L_HTTP, "%s: %p %d %d %d %d\n",
"upnpevents_processfds", obj, obj->state, obj->s,
FD_ISSET(obj->s, readset), FD_ISSET(obj->s, writeset));
if(obj->s >= 0) {
if(FD_ISSET(obj->s, readset) || FD_ISSET(obj->s, writeset
))
upnp_event_process_notify(obj);
}
}
obj = notifylist.lh_first; obj = notifylist.lh_first;
while(obj != NULL) { while(obj != NULL) {
next = obj->entries.le_next; next = obj->entries.le_next;
if(obj->state == EError || obj->state == EFinished) { if(obj->state == EError || obj->state == EFinished) {
if(obj->s >= 0) { if(obj->ev.fd >= 0) {
close(obj->s); close(obj->ev.fd);
} }
if(obj->sub) if(obj->sub)
obj->sub->notify = NULL; obj->sub->notify = NULL;
/* remove also the subscriber from the list if there was an error */ /* remove also the subscriber from the list if there was an error */
if(obj->state == EError && obj->sub) { if(obj->state == EError && obj->sub) {
LIST_REMOVE(obj->sub, entries); LIST_REMOVE(obj->sub, entries);
nsubscribers--; nsubscribers--;
free(obj->sub); free(obj->sub);
} }
free(obj->buffer); free(obj->buffer);
 End of changes. 31 change blocks. 
86 lines changed or deleted 53 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)