minissdpd: Properly parse when several requests are read() at once
This commit is contained in:
parent
7f17837253
commit
b11ed5a37e
|
@ -48,6 +48,9 @@
|
||||||
#include "asyncsendto.h"
|
#include "asyncsendto.h"
|
||||||
|
|
||||||
#define SET_MAX(max, x) if((x) > (max)) (max) = (x)
|
#define SET_MAX(max, x) if((x) > (max)) (max) = (x)
|
||||||
|
#ifndef MIN
|
||||||
|
#define MIN(x,y) (((x)<(y))?(x):(y))
|
||||||
|
#endif
|
||||||
|
|
||||||
/* current request management structure */
|
/* current request management structure */
|
||||||
struct reqelem {
|
struct reqelem {
|
||||||
|
@ -539,15 +542,36 @@ processMSEARCH(int s, const char * st, int st_len,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* find matching services */
|
int l;
|
||||||
|
int st_ver = 0;
|
||||||
|
char atoi_buffer[8];
|
||||||
|
|
||||||
/* remove version at the end of the ST string */
|
/* remove version at the end of the ST string */
|
||||||
if(st[st_len-2]==':' && isdigit(st[st_len-1]))
|
for (l = st_len; l > 0; l--) {
|
||||||
st_len -= 2;
|
if (st[l-1] == ':') {
|
||||||
|
memset(atoi_buffer, 0, sizeof(atoi_buffer));
|
||||||
|
memcpy(atoi_buffer, st + l, MIN((int)(sizeof(atoi_buffer) - 1), st_len - l));
|
||||||
|
st_ver = atoi(atoi_buffer);
|
||||||
|
st_len = l - 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
/* answer for each matching service */
|
/* answer for each matching service */
|
||||||
|
/* From UPnP Device Architecture v1.1 :
|
||||||
|
* 1.3.2 [...] Updated versions of device and service types
|
||||||
|
* are REQUIRED to be full backward compatible with
|
||||||
|
* previous versions. Devices MUST respond to M-SEARCH
|
||||||
|
* requests for any supported version. For example, if a
|
||||||
|
* device implements “urn:schemas-upnporg:service:xyz:2”,
|
||||||
|
* it MUST respond to search requests for both that type
|
||||||
|
* and “urn:schemas-upnp-org:service:xyz:1”. The response
|
||||||
|
* MUST specify the same version as was contained in the
|
||||||
|
* search request. [...] */
|
||||||
for(serv = servicelisthead.lh_first;
|
for(serv = servicelisthead.lh_first;
|
||||||
serv;
|
serv;
|
||||||
serv = serv->entries.le_next) {
|
serv = serv->entries.le_next) {
|
||||||
if(0 == strncmp(serv->st, st, st_len)) {
|
if(0 == strncmp(serv->st, st, st_len)) {
|
||||||
|
syslog(LOG_DEBUG, "Found matching service : %s %s", serv->st, serv->usn);
|
||||||
SendSSDPMSEARCHResponse(s, addr,
|
SendSSDPMSEARCHResponse(s, addr,
|
||||||
serv->st, serv->usn,
|
serv->st, serv->usn,
|
||||||
serv->server, serv->location);
|
serv->server, serv->location);
|
||||||
|
@ -820,22 +844,15 @@ OpenUnixSocket(const char * path)
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ssize_t processRequestSub(struct reqelem * req, const unsigned char * buf, ssize_t n);
|
||||||
|
|
||||||
/* processRequest() :
|
/* processRequest() :
|
||||||
* process the request coming from a unix socket */
|
* process the request coming from a unix socket */
|
||||||
void processRequest(struct reqelem * req)
|
void processRequest(struct reqelem * req)
|
||||||
{
|
{
|
||||||
ssize_t n;
|
ssize_t n, r;
|
||||||
unsigned int l, m;
|
|
||||||
unsigned char buf[2048];
|
unsigned char buf[2048];
|
||||||
const unsigned char * p;
|
const unsigned char * p;
|
||||||
enum request_type type;
|
|
||||||
struct device * d = devlist;
|
|
||||||
unsigned char rbuf[RESPONSE_BUFFER_SIZE];
|
|
||||||
unsigned char * rp;
|
|
||||||
unsigned char nrep = 0;
|
|
||||||
time_t t;
|
|
||||||
struct service * newserv = NULL;
|
|
||||||
struct service * serv;
|
|
||||||
|
|
||||||
n = read(req->socket, buf, sizeof(buf));
|
n = read(req->socket, buf, sizeof(buf));
|
||||||
if(n<0) {
|
if(n<0) {
|
||||||
|
@ -848,6 +865,34 @@ void processRequest(struct reqelem * req)
|
||||||
syslog(LOG_INFO, "(s=%d) request connection closed", req->socket);
|
syslog(LOG_INFO, "(s=%d) request connection closed", req->socket);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
p = buf;
|
||||||
|
while (n > 0)
|
||||||
|
{
|
||||||
|
r = processRequestSub(req, p, n);
|
||||||
|
if (r < 0)
|
||||||
|
goto error;
|
||||||
|
p += r;
|
||||||
|
n -= r;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
error:
|
||||||
|
close(req->socket);
|
||||||
|
req->socket = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t processRequestSub(struct reqelem * req, const unsigned char * buf, ssize_t n)
|
||||||
|
{
|
||||||
|
unsigned int l, m;
|
||||||
|
const unsigned char * p;
|
||||||
|
enum request_type type;
|
||||||
|
struct device * d = devlist;
|
||||||
|
unsigned char rbuf[RESPONSE_BUFFER_SIZE];
|
||||||
|
unsigned char * rp;
|
||||||
|
unsigned char nrep = 0;
|
||||||
|
time_t t;
|
||||||
|
struct service * newserv = NULL;
|
||||||
|
struct service * serv;
|
||||||
|
|
||||||
t = time(NULL);
|
t = time(NULL);
|
||||||
type = buf[0];
|
type = buf[0];
|
||||||
p = buf + 1;
|
p = buf + 1;
|
||||||
|
@ -874,6 +919,7 @@ void processRequest(struct reqelem * req)
|
||||||
syslog(LOG_ERR, "(s=%d) write: %m", req->socket);
|
syslog(LOG_ERR, "(s=%d) write: %m", req->socket);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
p += l;
|
||||||
break;
|
break;
|
||||||
case MINISSDPD_SEARCH_TYPE: /* request by type */
|
case MINISSDPD_SEARCH_TYPE: /* request by type */
|
||||||
case MINISSDPD_SEARCH_USN: /* request by USN (unique id) */
|
case MINISSDPD_SEARCH_USN: /* request by USN (unique id) */
|
||||||
|
@ -949,6 +995,7 @@ void processRequest(struct reqelem * req)
|
||||||
syslog(LOG_ERR, "(s=%d) write: %m", req->socket);
|
syslog(LOG_ERR, "(s=%d) write: %m", req->socket);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
p += l;
|
||||||
break;
|
break;
|
||||||
case MINISSDPD_SUBMIT: /* submit service */
|
case MINISSDPD_SUBMIT: /* submit service */
|
||||||
newserv = malloc(sizeof(struct service));
|
newserv = malloc(sizeof(struct service));
|
||||||
|
@ -1026,6 +1073,7 @@ void processRequest(struct reqelem * req)
|
||||||
}
|
}
|
||||||
memcpy(newserv->location, p, l);
|
memcpy(newserv->location, p, l);
|
||||||
newserv->location[l] = '\0';
|
newserv->location[l] = '\0';
|
||||||
|
p += l;
|
||||||
/* look in service list for duplicate */
|
/* look in service list for duplicate */
|
||||||
for(serv = servicelisthead.lh_first;
|
for(serv = servicelisthead.lh_first;
|
||||||
serv;
|
serv;
|
||||||
|
@ -1041,7 +1089,7 @@ void processRequest(struct reqelem * req)
|
||||||
serv->location = newserv->location;
|
serv->location = newserv->location;
|
||||||
free(newserv);
|
free(newserv);
|
||||||
newserv = NULL;
|
newserv = NULL;
|
||||||
return;
|
return (p - buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Inserting new service */
|
/* Inserting new service */
|
||||||
|
@ -1056,6 +1104,7 @@ void processRequest(struct reqelem * req)
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
req->is_notify = 1;
|
req->is_notify = 1;
|
||||||
|
p += l;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
syslog(LOG_WARNING, "Unknown request type %d", type);
|
syslog(LOG_WARNING, "Unknown request type %d", type);
|
||||||
|
@ -1065,7 +1114,7 @@ void processRequest(struct reqelem * req)
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return (p - buf);
|
||||||
error:
|
error:
|
||||||
if(newserv) {
|
if(newserv) {
|
||||||
free(newserv->st);
|
free(newserv->st);
|
||||||
|
@ -1075,9 +1124,7 @@ error:
|
||||||
free(newserv);
|
free(newserv);
|
||||||
newserv = NULL;
|
newserv = NULL;
|
||||||
}
|
}
|
||||||
close(req->socket);
|
return -1;
|
||||||
req->socket = -1;
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static volatile sig_atomic_t quitting = 0;
|
static volatile sig_atomic_t quitting = 0;
|
||||||
|
|
Loading…
Reference in New Issue