M7350/wlan/8192es/DriverSrcPkg/Users/mini_upnp/upnphttp.c
2024-09-09 08:59:52 +00:00

1824 lines
45 KiB
C
Executable File

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <syslog.h>
#include <arpa/inet.h>
#include <limits.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include "upnphttp.h"
#include "upnpsoap.h"
static int get_sockfd(void)
{
static int sockfd = -1;
if (sockfd == -1) {
if ((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) == -1) {
perror("user: socket creation failed");
return(-1);
}
}
return sockfd;
}
IPCon IPCon_New(char * ifname)
{
IPCon ipcon=NULL;
ipcon = (IPCon)malloc(sizeof(_IPCon));
if (!ipcon) {
printf("Error in IPCon_New:Cannot allocate memory\n");
return NULL;
}
ipcon->ifname = ifname;
return (ipcon);
}
IPCon IPCon_Destroy(IPCon this)
{
if (!this)
return (NULL);
free(this);
return (NULL);
}
BOOLEAN IPCon_GetIpAddr(IPCon this, struct in_addr *adr)
{
struct ifreq ifr;
int fd;
fd = get_sockfd();
if (fd >= 0) {
strcpy(ifr.ifr_name, this->ifname);
ifr.ifr_addr.sa_family = AF_INET;
if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
memcpy(adr,&((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr,sizeof(struct in_addr));
close(fd);
return TRUE;
} else {
close(fd);
return FALSE;
}
}
return FALSE;
}
char *IPCon_GetIpAddrByStr(IPCon this)
{
struct in_addr adr;
BOOLEAN result=FALSE;
result = IPCon_GetIpAddr(this,&adr);
if (result == FALSE) {
return NULL;
} else {
return inet_ntoa(adr);
}
}
int OpenAndConfHTTPSocket(const char * addr, unsigned short port)
{
int s;
int i = 1;
struct sockaddr_in listenname;
if( (s = socket(PF_INET, SOCK_STREAM, 0)) < 0)
{
syslog(LOG_ERR, "socket(http): %m");
return -1;
}
if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)) < 0)
{
syslog(LOG_WARNING, "setsockopt(http, SO_REUSEADDR): %m");
}
memset(&listenname, 0, sizeof(struct sockaddr_in));
listenname.sin_family = AF_INET;
listenname.sin_port = htons(port);
listenname.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(s, (struct sockaddr *)&listenname, sizeof(struct sockaddr_in)) < 0)
{
syslog(LOG_ERR, "bind(http): %m");
return -1;
}
if(listen(s, 6) < 0)
{
syslog(LOG_ERR, "listen(http): %m");
return -1;
}
return s;
}
int ReliableSend(int socket, const char *data, const int len)
{
int n;
unsigned int byte_left = len;
int bytes_sent = 0;
if (socket < 0 || data == NULL || len <= 0)
return -1;
while (byte_left > 0) {
// write data
n = send(socket, data + bytes_sent, byte_left,
MSG_DONTROUTE | MSG_NOSIGNAL );
if( n == -1 ) {
syslog(LOG_ERR, "ReliableSend: sending failed!");
return -1;
}
byte_left = byte_left - n;
bytes_sent += n;
}
n = bytes_sent;
return n;
}
struct upnphttp * New_upnphttp(int s)
{
struct upnphttp * ret;
if(s<0)
return NULL;
ret = (struct upnphttp *)malloc(sizeof(struct upnphttp));
if(ret == NULL)
return NULL;
memset(ret, 0, sizeof(struct upnphttp));
ret->socket = s;
return ret;
}
void CloseSocket_upnphttp(struct upnphttp * h)
{
close(h->socket);
h->socket = -1;
h->state = 100;
}
void Delete_upnphttp(struct upnphttp * h)
{
if(h)
{
if(h->socket >= 0)
{
close(h->socket);
h->socket=-1;
}
if(h->req_buf)
{
free(h->req_buf);
h->req_buf=NULL;
}
if(h->res_buf)
{
free(h->res_buf);
h->res_buf=NULL;
}
free(h);
}
}
/* parse HttpHeaders of the REQUEST */
static void ParseHttpHeaders(struct upnphttp * h)
{
char * line;
char * colon;
char * p;
int n;
line = h->req_buf;
/* TODO : check if req_buf, contentoff are ok */
while(line < (h->req_buf + h->req_contentoff))
{
colon = strchr(line, ':');
if(colon)
{
if(strncasecmp(line, "Content-Length", 14)==0)
{
p = colon;
while(*p < '0' || *p > '9')
p++;
h->req_contentlen = atoi(p);
/*printf("*** Content-Lenght = %d ***\n", h->req_contentlen);
printf(" readbufflen=%d contentoff = %d\n",
h->req_buflen, h->req_contentoff);*/
}
else if(strncasecmp(line, "SOAPAction", 10)==0)
{
p = colon;
n = 0;
while(*p == ':' || *p == ' ' || *p == '\t')
p++;
while(p[n]>=' ')
{
n++;
}
if((p[0] == '"' && p[n-1] == '"')
|| (p[0] == '\'' && p[n-1] == '\''))
{
p++; n -= 2;
}
h->req_soapAction = p;
h->req_soapActionLen = n;
}
}
while(!(line[0] == '\r' && line[1] == '\n'))
line++;
line += 2;
}
}
/* very minimalistic 404 error message */
static void Send404(struct upnphttp * h)
{
static const char error404[] = "HTTP/1.1 404 Not found\r\n"
"Connection: close\r\n"
"Content-type: text/html\r\n"
"\r\n"
"<HTML><HEAD><TITLE>404 Not Found</TITLE></HEAD>"
"<BODY><H1>Not Found</H1>The requested URL was not found"
" on this server.</BODY></HTML>\r\n";
int n;
n = ReliableSend(h->socket, error404, sizeof(error404) - 1);
if (n != (sizeof(error404) - 1))
{
syslog(LOG_ERR, "Send404: %d bytes sent (out of %d)",
n, (sizeof(error404) - 1));
}
CloseSocket_upnphttp(h);
}
// support HNAP1
void SendError(struct upnphttp * h, const int code, const char *title, const char *realm, const char *body)
{
char *error_title=NULL;
char *error_realm=NULL;
char *error_body=NULL;
int len;
int n;
if (code <=0 || title == NULL) {
Send404(h);
return;
}
error_title = (char *)malloc(2048);
sprintf(error_title, "HTTP/1.1 %d %s\r\n"
"Connection: close\r\n"
"Content-type: text/html\r\n", code, title);
if (realm) {
error_realm = (char *)malloc(256);
sprintf(error_realm, "WWW-Authenticate: Basic realm=\"%s\"\r\n", realm);
strcat(error_title, error_realm);
}
strcat(error_title, "\r\n");
if (body) {
error_body = (char *)malloc(1024);
sprintf(error_body, "<HTML><HEAD><TITLE>%d %s</TITLE></HEAD>"
"<BODY><H1>%s</H1>%s</BODY></HTML>\r\n", code, title, title, body);
strcat(error_title, error_body);
}
len = strlen(error_title);
n = ReliableSend(h->socket, error_title, len);
if (n != len)
{
syslog(LOG_ERR, "Send%d: %d bytes sent (out of %d)", code,
n, len);
}
CloseSocket_upnphttp(h);
if (error_title)
{
free(error_title);
error_title=NULL;
}
if (error_realm)
{
free(error_realm);
error_realm=NULL;
}
if(error_body)
{
free(error_body);
error_body=NULL;
}
}
/* Precondition Failed */
static void Send412PreconditionFailed(struct upnphttp * h)
{
static const char error412[] = "HTTP/1.1 412 Precondition Failed\r\n"
"Content-Length: 0\r\n"
"Connection: close\r\n\r\n";
int n;
n = ReliableSend(h->socket, error412, sizeof(error412) - 1);
if (n != (sizeof(error412) - 1))
{
syslog(LOG_ERR, "Send412PreconditionFailed: %d bytes sent (out of %d)",
n, (sizeof(error412) - 1));
}
CloseSocket_upnphttp(h);
}
/* Too Many Subscribers */
static void Send412TooManySubscribers(struct upnphttp * h)
{
static const char error412[] = "HTTP/1.1 412 Too Many Subscribers\r\n"
"Content-Length: 0\r\n"
"Connection: close\r\n\r\n";
int n;
n = ReliableSend(h->socket, error412, sizeof(error412) - 1);
if (n != (sizeof(error412) - 1))
{
syslog(LOG_ERR, "Send412TooManySubscribers: %d bytes sent (out of %d)",
n, (sizeof(error412) - 1));
}
CloseSocket_upnphttp(h);
}
/* very minimalistic 501 error message */
static void Send501(struct upnphttp * h)
{
static const char error501[] = "HTTP/1.1 501 Not Implemented\r\n"
"Connection: close\r\n"
"Content-type: text/html\r\n"
"\r\n"
"<HTML><HEAD><TITLE>501 Not Implemented</TITLE></HEAD>"
"<BODY><H1>Not Implemented</H1>The HTTP Method "
"is not implemented by this server.</BODY></HTML>\r\n";
int n;
n = ReliableSend(h->socket, error501, sizeof(error501) - 1);
if (n != (sizeof(error501) - 1))
{
syslog(LOG_ERR, "Send501: %d bytes sent (out of %d)",
n, (sizeof(error501) - 1));
}
CloseSocket_upnphttp(h);
}
static const char * findendheaders(const char * s, int len)
{
while(len-->0)
{
if(s[0]=='\r' && s[1]=='\n' && s[2]=='\r' && s[3]=='\n')
return s;
s++;
}
return NULL;
}
/* Sends the description generated by the parameter */
static void sendXMLdesc(struct upnphttp * h, char * (f)(int *))
{
char * desc;
int len;
desc = f(&len);
if(!desc)
{
syslog(LOG_ERR, "XML description generation failed");
return;
}
BuildResp_upnphttp(h, desc, len);
SendResp_upnphttp(h);
CloseSocket_upnphttp(h);
free(desc);
}
/* ProcessHTTPPOST_upnphttp()
* executes the SOAP query if it is possible */
static void ProcessHTTPPOST_upnphttp(struct upnphttp * h)
{
if((h->req_buflen - h->req_contentoff) >= h->req_contentlen)
{
if(h->req_soapAction)
{
/* we can process the request */
syslog(LOG_INFO, "SOAPAction: %.*s",
h->req_soapActionLen, h->req_soapAction);
ExecuteSoapAction(h,
h->req_soapAction,
h->req_soapActionLen);
}
else
{
static const char err400str[] =
"<html><body>Bad request</body></html>";
syslog(LOG_INFO, "No SOAPAction in HTTP headers");
BuildResp2_upnphttp(h, 400, "Bad Request",
err400str, sizeof(err400str) - 1);
SendResp_upnphttp(h);
CloseSocket_upnphttp(h);
}
}
else
{
/* waiting for remaining data */
h->state = 1;
}
}
Upnp_Document CreatePropertySet(void)
{
Upnp_Document PropSet=NULL;
PropSet = (Upnp_Document) malloc(sizeof(Upnp_Document_CTX));
if (PropSet == NULL) {
syslog(LOG_ERR, "CreatePropertySet: out of memory!");
return NULL;
}
memset(PropSet, 0, sizeof(Upnp_Document_CTX));
LIST_INIT(&PropSet->doc_head);
return PropSet;
}
int UpnpAddToPropertySet(Upnp_Document PropSet,
const char *VarName, const char *message)
{
struct Upnp_Document_element *tmp=NULL;
char *name=NULL;
char *content=NULL;
if (PropSet == NULL || VarName == NULL || message == NULL)
return UPNP_E_INVALID_PARAM;
tmp = (struct Upnp_Document_element *) malloc(sizeof(struct Upnp_Document_element));
if (tmp == NULL) {
syslog(LOG_ERR, "UpnpAddToPropertySet: out of memory!");
return UPNP_E_OUTOF_MEMORY;
}
memset(tmp, 0, sizeof(struct Upnp_Document_element));
name = (char *) malloc(strlen(VarName) + 1);
if (name == NULL) {
syslog(LOG_ERR, "UpnpAddToPropertySet: out of memory!");
free(tmp);
return UPNP_E_OUTOF_MEMORY;
}
memset(name, 0, strlen(VarName) + 1);
memcpy(name, VarName, strlen(VarName));
content = (char *) malloc(strlen(message) + 1);
if (content == NULL) {
syslog(LOG_ERR, "UpnpAddToPropertySet: out of memory!");
free(tmp);
free(name);
return UPNP_E_OUTOF_MEMORY;
}
memset(content, 0, strlen(message) + 1);
memcpy(content, message, strlen(message));
PropSet->NumOfVarName += 1;
PropSet->TotalMessageLen = strlen(message) + (strlen(VarName) * 2);
tmp->VarName = name;
tmp->message = content;
LIST_INSERT_HEAD(&PropSet->doc_head, tmp, entries);
return UPNP_E_SUCCESS;
}
static char *MakeEventBody(Upnp_Document PropSet, unsigned int *total_len)
{
unsigned int len=0;
char *buf=NULL;
unsigned int buf_len=0;
struct Upnp_Document_element *e;
if (PropSet == NULL || PropSet->NumOfVarName == 0)
return NULL;
buf_len = (strlen("<e:property><></></e:property>") * PropSet->NumOfVarName)
+ PropSet->TotalMessageLen + 100;
buf = (char *) malloc(buf_len);
if (buf == NULL) {
syslog(LOG_ERR, "MakeEventBody: out of memory!");
return NULL;
}
memset(buf, 0, buf_len);
for(e = PropSet->doc_head.lh_first; e != NULL; e = e->entries.le_next)
{
if (e->VarName) {
char *tmpbuf=NULL;
unsigned int tmpbuf_len=0;
unsigned int propertyLen=0;
tmpbuf_len = strlen("<e:property><></></e:property>")
+ (strlen(e->VarName) * 2)
+ strlen(e->message) + 1;
tmpbuf = (char *) malloc(tmpbuf_len);
if (tmpbuf == NULL) {
syslog(LOG_ERR, "MakeEventBody: out of memory!");
free(buf);
return NULL;
}
memset(tmpbuf, 0, tmpbuf_len);
propertyLen = sprintf(tmpbuf,
"<e:property><%s>%s</%s></e:property>",
e->VarName, e->message, e->VarName);
len += propertyLen;
strcat(buf, tmpbuf);
free(tmpbuf);
}
}
*total_len = len;
return buf;
}
static void UpnpSendEvent(char *packet,
const char *EventBody, const unsigned int bodylength,
struct upnp_subscription_record *subscribe_list,
struct upnp_subscription_element *sub)
{
unsigned int packetLength;
struct sockaddr_in dest;
int n, sockfd=-1;
struct EvtRespElement *EvtResp=NULL;
if (packet == NULL || EventBody == NULL || bodylength == 0 ||
subscribe_list == NULL || sub == NULL)
return;
packetLength = sprintf(packet,
"NOTIFY %s HTTP/1.1\r\n"
"SERVER: " MINIUPNPD_SERVER_STRING "\r\n"
"HOST: %s:%d\r\n"
"Content-Type: text/xml; charset=\"utf-8\"\r\n"
"NT: upnp:event\r\n"
"NTS: upnp:propchange\r\n"
"SID: %s\r\n"
"SEQ: %d\r\n"
"Content-Length: %d\r\n\r\n"
"<?xml version=\"1.0\" encoding=\"utf-8\"?>"
"<e:propertyset xmlns:e=\"urn:schemas-upnp-org:event-1-0\">"
"%s"
"</e:propertyset>",
sub->callback_url,
sub->IP,
sub->port,
sub->sid,
(int)sub->seq,
bodylength+110,
EventBody);
sub->seq++;
if (sub->seq >= UINT_MAX)
sub->seq = 1;
//printf("Packet------------>\n%s\n<-----------------Packet\n\n", packet);
memset(&dest,0,sizeof(struct sockaddr_in));
dest.sin_addr.s_addr = sub->IP_inet_addr;
dest.sin_port = htons(sub->port);
dest.sin_family = AF_INET;
// create a socket
if ((sockfd = socket( AF_INET, SOCK_STREAM, 0 )) == -1) {
syslog(LOG_ERR, "UpnpSendEvent: creating a socket falied!");
return;
}
if (connect( sockfd, ( struct sockaddr * )&dest,
sizeof( struct sockaddr_in ) ) == -1) {
syslog(LOG_ERR, "UpnpSendEvent: connecting a socket falied!");
close(sockfd);
return;
}
n = ReliableSend(sockfd, packet, packetLength);
if (n != packetLength)
{
syslog(LOG_ERR, "UpnpSendEvent: %d bytes sent (out of %d)",
n, packetLength);
close(sockfd);
return;
}
EvtResp = (struct EvtRespElement *) malloc(sizeof(struct EvtRespElement));
if (EvtResp == NULL) {
syslog(LOG_ERR, "UpnpSendEvent: out of memory!");
close(sockfd);
return;
}
memset(EvtResp, 0, sizeof(struct EvtRespElement));
EvtResp->socket = sockfd;
memcpy(EvtResp->sid, sub->sid, strlen(sub->sid));
EvtResp->TimeOut = 30;
LIST_INSERT_HEAD(&subscribe_list->EvtResp_head, EvtResp, entries);
}
void UpnpSendEventSingle(Upnp_Document PropSet,
struct upnp_subscription_record *subscribe_list,
struct upnp_subscription_element *sub)
{
char *packet=NULL;
unsigned int bodylength=0;
char *EventBody=NULL;
if (PropSet == NULL || sub == NULL || subscribe_list == NULL ||
subscribe_list->subscription_head.lh_first == NULL)
return;
EventBody = MakeEventBody(PropSet, &bodylength);
if (EventBody == NULL) {
syslog(LOG_ERR, "UpnpSendEventSingle: MakeEventBody failed!");
return;
}
packet = (char *) malloc(bodylength + 483);
if (packet == NULL) {
syslog(LOG_ERR, "UpnpSendEventSingle: out of memory!");
free(EventBody);
return;
}
memset(packet, 0, bodylength + 483);
UpnpSendEvent(packet, EventBody, bodylength, subscribe_list, sub);
free(EventBody);
free(packet);
}
void ProcessEventingResp(struct EvtRespElement *EvtResp)
{
char *buf=NULL;
int n;
if (EvtResp == NULL)
return;
buf = (char *) malloc(512);
if (buf == NULL) {
close(EvtResp->socket);
return;
}
memset(buf, 0, 512);
if ((n = recv(EvtResp->socket, buf, 512, 0)) == -1) {
syslog(LOG_ERR, "ProcessEventingResp: Receive failed!");
}
else if(n==0)
{
syslog(LOG_WARNING, "ProcessEventingResp: connection closed inexpectedly");
}
//printf("------------>\nProcessEventingResp: sid[%s]\n%s\n<--------------\n", EvtResp->sid, buf);
close(EvtResp->socket);
free(buf);
}
void UpnpSendEventAll(Upnp_Document PropSet,
struct upnp_subscription_record *sub_list)
{
struct upnp_subscription_element *sub;
unsigned int bodylength=0;
char *EventBody=NULL;
char *packet=NULL;
if (PropSet == NULL || sub_list == NULL || sub_list->subscription_head.lh_first == NULL)
return;
EventBody = MakeEventBody(PropSet, &bodylength);
if (EventBody == NULL) {
syslog(LOG_ERR, "UpnpSendEventAll: MakeEventBody failed!");
return;
}
packet = (char *) malloc(bodylength + 483);
if (packet == NULL) {
syslog(LOG_ERR, "UpnpSendEventAll: out of memory!");
free(EventBody);
return;
}
for (sub = sub_list->subscription_head.lh_first; sub != NULL; sub = sub->entries.le_next)
{
memset(packet, 0, bodylength + 483);
UpnpSendEvent(packet, EventBody, bodylength, sub_list, sub);
}
free(EventBody);
free(packet);
}
void UpnpDocument_free(Upnp_Document PropSet)
{
struct Upnp_Document_element *e;
struct Upnp_Document_element *next;
if (PropSet == NULL)
return;
for(e = PropSet->doc_head.lh_first; e != NULL; )
{
next = e->entries.le_next;
if (e->VarName)
free(e->VarName);
if (e->message)
free(e->message);
LIST_REMOVE(e, entries);
free(e);
e = next;
}
free(PropSet);
}
static int BuildSubscribeResponse(struct upnphttp * h, struct process_upnp_subscription *sub)
{
char *Subresp=NULL;
int n, packet_len, ret=UPNP_E_SUCCESS;
Subresp = (char *) malloc(300);
if (Subresp == NULL) {
syslog(LOG_ERR, "BuildSubscribeResponse: out of memory!");
return UPNP_E_OUTOF_MEMORY;
}
memset(Subresp, 0, 300);
packet_len = sprintf(Subresp,
"HTTP/1.1 200 OK \r\n"
"Server: " MINIUPNPD_SERVER_STRING "\r\n"
"SID: %s\r\n"
"TIMEOUT: Second-%d\r\n"
"Content-Length: 0\r\n"
"\r\n",
sub->sid, (int)h->subscribe_list->max_subscription_time);
//printf("BuildSubscribeResponse------->\n%s<------------BuildSubscribeResponse\n", Subresp);
n = ReliableSend(h->socket, Subresp, packet_len);
if (n != packet_len)
{
syslog(LOG_ERR, "BuildSubscribeResponse: %d bytes sent (out of %d)",
n, packet_len);
}
free(Subresp);
CloseSocket_upnphttp(h);
return ret;
}
static void BuildUnSubscribeResponse(struct upnphttp * h)
{
static const char UnSubresp[] =
"HTTP/1.1 200 OK \r\n"
"Content-Length: 0\r\n"
"\r\n";
int n;
n = ReliableSend(h->socket, UnSubresp, sizeof(UnSubresp) - 1);
if (n != (sizeof(UnSubresp) - 1))
{
syslog(LOG_ERR, "BuildUnSubscribeResponse: %d bytes sent (out of %d)",
n, (sizeof(UnSubresp) - 1));
}
CloseSocket_upnphttp(h);
}
static struct upnp_subscription_element *UPnPTryToSubscribe
(struct upnphttp * h, struct process_upnp_subscription *sub)
{
int SIDNumber,rnumber;
char *SID=NULL;
struct upnp_subscription_element *new_sub=NULL;
if (h == NULL || sub == NULL)
return NULL;
if (h->subscribe_list->total_subscription >= h->subscribe_list->max_subscription_num)
return NULL;
new_sub = (struct upnp_subscription_element *) malloc(sizeof(struct upnp_subscription_element));
if (new_sub == NULL)
return NULL;
memset(new_sub, 0, sizeof(struct upnp_subscription_element));
//
// The SID must be globally unique, so lets generate it using
// a bunch of random hex characters
//
SID = (char*)malloc(SID_LEN);
if (SID == NULL) {
free(new_sub);
return NULL;
}
memset(SID,0,SID_LEN);
sprintf(SID,"uuid:");
for(SIDNumber=5;SIDNumber<=12;++SIDNumber)
{
rnumber = rand()%16;
sprintf(SID+SIDNumber,"%x",rnumber);
}
sprintf(SID+SIDNumber,"-");
for(SIDNumber=14;SIDNumber<=17;++SIDNumber)
{
rnumber = rand()%16;
sprintf(SID+SIDNumber,"%x",rnumber);
}
sprintf(SID+SIDNumber,"-");
for(SIDNumber=19;SIDNumber<=22;++SIDNumber)
{
rnumber = rand()%16;
sprintf(SID+SIDNumber,"%x",rnumber);
}
sprintf(SID+SIDNumber,"-");
for(SIDNumber=24;SIDNumber<=27;++SIDNumber)
{
rnumber = rand()%16;
sprintf(SID+SIDNumber,"%x",rnumber);
}
sprintf(SID+SIDNumber,"-");
for(SIDNumber=29;SIDNumber<=40;++SIDNumber)
{
rnumber = rand()%16;
sprintf(SID+SIDNumber,"%x",rnumber);
}
memcpy(sub->sid, SID, SID_LEN);
if (BuildSubscribeResponse(h, sub) != UPNP_E_SUCCESS) {
free(SID);
free(new_sub);
return NULL;
}
memcpy(new_sub->IP, sub->IP, IP_ADDRLEN);
new_sub->IP_inet_addr = sub->IP_inet_addr;
new_sub->port = sub->port;
memcpy(new_sub->sid, SID, SID_LEN);
memcpy(new_sub->callback_url, sub->callback_url, URL_MAX_LEN);
new_sub->TimeOut = sub->TimeOut;
//WPS2DOTX
// new_sub->subscription_timeout = h->subscribe_list->subscription_timeout;
new_sub->subscription_timeout = sub->TimeOut;
// printf("\n\nsubscription_timeout=%d\n",new_sub->subscription_timeout);
new_sub->eventID = UPNP_EVENT_SUBSCRIPTION_REQUEST;
LIST_INSERT_HEAD(&h->subscribe_list->subscription_head, new_sub, entries);
h->subscribe_list->total_subscription++;
syslog(LOG_INFO, "Subscribe: total_subscription [%d]",
(int)h->subscribe_list->total_subscription);
free(SID);
return new_sub;
}
static char *GetTokenValue(const unsigned long buf, const unsigned long len, unsigned int *Value_len)
{
unsigned long start=0, end=0;
unsigned long buffer_end;
char *line;
if (len == 0)
return NULL;
line = (char *)buf;
buffer_end = (unsigned long)line + len;
while ((unsigned long)line < buffer_end) {
if ((*line == ' ') || (*line == ':') || (*line == '-'))
line++;
else {
start = (unsigned long)line;
break;
}
}
if (start == 0) {
*Value_len = 0;
return NULL;
}
while ((unsigned long)line < buffer_end) {
if ((*line == ' ') || (*line == '\r') || (*line == '\n')) {
end = (unsigned long)line;
break;
}
else
line++;
}
if (end == 0) {
*Value_len = 0;
return NULL;
}
*Value_len = (unsigned int)(end - start);
return (char *)start;
}
static __inline__ void GetLineLen(const unsigned long buf, unsigned int *line_len)
{
unsigned long start=0;
const unsigned short MaxCharsPerLine = 1000;
unsigned short NumChars=0;
char *line;
line = (char *)buf;
start = (unsigned long)line;
while (*line != '\n') {
NumChars++;
if (NumChars >= MaxCharsPerLine) {
syslog(LOG_WARNING, "Too many characters in a line!");
*line_len = 0;
return;
}
line++;
}
*line_len = (unsigned long)line + 1 - start;
return;
}
// To do : support IPv6
static __inline__ int GetIPandPortandCallBack(const unsigned long buf, const unsigned int buf_len,
struct process_upnp_subscription *sub)
{
char *line=NULL;
unsigned long buffer_end=0;
unsigned char dot_count=0;
unsigned long start=0;
unsigned long end=0;
unsigned char GotIPandPort=0;
line = (char *)buf;
buffer_end = (unsigned long)line + buf_len;
while ((unsigned long)line < buffer_end) {
if (*line == ' ') {
line++;
continue;
}
if (strncasecmp("<http://", line, 8) != 0)
return UPNP_E_INVALID_PARAM;
else
break;
}
line += 8;
start =(unsigned long) line;
while ((unsigned long)line < buffer_end) {
if (*line == '.')
dot_count++;
if ((*line == ':') || (*line == '/')) {
if (dot_count != IP_V4_DOT_COUNT)
return UPNP_E_INVALID_PARAM;
memcpy(sub->IP, (char *)start, (unsigned long)line-start);
if ((sub->IP_inet_addr = inet_addr(sub->IP)) == -1)
return UPNP_E_INVALID_PARAM;
break;
}
line++;
}
if (*line == '/') {
sub->port = 80;
GotIPandPort = 1;
start = (unsigned long)line;
end = 0;
goto get_callback;
}
line += 1;
start = (unsigned long)line;
while ((unsigned long)line < buffer_end) {
if (*line == '/') {
end = (unsigned long)line;
if (end <= start)
return UPNP_E_INVALID_PARAM;
else {
char port[10];
char copy_size;/*CVE-2021-35392*/
memset(port, 0, 10);
/*CVE-2021-35392*/
copy_size=end-start;
if( copy_size>10 )
{
copy_size=10;
}
memcpy(port, (char *)start, copy_size);
sub->port = atoi(port);
GotIPandPort = 1;
start = (unsigned long)line;
end = 0;
break;
}
}
line++;
}
get_callback:
if (!GotIPandPort)
return UPNP_E_INVALID_PARAM;
while ((unsigned long)line < buffer_end) {
if (*line == '>') {
end = (unsigned long)line;
if (end <= start)
return UPNP_E_INVALID_PARAM;
else {
memcpy(sub->callback_url, (char *)start, end-start);
return UPNP_E_SUCCESS;
}
}
line++;
}
return UPNP_E_INVALID_PARAM;
}
static int ParseSUBSCRIBEPacket(struct upnphttp * h,
struct process_upnp_subscription *sub)
{
char *line=NULL, *value=NULL, *tmp=NULL;
unsigned int line_len=0, value_len=0, tmp_len=0;
unsigned long buffer_end=0;
if (h->req_buf == NULL || h->req_contentoff == 0)
return UPNP_E_INVALID_PARAM;
line = h->req_buf;
buffer_end = (unsigned long)h->req_buf + h->req_contentoff;
while ((unsigned long)line < buffer_end) {
if (*line == ' ') {
line++;
continue;
}
GetLineLen((const unsigned long)line, &line_len);
if (line_len == 0)
return UPNP_E_INVALID_PARAM;
else if (line_len > 2) {
if (strncasecmp("SUBSCRIBE", line, 9) == 0) {
value = GetTokenValue((const unsigned long)line+9, line_len-9, &value_len);
if (value == NULL || value_len == 0)
return UPNP_E_INVALID_PARAM;
if (strncasecmp(h->subscribe_list->event_url, value, value_len) != 0) {
syslog(LOG_WARNING, "SUBSCRIBE event url mismatched!");
return UPNP_E_INVALID_PARAM;
}
}
else if (strncasecmp("UNSUBSCRIBE", line, 11) == 0) {
value = GetTokenValue((const unsigned long)line+11, line_len-11, &value_len);
if (value == NULL || value_len == 0)
return UPNP_E_INVALID_PARAM;
if (strncasecmp(h->subscribe_list->event_url, value, value_len) != 0) {
syslog(LOG_WARNING, "UNSUBSCRIBE event url mismatched!");
return UPNP_E_INVALID_PARAM;
}
}
else if (strncasecmp("Host", line, 4) == 0) {
value = GetTokenValue((const unsigned long)line+4, line_len-4, &value_len);
if (value == NULL || value_len == 0)
return UPNP_E_INVALID_PARAM;
char host_info[30];
memset(host_info, 0, 30);
sprintf(host_info, "%s:%d", h->subscribe_list->my_IP, h->subscribe_list->my_port);
if (strncmp(value, host_info, value_len) != 0) {
syslog(LOG_WARNING, "Wrong host [%s]", host_info);
return UPNP_E_INVALID_PARAM;
}
}
else if (strncasecmp("Callback", line, 8) == 0) {
value = GetTokenValue((const unsigned long)line+8, line_len-8, &value_len);
if (value == NULL || value_len == 0 || (value_len > (URL_MAX_LEN-1)))
return UPNP_E_INVALID_PARAM;
if (GetIPandPortandCallBack((const unsigned long) value, value_len, sub) != UPNP_E_SUCCESS)
return UPNP_E_INVALID_PARAM;
}
else if (strncasecmp("Timeout", line, 7) == 0) {
value = GetTokenValue((const unsigned long)line+7, line_len-7, &value_len);
if (value == NULL || value_len == 0 || value_len < 8)
return UPNP_E_INVALID_PARAM;
if (strncasecmp("Second", value, 6) != 0)
return UPNP_E_INVALID_PARAM;
tmp = value + 6;
tmp_len = value_len - 6;
value = GetTokenValue((const unsigned long)tmp, tmp_len+1, &value_len);
if (value_len == 0)
return UPNP_E_INVALID_PARAM;
else if (value_len == 8 && (strncasecmp("infinite", line, 8) == 0))
sub->TimeOut = MAX_SUB_TIMEOUT;
else {
if (value_len > 4)
sub->TimeOut = MAX_SUB_TIMEOUT;
else {
char time_out[5];
memset(time_out, 0, 5);
memcpy(time_out, value, value_len);
sub->TimeOut = atoi(time_out);
}
}
}
else if (strncasecmp("SID", line, 3) == 0) {
value = GetTokenValue((const unsigned long)line+3, line_len-3, &value_len);
if (value == NULL || value_len == 0 || value_len < 4)
return UPNP_E_INVALID_PARAM;
if (strncasecmp("uuid", value, 4) != 0)
return UPNP_E_INVALID_PARAM;
tmp = value + 4;
tmp_len = value_len - 4;
value = GetTokenValue((const unsigned long)tmp, tmp_len+1, &value_len);
if (value == NULL || value_len == 0 || value_len != 36)
return UPNP_E_INVALID_PARAM;
char sid[SID_LEN];
memset(sid, 0, SID_LEN);
memcpy(sub->sid, "uuid:", 5);
memcpy(sub->sid+5, value, value_len);
}
}
line += line_len;
}
return UPNP_E_SUCCESS;
}
static void UPnPProcessSUBSCRIBE(struct upnphttp * h)
{
struct process_upnp_subscription sub;
struct upnp_subscription_element *new_sub=NULL;
int ret;
memset(&sub, 0, sizeof(struct process_upnp_subscription));
ret = ParseSUBSCRIBEPacket(h, &sub);
if (ret != UPNP_E_SUCCESS) {
Send412PreconditionFailed(h);
return;
}
else {
#ifdef DEBUG
printf("IP [%s]\n", sub.IP);
printf("Host [%d.%d.%d.%d:%d]\n", (sub.IP_inet_addr>>24)&0xFF,
(sub.IP_inet_addr>>16)&0xFF,
(sub.IP_inet_addr>>8)&0xFF,
(sub.IP_inet_addr)&0xFF, sub.port);
printf("SID [%s]\n", sub.sid);
printf("CallBack %s\n", sub.callback_url);
printf("Timeout [%d]\n", (int)sub.TimeOut);
#endif
if (sub.TimeOut == 0)
sub.TimeOut = MAX_SUB_TIMEOUT;
if (sub.sid[0] == 0)
{ //Subscribe
if (sub.callback_url[0] == 0) {
Send412PreconditionFailed(h);
return;
}
new_sub = UPnPTryToSubscribe(h, &sub);
if (new_sub == NULL) {
Send412TooManySubscribers(h);
return;
}
if (h->subscribe_list->EventCallBack)
h->subscribe_list->EventCallBack(new_sub);
}
else
{ // Renewal subscription
struct upnp_subscription_element *e;
struct upnp_subscription_element *next;
unsigned char count=0;
for(e = h->subscribe_list->subscription_head.lh_first; e != NULL; )
{
next = e->entries.le_next;
if(strcmp(e->sid, sub.sid) == 0)
{
count++;
if (BuildSubscribeResponse(h, &sub) != UPNP_E_SUCCESS) {
LIST_REMOVE(e, entries);
h->subscribe_list->total_subscription--;
free(e);
syslog(LOG_ERR, "UPnPProcessSUBSCRIBE : renew failed!");
return;
}
else {
//WPS2DOTX
//e->subscription_timeout = h->subscribe_list->subscription_timeout;
e->subscription_timeout = (int)sub.TimeOut;
e->eventID = UPNP_EVENT_RENEWAL_COMPLETE;
}
syslog(LOG_INFO, "Renewal subscription: total_subscription [%d]",
(int)h->subscribe_list->total_subscription);
if (h->subscribe_list->EventCallBack){
h->subscribe_list->EventCallBack(e);
if(e->wscdReNewState == 1){
Send412PreconditionFailed(h);
e->wscdReNewState = 0;
}
}
}
e = next;
}
if (count == 0) {
Send412PreconditionFailed(h);
syslog(LOG_ERR, "UPnPProcessSUBSCRIBE[renew] : Could not find the sid[%s]!", sub.sid);
if (new_sub == NULL) {
new_sub = (struct upnp_subscription_element *)malloc(sizeof(struct upnp_subscription_element));
if (new_sub == NULL)
return;
memset(new_sub, 0, sizeof(struct upnp_subscription_element));
new_sub->eventID = UPNP_EVENT_RENEWAL_COMPLETE;
memcpy(new_sub->sid, sub.sid, strlen(sub.sid));
if (h->subscribe_list->EventCallBack)
h->subscribe_list->EventCallBack(new_sub);
free(new_sub);
}
else
syslog(LOG_ERR, "UPnPProcessSUBSCRIBE[renew] : Could not allocate buffer for new_sub!");
}
}
}
}
static void UPnPProcessUNSUBSCRIBE(struct upnphttp * h)
{
struct process_upnp_subscription sub;
struct upnp_subscription_element *e;
struct upnp_subscription_element *next;
int ret;
unsigned char count=0;
memset(&sub, 0, sizeof(struct process_upnp_subscription));
ret = ParseSUBSCRIBEPacket(h, &sub);
if (ret != UPNP_E_SUCCESS) {
Send412PreconditionFailed(h);
return;
}
else {
#ifdef DEBUG
printf("IP [%s]\n", sub.IP);
printf("Host [%d.%d.%d.%d:%d]\n", (sub.IP_inet_addr>>24)&0xFF,
(sub.IP_inet_addr>>16)&0xFF,
(sub.IP_inet_addr>>8)&0xFF,
(sub.IP_inet_addr)&0xFF, sub.port);
printf("SID [%s]\n", sub.sid);
printf("CallBack %s\n", sub.callback_url);
printf("Timeout [%d]\n", (int)sub.TimeOut);
#endif
if (sub.sid[0] == 0) {
Send412PreconditionFailed(h);
return;
}
for(e = h->subscribe_list->subscription_head.lh_first; e != NULL; )
{
next = e->entries.le_next;
if(strcmp(e->sid, sub.sid) == 0)
{
count++;
LIST_REMOVE(e, entries);
BuildUnSubscribeResponse(h);
h->subscribe_list->total_subscription--;
syslog(LOG_INFO, "UNSUBSCRIBE: total_subscription [%d]",
(int)h->subscribe_list->total_subscription);
e->eventID = UPNP_EVENT_UNSUBSCRIBE_COMPLETE;
if (h->subscribe_list->EventCallBack)
h->subscribe_list->EventCallBack(e);
free(e);
}
e = next;
}
if (count == 0) {
BuildUnSubscribeResponse(h);
syslog(LOG_ERR, "UPnPProcessUNSUBSCRIBE : Could not find the sid!");
}
}
}
/* Parse and process Http Query
* called once all the HTTP headers have been received. */
static void ProcessHttpQuery_upnphttp(struct upnphttp * h)
{
char HttpCommand[16];
char HttpUrl[128];
char * HttpVer;
char * p;
int i;
p = h->req_buf;
if(!p)
return;
for(i = 0; i<15 && *p != ' ' && *p != '\r'; i++)
HttpCommand[i] = *(p++);
HttpCommand[i] = '\0';
while(*p==' ')
p++;
for(i = 0; i<127 && *p != ' ' && *p != '\r'; i++)
HttpUrl[i] = *(p++);
HttpUrl[i] = '\0';
while(*p==' ')
p++;
HttpVer = h->HttpVer;
for(i = 0; i<15 && *p != '\r'; i++)
HttpVer[i] = *(p++);
HttpVer[i] = '\0';
syslog(LOG_INFO, "HTTP REQUEST : %s %s (%s)",
HttpCommand, HttpUrl, HttpVer);
ParseHttpHeaders(h);
if(strcmp("POST", HttpCommand) == 0)
{
h->req_command = EPost;
ProcessHTTPPOST_upnphttp(h);
}
else if(strcmp("GET", HttpCommand) == 0)
{
h->req_command = EGet;
if (strncasecmp((char *)h->req_buf, "GET /HNAP", 9) == 0) {
i = 0;
int len;
while(h->soapMethods[i].methodName)
{
len = strlen(h->soapMethods[i].methodName);
if(strncmp("GetDeviceSettings", h->soapMethods[i].methodName, len) == 0)
{
h->soapMethods[i].methodImpl(h);
return;
}
i++;
}
syslog(LOG_NOTICE, "%s not found, responding ERROR 404", HttpUrl);
Send404(h);
return;
}
i = 0;
if (h->sendDesc) {
while(h->sendDesc[i].DescName)
{
if(strcmp(h->sendDesc[i].DescName, HttpUrl) == 0)
{
sendXMLdesc(h, h->sendDesc[i].sendDescImpl);
return;
}
i++;
}
}
syslog(LOG_NOTICE, "%s not found, responding ERROR 404", HttpUrl);
Send404(h);
}
else if(strcmp("SUBSCRIBE", HttpCommand) == 0)
{
//printf("<<--------------------\n%s\n------------------->>\n", h->req_buf);
UPnPProcessSUBSCRIBE(h);
}
else if(strcmp("UNSUBSCRIBE", HttpCommand) == 0)
{
//printf("<<--------------------\n%s\n------------------->>\n", h->req_buf);
UPnPProcessUNSUBSCRIBE(h);
}
else
{
syslog(LOG_NOTICE, "Unsupported HTTP Command %s", HttpCommand);
Send501(h);
}
}
void Process_upnphttp(struct upnphttp * h)
{
char *buf=NULL;
int n;
if(!h)
return;
buf = (char *) malloc(2048);
if (buf == NULL) {
syslog(LOG_ERR, "Process_upnphttp: out of memory!");
return;
}
memset(buf, 0, 2048);
switch(h->state)
{
case 0:
n = recv(h->socket, buf, 2048, 0);
if(n<0)
{
syslog(LOG_ERR, "recv (state0): %m");
h->state = 100;
}
else if(n==0)
{
syslog(LOG_WARNING, "connection closed inexpectedly");
h->state = 100;
}
else
{
const char * endheaders;
/*printf("== PACKET RECEIVED (%d bytes) ==\n", n);
fwrite(buf, 1, n, stdout); // debug
printf("== END OF PACKET RECEIVED ==\n");*/
/* if 1st arg of realloc() is null,
* realloc behaves the same as malloc() */
//h->req_buf = (char *)realloc(h->req_buf, n + h->req_buflen + 1);
h->req_buf = (char *)realloc(h->req_buf, 2048); //Brad modify for HNAP, bug fix
memcpy(h->req_buf + h->req_buflen, buf, n);
h->req_buflen += n;
h->req_buf[h->req_buflen] = '\0';
/* search for the string "\r\n\r\n" */
endheaders = findendheaders(h->req_buf, h->req_buflen);
if(endheaders)
{
h->req_contentoff = endheaders - h->req_buf + 4;
ProcessHttpQuery_upnphttp(h);
}
}
break;
case 1:
n = recv(h->socket, buf, 2048, 0);
if(n<0)
{
syslog(LOG_ERR, "recv (state1): %m");
h->state = 100;
}
else if(n==0)
{
syslog(LOG_WARNING, "connection closed inexpectedly");
h->state = 100;
}
else
{
/*fwrite(buf, 1, n, stdout);*/ /* debug */
h->req_buf = (char *)realloc(h->req_buf, n + h->req_buflen);
memcpy(h->req_buf + h->req_buflen, buf, n);
h->req_buflen += n;
if((h->req_buflen - h->req_contentoff) >= h->req_contentlen)
{
ProcessHTTPPOST_upnphttp(h);
}
}
break;
default:
syslog(LOG_WARNING, "unexpected state (%d)", h->state);
}
free(buf);
}
static const char httpresphead[] =
"%s %d %s\r\n"
"Content-Type: text/xml; charset=\"utf-8\"\r\n"
"Connection: close\r\n"
"Content-Length: %d\r\n"
"Server: " MINIUPNPD_SERVER_STRING "\r\n"
"Ext:\r\n"
"\r\n";
/*
"<?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>"
"</s:Body>"
"</s:Envelope>";
*/
/* with response code and response message
* also allocate enough memory */
void
BuildHeader_upnphttp(struct upnphttp * h, int respcode,
const char * respmsg,
int bodylen)
{
int templen;
if(!h->res_buf)
{
templen = sizeof(httpresphead) + 64 + bodylen;
h->res_buf = (char *)malloc(templen);
memset(h->res_buf, 0, templen);
h->res_buf_alloclen = templen;
}
h->res_buflen = snprintf(h->res_buf, h->res_buf_alloclen,
httpresphead, h->HttpVer,
respcode, respmsg, bodylen);
if(h->res_buf_alloclen < (h->res_buflen + bodylen))
{
h->res_buf = (char *)realloc(h->res_buf, (h->res_buflen + bodylen));
memset(h->res_buf, 0, (h->res_buflen + bodylen));
h->res_buf_alloclen = h->res_buflen + bodylen;
}
}
void
BuildResp2_upnphttp(struct upnphttp * h, int respcode,
const char * respmsg,
const char * body, int bodylen)
{
BuildHeader_upnphttp(h, respcode, respmsg, bodylen);
memcpy(h->res_buf + h->res_buflen, body, bodylen);
h->res_buflen += bodylen;
}
/* responding 200 OK ! */
void BuildResp_upnphttp(struct upnphttp * h,
const char * body, int bodylen)
{
BuildResp2_upnphttp(h, 200, "OK", body, bodylen);
}
void SendResp_upnphttp(struct upnphttp * h)
{
int n;
n = ReliableSend(h->socket, h->res_buf, h->res_buflen);
if (n != h->res_buflen)
{
syslog(LOG_ERR, "SendResp_upnphttp: %d bytes sent (out of %d)",
n, h->res_buflen);
}
}
static const char cb64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static const char cd64[]="|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW$$$$$$XYZ[\\]^_`abcdefghijklmnopq";
/* encode 3 8-bit binary bytes as 4 '6-bit' characters */
static void ILibencodeblock( unsigned char in[3], unsigned char out[4], int len )
{
out[0] = cb64[ in[0] >> 2 ];
out[1] = cb64[ ((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4) ];
out[2] = (unsigned char) (len > 1 ? cb64[ ((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6) ] : '=');
out[3] = (unsigned char) (len > 2 ? cb64[ in[2] & 0x3f ] : '=');
}
/*! \fn ILibBase64Encode(unsigned char* input, const int inputlen, unsigned char** output)
\brief Base64 encode a stream adding padding and line breaks as per spec.
\par
\b Note: The encoded stream must be freed
\param input The stream to encode
\param inputlen The length of \a input
\param output The encoded stream
\returns The length of the encoded stream
*/
int ILibBase64Encode(unsigned char* input, const int inputlen, unsigned char** output)
{
unsigned char* out=NULL;
unsigned char* in;
*output = (unsigned char*)malloc(((inputlen * 4) / 3) + 5);
out = *output;
if (out == NULL)
return 0;
in = input;
if (input == NULL || inputlen == 0)
{
*output = NULL;
return 0;
}
while ((in+3) <= (input+inputlen))
{
ILibencodeblock(in, out, 3);
in += 3;
out += 4;
}
if ((input+inputlen)-in == 1)
{
ILibencodeblock(in, out, 1);
out += 4;
}
else
if ((input+inputlen)-in == 2)
{
ILibencodeblock(in, out, 2);
out += 4;
}
*out = 0;
return (int)(out-*output);
}
/* Decode 4 '6-bit' characters into 3 8-bit binary bytes */
static void ILibdecodeblock( unsigned char in[4], unsigned char out[3] )
{
out[ 0 ] = (unsigned char ) (in[0] << 2 | in[1] >> 4);
out[ 1 ] = (unsigned char ) (in[1] << 4 | in[2] >> 2);
out[ 2 ] = (unsigned char ) (((in[2] << 6) & 0xc0) | in[3]);
}
/*! \fn ILibBase64Decode(unsigned char* input, const int inputlen, unsigned char** output)
\brief Decode a base64 encoded stream discarding padding, line breaks and noise
\par
\b Note: The decoded stream must be freed
\param input The stream to decode
\param inputlen The length of \a input
\param output The decoded stream
\returns The length of the decoded stream
*/
int ILibBase64Decode(unsigned char* input, const int inputlen, unsigned char** output)
{
unsigned char* inptr;
unsigned char* out=NULL;
unsigned char v;
unsigned char in[4];
int i, len;
if (input == NULL || inputlen == 0)
{
*output = NULL;
return 0;
}
*output = (unsigned char*)malloc(((inputlen * 3) / 4) + 4);
out = *output;
if (out == NULL)
return 0;
inptr = input;
while( inptr <= (input+inputlen) )
{
for( len = 0, i = 0; i < 4 && inptr <= (input+inputlen); i++ )
{
v = 0;
while( inptr <= (input+inputlen) && v == 0 ) {
v = (unsigned char) *inptr;
inptr++;
v = (unsigned char) ((v < 43 || v > 122) ? 0 : cd64[ v - 43 ]);
if( v ) {
v = (unsigned char) ((v == '$') ? 0 : v - 61);
}
}
if( inptr <= (input+inputlen) ) {
len++;
if( v ) {
in[ i ] = (unsigned char) (v - 1);
}
}
else {
in[i] = 0;
}
}
if( len )
{
ILibdecodeblock( in, out );
out += len-1;
}
}
*out = 0;
return (int)(out-*output);
}
int OpenAndConfUNIXSocket(const char *file_path)
{
int s, len;
struct sockaddr_un local;
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
perror("UNIXSocket");
return -1;
}
local.sun_family = AF_UNIX;
strcpy(local.sun_path, file_path);
unlink(local.sun_path);
//len = strlen(local.sun_path) + sizeof(local.sun_family);
len = sizeof(struct sockaddr_un);
if (bind(s, (struct sockaddr *)&local, len) == -1) {
perror("UNIXSocket bind");
return -1;
}
if (listen(s, 5) == -1) {
perror("UNIXSocket listen");
return -1;
}
return s;
}
int CreateUnixSocket(const char *function_name,
const char *file_path,
const int time_out)
{
struct sockaddr_un remote;
struct timeval tv;
int len, s;
if (file_path == NULL)
return -1;
if (time_out < 0)
return -1;
// Inter Process Communication
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
return -1;
}
tv.tv_sec = time_out;
tv.tv_usec = 0;
if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(struct timeval)) < 0)
{
if (function_name) {
syslog(LOG_WARNING, "%s : setsockopt(unix_socket, SO_RCVTIMEO): %m", function_name);
}
else {
syslog(LOG_WARNING, "setsockopt(unix_socket, SO_RCVTIMEO): %m");
}
}
remote.sun_family = AF_UNIX;
strcpy(remote.sun_path, file_path);
//len = strlen(remote.sun_path) + sizeof(remote.sun_family);
len = sizeof(struct sockaddr_un);
if (connect(s, (struct sockaddr *)&remote, len) == -1) {
close(s);
return -1;
}
return s;
}
int UnixSocketSendAndReceive(const char *function_name,
const char *file_path,
const int time_out,
const char *in, char *out, const int out_len)
{
int s=-1, t, in_len, ret=-1;
if (file_path == NULL || in == NULL || out == NULL || out_len < 1)
return -1;
s = CreateUnixSocket(function_name, file_path, time_out);
if (s == -1) {
if (function_name)
syslog(LOG_ERR, "%s : CreateUnixSocket failed", function_name);
goto finish;
}
in_len = strlen(in);
if (ReliableSend(s, in, in_len) != in_len) {
if (function_name) {
syslog(LOG_ERR, "%s : Unix socket send: %m", function_name);
}
goto finish;
}
if ((t = recv(s, out, out_len, 0)) > 0) {
out[t] = '\0';
ret = 0;
}
else {
if (t < 0) {
if (function_name) {
syslog(LOG_ERR, "%s : Unix socket recv: %m", function_name);
}
}
else {
if (function_name) {
syslog(LOG_WARNING, "%s : Server closed connection: %m", function_name);
}
}
}
finish:
if (s >= 0)
close(s);
return ret;
}