M7350v7_en_gpl

This commit is contained in:
T
2024-09-09 08:59:52 +00:00
parent f75098198c
commit 46ba6f09ec
1372 changed files with 1231198 additions and 1184 deletions

View File

@ -0,0 +1,22 @@
LOCAL_PATH := $(call my-dir)
#########################
SOURCES = minixml.c \
upnphttp.c \
upnpreplyparse.c \
upnpsoap.c \
mini_upnp.c
#########################
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_PRELINK_MODULE := false
LOCAL_SRC_FILES := $(SOURCES)
LOCAL_MODULE := lib_mini_upnp
LOCAL_CFLAGS := -Os -Wall -D__ANDROID__
LOCAL_C_INCLUDES:=$(LOCAL_PATH)/../include
include $(BUILD_SHARED_LIBRARY)

View File

@ -0,0 +1,95 @@
# $Id: Makefile,v 1.2 2009/01/13 02:50:10 bradhuang Exp $
.SUFFIXES:
.SUFFIXES: .o .c
.PHONY: clean all depend
LIBS =
INCS = -I$(TOP_USERS_DIR)/include
#CFLAGS = -g -O2 -Wall
CFLAGS := -Os -Wall $(CFLAGS) $(INCS)
CPPFLAGS = -I. -I.
DEPEND = .depend
LDFLAGS += -g -s
#CC = rsdk-linux-gcc
#CC = $(CROSS_COMPILE)gcc
CPP = gcc -E
#AR = rsdk-linux-ar
#AR = $(CROSS_COMPILE)ar
SOURCES = minixml.c, upnphttp.c, upnpreplyparse.c, upnpsoap.c \
mini_upnp.c
OBJS = $(SOURCES:.c=.o)
UPNP_DAEMON = mini_upnpd
# For mini_upnp stand alone
STATIC_LIB=1
ifeq ($(STATIC_LIB),1)
########## Build Static Library ##################
all: mini_upnp.a
UPNP_LIB = mini_upnp.a
mini_upnp.a: mini_upnp.o minixml.o upnphttp.o upnpreplyparse.o upnpsoap.o
$(AR) rcs $@ mini_upnp.o minixml.o upnphttp.o upnpreplyparse.o upnpsoap.o
else
########## Build Shared Library ##################
all: $(UPNP_DAEMON) $(UPNP_LIB)
UPNP_LIB = mini_upnp.so
CFLAGS += -DUSE_SHARED_DAEMON
minixml.o: minixml.c
$(CC) -c -o $@ -fpic $(CFLAGS) $(IFLAGS) $<
upnphttp.o: upnphttp.c
$(CC) -c -o $@ -fpic $(CFLAGS) $(IFLAGS) $<
upnpreplyparse.o: upnpreplyparse.c
$(CC) -c -o $@ -fpic $(CFLAGS) $(IFLAGS) $<
upnpsoap.o: upnpsoap.c
$(CC) -c -o $@ -fpic $(CFLAGS) $(IFLAGS) $<
$(UPNP_LIB): minixml.o upnphttp.o upnpreplyparse.o upnpsoap.o
$(CC) -s -shared -o $@ minixml.o upnphttp.o upnpreplyparse.o upnpsoap.o
$(UPNP_DAEMON): mini_upnp.o $(UPNP_LIB)
$(CC) -o $@ $(APMIB_LIB) $^ $(LDFLAGS) $(LIBS)
endif
clean:
rm -f *.o *.so *.a $(UPNP_DAEMON)
romfs:
ifeq ($(STATIC_LIB),1)
@echo "Do nothing here."
else
$(ROMFSINST) mini_upnpd /bin/mini_upnpd
$(ROMFSINST) mini_upnp.so /lib/mini_upnp.so
endif
# depend stuff
depend: $(SOURCES)
$(CPP) $(CPPFLAGS) -MM $^ > $(DEPEND)
-include $(DEPEND)
# tags
tags: $(SOURCES)
ctags -o tags $^ *.h
.c.o:
$(CC) -c -o $@ $(CFLAGS) $(IFLAGS) $<

View File

@ -0,0 +1,964 @@
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <sys/file.h>
#include <syslog.h>
#include <sys/time.h>
#include <time.h>
#include <signal.h>
/* for BSD's sysctl */
#include <sys/param.h>
#ifndef __ANDROID__
#include <sys/sysctl.h>
#endif
#include "upnphttp.h"
#include "mini_upnp.h"
#include "upnpreplyparse.h"
/* ip et port pour le SSDP */
static int ssdpPort=1900;//#define PORT (1900)
#define UPNP_MCAST_ADDR ("239.255.255.250")
#ifdef USE_SHARED_DAEMON
#include <sys/stat.h>
#if 0
#define DEBUG_PRINT(fmt, args...) printf(fmt, ## args)
#else
#define DEBUG_PRINT(fmt, args...)
#endif
static daemon_CTX_Tp pGlobalCtx;
static char *Get_start(const unsigned long addr)
{
char *pos;
pos = (char *)addr;
while (*pos == ' ' || *pos == '\r' || *pos == '\n')
pos++;
return pos;
}
static char *Get_end(const unsigned long addr)
{
char *pos;
pos = (char *)addr;
while (*pos != ' ' && *pos != '\r' && *pos != '\n')
pos++;
return pos;
}
static int parse_ssdp_file(const char *line, const int len, device_CTX_Tp device)
{
unsigned long string_begin=0;
unsigned long string_end=0;
unsigned long file_end=0;
unsigned long file_pos=0;
char tmp[10];
unsigned char num_service=0;
char *service_name;
if (line == NULL || len == 0 || device == NULL)
return -1;
file_pos = (unsigned long) line;
file_end = file_pos + len;
while (file_pos < file_end) {
if (strncmp((char *)file_pos, "port", 4) == 0) {
string_begin = (unsigned long)Get_start(file_pos+4);
string_end = (unsigned long)Get_end(string_begin);
if (string_end <= string_begin)
return -1;
memset(tmp, 0, 10);
memcpy(tmp, (char *)string_begin, string_end - string_begin);
device->port = atoi(tmp);
file_pos = string_end;
continue;
}
else if (strncmp((char *)file_pos, "max_age", 7) == 0) {
string_begin = (unsigned long)Get_start(file_pos+7);
string_end = (unsigned long)Get_end(string_begin);
if (string_end <= string_begin)
return -1;
memset(tmp, 0, 10);
memcpy(tmp, (char *)string_begin, string_end - string_begin);
device->ctx.max_age = atoi(tmp);
device->ctx.alive_timeout = device->ctx.max_age / 2;
file_pos = string_end;
continue;
}
else if (strncmp((char *)file_pos, "uuid", 4) == 0) {
string_begin = (unsigned long)Get_start(file_pos+4);
string_end = (unsigned long)Get_end(string_begin);
if (string_end <= string_begin)
return -1;
memcpy(device->ctx.uuid, (char *)string_begin, string_end - string_begin);
file_pos = string_end;
continue;
}
else if (strncmp((char *)file_pos, "root_desc_name", 14) == 0) {
string_begin = (unsigned long)Get_start(file_pos+14);
string_end = (unsigned long)Get_end(string_begin);
if (string_end <= string_begin)
return -1;
memcpy(device->ctx.root_desc_name, (char *)string_begin, string_end - string_begin);
file_pos = string_end;
continue;
}
else if (strncmp((char *)file_pos, "known_service_types", 19) == 0) {
string_begin = (unsigned long)Get_start(file_pos+19);
string_end = (unsigned long)Get_end(string_begin);
if (string_end <= string_begin)
return -1;
service_name = (char *) malloc(string_end - string_begin + 1);
if (service_name == NULL) {
int i;
for (i=0; i < MAX_NUMBER_OF_Service; i++) {
if (device->known_service_types[i])
free(device->known_service_types[i]);
}
return -1;
}
memset(service_name, 0, string_end - string_begin + 1);
memcpy(service_name, (char *)string_begin, string_end - string_begin);
device->known_service_types[num_service] = service_name;
num_service++;
file_pos = string_end;
continue;
}
file_pos++;
}
device->ctx.known_service_types = device->known_service_types;
return 0;
}
static int get_file(char *fname, device_CTX_Tp pDevCtx)
{
char *ssdp_file;
int len, ret;
if ((ssdp_file = mini_UPnP_UploadXML(fname)) != NULL) {
len = strlen(ssdp_file);
ret = parse_ssdp_file(ssdp_file, len, pDevCtx);
free(ssdp_file);
if (ret != -1)
return 1;
}
return 0;
}
static int parse_argument(daemon_CTX_Tp pCtx, int argc, char *argv[])
{
int argNum=1;
IPCon ipcon=NULL;
char *wsc_file=NULL, *igd_file=NULL;
int wait_time=5, is_ok;
char wsc_file_old[200], igd_file_old[200];
while (argNum < argc) {
if (!strcmp(argv[argNum], "-interface")) {
if (++argNum >= argc)
break;
strcpy(pCtx->interfacename, argv[argNum]);
}
else if (!strcmp(argv[argNum], "-wsc")) {
if (++argNum >= argc)
break;
if (pCtx->num_device >= MAX_NUMBER_OF_DEVICE) {
printf("The max number of supported devices is %d!\n", MAX_NUMBER_OF_DEVICE);
return -1;
}
wsc_file = argv[argNum];
strcpy(wsc_file_old, wsc_file);
strcat(wsc_file_old, ".old");
}
else if ( !strcmp(argv[argNum], "-igd")) {
if (++argNum >= argc)
break;
if (pCtx->num_device >= MAX_NUMBER_OF_DEVICE) {
printf("The max number of supported devices is %d!\n", MAX_NUMBER_OF_DEVICE);
return -1;
}
igd_file = argv[argNum];
strcpy(igd_file_old, igd_file);
strcat(igd_file_old, ".old");
}
else if ( !strcmp(argv[argNum], "-daemon")) {
pCtx->daemon = 1;
}
else if ( !strcmp(argv[argNum], "-p")) {
if (++argNum >= argc)
break;
ssdpPort=atoi(argv[argNum]);
if((ssdpPort<0)||(ssdpPort>65535))
{
printf("Wrong -p option: port number should be 0~65535!\n");
return -1;
}
}
argNum++;
}
while (wait_time-- > 0 && (wsc_file || igd_file)) {
if (wsc_file) {
is_ok = 0;
if (!get_file(wsc_file, &pCtx->device[pCtx->num_device])) {
if (get_file(wsc_file_old, &pCtx->device[pCtx->num_device]))
is_ok = 2;
}
else {
is_ok = 1;
rename(wsc_file, wsc_file_old);
}
if (is_ok) {
pCtx->device[pCtx->num_device].used = DEVICE_WSC;
strcpy(pCtx->device[pCtx->num_device].SSDP_file_name, WSCD_BYEBYE_FILE);
strcpy(pCtx->device[pCtx->num_device].input_file_name, wsc_file);
DEBUG_PRINT("Mini_upnpd: Read file [%s] success!\n", ((is_ok == 1) ? wsc_file : wsc_file_old));
pCtx->num_device++;
wsc_file = NULL;
}
}
if (igd_file) {
is_ok = 0;
if (!get_file(igd_file, &pCtx->device[pCtx->num_device])) {
if (get_file(igd_file_old, &pCtx->device[pCtx->num_device]))
is_ok = 2;
}
else {
is_ok = 1;
rename(igd_file, igd_file_old);
}
if (is_ok) {
pCtx->device[pCtx->num_device].used = DEVICE_IGD;
strcpy(pCtx->device[pCtx->num_device].SSDP_file_name, IGD_BYEBYE_FILE);
strcpy(pCtx->device[pCtx->num_device].input_file_name, igd_file);
DEBUG_PRINT("Mini_upnpd: Read file [%s] success!\n", ((is_ok == 1) ? igd_file : igd_file_old));
pCtx->num_device++;
igd_file = NULL;
}
}
sleep(1);
}
if (pCtx->interfacename[0] == 0) {
strcpy(pCtx->interfacename, "bridge0");
}
ipcon = IPCon_New(pCtx->interfacename);
if (ipcon == NULL) {
printf("Error in IPCon_New!\n");
return -1;
}
strcpy(pCtx->lan_ip_address, IPCon_GetIpAddrByStr(ipcon));
IPCon_Destroy(ipcon);
return 0;
}
static void free_resource(daemon_CTX_Tp pCtx)
{
int i, j;
for (i=0; i<MAX_NUMBER_OF_DEVICE; i++)
for (j=0; j<MAX_NUMBER_OF_Service; j++) {
if (pCtx->device[i].known_service_types[j])
free(pCtx->device[i].known_service_types[j]);
}
if (pCtx->sudp >= 0)
close(pCtx->sudp);
if (pCtx->snotify >= 0)
close(pCtx->snotify);
free(pCtx);
}
static void sigHandler_alarm(int signo) {
daemon_CTX_Tp pCtx=pGlobalCtx;
unsigned char device_num=0;
FILE *fp = NULL;
struct stat status;
char tmpbuf[100];
for (device_num=0; device_num<MAX_NUMBER_OF_DEVICE; device_num++) {
if (pCtx->device[device_num].used == 0)
continue;
if (get_file(pCtx->device[device_num].input_file_name, &pCtx->device[device_num])) {
DEBUG_PRINT("Mini_upnpd-Alarm: Read file [%s] success!\n", pCtx->device[device_num].input_file_name);
// when wscd case ; don't send "bye-bye+alive " for fix windows7 IOT issue;
if(strcmp(pCtx->device[device_num].input_file_name , (WIFI_WPS_TMP_DIR "/wscd_config")))
{
SendSSDPNotifies(pCtx->snotify, pCtx->lan_ip_address, pCtx->device[device_num].port,
&pCtx->device[device_num].ctx, 1, 1);
SendSSDPNotifies(pCtx->snotify, pCtx->lan_ip_address, pCtx->device[device_num].port,
&pCtx->device[device_num].ctx, 0, pCtx->device[device_num].ctx.max_age);
}
strcpy(tmpbuf, pCtx->device[device_num].input_file_name);
strcat(tmpbuf, ".old");
rename(pCtx->device[device_num].input_file_name, tmpbuf);
}
if (pCtx->device[device_num].ctx.alive_timeout > 0 && --pCtx->device[device_num].ctx.alive_timeout <= 0) {
//sending alive
SendSSDPNotifies(pCtx->snotify, pCtx->lan_ip_address, pCtx->device[device_num].port,
&pCtx->device[device_num].ctx, 0, pCtx->device[device_num].ctx.max_age);
pCtx->device[device_num].ctx.alive_timeout = pCtx->device[device_num].ctx.max_age/2;
}
//check whether the bye-bye file is there
if (stat(pCtx->device[device_num].SSDP_file_name, &status) != 0)
continue;
if ((fp = fopen(pCtx->device[device_num].SSDP_file_name, "r")) != NULL) {
int event=0;
unsigned char line[3];
memset(line, 0, 3);
fgets(line, sizeof(line), fp);
if (sscanf(line, "%d", &event)) {
if (event == 1) {
//sending byebye
SendSSDPNotifies(pCtx->snotify, pCtx->lan_ip_address, pCtx->device[device_num].port,
&pCtx->device[device_num].ctx, 1, 1);
//syslog(LOG_INFO, "Sending bye bye...");
DEBUG_PRINT("Sending bye bye...\n");
//sending alive
SendSSDPNotifies(pCtx->snotify, pCtx->lan_ip_address, pCtx->device[device_num].port,
&pCtx->device[device_num].ctx, 0, pCtx->device[device_num].ctx.max_age);
//syslog(LOG_INFO, "Sending Advertisement...");
DEBUG_PRINT("Sending Advertisement...\n");
pCtx->device[device_num].ctx.alive_timeout = pCtx->device[device_num].ctx.max_age/2;
}
else if (event == 2) {
//sending byebye
SendSSDPNotifies(pCtx->snotify, pCtx->lan_ip_address, pCtx->device[device_num].port,
&pCtx->device[device_num].ctx, 1, 1);
//syslog(LOG_INFO, "Sending bye bye...");
DEBUG_PRINT("Sending bye bye...\n");
}
}
fclose(fp);
remove(pCtx->device[device_num].SSDP_file_name);
}
}
alarm(1);
}
int main(int argc, char *argv[])
{
daemon_CTX_Tp pCtx=NULL;
unsigned char device_num=0;
int selret;
fd_set netFD;
/* Allocate context */
pCtx = (daemon_CTX_Tp) calloc(1, sizeof(daemon_CTX_T));
if (pCtx == NULL) {
printf("allocate context failed!\n");
return 0;
}
pGlobalCtx = pCtx;
pCtx->sudp = -1;
pCtx->snotify = -1;
// sleep(3);
if (parse_argument(pCtx, argc, argv) < 0) {
printf("Parse argument failed!\n");
free_resource(pCtx);
return 0;
}
if (pCtx->num_device <= 0) {
DEBUG_PRINT("Number of device is 0!\n");
free_resource(pCtx);
return 0;
}
if (pCtx->daemon) {
if (daemon(0,1) == -1) {
printf("fork mini_upnp daemon error!\n");
return 0;
}
}
#if 0
int openlog_option;
int debug_flag = 1;
openlog_option = LOG_PID|LOG_CONS;
if(debug_flag)
openlog_option |= LOG_PERROR; /* also log on stderr */
openlog("mini_upnpd", openlog_option, LOG_USER/*LOG_LOCAL0*/);
#endif
DEBUG_PRINT("Interface name : %s\n", pCtx->interfacename);
DEBUG_PRINT("IP : %s\n", pCtx->lan_ip_address);
DEBUG_PRINT("Number of devices : %d\n", pCtx->num_device);
for (device_num=0; device_num<MAX_NUMBER_OF_DEVICE; device_num++) {
if (pCtx->device[device_num].used) {
DEBUG_PRINT("Device port : %d\n", pCtx->device[device_num].port);
DEBUG_PRINT("\t%s\n", pCtx->device[device_num].ctx.uuid);
DEBUG_PRINT("\tmax_age : %d\n", pCtx->device[device_num].ctx.max_age);
DEBUG_PRINT("\troot_desc_name : %s\n", pCtx->device[device_num].ctx.root_desc_name);
int i=0;
while (pCtx->device[device_num].ctx.known_service_types[i]) {
DEBUG_PRINT("\t%s%s\n", pCtx->device[device_num].ctx.known_service_types[i],
(i==0?"":"1"));
i++;
}
}
}
/* socket d'ecoute pour le SSDP */
pCtx->sudp = OpenAndConfUdpSocket(pCtx->lan_ip_address);
if (pCtx->sudp < 0)
{
printf("Failed to open socket for SSDP. EXITING\n");
free_resource(pCtx);
return 0;
}
/* open socket for sending notifications */
pCtx->snotify = OpenAndConfNotifySocket(pCtx->lan_ip_address);
if (pCtx->snotify < 0)
{
printf("Failed to open socket for SSDP notify messages\n");
free_resource(pCtx);
return 0;
}
signal(SIGALRM, sigHandler_alarm);
for (device_num=0; device_num<MAX_NUMBER_OF_DEVICE; device_num++) {
//sending byebye
if (pCtx->device[device_num].used)
SendSSDPNotifies(pCtx->snotify, pCtx->lan_ip_address, pCtx->device[device_num].port,
&pCtx->device[device_num].ctx, 1, 1);
}
sleep(1);
for (device_num=0; device_num<MAX_NUMBER_OF_DEVICE; device_num++) {
//sending alive
if (pCtx->device[device_num].used)
SendSSDPNotifies(pCtx->snotify, pCtx->lan_ip_address, pCtx->device[device_num].port,
&pCtx->device[device_num].ctx, 0, pCtx->device[device_num].ctx.max_age);
}
/* Start one second timer */
alarm(1);
while (1) {
FD_ZERO(&netFD);
if (pCtx->sudp >= 0)
FD_SET(pCtx->sudp, &netFD);
selret = select(pCtx->sudp+1, &netFD, NULL, NULL, NULL);
if (selret >= 0) {
if(pCtx->sudp >= 0 && FD_ISSET(pCtx->sudp, &netFD))
{
ProcessSSDPRequest(pCtx);
}
}
}
}
#endif
static int AddMulticastMembership(int s, const char * ifaddr)
{
struct ip_mreq imr; /* Ip multicast membership */
/* setting up imr structure */
imr.imr_multiaddr.s_addr = inet_addr(UPNP_MCAST_ADDR);
/*imr.imr_interface.s_addr = htonl(INADDR_ANY);*/
imr.imr_interface.s_addr = inet_addr(ifaddr);
if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&imr, sizeof(struct ip_mreq)) < 0)
{
syslog(LOG_ERR, "setsockopt(udp, IP_ADD_MEMBERSHIP): %m");
return -1;
}
return 0;
}
int OpenAndConfUdpSocket(const char * ifaddr)
{
int s, onOff=1;
struct sockaddr_in sockname;
if( (s = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
{
syslog(LOG_ERR, "socket(udp): %m");
return -1;
}
if( setsockopt( s, SOL_SOCKET, SO_REUSEADDR, (char *)&onOff, sizeof(onOff) ) != 0 ) {
syslog(LOG_ERR, "setsockopt(udp): %m");
return -1;
}
memset(&sockname, 0, sizeof(struct sockaddr_in));
sockname.sin_family = AF_INET;
sockname.sin_port = htons(ssdpPort);//PORT=>ssdpPort
/* NOTE : it seems it doesnt work when binding on the specific address */
/*sockname.sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR);*/
sockname.sin_addr.s_addr = htonl(INADDR_ANY);
/*sockname.sin_addr.s_addr = inet_addr(ifaddr);*/
if(bind(s, (struct sockaddr *)&sockname, sizeof(struct sockaddr_in)) < 0)
{
syslog(LOG_ERR, "bind(udp): %m");
close(s);
return -1;
}
if(AddMulticastMembership(s, ifaddr) < 0)
{
close(s);
return -1;
}
return s;
}
/* open the UDP socket used to send SSDP notifications to
* the multicast group reserved for them */
int OpenAndConfNotifySocket(const char * addr)
{
int s;
unsigned char loopchar = 0;
struct in_addr mc_if;
struct sockaddr_in sockname;
if( (s = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
{
syslog(LOG_ERR, "socket(udp_notify): %m");
return -1;
}
mc_if.s_addr = inet_addr(addr);
if(setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&loopchar, sizeof(loopchar)) < 0)
{
syslog(LOG_ERR, "setsockopt(udp_notify, IP_MULTICAST_LOOP): %m");
close(s);
return -1;
}
if(setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, (char *)&mc_if, sizeof(mc_if)) < 0)
{
syslog(LOG_ERR, "setsockopt(udp_notify, IP_MULTICAST_IF): %m");
close(s);
return -1;
}
memset(&sockname, 0, sizeof(struct sockaddr_in));
sockname.sin_family = AF_INET;
sockname.sin_addr.s_addr = inet_addr(addr);
if (bind(s, (struct sockaddr *)&sockname, sizeof(struct sockaddr_in)) < 0)
{
syslog(LOG_ERR, "bind(udp_notify): %m");
close(s);
return -1;
}
return s;
}
/*
* response from a LiveBox (Wanadoo)
HTTP/1.1 200 OK
CACHE-CONTROL: max-age=1800
DATE: Thu, 01 Jan 1970 04:03:23 GMT
EXT:
LOCATION: http://192.168.0.1:49152/gatedesc.xml
SERVER: Linux/2.4.17, UPnP/1.0, Intel SDK for UPnP devices /1.2
ST: upnp:rootdevice
USN: uuid:75802409-bccb-40e7-8e6c-fa095ecce13e::upnp:rootdevice
* response from a Linksys 802.11b :
HTTP/1.1 200 OK
Cache-Control:max-age=120
Location:http://192.168.5.1:5678/rootDesc.xml
Server:NT/5.0 UPnP/1.0
ST:upnp:rootdevice
USN:uuid:upnp-InternetGatewayDevice-1_0-0090a2777777::upnp:rootdevice
EXT:
*/
/* not really an SSDP "announce" as it is the response
* to a SSDP "M-SEARCH" */
void SendSSDPAnnounce2(int s, struct sockaddr_in sockname,
const char * st, int st_len,
const char * host, unsigned short port,
SSDP_CTX_Tp SSDP)
{
int l, n;
char *buf=NULL;
/* TODO :
* follow guideline from document "UPnP Device Architecture 1.0"
* put in uppercase.
* DATE: is recommended
* SERVER: OS/ver UPnP/1.0 miniupnpd/1.0
* */
if (st == NULL || host == NULL || SSDP == NULL)
return;
buf = (char *) malloc(512);
if (buf == NULL) {
syslog(LOG_ERR, "SendSSDPAnnounce2: out of memory!");
return;
}
memset(buf, 0, 512);
/*CVE-2021-35392*/
//l = sprintf(buf,
l = snprintf(buf,512,
"HTTP/1.1 200 OK\r\n"
"Cache-Control: max-age=%d\r\n"
"ST: %.*s\r\n"
"USN: %s::%.*s\r\n"
"EXT:\r\n"
"Server: " MINIUPNPD_SERVER_STRING "\r\n"
"Location: http://%s:%u/%s.xml" "\r\n"
"\r\n",
SSDP->max_age,
st_len, st,
SSDP->uuid, st_len, st,
host, (unsigned int)port, SSDP->root_desc_name);
n = sendto(s, buf, l, 0,
(struct sockaddr *)&sockname, sizeof(struct sockaddr_in) );
if(n<0)
{
syslog(LOG_ERR, "sendto: %m");
}
free(buf);
}
// type = 0 (alive); type = 1 (byebye)
void SendSSDPNotifies(int s, const char * host, unsigned short port,
SSDP_CTX_Tp SSDP,
unsigned char type, unsigned int max_age)
{
struct sockaddr_in sockname;
int n, i, j;
char *bufr=NULL;
if (host == NULL || SSDP->root_desc_name == NULL || SSDP->uuid == NULL ||
SSDP->known_service_types == NULL)
return;
bufr = (char *) malloc(512);
if (bufr == NULL) {
syslog(LOG_ERR, "SendSSDPNotifies: out of memory!");
return;
}
memset(bufr, 0, 512);
memset(&sockname, 0, sizeof(struct sockaddr_in));
sockname.sin_family = AF_INET;
sockname.sin_port = htons(ssdpPort);//PORT=>ssdpPort
sockname.sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR);
for (j=0; j <2; j++) {
i = 0;
while(SSDP->known_service_types[i])
{
if (i == 1) {
snprintf(bufr,512, \
"NOTIFY * HTTP/1.1\r\n"
"Host:%s:%d\r\n"
"Cache-Control:max-age=%d\r\n"
"Location:http://%s:%d/%s.xml" "\r\n"
"Server:" MINIUPNPD_SERVER_STRING "\r\n"
"NT:%s\r\n"
"USN:%s\r\n"
"NTS:ssdp:%s\r\n"
"\r\n",
UPNP_MCAST_ADDR, ssdpPort, max_age,//PORT=>ssdpPort
host, port, SSDP->root_desc_name,
SSDP->uuid,
SSDP->uuid,
(type==0?"alive":"byebye"));
n = sendto(s, bufr, strlen(bufr), 0,
(struct sockaddr *)&sockname, sizeof(struct sockaddr_in) );
if(n<0)
{
syslog(LOG_ERR, "sendto: %m");
}
}
snprintf(bufr,512, \
"NOTIFY * HTTP/1.1\r\n"
"Host:%s:%d\r\n"
"Cache-Control:max-age=%d\r\n"
"Location:http://%s:%d/%s.xml" "\r\n"
"Server:" MINIUPNPD_SERVER_STRING "\r\n"
"NT:%s%s\r\n"
"USN:%s::%s%s\r\n"
"NTS:ssdp:%s\r\n"
"\r\n",
UPNP_MCAST_ADDR, ssdpPort, max_age,//PORT=>ssdpPort
host, port, SSDP->root_desc_name,
SSDP->known_service_types[i], (i==0?"":"1"),
SSDP->uuid, SSDP->known_service_types[i], (i==0?"":"1"),
(type==0?"alive":"byebye"));
n = sendto(s, bufr, strlen(bufr), 0,
(struct sockaddr *)&sockname, sizeof(struct sockaddr_in) );
if(n<0)
{
syslog(LOG_ERR, "sendto: %m");
}
i++;
}
}
free(bufr);
}
#ifdef USE_SHARED_DAEMON
void ProcessSSDPRequest(daemon_CTX_Tp pCtx)
{
int n;
char *bufr=NULL;
socklen_t len_r;
struct sockaddr_in sendername;
int i, l, j;
char * st = 0;
int st_len = 0;
if (pCtx == NULL)
return;
bufr = (char *) malloc(2048);
if (bufr == NULL) {
syslog(LOG_ERR, "ProcessSSDPRequest: out of memory!");
return;
}
memset(bufr, 0, 2048);
len_r = sizeof(struct sockaddr_in);
n = recvfrom(pCtx->sudp, bufr, 2048, 0,
(struct sockaddr *)&sendername, &len_r);
if(n<0)
{
syslog(LOG_ERR, "recvfrom: %m");
free(bufr);
return;
}
if(memcmp(bufr, "NOTIFY", 6) == 0)
{
/* ignore NOTIFY packets. We could log the sender and device type */
free(bufr);
return;
}
else if(memcmp(bufr, "M-SEARCH", 8) == 0)
{
i = 0;
while(i<n)
{
while(bufr[i] != '\r' || bufr[i+1] != '\n')
i++;
i += 2;
if(strncasecmp(bufr+i, "st:", 3) == 0)
{
st = bufr+i+3;
st_len = 0;
while(*st == ' ' || *st == '\t') st++;
while(st[st_len]!='\r' && st[st_len]!='\n') st_len++;
/*syslog(LOG_INFO, "ST: %.*s", st_len, st);*/
/*j = 0;*/
/*while(bufr[i+j]!='\r') j++;*/
/*syslog(LOG_INFO, "%.*s", j, bufr+i);*/
}
}
/*syslog(LOG_INFO, "SSDP M-SEARCH packet received from %s:%d",
inet_ntoa(sendername.sin_addr),
ntohs(sendername.sin_port) );*/
if(st)
{
for (j=0; j<MAX_NUMBER_OF_DEVICE; j++) {
if (pCtx->device[j].used) {
i = 0;
while(pCtx->device[j].known_service_types[i])
{
l = (int)strlen(pCtx->device[j].known_service_types[i]);
if(l<=st_len && (0 == memcmp(st, pCtx->device[j].known_service_types[i], l)))
{
/* TODO : doesnt answer at once but wait for a random time */
/*syslog(LOG_INFO, "ST: %.*s", st_len, st);*/
syslog(LOG_INFO, "SSDP M-SEARCH from %s:%d ST: %.*s",
inet_ntoa(sendername.sin_addr),
ntohs(sendername.sin_port),
st_len, st);
SendSSDPAnnounce2(pCtx->sudp, sendername, st, st_len, pCtx->lan_ip_address, pCtx->device[j].port,
&pCtx->device[j].ctx);
break;
}
i++;
}
l = (int)strlen(pCtx->device[j].ctx.uuid);
if(l==st_len && (0 == memcmp(st, pCtx->device[j].ctx.uuid, l)))
{
/* TODO : doesnt answer at once but wait for a random time */
/*syslog(LOG_INFO, "ST: %.*s", st_len, st);*/
syslog(LOG_INFO, "SSDP M-SEARCH from %s:%d ST: %.*s",
inet_ntoa(sendername.sin_addr),
ntohs(sendername.sin_port),
st_len, st);
SendSSDPAnnounce2(pCtx->sudp, sendername, st, st_len, pCtx->lan_ip_address, pCtx->device[j].port,
&pCtx->device[j].ctx);
}
}
}
}
else
{
syslog(LOG_INFO, "invalid SSDP M-SEARCH from %s:%d",
inet_ntoa(sendername.sin_addr),
ntohs(sendername.sin_port) );
}
}
else
{
syslog(LOG_NOTICE, "Unknown udp packet received from %s:%d",
inet_ntoa(sendername.sin_addr),
ntohs(sendername.sin_port) );
}
free(bufr);
}
#else
void ProcessSSDPRequest(int s, const char * host, unsigned short port,
SSDP_CTX_Tp SSDP)
{
int n;
char *bufr=NULL;
socklen_t len_r;
struct sockaddr_in sendername;
int i, l;
char * st = 0;
int st_len = 0;
if (SSDP == NULL || host == NULL)
return;
bufr = (char *) malloc(2048);
if (bufr == NULL) {
syslog(LOG_ERR, "ProcessSSDPRequest: out of memory!");
return;
}
memset(bufr, 0, 2048);
len_r = sizeof(struct sockaddr_in);
n = recvfrom(s, bufr, 2048, 0,
(struct sockaddr *)&sendername, &len_r);
if(n<0)
{
syslog(LOG_ERR, "recvfrom: %m");
free(bufr);
return;
}
if(memcmp(bufr, "NOTIFY", 6) == 0)
{
/* ignore NOTIFY packets. We could log the sender and device type */
free(bufr);
return;
}
else if(memcmp(bufr, "M-SEARCH", 8) == 0)
{
i = 0;
while(i<n)
{
while(bufr[i] != '\r' || bufr[i+1] != '\n')
i++;
i += 2;
if(strncasecmp(bufr+i, "st:", 3) == 0)
{
st = bufr+i+3;
st_len = 0;
while(*st == ' ' || *st == '\t') st++;
while(st[st_len]!='\r' && st[st_len]!='\n') st_len++;
/*syslog(LOG_INFO, "ST: %.*s", st_len, st);*/
/*j = 0;*/
/*while(bufr[i+j]!='\r') j++;*/
/*syslog(LOG_INFO, "%.*s", j, bufr+i);*/
}
}
/*syslog(LOG_INFO, "SSDP M-SEARCH packet received from %s:%d",
inet_ntoa(sendername.sin_addr),
ntohs(sendername.sin_port) );*/
if(st)
{
i = 0;
while(SSDP->known_service_types[i])
{
l = (int)strlen(SSDP->known_service_types[i]);
if(l<=st_len && (0 == memcmp(st, SSDP->known_service_types[i], l)))
{
/* TODO : doesnt answer at once but wait for a random time */
/*syslog(LOG_INFO, "ST: %.*s", st_len, st);*/
syslog(LOG_INFO, "SSDP M-SEARCH from %s:%d ST: %.*s",
inet_ntoa(sendername.sin_addr),
ntohs(sendername.sin_port),
st_len, st);
SendSSDPAnnounce2(s, sendername, st, st_len, host, port,
SSDP);
break;
}
i++;
}
l = (int)strlen(SSDP->uuid);
if(l==st_len && (0 == memcmp(st, SSDP->uuid, l)))
{
/* TODO : doesnt answer at once but wait for a random time */
/*syslog(LOG_INFO, "ST: %.*s", st_len, st);*/
syslog(LOG_INFO, "SSDP M-SEARCH from %s:%d ST: %.*s",
inet_ntoa(sendername.sin_addr),
ntohs(sendername.sin_port),
st_len, st);
SendSSDPAnnounce2(s, sendername, st, st_len, host, port,
SSDP);
}
}
else
{
syslog(LOG_INFO, "invalid SSDP M-SEARCH from %s:%d",
inet_ntoa(sendername.sin_addr),
ntohs(sendername.sin_port) );
}
}
else
{
syslog(LOG_NOTICE, "Unknown udp packet received from %s:%d",
inet_ntoa(sendername.sin_addr),
ntohs(sendername.sin_port) );
}
free(bufr);
}
#endif

View File

@ -0,0 +1,78 @@
#ifndef MINI_UPNP_H
#define MINI_UPNP_H
#include <sys/queue.h>
#include "mini_upnp_global.h"
#include "upnphttp.h"
#include "rtk_arch.h"
typedef struct SSDP_context {
char **known_service_types;
char root_desc_name[100];
char uuid[42];
unsigned int max_age;
unsigned int alive_timeout;
} SSDP_CTX_T, *SSDP_CTX_Tp;
#ifdef USE_SHARED_DAEMON
#define MAX_NUMBER_OF_DEVICE 2
#define MAX_NUMBER_OF_Service 10
#define WSCD_BYEBYE_FILE (WIFI_WPS_TMP_DIR "/wscd_byebye")
#define IGD_BYEBYE_FILE ("/tmp/igd_byebye")
enum { DEVICE_UNUSED=0, DEVICE_IGD=1, DEVICE_WSC=2 };
typedef struct device_context {
unsigned char used;
int port;
char SSDP_file_name[30];
SSDP_CTX_T ctx;
char *known_service_types[MAX_NUMBER_OF_Service];
char input_file_name[40];
} device_CTX_T, *device_CTX_Tp;
typedef struct daemon_context {
char lan_ip_address[IP_ADDRLEN];
char interfacename[20];
unsigned char num_device;
device_CTX_T device[MAX_NUMBER_OF_DEVICE];
int sudp;
int snotify;
int daemon; // run as daemon
} daemon_CTX_T, *daemon_CTX_Tp;
#endif
typedef struct mini_upnp_context {
LIST_HEAD(httplisthead, upnphttp) upnphttphead;
SSDP_CTX_T SSDP;
char lan_ip_address[IP_ADDRLEN];
struct _soapMethods *soapMethods;
struct _sendDesc *sendDesc;
struct upnp_subscription_record subscribe_list;
int port;
int sudp;
int shttpl;
int snotify;
char *rootXML;
unsigned int rootXML_len;
char *serviceXML;
unsigned int serviceXML_len;
} mini_upnp_CTX_T, *mini_upnp_CTX_Tp;
extern int OpenAndConfUdpSocket(const char * ifaddr);
extern int OpenAndConfNotifySocket(const char * addr);
extern void SendSSDPAnnounce2(int s, struct sockaddr_in sockname,
const char * st, int st_len,
const char * host, unsigned short port,
SSDP_CTX_Tp SSDP);
extern void SendSSDPNotifies(int s, const char * host, unsigned short port,
SSDP_CTX_Tp SSDP,
unsigned char type, unsigned int max_age);
#ifdef USE_SHARED_DAEMON
extern void ProcessSSDPRequest(daemon_CTX_Tp pCtx);
#else
extern void ProcessSSDPRequest(int s, const char * host, unsigned short port, SSDP_CTX_Tp SSDP);
#endif
#endif

View File

@ -0,0 +1,18 @@
#ifndef _MINI_UPNP_GLOBAL_H
#define _MINI_UPNP_GLOBAL_H
/* Server: HTTP header returned in all HTTP responses : */
#define MINIUPNPD_SERVER_STRING "OS 1.0 UPnP/1.0 Realtek/V1.3"
#define IP_ADDRLEN 17
#define SID_LEN 44
#define URL_MAX_LEN 200
#define IP_V4_DOT_COUNT 3
#define MAX_SUB_TIMEOUT 7200
#define BOOLEAN char
#define TRUE (1==1)
#define FALSE (1==0)
#define syslog(x, fmt, args...);
#endif

View File

@ -0,0 +1,160 @@
#include "minixml.h"
/* parseatt : used to parse the argument list
* return 0 (false) in case of success and -1 (true) if the end
* of the xmlbuffer is reached. */
int parseatt(struct xmlparser * p)
{
const char * attname;
int attnamelen;
const char * attvalue;
int attvaluelen;
while(p->xml < p->xmlend)
{
if(*p->xml=='/' || *p->xml=='>')
return 0;
if( !IS_WHITE_SPACE(*p->xml) )
{
char sep;
attname = p->xml;
attnamelen = 0;
while(*p->xml!='=' && !IS_WHITE_SPACE(*p->xml) )
{
attnamelen++; p->xml++;
if(p->xml >= p->xmlend)
return -1;
}
while(*(p->xml++) != '=')
{
if(p->xml >= p->xmlend)
return -1;
}
while(IS_WHITE_SPACE(*p->xml))
{
p->xml++;
if(p->xml >= p->xmlend)
return -1;
}
sep = *p->xml;
if(sep=='\'' || sep=='\"')
{
p->xml++;
if(p->xml >= p->xmlend)
return -1;
attvalue = p->xml;
attvaluelen = 0;
while(*p->xml != sep)
{
attvaluelen++; p->xml++;
if(p->xml >= p->xmlend)
return -1;
}
}
else
{
attvalue = p->xml;
attvaluelen = 0;
while( !IS_WHITE_SPACE(*p->xml)
&& *p->xml != '>' && *p->xml != '/')
{
attvaluelen++; p->xml++;
if(p->xml >= p->xmlend)
return -1;
}
}
/*printf("%.*s='%.*s'\n",
attnamelen, attname, attvaluelen, attvalue);*/
if(p->attfunc)
p->attfunc(p->data, attname, attnamelen, attvalue, attvaluelen);
}
p->xml++;
}
return -1;
}
/* parseelt parse the xml stream and
* call the callback functions when needed... */
void parseelt(struct xmlparser * p)
{
int i;
const char * elementname;
while(p->xml < (p->xmlend - 1))
{
if((p->xml)[0]=='<' && (p->xml)[1]!='?')
{
i = 0; elementname = ++p->xml;
while( !IS_WHITE_SPACE(*p->xml)
&& (*p->xml!='>') && (*p->xml!='/')
)
{
i++; p->xml++;
if (p->xml >= p->xmlend)
return;
/* to ignore namespace : */
if(*p->xml==':')
{
i = 0;
elementname = ++p->xml;
}
}
if(i>0)
{
if(p->starteltfunc)
p->starteltfunc(p->data, elementname, i);
if(parseatt(p))
return;
if(*p->xml!='/')
{
const char * data;
i = 0; data = ++p->xml;
if (p->xml >= p->xmlend)
return;
while( IS_WHITE_SPACE(*p->xml) )
{
i++; p->xml++; // support HNAP1
if (p->xml >= p->xmlend)
return;
}
while(*p->xml!='<')
{
i++; p->xml++;
if (p->xml >= p->xmlend)
return;
}
if(i>0 && p->datafunc)
p->datafunc(p->data, data, i);
}
}
else if(*p->xml == '/')
{
i = 0; elementname = ++p->xml;
if (p->xml >= p->xmlend)
return;
while((*p->xml != '>'))
{
i++; p->xml++;
if (p->xml >= p->xmlend)
return;
}
if(p->endeltfunc)
p->endeltfunc(p->data, elementname, i);
p->xml++;
}
}
else
{
p->xml++;
}
}
}
/* the parser must be initialized before calling this function */
void parsexml(struct xmlparser * parser)
{
parser->xml = parser->xmlstart;
parser->xmlend = parser->xmlstart + parser->xmlsize;
parseelt(parser);
}

View File

@ -0,0 +1,37 @@
/* $Id: minixml.h,v 1.1.1.1 2007/08/06 10:04:43 root Exp $ */
/* minimal xml parser
*
* Project : miniupnp
* Website : http://miniupnp.free.fr/
* Author : Thomas Bernard
* Copyright (c) 2005 Thomas Bernard
* This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution.
* */
#ifndef __MINIXML_H__
#define __MINIXML_H__
#define IS_WHITE_SPACE(c) ((c==' ') || (c=='\t') || (c=='\r') || (c=='\n'))
/* if a callback function pointer is set to NULL,
* the function is not called */
struct xmlparser {
const char *xmlstart;
const char *xmlend;
const char *xml; /* pointer to current character */
int xmlsize;
void * data;
void (*starteltfunc) (void *, const char *, int);
void (*endeltfunc) (void *, const char *, int);
void (*datafunc) (void *, const char *, int);
void (*attfunc) (void *, const char *, int, const char *, int);
};
/* parsexml()
* the xmlparser structure must be initialized before the call
* the following structure members have to be initialized :
* xmlstart, xmlsize, data, *func
* xml is for internal usage, xmlend is computed automatically */
void parsexml(struct xmlparser *);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,212 @@
#ifndef __UPNPHTTP_H__
#define __UPNPHTTP_H__
#include <sys/queue.h>
#include <sys/un.h>
#include "mini_upnp_global.h"
/** @name UPNP_E_SUCCESS [0]
* {\tt UPNP_E_SUCCESS} signifies that the operation completed successfully.
* For asynchronous functions, this only means that the packet generated by
* the operation was successfully transmitted on the network. The result of
* the entire operation comes as part of the callback for that operation.
*/
//@{
#define UPNP_E_SUCCESS 0
//@}
/** @name UPNP_E_INVALID_PARAM [-101]
* {\tt UPNP_E_INVALID_PARAM} signifies that one or more of the parameters
* passed to the function is not valid. Refer to the documentation for each
* function for more information on the valid ranges of the parameters.
*/
//@{
#define UPNP_E_INVALID_PARAM -101
//@}
/** @name UPNP_E_OUTOF_MEMORY [-104]
* {\tt UPNP_E_OUTOF_MEMORY} signifies that not enough resources are
* currently available to complete the operation. Most operations require
* some free memory in order to complete their work.
*/
//@{
#define UPNP_E_OUTOF_MEMORY -102
//@}
#define UPNP_E_TOOMANY_SUBSCRIBERS -103
/* event ID */
#define UPNP_EVENT_SUBSCRIPTION_REQUEST 1
#define UPNP_EVENT_RENEWAL_COMPLETE 2
#define UPNP_EVENT_UNSUBSCRIBE_COMPLETE 3
typedef struct _IPCon {
char *ifname;
} _IPCon;
typedef struct _IPCon *IPCon;
/*
States :
0 - Waiting for data to read
1 - Waiting for HTTP Post Content.
...
>= 100 - to be deleted
*/
enum httpCommands {
EUnknown = 0,
EGet,
EPost
};
struct Upnp_Document_element {
char *VarName;
char *message;
LIST_ENTRY(Upnp_Document_element) entries;
};
typedef struct Upnp_Document_record {
unsigned int TotalMessageLen; // (total strlen(VarName) * 2) + total strlen(message)
unsigned short NumOfVarName;
LIST_HEAD(DocumentHead, Upnp_Document_element) doc_head;
} Upnp_Document_CTX, *Upnp_Document;
struct EvtRespElement {
int socket;
char sid[SID_LEN];
unsigned short TimeOut;
LIST_ENTRY(EvtRespElement) entries;
};
struct process_upnp_subscription {
char IP[IP_ADDRLEN];
int IP_inet_addr;
unsigned int port;
char sid[SID_LEN];
char callback_url[URL_MAX_LEN];
unsigned long TimeOut;
};
struct upnp_subscription_element {
char IP[IP_ADDRLEN];
int IP_inet_addr;
unsigned int port;
char sid[SID_LEN];
char callback_url[URL_MAX_LEN];
unsigned long seq;
unsigned long TimeOut;
unsigned int subscription_timeout;
int eventID;
int wscdReNewState; //add for wscd report renew state;2009-09-10
LIST_ENTRY(upnp_subscription_element) entries;
};
struct upnp_subscription_record {
char my_IP[IP_ADDRLEN];
unsigned int my_port;
unsigned short total_subscription;
unsigned short max_subscription_num;
char event_url[URL_MAX_LEN];
unsigned short max_subscription_time;
unsigned short subscription_timeout;
void (*EventCallBack)(struct upnp_subscription_element *sub);
LIST_HEAD(subscriptionlisthead, upnp_subscription_element) subscription_head;
LIST_HEAD(EvtResplisthead, EvtRespElement) EvtResp_head;
};
struct upnphttp {
int socket;
/* Data structure added by Sean --begin-- */
char IP[IP_ADDRLEN];
struct _soapMethods *soapMethods;
struct _sendDesc *sendDesc;
struct upnp_subscription_record *subscribe_list;
/* Data structure added by Sean --end-- */
struct in_addr clientaddr; /* client address */
int state;
char HttpVer[16];
/* request */
char * req_buf;
int req_buflen;
int req_contentlen;
int req_contentoff; /* header length */
enum httpCommands req_command;
char * req_soapAction;
int req_soapActionLen;
/* response */
char * res_buf;
int res_buflen;
int res_buf_alloclen;
/*int res_contentlen;*/
/*int res_contentoff;*/ /* header length */
LIST_ENTRY(upnphttp) entries;
};
struct _soapMethods {
char * methodName;
void (*methodImpl)(struct upnphttp *h);
};
struct _sendDesc {
char * DescName;
char * (*sendDescImpl)(int *len);
};
struct upnphttp * New_upnphttp(int);
void CloseSocket_upnphttp(struct upnphttp *);
void Delete_upnphttp(struct upnphttp *);
void Process_upnphttp(struct upnphttp *);
/* Build the header for the HTTP Response
* Also allocate the buffer for body data */
void
BuildHeader_upnphttp(struct upnphttp * h, int respcode,
const char * respmsg,
int bodylen);
/* BuildResp_upnphttp() fill the res_buf buffer with the complete
* HTTP 200 OK response from the body passed as argument */
void BuildResp_upnphttp(struct upnphttp *, const char *, int);
/* same but with given response code/message */
void
BuildResp2_upnphttp(struct upnphttp * h, int respcode,
const char * respmsg,
const char * body, int bodylen);
void SendResp_upnphttp(struct upnphttp *);
extern Upnp_Document CreatePropertySet(void);
extern int UpnpAddToPropertySet(Upnp_Document PropSet,
const char *VarName, const char *message);
extern void UpnpSendEventSingle(Upnp_Document PropSet,
struct upnp_subscription_record *subscribe_list,
struct upnp_subscription_element *sub);
extern void UpnpSendEventAll(Upnp_Document PropSet,
struct upnp_subscription_record *sub);
extern void UpnpDocument_free(Upnp_Document PropSet);
extern void ProcessEventingResp(struct EvtRespElement *EvtResp);
extern int OpenAndConfHTTPSocket(const char * addr, unsigned short port);
extern IPCon IPCon_New(char *ifname);
extern IPCon IPCon_Destroy(IPCon this);
extern BOOLEAN IPCon_GetIpAddr(IPCon this, struct in_addr *adr);
extern char *IPCon_GetIpAddrByStr(IPCon this);
extern int ILibBase64Encode(unsigned char* input, const int inputlen, unsigned char** output);
extern int ILibBase64Decode(unsigned char* input, const int inputlen, unsigned char** output);
extern int ReliableSend(int socket, const char *data, const int len);
// support HNAP1
extern void SendError(struct upnphttp * h, const int code, const char *title, const char *realm, const char *body);
extern int OpenAndConfUNIXSocket(const char *file_path);
extern int CreateUnixSocket(const char *function_name,
const char *file_path,
const int time_out);
extern int UnixSocketSendAndReceive(const char *function_name,
const char *file_path,
const int time_out,
const char *in, char *out, const int out_len);
#endif

View File

@ -0,0 +1,397 @@
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <sys/stat.h>
#include "upnpreplyparse.h"
#include "minixml.h"
static void
NameValueParserStartElt(void * d, const char * name, int l)
{
struct NameValueParserData * data = (struct NameValueParserData *)d;
if(l>63)
l = 63;
memcpy(data->curelt, name, l);
data->curelt[l] = '\0';
}
static void
NameValueParserGetData(void * d, const char * datas, int l)
{
struct NameValueParserData * data = (struct NameValueParserData *)d;
struct NameValue * nv;
nv = malloc(sizeof(struct NameValue));
memset(nv, 0, sizeof(struct NameValue));
nv->value = (char *) malloc(l+1);
memset(nv->value, 0, l+1);
strncpy(nv->name, data->curelt, 64);
memcpy(nv->value, datas, l);
LIST_INSERT_HEAD( &(data->head), nv, entries);
}
void ParseNameValue(const char * buffer, int bufsize,
struct NameValueParserData * data)
{
struct xmlparser parser;
LIST_INIT(&(data->head));
/* init xmlparser object */
parser.xmlstart = buffer;
parser.xmlsize = bufsize;
parser.data = data;
parser.starteltfunc = NameValueParserStartElt;
parser.endeltfunc = 0;
parser.datafunc = NameValueParserGetData;
parser.attfunc = 0;
parsexml(&parser);
}
void ClearNameValueList(struct NameValueParserData * pdata)
{
struct NameValue * nv;
while((nv = pdata->head.lh_first) != NULL)
{
if (nv->value)
free(nv->value);
LIST_REMOVE(nv, entries);
free(nv);
}
}
char *
GetValueFromNameValueList(struct NameValueParserData * pdata,
const char * Name)
{
struct NameValue * nv;
char * p = NULL;
for(nv = pdata->head.lh_first;
(nv != NULL) && (p == NULL);
nv = nv->entries.le_next)
{
if(strcmp(nv->name, Name) == 0)
p = nv->value;
}
return p;
}
char *
GetValueFromNameValueListIgnoreNS(struct NameValueParserData * pdata,
const char * Name)
{
struct NameValue * nv;
char * p = NULL;
char * pname;
for(nv = pdata->head.lh_first;
(nv != NULL) && (p == NULL);
nv = nv->entries.le_next)
{
pname = strrchr(nv->name, ':');
if(pname)
pname++;
else
pname = nv->name;
if(strcmp(pname, Name)==0)
p = nv->value;
}
return p;
}
/* debug all-in-one function
* do parsing then display to stdout */
void DisplayNameValueList(char * buffer, int bufsize)
{
struct NameValueParserData pdata;
struct NameValue * nv;
ParseNameValue(buffer, bufsize, &pdata);
for(nv = pdata.head.lh_first;
nv != NULL;
nv = nv->entries.le_next)
{
printf("%s = %s\n", nv->name, nv->value);
}
ClearNameValueList(&pdata);
}
/* MUST free the returned buffer after this call */
char *mini_UPnPGetFirstElement(char *file_start, unsigned int len, char *tag_name, unsigned int tag_name_len)
{
char * line;
unsigned long file_end;
unsigned long string_begin=0;
unsigned long string_end=0;
char *tag_name_first=NULL;
char *tag_name_second=NULL;
char *buf=NULL;
unsigned int string_len=0;
if (file_start == NULL || tag_name == NULL)
return NULL;
if (len <= 0 || tag_name_len <= 0)
return NULL;
tag_name_first = (char *)malloc(tag_name_len+3);
if (tag_name_first == NULL)
return NULL;
memcpy(tag_name_first+1, tag_name, tag_name_len);
tag_name_first[0] = '<';
tag_name_first[tag_name_len+1] = '>';
tag_name_first[tag_name_len+2] = 0;
tag_name_second = (char *)malloc(tag_name_len+4);
if (tag_name_second == NULL) {
free(tag_name_first);
return NULL;
}
memcpy(tag_name_second+2, tag_name, tag_name_len);
tag_name_second[0] = '<';
tag_name_second[1] = '/';
tag_name_second[tag_name_len+2] = '>';
tag_name_second[tag_name_len+3] = 0;
line = file_start;
file_end = (unsigned long)file_start + len;
while ((unsigned long)line < (file_end-tag_name_len-3))
{
if (strncasecmp(line, tag_name_first, tag_name_len+2) == 0) {
if (string_begin == 0) {
string_begin = (unsigned long)line + tag_name_len + 2;
}
else {
//DEBUG_ERR("Duplicated tag %s\n", tag_name_first);
free(tag_name_first);
free(tag_name_second);
return NULL;
}
}
else if (strncasecmp(line, tag_name_second, tag_name_len+3) == 0) {
if (string_begin == 0) {
//DEBUG_ERR("Missing tag %s\n", tag_name_first);
free(tag_name_first);
free(tag_name_second);
return NULL;
}
else {
string_end = (unsigned long)line;
break;
}
}
line++;
}
free(tag_name_first);
free(tag_name_second);
if (string_begin < string_end) {
string_len = string_end - string_begin;
buf = (char *)malloc(string_len+1);
if (buf == NULL)
return NULL;
memcpy(buf, (char *)string_begin, string_len);
buf[string_len] = 0;
return buf;
}
else {
//DEBUG_ERR("XML parse erroe!\n");
return NULL;
}
}
char *mini_UPnPGetFirstElementAndReturnAddr(char *file_start, unsigned int len, char *tag_name, unsigned int tag_name_len, char *buf)
{
char * line;
unsigned long file_end;
unsigned long string_begin=0;
unsigned long string_end=0;
char *tag_name_first=NULL;
char *tag_name_second=NULL;
unsigned int string_len=0;
char *end=NULL;
unsigned char found=0;
if (file_start == NULL || tag_name == NULL || buf == NULL)
return NULL;
if (len <= 0 || tag_name_len <= 0)
return NULL;
tag_name_first = (char *)malloc(tag_name_len+3);
if (tag_name_first == NULL)
return NULL;
memcpy(tag_name_first+1, tag_name, tag_name_len);
tag_name_first[0] = '<';
tag_name_first[tag_name_len+1] = '>';
tag_name_first[tag_name_len+2] = 0;
tag_name_second = (char *)malloc(tag_name_len+4);
if (tag_name_second == NULL) {
free(tag_name_first);
return NULL;
}
memcpy(tag_name_second+2, tag_name, tag_name_len);
tag_name_second[0] = '<';
tag_name_second[1] = '/';
tag_name_second[tag_name_len+2] = '>';
tag_name_second[tag_name_len+3] = 0;
line = file_start;
file_end = (unsigned long)file_start + len;
while ((unsigned long)line < (file_end-tag_name_len-3))
{
if (strncasecmp(line, tag_name_first, tag_name_len+2) == 0) {
if (string_begin == 0) {
string_begin = (unsigned long)line + tag_name_len + 2;
}
else {
//DEBUG_ERR("Duplicated tag %s\n", tag_name_first);
free(tag_name_first);
free(tag_name_second);
return NULL;
}
}
else if (strncasecmp(line, tag_name_second, tag_name_len+3) == 0) {
if (string_begin == 0) {
//DEBUG_ERR("Missing tag %s\n", tag_name_first);
free(tag_name_first);
free(tag_name_second);
return NULL;
}
else {
string_end = (unsigned long)line;
end = (char *)(line + (tag_name_len+3));
found = 1;
break;
}
}
line++;
}
free(tag_name_first);
free(tag_name_second);
if (string_begin < string_end) {
string_len = string_end - string_begin;
memcpy(buf, (char *)string_begin, string_len);
buf[string_len] = 0;
return end;
}
else {
if (found) {
buf[0] = 0;
return end;
}
else
return NULL;
}
}
char *mini_UPnP_UploadXML(char *file_path)
{
FILE *fp = NULL;
int retVal = 0;
struct stat file_info;
char *buf=NULL;
unsigned int fileLen=0;
unsigned int num_read=0;
char *membuf=NULL;
buf = file_path;
retVal = stat(buf, &file_info );
if ( retVal == -1 ) {
//printf("Failed to get file info. EXITING\n");
return NULL;
}
fileLen = file_info.st_size;
if ( ( fp = fopen( buf, "rb" ) ) == NULL ) {
printf("Failed to open file [%s]. EXITING\n", buf);
return NULL;
}
if ( ( membuf = ( char * )malloc( fileLen + 1 ) ) == NULL ) {
fclose( fp );
printf("mini_UPnP_UploadXML Out of memory! EXITING\n");
return NULL;
}
num_read = fread( membuf, 1, fileLen, fp );
if ( num_read != fileLen ) {
fclose( fp );
free( membuf );
printf("mini_UPnP_UploadXML File length mismatched! EXITING\n");
return NULL;
}
membuf[fileLen] = 0;
fclose( fp );
return membuf;
}
char *get_token(char *data, char *token)
{
char *ptr=data;
int len=0, idx=0;
while (*ptr && *ptr != '\n' ) {
if (*ptr == '=') {
if (len <= 1)
return NULL;
memcpy(token, data, len);
/* delete ending space */
for (idx=len-1; idx>=0; idx--) {
if (token[idx] != ' ')
break;
}
token[idx+1] = '\0';
return ptr+1;
}
len++;
ptr++;
}
return NULL;
}
int get_value(char *data, char *value)
{
char *ptr=data;
int len=0, idx, i;
while (*ptr && *ptr != '\n' && *ptr != '\r') {
len++;
ptr++;
}
/* delete leading space */
idx = 0;
while (len-idx > 0) {
if (data[idx] != ' ')
break;
idx++;
}
len -= idx;
/* delete bracing '"' */
if (data[idx] == '"') {
for (i=idx+len-1; i>idx; i--) {
if (data[i] == '"') {
idx++;
len = i - idx;
}
break;
}
}
if (len > 0) {
memcpy(value, &data[idx], len);
value[len] = '\0';
}
return len;
}

View File

@ -0,0 +1,69 @@
/* $Id: upnpreplyparse.h,v 1.1.1.1 2007/08/06 10:04:43 root Exp $ */
/* miniupnp project
* see http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2005-2006 Thomas Bernard
* This software is subjects to the conditions detailed in the LICENCE
* file provided with this distribution */
#ifndef __UPNPREPLYPARSE_H__
#define __UPNPREPLYPARSE_H__
#if defined(sun) || defined(__sun) || defined(WIN32)
#include "bsdqueue.h"
#else
#include <sys/queue.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
struct NameValue {
LIST_ENTRY(NameValue) entries;
char name[64];
char *value;
};
struct NameValueParserData {
LIST_HEAD(listhead, NameValue) head;
char curelt[64];
};
void
ParseNameValue(const char * buffer, int bufsize,
struct NameValueParserData * data);
void
ClearNameValueList(struct NameValueParserData * pdata);
char *
GetValueFromNameValueList(struct NameValueParserData * pdata,
const char * Name);
char *
GetValueFromNameValueListIgnoreNS(struct NameValueParserData * pdata,
const char * Name);
void
DisplayNameValueList(char * buffer, int bufsize);
char *
mini_UPnPGetFirstElement(char *file_start, unsigned int len,
char *tag_name, unsigned int tag_name_len);
char *
mini_UPnPGetFirstElementAndReturnAddr(char *file_start, unsigned int len, char *tag_name, unsigned int tag_name_len, char *buf);
char *
mini_UPnP_UploadXML(char *file_path);
char *
get_token(char *data, char *token);
int
get_value(char *data, char *value);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,124 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#include <syslog.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
#include "upnphttp.h"
#include "upnpsoap.h"
void
BuildSendAndCloseSoapResp(struct upnphttp * h,
const char * body, int bodylen)
{
static const char beforebody[] =
"<?xml version=\"1.0\"?>\n"
"<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
"s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
"<s:Body>";
static const char afterbody[] =
"</s:Body>"
"</s:Envelope>";
BuildHeader_upnphttp(h, 200, "OK", sizeof(beforebody) - 1
+ sizeof(afterbody) - 1
+ bodylen );
memcpy(h->res_buf + h->res_buflen, beforebody, sizeof(beforebody) - 1);
h->res_buflen += sizeof(beforebody) - 1;
memcpy(h->res_buf + h->res_buflen, body, bodylen);
h->res_buflen += bodylen;
memcpy(h->res_buf + h->res_buflen, afterbody, sizeof(afterbody) - 1);
h->res_buflen += sizeof(afterbody) - 1;
SendResp_upnphttp(h);
CloseSocket_upnphttp(h);
}
void ExecuteSoapAction(struct upnphttp * h, const char * action, int n)
{
char * p;
int i, len;
i = 0;
// support HNAP1
len = strlen("http://purenetworks.com/HNAP");
if (strncasecmp((char *)action, "http://purenetworks.com/HNAP", len) == 0) {
char *pos;
pos = (char *)(action + len);
p = strchr(pos, '/');
//if (p)
//printf("action [%s]\n", p+1);
}
else
p = strchr(action, '#');
if (p)
{
p++;
while(h->soapMethods[i].methodName)
{
len = strlen(h->soapMethods[i].methodName);
if(strncmp(p, h->soapMethods[i].methodName, len) == 0)
{
h->soapMethods[i].methodImpl(h);
return;
}
i++;
}
}
syslog(LOG_NOTICE, "Unknown soap method");
SoapError(h, 401, "Invalid Action");
}
/* Standard errors :
errorCode errorDescription Description
401 Invalid Action No action by that name at this service.
402 Invalid Args Could be any of the following: not enough in args, too many in args, no in arg by that name, one or more in args are of the wrong data type.
403 Out of Sync Out of synchronization.
501 Action Failed May be returned in current state of service prevents invoking that action.
600-699 TBD Common action errors. Defined by UPnP Forum Technical Committee.
700-799 TBD Action-specific errors for standard actions. Defined by UPnP Forum working committee.
800-899 TBD Action-specific errors for non-standard actions. Defined by UPnP vendor.
*/
void
SoapError(struct upnphttp * h, int errCode, const char * errDesc)
{
char *body=NULL;
int bodylen;
static const char resp[] =
"<s:Envelope "
"xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
"s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
"<s:Body>"
"<s:Fault>"
"<faultcode>s:Client</faultcode>"
"<faultstring>UPnPError</faultstring>"
"<detail>"
"<UPnPError xmlns=\"urn:schemas-upnp-org:control-1-0\">"
"<errorCode>%d</errorCode>"
"<errorDescription>%s</errorDescription>"
"</UPnPError>"
"</detail>"
"</s:Fault>"
"</s:Body>"
"</s:Envelope>";
body = (char *) malloc(2048);
if (body == NULL) {
syslog(LOG_ERR, "SoapError: out of memory!");
return;
}
memset(body, 0, 2048);
bodylen = sprintf(body, resp, errCode, errDesc);
BuildResp2_upnphttp(h, 500, "Internal Server Error", body, bodylen);
SendResp_upnphttp(h);
CloseSocket_upnphttp(h);
free(body);
}

View File

@ -0,0 +1,15 @@
#ifndef _UPNPSOAP_H_
#define _UPNPSOAP_H_
/* ExecuteSoapAction() :
* This method execute the requested Soap Action */
void ExecuteSoapAction(struct upnphttp *, const char *, int);
/* Sends a correct SOAP error with an UPNPError code and
* description */
void
SoapError(struct upnphttp * h, int errCode, const char * errDesc);
extern void BuildSendAndCloseSoapResp(struct upnphttp * h, const char * body, int bodylen);
#endif