minissdpc: add a libuv client

This commit is contained in:
Nicolas Cornu 2019-01-31 10:42:30 +01:00
parent 2656f41c7a
commit 9d574f6e79
7 changed files with 503 additions and 0 deletions

11
miniupnpc-libuv/README Normal file
View File

@ -0,0 +1,11 @@
Here is a basic libuv implementation of minissdp client.
You can find an example find attached to test it.
BUILD
gcc -luv example.c minissdpc-libuv.c -o minissdpc
EXECUTION
./minissdpc /var/run/your.sock ssdp:all
This should print all find upnp services.

View File

@ -0,0 +1,54 @@
/* $Id: codelength.h,v 1.3 2011/07/30 13:10:05 nanard Exp $ */
/* Project : miniupnp
* Author : Thomas BERNARD
* copyright (c) 2005-2015 Thomas Bernard
* This software is subjet to the conditions detailed in the
* provided LICENCE file. */
#ifndef CODELENGTH_H_INCLUDED
#define CODELENGTH_H_INCLUDED
/* Encode length by using 7bit per Byte :
* Most significant bit of each byte specifies that the
* following byte is part of the code */
/* n : unsigned
* p : unsigned char *
*/
#define DECODELENGTH(n, p) n = 0; \
do { n = (n << 7) | (*p & 0x7f); } \
while((*(p++)&0x80) && (n<(1<<25)));
/* n : unsigned
* READ : function/macro to read one byte (unsigned char)
*/
#define DECODELENGTH_READ(n, READ) \
n = 0; \
do { \
unsigned char c; \
READ(c); \
n = (n << 7) | (c & 0x07f); \
if(!(c&0x80)) break; \
} while(n<(1<<25));
/* n : unsigned
* p : unsigned char *
* p_limit : unsigned char *
*/
#define DECODELENGTH_CHECKLIMIT(n, p, p_limit) \
n = 0; \
do { \
if((p) >= (p_limit)) break; \
n = (n << 7) | (*(p) & 0x7f); \
} while((*((p)++)&0x80) && (n<(1<<25)));
/* n : unsigned
* p : unsigned char *
*/
#define CODELENGTH(n, p) if(n>=268435456) *(p++) = (n >> 28) | 0x80; \
if(n>=2097152) *(p++) = (n >> 21) | 0x80; \
if(n>=16384) *(p++) = (n >> 14) | 0x80; \
if(n>=128) *(p++) = (n >> 7) | 0x80; \
*(p++) = n & 0x7f;
#endif /* CODELENGTH_H_INCLUDED */

55
miniupnpc-libuv/example.c Normal file
View File

@ -0,0 +1,55 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "minissdpc-libuv.h"
#include <uv.h>
void requestFinish2(void* session, void* userdata, struct UPNPDev* upnpdev)
{
struct UPNPDev* it = upnpdev;
while(it != NULL) {
printf("url = %s\n", it->descURL);
printf("st = %s\n", it->st);
printf("usn = %s\n", it->usn);
printf("\n");
it = it->pNext;
}
disconnectFromMiniSSDPD((uv_stream_t*)session);
}
void requestFinish(void* session, int success, void* userdata)
{
if (success == 0)
{
printf("Error while requesting results.\n");
return;
}
receiveDevicesFromMiniSSDPD(session, &requestFinish2, NULL);
}
void connect_cb(void* session, void* userdata)
{
if (session == 0) {
printf("Error while connecting\n");
return;
}
char* search = userdata;
int ret;
if ((ret = requestDevicesFromMiniSSDPD(session, search, &requestFinish, NULL)) != MINISSDPC_SUCCESS) {
printf("Error while requesting devices\n");
if (ret == MINISSDPC_INVALID_INPUT)
printf("Invalid input!!\n");
else if (ret == MINISSDPC_MEMORY_ERROR)
printf("Can't malloc?\n");
}
}
int main(int argc, char *argv[])
{
char* pipeName = argv[1];
char* search = argv[2];
connectToMiniSSDPD(pipeName, &connect_cb, search);
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
}

View File

@ -0,0 +1,270 @@
/* $Id: minissdpc.c,v 1.32 2016/10/07 09:04:36 nanard Exp $ */
/* vim: tabstop=4 shiftwidth=4 noexpandtab
* Project : miniupnp
* Web : http://miniupnp.free.fr/
* Author : Thomas BERNARD
* copyright (c) 2005-2019 Thomas Bernard
* This software is subjet to the conditions detailed in the
* provided LICENCE file. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "minissdpc-libuv.h"
#include "codelength.h"
#include <uv.h>
struct userdata_s
{
void* cb;
void* userdata;
};
static void connect_cb(uv_connect_t* req, int status)
{
uv_stream_t *stream = req->handle;
struct userdata_s *us = stream->data;
void(*user_connect_cb)(void*, void*) = us->cb;
if(status < 0)
user_connect_cb(0, us->userdata);
else
user_connect_cb(req->handle, us->userdata);
free(req);
free(us);
if(status < 0)
free(stream);
}
int
connectToMiniSSDPD(const char * socketpath, void(*user_connect_cb)(void* connect, void* userdata), void *userdata)
{
if(user_connect_cb == 0)
return MINISSDPC_INVALID_INPUT;
if(!socketpath)
socketpath = "/var/run/minissdpd.sock";
uv_pipe_t *p = malloc(sizeof(uv_pipe_t));
if(uv_pipe_init(uv_default_loop(), p, 1) < 0)
return MINISSDPC_SOCKET_ERROR;
uv_connect_t *conn = malloc(sizeof(uv_connect_t));
struct userdata_s *us = malloc(sizeof(struct userdata_s));
us->cb = user_connect_cb;
us->userdata = userdata;
p->data = us;
uv_pipe_connect(conn, p, socketpath, &connect_cb);
return MINISSDPC_SUCCESS;
}
static void
close_cb(uv_handle_t *handle)
{
free(handle);
}
MINIUPNP_LIBSPEC void
disconnectFromMiniSSDPD(void *session)
{
uv_close((uv_handle_t *)session, close_cb);
}
static void write_cb(uv_write_t* req, int status)
{
uv_stream_t* stream = req->handle;
struct userdata_s *us = stream->data;
void(*user_write_cb)(void*, int, void*) = us->cb;
user_write_cb(req->handle, status == 0, us->userdata);
// free(req->bufs->base);
free(req);
free(us);
}
MINIUPNP_LIBSPEC int
requestDevicesFromMiniSSDPD(void *session, const char * devtype, void(*requestFinish)(void *connect, int success, void* userdata), void* userdata)
{
char *buffer = malloc(256);
if(buffer == NULL)
{
return MINISSDPC_MEMORY_ERROR;
}
char *p = buffer;
unsigned int 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++;
unsigned int l = stsize;
CODELENGTH(l, p);
if(p + stsize > buffer + 256)
{
/* devtype is too long ! */
#ifdef DEBUG
fprintf(stderr, "devtype is too long ! stsize=%u sizeof(buffer)=%u\n",
stsize, (unsigned)sizeof(buffer));
#endif /* DEBUG */
free(buffer);
return MINISSDPC_INVALID_INPUT;
}
memcpy(p, devtype, stsize);
p += stsize;
uv_write_t *req = malloc(sizeof(uv_write_t));
if(req == NULL)
{
free(buffer);
return MINISSDPC_MEMORY_ERROR;
}
struct userdata_s *us = malloc(sizeof(struct userdata_s));
if(us == NULL)
{
free(req);
free(buffer);
return MINISSDPC_MEMORY_ERROR;
}
us->cb = requestFinish;
us->userdata = userdata;
uv_stream_t* stream = session;
stream->data = us;
uv_buf_t data[] =
{
{ .base = buffer, .len = p - buffer }
};
uv_write(req, stream, data, 1, write_cb);
return MINISSDPC_SUCCESS;
}
static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf)
{
buf->base = malloc(size);
buf->len = size;
}
static void read_cb(uv_stream_t *stream, ssize_t size, const uv_buf_t* buffer)
{
struct userdata_s *us = stream->data;
void(*user_write_cb)(void *connect, void *userdata, struct UPNPDev*) = us->cb;
struct UPNPDev * devlist = NULL;
char * p = buffer->base;
unsigned int i, ndev;
if(size == 0)
{
return;
}
if(size < 0)
{
user_write_cb(stream, us->userdata, devlist);
uv_read_stop(stream);
free(us);
stream->data = NULL;
return;
}
ndev = *p;
p++;
for(i = 0; i < ndev; i++)
{
unsigned int urlsize;
DECODELENGTH(urlsize, p);
char *url = NULL;
if(size != 0)
{
url = strndup(p, urlsize);
if(url == NULL)
break;
}
p += urlsize;
unsigned int stsize;
DECODELENGTH(stsize, p);
char *st = NULL;
if(size != 0)
{
st = strndup(p, stsize);
if(st == NULL)
{
free(url);
break;
}
}
p += stsize;
unsigned int usnsize;
DECODELENGTH(usnsize, p);
char *usn = NULL;
if(size != 0)
{
usn = strndup(p, usnsize);
if(usn == NULL)
{
free(url);
free(st);
break;
}
}
p += usnsize;
struct UPNPDev *tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize+usnsize);
if(tmp == NULL)
{
free(url);
free(st);
free(usn);
break;
}
tmp->pNext = devlist;
tmp->descURL = tmp->buffer;
tmp->st = tmp->buffer + 1 + urlsize;
tmp->usn = tmp->buffer + 1 + urlsize + 1 + stsize;
memcpy(tmp->descURL, url, urlsize+1);
memcpy(tmp->st, st, stsize+1);
memcpy(tmp->usn, usn, usnsize+1);
free(url);
free(st);
free(usn);
tmp->scope_id = 0; /* default value. scope_id is not available with MiniSSDPd */
devlist = tmp;
}
user_write_cb(stream, us->userdata, devlist);
uv_read_stop(stream);
stream->data = NULL;
free(us);
}
void
receiveDevicesFromMiniSSDPD(void *session, void(*requestFinish)(void *session, void *userdata, struct UPNPDev*), void* userdata)
{
struct userdata_s *us = malloc(sizeof(struct userdata_s));
us->cb = requestFinish;
us->userdata = userdata;
uv_stream_t *stream = session;
stream->data = us;
uv_read_start(stream, alloc_cb, read_cb);
}

