Make my little standalone http server report its own public address instead of needing to visit random websites.
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5879 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
parent
84d6ef3e45
commit
c8ca5f09e1
3 changed files with 689 additions and 445 deletions
|
@ -126,8 +126,36 @@ void checknatpmp(int port)
|
||||||
typedef enum {HTTP_WAITINGFORREQUEST,HTTP_SENDING} http_mode_t;
|
typedef enum {HTTP_WAITINGFORREQUEST,HTTP_SENDING} http_mode_t;
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
static qboolean HTTP_DoAccepts(int epfd);
|
||||||
|
struct http_epoll_ctx
|
||||||
|
{
|
||||||
|
struct epollctx_s pub;
|
||||||
|
int epollfd;
|
||||||
|
};
|
||||||
|
static void HTTP_ServerEPolled(struct epollctx_s *pubctx, unsigned int ev)
|
||||||
|
{
|
||||||
|
struct http_epoll_ctx *ctx = (struct http_epoll_ctx*)pubctx;
|
||||||
|
if (!HTTP_DoAccepts(ctx->epollfd))
|
||||||
|
{
|
||||||
|
int e = neterrno();
|
||||||
|
switch(e)
|
||||||
|
{
|
||||||
|
/*case NET_EWOULDBLOCK:
|
||||||
|
break;
|
||||||
|
case NET_ECONNABORTED:
|
||||||
|
case NET_ECONNRESET:
|
||||||
|
Con_TPrintf ("Connection lost or aborted\n");
|
||||||
|
break;*/
|
||||||
|
default:
|
||||||
|
IWebPrintf ("NET_GetPacket: %s\n", strerror(e));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
qboolean HTTP_ServerInit(int port)
|
qboolean HTTP_ServerInit(int epfd, int port)
|
||||||
{
|
{
|
||||||
struct sockaddr_qstorage address;
|
struct sockaddr_qstorage address;
|
||||||
unsigned long _true = true;
|
unsigned long _true = true;
|
||||||
|
@ -173,7 +201,7 @@ qboolean HTTP_ServerInit(int port)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( bind (httpserversocket, (void *)&address, sizeof(address)) == -1)
|
if (bind (httpserversocket, (void *)&address, sizeof(address)) == -1)
|
||||||
{
|
{
|
||||||
closesocket(httpserversocket);
|
closesocket(httpserversocket);
|
||||||
IWebPrintf("HTTP_ServerInit: failed to bind to socket\n");
|
IWebPrintf("HTTP_ServerInit: failed to bind to socket\n");
|
||||||
|
@ -187,6 +215,19 @@ qboolean HTTP_ServerInit(int port)
|
||||||
httpserverfailed = false;
|
httpserverfailed = false;
|
||||||
httpserverport = port;
|
httpserverport = port;
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
if (epfd >= 0)
|
||||||
|
{
|
||||||
|
static struct http_epoll_ctx ctx;
|
||||||
|
struct epoll_event ev;
|
||||||
|
ctx.epollfd = epfd;
|
||||||
|
ctx.pub.Polled = HTTP_ServerEPolled;
|
||||||
|
ev.events = EPOLLIN;
|
||||||
|
ev.data.ptr = &ctx;
|
||||||
|
epoll_ctl(epfd, EPOLL_CTL_ADD, httpserversocket, &ev);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
IWebPrintf("HTTP server is running\n");
|
IWebPrintf("HTTP server is running\n");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -200,6 +241,10 @@ void HTTP_ServerShutdown(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct HTTP_active_connections_s {
|
typedef struct HTTP_active_connections_s {
|
||||||
|
#ifndef _WIN32
|
||||||
|
struct epollctx_s pub;
|
||||||
|
int epfd;
|
||||||
|
#endif
|
||||||
SOCKET datasock;
|
SOCKET datasock;
|
||||||
char peername[256];
|
char peername[256];
|
||||||
vfsfile_t *file;
|
vfsfile_t *file;
|
||||||
|
@ -208,7 +253,6 @@ typedef struct HTTP_active_connections_s {
|
||||||
http_mode_t mode;
|
http_mode_t mode;
|
||||||
qboolean modeswitched;
|
qboolean modeswitched;
|
||||||
qboolean closeaftertransaction;
|
qboolean closeaftertransaction;
|
||||||
char *closereason;
|
|
||||||
qboolean acceptgzip;
|
qboolean acceptgzip;
|
||||||
|
|
||||||
char *inbuffer;
|
char *inbuffer;
|
||||||
|
@ -249,7 +293,7 @@ static void ExpandOutBuffer(HTTP_active_connections_t *cl, unsigned int quant, q
|
||||||
cl->outbuffersize = newsize;
|
cl->outbuffersize = newsize;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HTTP_RunExisting (void)
|
const char *HTTP_RunClient (HTTP_active_connections_t *cl)
|
||||||
{
|
{
|
||||||
char *content;
|
char *content;
|
||||||
char *msg, *nl;
|
char *msg, *nl;
|
||||||
|
@ -263,35 +307,8 @@ void HTTP_RunExisting (void)
|
||||||
int HTTPmarkup; //version
|
int HTTPmarkup; //version
|
||||||
int localerrno;
|
int localerrno;
|
||||||
|
|
||||||
HTTP_active_connections_t **link, *cl;
|
|
||||||
|
|
||||||
link = &HTTP_ServerConnections;
|
|
||||||
for (link = &HTTP_ServerConnections; *link;)
|
|
||||||
{
|
|
||||||
int ammount, wanted;
|
int ammount, wanted;
|
||||||
|
|
||||||
cl = *link;
|
|
||||||
|
|
||||||
if (cl->closereason)
|
|
||||||
{
|
|
||||||
IWebPrintf("%s: Closing connection: %s\n", cl->peername, cl->closereason);
|
|
||||||
|
|
||||||
*link = cl->next;
|
|
||||||
closesocket(cl->datasock);
|
|
||||||
cl->datasock = INVALID_SOCKET;
|
|
||||||
if (cl->inbuffer)
|
|
||||||
IWebFree(cl->inbuffer);
|
|
||||||
if (cl->outbuffer)
|
|
||||||
IWebFree(cl->outbuffer);
|
|
||||||
if (cl->file)
|
|
||||||
VFS_CLOSE(cl->file);
|
|
||||||
IWebFree(cl);
|
|
||||||
httpconnectioncount--;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
link = &(*link)->next;
|
|
||||||
|
|
||||||
switch(cl->mode)
|
switch(cl->mode)
|
||||||
{
|
{
|
||||||
case HTTP_WAITINGFORREQUEST:
|
case HTTP_WAITINGFORREQUEST:
|
||||||
|
@ -301,10 +318,7 @@ void HTTP_RunExisting (void)
|
||||||
if (ammount < 128)
|
if (ammount < 128)
|
||||||
{
|
{
|
||||||
if (cl->inbuffersize>128*1024)
|
if (cl->inbuffersize>128*1024)
|
||||||
{
|
return "headers larger than 128kb"; //that's just taking the piss.
|
||||||
cl->closereason = "headers larger than 128kb"; //that's just taking the piss.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ExpandInBuffer(cl, 1500, false);
|
ExpandInBuffer(cl, 1500, false);
|
||||||
ammount = cl->inbuffersize-1 - cl->inbufferused;
|
ammount = cl->inbuffersize-1 - cl->inbufferused;
|
||||||
|
@ -320,17 +334,12 @@ void HTTP_RunExisting (void)
|
||||||
if (ammount < 0)
|
if (ammount < 0)
|
||||||
{
|
{
|
||||||
int e = neterrno();
|
int e = neterrno();
|
||||||
if (e != NET_EWOULDBLOCK) //they closed on us. Assume end.
|
if (e == NET_EWOULDBLOCK) //they closed on us. Assume end.
|
||||||
{
|
return NULL;
|
||||||
cl->closereason = "recv error";
|
return "recv error";
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
if (ammount == 0)
|
if (ammount == 0)
|
||||||
{
|
return "peer closed connection";
|
||||||
cl->closereason = "peer closed connection";
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
cl->modeswitched = false;
|
cl->modeswitched = false;
|
||||||
|
|
||||||
|
@ -341,10 +350,7 @@ void HTTP_RunExisting (void)
|
||||||
msg = cl->inbuffer;
|
msg = cl->inbuffer;
|
||||||
nl = strchr(msg, '\n');
|
nl = strchr(msg, '\n');
|
||||||
if (!nl)
|
if (!nl)
|
||||||
{
|
return NULL; //we need more... MORE!!! MORE I TELL YOU!!!!
|
||||||
cont:
|
|
||||||
continue; //we need more... MORE!!! MORE I TELL YOU!!!!
|
|
||||||
}
|
|
||||||
|
|
||||||
//FIXME: COM_ParseOut recognises // comments, which is not correct.
|
//FIXME: COM_ParseOut recognises // comments, which is not correct.
|
||||||
msg = COM_ParseOut(msg, mode, sizeof(mode));
|
msg = COM_ParseOut(msg, mode, sizeof(mode));
|
||||||
|
@ -352,10 +358,7 @@ cont:
|
||||||
msg = COM_ParseOut(msg, resource, sizeof(resource));
|
msg = COM_ParseOut(msg, resource, sizeof(resource));
|
||||||
|
|
||||||
if (!*resource)
|
if (!*resource)
|
||||||
{
|
return "not http"; //even if they forgot to specify a resource, we didn't find an HTTP so we have no option but to close.
|
||||||
cl->closereason = "not http"; //even if they forgot to specify a resource, we didn't find an HTTP so we have no option but to close.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
host[0] = '?';
|
host[0] = '?';
|
||||||
host[1] = 0;
|
host[1] = 0;
|
||||||
|
@ -478,7 +481,10 @@ cont:
|
||||||
{
|
{
|
||||||
if (!*msg)
|
if (!*msg)
|
||||||
{
|
{
|
||||||
goto cont;
|
if (msg == cl->inbuffer+cl->inbufferused)
|
||||||
|
return NULL;
|
||||||
|
else
|
||||||
|
return "Unexpected null byte";
|
||||||
}
|
}
|
||||||
msg++;
|
msg++;
|
||||||
}
|
}
|
||||||
|
@ -493,7 +499,7 @@ cont:
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cl->inbufferused-(msg-cl->inbuffer) < contentlen)
|
if (cl->inbufferused-(msg-cl->inbuffer) < contentlen)
|
||||||
continue;
|
return NULL;
|
||||||
|
|
||||||
cl->modeswitched = true;
|
cl->modeswitched = true;
|
||||||
|
|
||||||
|
@ -623,7 +629,7 @@ notimplemented:
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
msg = NULL;
|
msg = NULL;
|
||||||
cl->closereason = "unsupported http version";
|
return "unsupported http version";
|
||||||
}
|
}
|
||||||
IWebPrintf("%s: 501 - not implemented\n", cl->peername);
|
IWebPrintf("%s: 501 - not implemented\n", cl->peername);
|
||||||
|
|
||||||
|
@ -668,9 +674,7 @@ notimplemented:
|
||||||
{
|
{
|
||||||
localerrno = neterrno();
|
localerrno = neterrno();
|
||||||
if (localerrno != NET_EWOULDBLOCK)
|
if (localerrno != NET_EWOULDBLOCK)
|
||||||
{
|
return "some error when sending";
|
||||||
cl->closereason = "some error when sending";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (ammount||!cl->outbufferused)
|
else if (ammount||!cl->outbufferused)
|
||||||
{
|
{
|
||||||
|
@ -681,14 +685,14 @@ notimplemented:
|
||||||
cl->modeswitched = true;
|
cl->modeswitched = true;
|
||||||
cl->mode = HTTP_WAITINGFORREQUEST;
|
cl->mode = HTTP_WAITINGFORREQUEST;
|
||||||
if (cl->closeaftertransaction)
|
if (cl->closeaftertransaction)
|
||||||
cl->closereason = "file sent";
|
return "file sent";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
cl->closereason = "peer prematurely closed connection";
|
return "peer prematurely closed connection";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* case HTTP_RECEIVING:
|
/* case HTTP_RECEIVING:
|
||||||
sent = recv(cl->datasock, resource, ammount, 0);
|
sent = recv(cl->datasock, resource, ammount, 0);
|
||||||
if (sent == -1)
|
if (sent == -1)
|
||||||
{
|
{
|
||||||
|
@ -703,25 +707,141 @@ notimplemented:
|
||||||
if (sent != 0)
|
if (sent != 0)
|
||||||
IWebFWrite(resource, 1, sent, cl->file);
|
IWebFWrite(resource, 1, sent, cl->file);
|
||||||
break;*/
|
break;*/
|
||||||
|
default:
|
||||||
|
return "Unknown state";
|
||||||
}
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HTTP_RunExisting (void)
|
||||||
|
{
|
||||||
|
const char *err;
|
||||||
|
HTTP_active_connections_t **link, *cl;
|
||||||
|
|
||||||
|
link = &HTTP_ServerConnections;
|
||||||
|
for (link = &HTTP_ServerConnections; *link;)
|
||||||
|
{
|
||||||
|
cl = *link;
|
||||||
|
|
||||||
|
err = HTTP_RunClient(cl);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
IWebPrintf("%s: Closing connection: %s\n", cl->peername, err);
|
||||||
|
|
||||||
|
*link = cl->next;
|
||||||
|
closesocket(cl->datasock);
|
||||||
|
cl->datasock = INVALID_SOCKET;
|
||||||
|
if (cl->inbuffer)
|
||||||
|
IWebFree(cl->inbuffer);
|
||||||
|
if (cl->outbuffer)
|
||||||
|
IWebFree(cl->outbuffer);
|
||||||
|
if (cl->file)
|
||||||
|
VFS_CLOSE(cl->file);
|
||||||
|
IWebFree(cl);
|
||||||
|
httpconnectioncount--;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
link = &(*link)->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
static void HTTP_ClientEPolled(struct epollctx_s *pubctx, unsigned int ev)
|
||||||
|
{
|
||||||
|
HTTP_active_connections_t *cl = (HTTP_active_connections_t *)pubctx;
|
||||||
|
const char *err = HTTP_RunClient(cl);
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
IWebPrintf("%s: Closing connection: %s\n", cl->peername, err);
|
||||||
|
|
||||||
|
//should be automatic thanks to the closesocket, but do it just in case.
|
||||||
|
epoll_ctl(cl->epfd, EPOLL_CTL_DEL, cl->datasock, NULL);
|
||||||
|
|
||||||
|
closesocket(cl->datasock);
|
||||||
|
cl->datasock = INVALID_SOCKET;
|
||||||
|
if (cl->inbuffer)
|
||||||
|
IWebFree(cl->inbuffer);
|
||||||
|
if (cl->outbuffer)
|
||||||
|
IWebFree(cl->outbuffer);
|
||||||
|
if (cl->file)
|
||||||
|
VFS_CLOSE(cl->file);
|
||||||
|
IWebFree(cl);
|
||||||
|
httpconnectioncount--;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
struct epoll_event ev;
|
||||||
|
switch(cl->mode)
|
||||||
|
{
|
||||||
|
case HTTP_WAITINGFORREQUEST:
|
||||||
|
ev.events = EPOLLIN;
|
||||||
|
break;
|
||||||
|
case HTTP_SENDING:
|
||||||
|
ev.events = EPOLLOUT;
|
||||||
|
break;
|
||||||
|
default: //don't know, spam it.
|
||||||
|
ev.events = EPOLLIN|EPOLLOUT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ev.data.ptr = &cl->pub;
|
||||||
|
epoll_ctl(cl->epfd, EPOLL_CTL_ADD, cl->datasock, &ev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static qboolean HTTP_DoAccepts(int epfd)
|
||||||
|
{
|
||||||
|
struct sockaddr_qstorage from;
|
||||||
|
int fromlen = sizeof(from);
|
||||||
|
HTTP_active_connections_t *cl;
|
||||||
|
int _true = true;
|
||||||
|
int clientsock = accept(httpserversocket, (struct sockaddr *)&from, &fromlen);
|
||||||
|
|
||||||
|
if (clientsock < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (ioctlsocket (clientsock, FIONBIO, (u_long *)&_true) == -1)
|
||||||
|
{
|
||||||
|
IWebPrintf ("HTTP_ServerInit: ioctl FIONBIO: %s\n", strerror(neterrno()));
|
||||||
|
closesocket(clientsock);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
cl = IWebMalloc(sizeof(HTTP_active_connections_t));
|
||||||
|
NET_SockadrToString(cl->peername, sizeof(cl->peername), &from, sizeof(from));
|
||||||
|
IWebPrintf("%s: New http connection\n", cl->peername);
|
||||||
|
|
||||||
|
cl->datasock = clientsock;
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
if (epfd >= 0)
|
||||||
|
{
|
||||||
|
struct epoll_event ev;
|
||||||
|
cl->pub.Polled = HTTP_ClientEPolled;
|
||||||
|
cl->epfd = epfd;
|
||||||
|
ev.events = EPOLLIN|EPOLLOUT;
|
||||||
|
ev.data.ptr = &cl->pub;
|
||||||
|
epoll_ctl(epfd, EPOLL_CTL_ADD, clientsock, &ev);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
cl->next = HTTP_ServerConnections;
|
||||||
|
HTTP_ServerConnections = cl;
|
||||||
|
}
|
||||||
|
httpconnectioncount++;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
qboolean HTTP_ServerPoll(qboolean httpserverwanted, int portnum) //loop while true
|
qboolean HTTP_ServerPoll(qboolean httpserverwanted, int portnum) //loop while true
|
||||||
{
|
{
|
||||||
struct sockaddr_qstorage from;
|
|
||||||
int fromlen;
|
|
||||||
int clientsock;
|
|
||||||
int _true = true;
|
|
||||||
|
|
||||||
HTTP_active_connections_t *cl;
|
|
||||||
|
|
||||||
if (httpserverport != portnum && httpserverinitied)
|
if (httpserverport != portnum && httpserverinitied)
|
||||||
HTTP_ServerShutdown();
|
HTTP_ServerShutdown();
|
||||||
if (!httpserverinitied)
|
if (!httpserverinitied)
|
||||||
{
|
{
|
||||||
if (httpserverwanted)
|
if (httpserverwanted)
|
||||||
return HTTP_ServerInit(portnum);
|
return HTTP_ServerInit(-1, portnum);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (!httpserverwanted)
|
else if (!httpserverwanted)
|
||||||
|
@ -735,10 +855,7 @@ qboolean HTTP_ServerPoll(qboolean httpserverwanted, int portnum) //loop while tr
|
||||||
if (httpconnectioncount>32)
|
if (httpconnectioncount>32)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
fromlen = sizeof(from);
|
if (!HTTP_DoAccepts(-1))
|
||||||
clientsock = accept(httpserversocket, (struct sockaddr *)&from, &fromlen);
|
|
||||||
|
|
||||||
if (clientsock == -1)
|
|
||||||
{
|
{
|
||||||
int e = neterrno();
|
int e = neterrno();
|
||||||
if (e == NET_EWOULDBLOCK)
|
if (e == NET_EWOULDBLOCK)
|
||||||
|
@ -757,24 +874,6 @@ qboolean HTTP_ServerPoll(qboolean httpserverwanted, int portnum) //loop while tr
|
||||||
IWebPrintf ("NET_GetPacket: %s\n", strerror(e));
|
IWebPrintf ("NET_GetPacket: %s\n", strerror(e));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ioctlsocket (clientsock, FIONBIO, (u_long *)&_true) == -1)
|
|
||||||
{
|
|
||||||
IWebPrintf ("HTTP_ServerInit: ioctl FIONBIO: %s\n", strerror(neterrno()));
|
|
||||||
closesocket(clientsock);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
cl = IWebMalloc(sizeof(HTTP_active_connections_t));
|
|
||||||
NET_SockadrToString(cl->peername, sizeof(cl->peername), &from, sizeof(from));
|
|
||||||
IWebPrintf("%s: New http connection\n", cl->peername);
|
|
||||||
|
|
||||||
cl->datasock = clientsock;
|
|
||||||
|
|
||||||
cl->next = HTTP_ServerConnections;
|
|
||||||
HTTP_ServerConnections = cl;
|
|
||||||
httpconnectioncount++;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -62,7 +62,8 @@ char *Q_strcpyline(char *out, const char *in, int maxlen);
|
||||||
|
|
||||||
//server tick/control functions
|
//server tick/control functions
|
||||||
iwboolean FTP_ServerRun(iwboolean ftpserverwanted, int port);
|
iwboolean FTP_ServerRun(iwboolean ftpserverwanted, int port);
|
||||||
qboolean HTTP_ServerPoll(qboolean httpserverwanted, int port);
|
|
||||||
|
qboolean HTTP_ServerInit(int epfd, int port);
|
||||||
|
|
||||||
//server interface called from main server routines.
|
//server interface called from main server routines.
|
||||||
void IWebInit(void);
|
void IWebInit(void);
|
||||||
|
|
|
@ -149,6 +149,132 @@ int COM_CheckParm(const char *parm)
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
struct stun_ctx
|
||||||
|
{
|
||||||
|
struct epollctx_s pub;
|
||||||
|
int udpsock;
|
||||||
|
int reportport;
|
||||||
|
int id[3];
|
||||||
|
};
|
||||||
|
struct stunheader_s
|
||||||
|
{
|
||||||
|
unsigned short msgtype;
|
||||||
|
unsigned short msglen;
|
||||||
|
unsigned int magiccookie;
|
||||||
|
unsigned int transactid[3];
|
||||||
|
};
|
||||||
|
static void StunResponse(struct epollctx_s *pubctx, unsigned int ev)
|
||||||
|
{
|
||||||
|
struct stun_ctx *ctx = (struct stun_ctx*)pubctx;
|
||||||
|
unsigned char buf[8192];
|
||||||
|
int respsize = recvfrom(ctx->udpsock, buf, sizeof(buf), 0, NULL, NULL);
|
||||||
|
int offset;
|
||||||
|
struct stunheader_s *h = (struct stunheader_s*)buf;
|
||||||
|
if (h->transactid[0] != ctx->id[0] ||
|
||||||
|
h->transactid[1] != ctx->id[1] ||
|
||||||
|
h->transactid[2] != ctx->id[2])
|
||||||
|
return; //someone trying to spoof?
|
||||||
|
|
||||||
|
if (((buf[0]<<8)|buf[1]) == 0x0101)
|
||||||
|
{
|
||||||
|
unsigned short attr;
|
||||||
|
unsigned short sz;
|
||||||
|
offset = sizeof(struct stunheader_s);
|
||||||
|
while (offset+4 < respsize)
|
||||||
|
{
|
||||||
|
attr = (buf[offset+0]<<8)|buf[offset+1];
|
||||||
|
sz = (buf[offset+2]<<8)|buf[offset+3];
|
||||||
|
offset+= 4;
|
||||||
|
|
||||||
|
if (offset + sz > respsize)
|
||||||
|
break; //corrupt.
|
||||||
|
if ((attr == 0x1 || attr == 0x20) && sz >= 4)
|
||||||
|
{
|
||||||
|
unsigned short type = (buf[offset+0]<<8)|buf[offset+1];
|
||||||
|
unsigned short port = (buf[offset+2]<<8)|buf[offset+3];
|
||||||
|
if (attr == 0x20)
|
||||||
|
port ^= (buf[4]<<8)|buf[5];
|
||||||
|
if (sz == 4+4 && type == 1)
|
||||||
|
{
|
||||||
|
printf("Address: %s%i.%i.%i.%i:%u\n",
|
||||||
|
ctx->reportport?"http://":"",
|
||||||
|
buf[offset+4]^((attr == 0x20)?buf[4]:0),
|
||||||
|
buf[offset+5]^((attr == 0x20)?buf[5]:0),
|
||||||
|
buf[offset+6]^((attr == 0x20)?buf[6]:0),
|
||||||
|
buf[offset+7]^((attr == 0x20)?buf[7]:0),ctx->reportport?ctx->reportport:port
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
offset += sz;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void PrepareStun(int epfd, int reportport)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
char *stunserver = "localhost";
|
||||||
|
int stunport = 27500;
|
||||||
|
#elif 1
|
||||||
|
char *stunserver = "stun.l.google.com";
|
||||||
|
int stunport = 19302;
|
||||||
|
#else
|
||||||
|
char *stunserver = "master.frag-net.com";
|
||||||
|
int stunport = 27950;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SOCKET newsocket;
|
||||||
|
struct sockaddr_in address;
|
||||||
|
struct hostent *h;
|
||||||
|
|
||||||
|
struct stunheader_s msg = {htons(1), 0, htonl(0x2112a442), {42,42,42}};
|
||||||
|
if (epfd < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
h = gethostbyname(stunserver);
|
||||||
|
if (!h)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (h->h_addrtype != AF_INET)
|
||||||
|
return; //too many assumptions
|
||||||
|
|
||||||
|
if ((newsocket = socket (h->h_addrtype, SOCK_CLOEXEC|SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET)
|
||||||
|
return;
|
||||||
|
|
||||||
|
address.sin_family = h->h_addrtype;
|
||||||
|
address.sin_addr.s_addr = INADDR_ANY;
|
||||||
|
address.sin_port = 0;
|
||||||
|
|
||||||
|
if (bind (newsocket, (void *)&address, sizeof(address)) == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
//FIXME: not random enough to avoid hacks.
|
||||||
|
srand(time(NULL)^*(int*)&msg);
|
||||||
|
msg.transactid[0] = rand();
|
||||||
|
msg.transactid[1] = rand();
|
||||||
|
msg.transactid[2] = rand();
|
||||||
|
if (epfd >= 0)
|
||||||
|
{
|
||||||
|
static struct stun_ctx ctx;
|
||||||
|
struct epoll_event ev;
|
||||||
|
ctx.udpsock = newsocket;
|
||||||
|
ctx.pub.Polled = StunResponse;
|
||||||
|
ctx.id[0] = msg.transactid[0];
|
||||||
|
ctx.id[1] = msg.transactid[1];
|
||||||
|
ctx.id[2] = msg.transactid[2];
|
||||||
|
ctx.reportport = reportport;
|
||||||
|
ev.events = EPOLLIN;
|
||||||
|
ev.data.ptr = &ctx;
|
||||||
|
epoll_ctl(epfd, EPOLL_CTL_ADD, newsocket, &ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
msg.msglen = htons(sizeof(msg)-20);
|
||||||
|
memcpy(&address.sin_addr, h->h_addr, h->h_length);
|
||||||
|
address.sin_port = htons(stunport);
|
||||||
|
sendto(newsocket, &msg, sizeof(msg), 0, (struct sockaddr*)&address, sizeof(address));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
char *authedusername;
|
char *authedusername;
|
||||||
char *autheduserpassword;
|
char *autheduserpassword;
|
||||||
int lport_min, lport_max;
|
int lport_min, lport_max;
|
||||||
|
@ -163,6 +289,7 @@ int main(int argc, char **argv)
|
||||||
WSADATA pointlesscrap;
|
WSADATA pointlesscrap;
|
||||||
WSAStartup(2, &pointlesscrap);
|
WSAStartup(2, &pointlesscrap);
|
||||||
#else
|
#else
|
||||||
|
int ep = epoll_create1(0);
|
||||||
signal(SIGPIPE, SIG_IGN); //so we don't crash out if a peer closes the socket half way through.
|
signal(SIGPIPE, SIG_IGN); //so we don't crash out if a peer closes the socket half way through.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -240,6 +367,7 @@ int main(int argc, char **argv)
|
||||||
else
|
else
|
||||||
printf("Server is read only\n");
|
printf("Server is read only\n");
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
while(1)
|
while(1)
|
||||||
{
|
{
|
||||||
if (ftpport)
|
if (ftpport)
|
||||||
|
@ -252,6 +380,22 @@ int main(int argc, char **argv)
|
||||||
usleep(10000);
|
usleep(10000);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
|
||||||
|
while (!HTTP_ServerInit(ep, httpport))
|
||||||
|
sleep(5);
|
||||||
|
PrepareStun(ep, httpport);
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
struct epoll_event events[1];
|
||||||
|
int e, me = epoll_wait(ep, events, countof(events), -1);
|
||||||
|
for (e = 0; e < me; e++)
|
||||||
|
{
|
||||||
|
struct epollctx_s *ctx = events[e].data.ptr;
|
||||||
|
ctx->Polled(ctx, events[e].events);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int IWebGetSafeListeningPort(void)
|
int IWebGetSafeListeningPort(void)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue