minissdpc: add a libuv client
This commit is contained in:
parent
2656f41c7a
commit
9d574f6e79
|
@ -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.
|
|
@ -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 */
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
Loading…
Reference in New Issue