View File

@ -0,0 +1,56 @@
/* $Id: minissdpc.h,v 1.6 2015/09/18 12:45:16 nanard Exp $ */
/* Project: miniupnp
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* Author: Thomas Bernard
* Copyright (c) 2005-2015 Thomas Bernard
* This software is subjects to the conditions detailed
* in the LICENCE file provided within this distribution */
#ifndef MINISSDPC_H_INCLUDED
#define MINISSDPC_H_INCLUDED
#include "miniupnpc_declspec.h"
#include "upnpdev.h"
/* error codes : */
#define MINISSDPC_SUCCESS (0)
#define MINISSDPC_UNKNOWN_ERROR (-1)
#define MINISSDPC_SOCKET_ERROR (-101)
#define MINISSDPC_MEMORY_ERROR (-102)
#define MINISSDPC_INVALID_INPUT (-103)
#define MINISSDPC_INVALID_SERVER_REPLY (-104)
#ifdef __cplusplus
extern "C" {
#endif
MINIUPNP_LIBSPEC int
connectToMiniSSDPD(const char *socketpath, void(*connect_cb)(void *session, void *userdata), void *userdata);
MINIUPNP_LIBSPEC void
disconnectFromMiniSSDPD(void *session);
MINIUPNP_LIBSPEC int
requestDevicesFromMiniSSDPD(void *session, const char *devtype, void(*requestFinish)(void *session, int success, void *userdata), void *userdata);
MINIUPNP_LIBSPEC void
receiveDevicesFromMiniSSDPD(void *session, void(*requestFinish)(void *session, void *userdata, struct UPNPDev *upnpdev), void *userdata);
/****
MINIUPNP_LIBSPEC struct UPNPDev *
getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath, int * error);
MINIUPNP_LIBSPEC struct UPNPDev *
ssdpDiscoverDevices(const char * const deviceTypes[],
int delay, const char * multicastif,
int localport,
int ipv6, unsigned char ttl,
int * error,
int searchalltypes);
****/
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,21 @@
#ifndef MINIUPNPC_DECLSPEC_H_INCLUDED
#define MINIUPNPC_DECLSPEC_H_INCLUDED
#if defined(_WIN32) && !defined(MINIUPNP_STATICLIB)
/* for windows dll */
#ifdef MINIUPNP_EXPORTS
#define MINIUPNP_LIBSPEC __declspec(dllexport)
#else
#define MINIUPNP_LIBSPEC __declspec(dllimport)
#endif
#else
#if defined(__GNUC__) && __GNUC__ >= 4
/* fix dynlib for OS X 10.9.2 and Apple LLVM version 5.0 */
#define MINIUPNP_LIBSPEC __attribute__ ((visibility ("default")))
#else
#define MINIUPNP_LIBSPEC
#endif
#endif
#endif /* MINIUPNPC_DECLSPEC_H_INCLUDED */

36
miniupnpc-libuv/upnpdev.h Normal file
View File

@ -0,0 +1,36 @@
/* $Id: upnpdev.h,v 1.1 2015/08/28 12:14:19 nanard Exp $ */
/* Project : miniupnp
* Web : http://miniupnp.free.fr/
* Author : Thomas BERNARD
* copyright (c) 2005-2018 Thomas Bernard
* This software is subjet to the conditions detailed in the
* provided LICENSE file. */
#ifndef UPNPDEV_H_INCLUDED
#define UPNPDEV_H_INCLUDED
#include "miniupnpc_declspec.h"
#ifdef __cplusplus
extern "C" {
#endif
struct UPNPDev {
struct UPNPDev * pNext;
char * descURL;
char * st;
char * usn;
unsigned int scope_id;
char buffer[3];
};
/* freeUPNPDevlist()
* free list returned by upnpDiscover() */
MINIUPNP_LIBSPEC void freeUPNPDevlist(struct UPNPDev * devlist);
#ifdef __cplusplus
}
#endif
#endif /* UPNPDEV_H_INCLUDED */