/* SubmitServicesToMiniSSDPD() : * register services offered by MiniUPnPd to a running instance of * MiniSSDPd */ int SubmitServicesToMiniSSDPD(const char * host, unsigned short port) { struct sockaddr_un addr; int s; unsigned char buffer[2048]; char strbuf[256]; unsigned char * p; int i, l; s = socket(AF_UNIX, SOCK_STREAM, 0); if(s < 0) { NP_UPNP_ERROR("socket(unix): %s\n", strerror(errno)); return -1; } addr.sun_family = AF_UNIX; strncpy(addr.sun_path, minissdpdsocketpath, sizeof(addr.sun_path)); if(connect(s, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0) { NP_UPNP_ERROR("connect(\"%s\"): %s\n", minissdpdsocketpath, strerror(errno)); close(s); return -1; } for(i = 0; known_service_types[i]; i++) { buffer[0] = 4; p = buffer + 1; l = (int)strlen(known_service_types[i]); if(i > 0) l++; CODELENGTH(l, p); memcpy(p, known_service_types[i], l); if(i > 0) p[l-1] = '1'; p += l; l = snprintf(strbuf, sizeof(strbuf), "%s::%s%s", uuidvalue, known_service_types[i], (i==0)?"":"1"); CODELENGTH(l, p); memcpy(p, strbuf, l); p += l; l = (int)strlen(MINIUPNPD_SERVER_STRING); CODELENGTH(l, p); memcpy(p, MINIUPNPD_SERVER_STRING, l); p += l; l = snprintf(strbuf, sizeof(strbuf), "http://%s:%u" ROOTDESC_PATH, host, (unsigned int)port); CODELENGTH(l, p); memcpy(p, strbuf, l); p += l; if(write(s, buffer, p - buffer) < 0) { NP_UPNP_ERROR("write(): %s", strerror(errno)); /*BEGIN 3082010042 y00248130 2013-8-22 added/modified*/ close(s); /* END 3082010042 y00248130 2013-8-22 added/modified*/ return -1; } } close(s); return 0; }
char * writeString(char * p, const char * string) { int stringLen = (int)strlen(string); CODELENGTH(stringLen, p); memcpy(p, string, stringLen); p += stringLen; return p; }
int main(int argc, char * * argv) { unsigned char buf[256]; unsigned char * p; long i, j; (void)argc; (void)argv; for(i = 1; i < 1000000000; i *= 2) { /* encode i, decode to j */ printf("%ld ", i); p = buf; CODELENGTH(i, p); p = buf; DECODELENGTH(j, p); if(i != j) { fprintf(stderr, "Error ! encoded %ld, decoded %ld.\n", i, j); return 1; } } printf("Test succesful\n"); return 0; }
int requestDevicesFromMiniSSDPD(int s, const char * devtype) { unsigned char buffer[256]; unsigned char * p; unsigned int stsize, l; stsize = strlen(devtype); if(stsize == 8 && 0 == memcmp(devtype, "ssdp:all", 8)) { buffer[0] = 3; /* request type 3 : everything */ } else { buffer[0] = 1; /* request type 1 : request devices/services by type */ } p = buffer + 1; l = stsize; CODELENGTH(l, p); if(p + stsize > buffer + sizeof(buffer)) { /* devtype is too long ! */ #ifdef DEBUG fprintf(stderr, "devtype is too long ! stsize=%u sizeof(buffer)=%u\n", stsize, (unsigned)sizeof(buffer)); #endif /* DEBUG */ return MINISSDPC_INVALID_INPUT; } memcpy(p, devtype, stsize); p += stsize; if(write(s, buffer, p - buffer) < 0) { /*syslog(LOG_ERR, "write(): %m");*/ perror("minissdpc.c: write()"); return MINISSDPC_SOCKET_ERROR; } return MINISSDPC_SUCCESS; }
/* processRequest() : * process the request coming from a unix socket */ void processRequest(struct reqelem * req) { ssize_t n; unsigned int l, m; unsigned char buf[2048]; const unsigned char * p; int type; struct device * d = devlist; unsigned char rbuf[4096]; unsigned char * rp = rbuf+1; unsigned char nrep = 0; time_t t; struct service * newserv = NULL; struct service * serv; n = read(req->socket, buf, sizeof(buf)); if(n<0) { syslog(LOG_ERR, "(s=%d) processRequest(): read(): %m", req->socket); goto error; } if(n==0) { syslog(LOG_INFO, "(s=%d) request connection closed", req->socket); goto error; } t = time(NULL); type = buf[0]; p = buf + 1; DECODELENGTH_CHECKLIMIT(l, p, buf + n); if(p+l > buf+n) { syslog(LOG_WARNING, "bad request (length encoding)"); goto error; } if(l == 0) { syslog(LOG_WARNING, "bad request (length=0)"); goto error; } syslog(LOG_INFO, "(s=%d) request type=%d str='%.*s'", req->socket, type, l, p); switch(type) { case 1: case 2: case 3: while(d && (nrep < 255)) { if(d->t < t) { syslog(LOG_INFO, "outdated device"); } else { /* test if we can put more responses in the buffer */ if(d->headers[HEADER_LOCATION].l + d->headers[HEADER_NT].l + d->headers[HEADER_USN].l + 6 + (rp - rbuf) >= sizeof(rbuf)) break; if( (type==1 && 0==memcmp(d->headers[HEADER_NT].p, p, l)) ||(type==2 && 0==memcmp(d->headers[HEADER_USN].p, p, l)) ||(type==3) ) { /* response : * 1 - Location * 2 - NT (device/service type) * 3 - usn */ m = d->headers[HEADER_LOCATION].l; CODELENGTH(m, rp); memcpy(rp, d->headers[HEADER_LOCATION].p, d->headers[HEADER_LOCATION].l); rp += d->headers[HEADER_LOCATION].l; m = d->headers[HEADER_NT].l; CODELENGTH(m, rp); memcpy(rp, d->headers[HEADER_NT].p, d->headers[HEADER_NT].l); rp += d->headers[HEADER_NT].l; m = d->headers[HEADER_USN].l; CODELENGTH(m, rp); memcpy(rp, d->headers[HEADER_USN].p, d->headers[HEADER_USN].l); rp += d->headers[HEADER_USN].l; nrep++; } } d = d->next; } /* Also look in service list */ for(serv = servicelisthead.lh_first; serv && (nrep < 255); serv = serv->entries.le_next) { /* test if we can put more responses in the buffer */ if(strlen(serv->location) + strlen(serv->st) + strlen(serv->usn) + 6 + (rp - rbuf) >= sizeof(rbuf)) break; if( (type==1 && 0==strncmp(serv->st, (const char *)p, l)) ||(type==2 && 0==strncmp(serv->usn, (const char *)p, l)) ||(type==3) ) { /* response : * 1 - Location * 2 - NT (device/service type) * 3 - usn */ m = strlen(serv->location); CODELENGTH(m, rp); memcpy(rp, serv->location, m); rp += m; m = strlen(serv->st); CODELENGTH(m, rp); memcpy(rp, serv->st, m); rp += m; m = strlen(serv->usn); CODELENGTH(m, rp); memcpy(rp, serv->usn, m); rp += m; nrep++; } } rbuf[0] = nrep; if(write(req->socket, rbuf, rp - rbuf) < 0) { syslog(LOG_ERR, "(s=%d) write: %m", req->socket); goto error; } break; case 4: newserv = malloc(sizeof(struct service)); if(!newserv) { syslog(LOG_ERR, "cannot allocate memory"); goto error; } if(containsForbiddenChars(p, l)) { syslog(LOG_ERR, "bad request (st contains forbidden chars)"); goto error; } newserv->st = malloc(l + 1); if(!newserv->st) { syslog(LOG_ERR, "cannot allocate memory"); goto error; } memcpy(newserv->st, p, l); newserv->st[l] = '\0'; p += l; if(p >= buf + n) { syslog(LOG_WARNING, "bad request (missing usn)"); goto error; } DECODELENGTH_CHECKLIMIT(l, p, buf + n); if(p+l > buf+n) { syslog(LOG_WARNING, "bad request (length encoding)"); goto error; } if(containsForbiddenChars(p, l)) { syslog(LOG_ERR, "bad request (usn contains forbidden chars)"); goto error; } syslog(LOG_INFO, "usn='%.*s'", l, p); newserv->usn = malloc(l + 1); if(!newserv->usn) { syslog(LOG_ERR, "cannot allocate memory"); goto error; } memcpy(newserv->usn, p, l); newserv->usn[l] = '\0'; p += l; DECODELENGTH_CHECKLIMIT(l, p, buf + n); if(p+l > buf+n) { syslog(LOG_WARNING, "bad request (length encoding)"); goto error; } if(containsForbiddenChars(p, l)) { syslog(LOG_ERR, "bad request (server contains forbidden chars)"); goto error; } syslog(LOG_INFO, "server='%.*s'", l, p); newserv->server = malloc(l + 1); if(!newserv->server) { syslog(LOG_ERR, "cannot allocate memory"); goto error; } memcpy(newserv->server, p, l); newserv->server[l] = '\0'; p += l; DECODELENGTH_CHECKLIMIT(l, p, buf + n); if(p+l > buf+n) { syslog(LOG_WARNING, "bad request (length encoding)"); goto error; } if(containsForbiddenChars(p, l)) { syslog(LOG_ERR, "bad request (location contains forbidden chars)"); goto error; } syslog(LOG_INFO, "location='%.*s'", l, p); newserv->location = malloc(l + 1); if(!newserv->location) { syslog(LOG_ERR, "cannot allocate memory"); goto error; } memcpy(newserv->location, p, l); newserv->location[l] = '\0'; /* look in service list for duplicate */ for(serv = servicelisthead.lh_first; serv; serv = serv->entries.le_next) { if(0 == strcmp(newserv->usn, serv->usn) && 0 == strcmp(newserv->st, serv->st)) { syslog(LOG_INFO, "Service allready in the list. Updating..."); free(newserv->st); free(newserv->usn); free(serv->server); serv->server = newserv->server; free(serv->location); serv->location = newserv->location; free(newserv); newserv = NULL; return; } } /* Inserting new service */ LIST_INSERT_HEAD(&servicelisthead, newserv, entries); newserv = NULL; /*rbuf[0] = '\0'; if(write(req->socket, rbuf, 1) < 0) syslog(LOG_ERR, "(s=%d) write: %m", req->socket); */ break; default: syslog(LOG_WARNING, "Unknown request type %d", type); rbuf[0] = '\0'; if(write(req->socket, rbuf, 1) < 0) { syslog(LOG_ERR, "(s=%d) write: %m", req->socket); goto error; } } return; error: if(newserv) { free(newserv->st); free(newserv->usn); free(newserv->server); free(newserv->location); free(newserv); newserv = NULL; } close(req->socket); req->socket = -1; return; }
struct UPNPDev * getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath) { struct UPNPDev * tmp; struct UPNPDev * devlist = NULL; unsigned char buffer[2048]; ssize_t n; unsigned char * p; unsigned char * url; unsigned int i; unsigned int urlsize, stsize, usnsize, l; int s; struct sockaddr_un addr; s = socket(AF_UNIX, SOCK_STREAM, 0); if(s < 0) { /*syslog(LOG_ERR, "socket(unix): %m");*/ perror("socket(unix)"); return NULL; } addr.sun_family = AF_UNIX; strncpy(addr.sun_path, socketpath, sizeof(addr.sun_path)); /* TODO : check if we need to handle the EINTR */ if(connect(s, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0) { /*syslog(LOG_WARNING, "connect(\"%s\"): %m", socketpath);*/ close(s); return NULL; } stsize = strlen(devtype); buffer[0] = 1; /* request type 1 : request devices/services by type */ p = buffer + 1; l = stsize; CODELENGTH(l, p); if(p + stsize > buffer + sizeof(buffer)) { /* devtype is too long ! */ close(s); return NULL; } memcpy(p, devtype, stsize); p += stsize; if(write(s, buffer, p - buffer) < 0) { /*syslog(LOG_ERR, "write(): %m");*/ perror("minissdpc.c: write()"); close(s); return NULL; } n = read(s, buffer, sizeof(buffer)); if(n<=0) { perror("minissdpc.c: read()"); close(s); return NULL; } p = buffer + 1; for(i = 0; i < buffer[0]; i++) { if(p+2>=buffer+sizeof(buffer)) break; DECODELENGTH(urlsize, p); if(p+urlsize+2>=buffer+sizeof(buffer)) break; url = p; p += urlsize; DECODELENGTH(stsize, p); if(p+stsize+2>=buffer+sizeof(buffer)) break; tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize); tmp->pNext = devlist; tmp->descURL = tmp->buffer; tmp->st = tmp->buffer + 1 + urlsize; memcpy(tmp->buffer, url, urlsize); tmp->buffer[urlsize] = '\0'; memcpy(tmp->buffer + urlsize + 1, p, stsize); p += stsize; tmp->buffer[urlsize+1+stsize] = '\0'; devlist = tmp; /* added for compatibility with recent versions of MiniSSDPd * >= 2007/12/19 */ DECODELENGTH(usnsize, p); p += usnsize; if(p>buffer + sizeof(buffer)) break; } close(s); return devlist; }
/* SubmitServicesToMiniSSDPD() : * register services offered by MiniUPnPd to a running instance of * MiniSSDPd */ int SubmitServicesToMiniSSDPD(const char * host, unsigned short port) { struct sockaddr_un addr; int s; unsigned char buffer[2048]; char strbuf[256]; unsigned char * p; int i, l, n; char ver_str[4]; s = socket(AF_UNIX, SOCK_STREAM, 0); if(s < 0) { syslog(LOG_ERR, "socket(unix): %m"); return -1; } addr.sun_family = AF_UNIX; strncpy(addr.sun_path, minissdpdsocketpath, sizeof(addr.sun_path)); if(connect(s, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0) { syslog(LOG_ERR, "connect(\"%s\"): %m", minissdpdsocketpath); close(s); return -1; } for(i = 0; known_service_types[i].s; i++) { buffer[0] = 4; /* request type 4 : submit service */ /* 4 strings following : ST (service type), USN, Server, Location */ p = buffer + 1; l = (int)strlen(known_service_types[i].s); if(i > 0) l++; CODELENGTH(l, p); memcpy(p, known_service_types[i].s, l); if(i > 0) p[l-1] = '1'; p += l; if(i==0) ver_str[0] = '\0'; else snprintf(ver_str, sizeof(ver_str), "%d", known_service_types[i].version); l = snprintf(strbuf, sizeof(strbuf), "%s::%s%s", known_service_types[i].uuid, known_service_types[i].s, ver_str); if(l<0) { syslog(LOG_WARNING, "SubmitServicesToMiniSSDPD: snprintf %m"); continue; } else if((unsigned)l>=sizeof(strbuf)) { l = sizeof(strbuf) - 1; } CODELENGTH(l, p); memcpy(p, strbuf, l); p += l; l = (int)strlen(MINIUPNPD_SERVER_STRING); CODELENGTH(l, p); memcpy(p, MINIUPNPD_SERVER_STRING, l); p += l; l = snprintf(strbuf, sizeof(strbuf), "http://%s:%u" ROOTDESC_PATH, host, (unsigned int)port); if(l<0) { syslog(LOG_WARNING, "SubmitServicesToMiniSSDPD: snprintf %m"); continue; } else if((unsigned)l>=sizeof(strbuf)) { l = sizeof(strbuf) - 1; } CODELENGTH(l, p); memcpy(p, strbuf, l); p += l; /* now write the encoded data */ n = p - buffer; /* bytes to send */ p = buffer; /* start */ while(n > 0) { l = write(s, p, n); if (l < 0) { if(errno == EINTR) continue; syslog(LOG_ERR, "write(): %m"); close(s); return -1; } else if (l == 0) { syslog(LOG_ERR, "write() returned 0"); close(s); return -1; } p += l; n -= l; } } close(s); return 0; }