minissdpd: Properly parse when several requests are read() at once

This commit is contained in:
Thomas Bernard 2018-02-03 18:24:11 +01:00
parent 7f17837253
commit b11ed5a37e
1 changed files with 65 additions and 18 deletions

View File

@ -48,6 +48,9 @@
#include "asyncsendto.h"
#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 */
struct reqelem {
@ -539,15 +542,36 @@ processMSEARCH(int s, const char * st, int st_len,
}
}
} else {
/* find matching services */
int l;
int st_ver = 0;
char atoi_buffer[8];
/* remove version at the end of the ST string */
if(st[st_len-2]==':' && isdigit(st[st_len-1]))
st_len -= 2;
for (l = st_len; l > 0; l--) {
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 */
/* 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;
serv;
serv = serv->entries.le_next) {
if(0 == strncmp(serv->st, st, st_len)) {
syslog(LOG_DEBUG, "Found matching service : %s %s", serv->st, serv->usn);
SendSSDPMSEARCHResponse(s, addr,
serv->st, serv->usn,
serv->server, serv->location);
@ -820,22 +844,15 @@ OpenUnixSocket(const char * path)
return s;
}
static ssize_t processRequestSub(struct reqelem * req, const unsigned char * buf, ssize_t n);
/* processRequest() :
* process the request coming from a unix socket */
void processRequest(struct reqelem * req)
{
ssize_t n;
unsigned int l, m;
ssize_t n, r;
unsigned char buf[2048];
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));
if(n<0) {
@ -848,6 +865,34 @@ void processRequest(struct reqelem * req)
syslog(LOG_INFO, "(s=%d) request connection closed", req->socket);
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);
type = buf[0];
p = buf + 1;
@ -874,6 +919,7 @@ void processRequest(struct reqelem * req)
syslog(LOG_ERR, "(s=%d) write: %m", req->socket);
goto error;
}
p += l;
break;
case MINISSDPD_SEARCH_TYPE: /* request by type */
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);
goto error;
}
p += l;
break;
case MINISSDPD_SUBMIT: /* submit service */
newserv = malloc(sizeof(struct service));
@ -1026,6 +1073,7 @@ void processRequest(struct reqelem * req)
}
memcpy(newserv->location, p, l);
newserv->location[l] = '\0';
p += l;
/* look in service list for duplicate */
for(serv = servicelisthead.lh_first;
serv;
@ -1041,7 +1089,7 @@ void processRequest(struct reqelem * req)
serv->location = newserv->location;
free(newserv);
newserv = NULL;
return;
return (p - buf);
}
}
/* Inserting new service */
@ -1056,6 +1104,7 @@ void processRequest(struct reqelem * req)
goto error;
}
req->is_notify = 1;
p += l;
break;
default:
syslog(LOG_WARNING, "Unknown request type %d", type);
@ -1065,7 +1114,7 @@ void processRequest(struct reqelem * req)
goto error;
}
}
return;
return (p - buf);
error:
if(newserv) {
free(newserv->st);
@ -1075,9 +1124,7 @@ error:
free(newserv);
newserv = NULL;
}
close(req->socket);
req->socket = -1;
return;
return -1;
}
static volatile sig_atomic_t quitting = 0;