From 3aa7e4d114af9f28190f2e964080a01ee4da5b68 Mon Sep 17 00:00:00 2001 From: Thulinma Date: Thu, 22 Sep 2011 06:56:39 +0200 Subject: [PATCH 1/4] Removing epoll in favor of more cross-platform poll - also adding RTMP push support and Buffer push support with IP security --- util/socket.cpp | 26 ++++++++++++++++++++++++++ util/socket.h | 2 ++ 2 files changed, 28 insertions(+) diff --git a/util/socket.cpp b/util/socket.cpp index ecb1dab5..b0046d02 100644 --- a/util/socket.cpp +++ b/util/socket.cpp @@ -3,6 +3,11 @@ /// Written by Jaron Vietor in 2010 for DDVTech #include "socket.h" +#include + +#ifdef __FreeBSD__ +#include +#endif /// Create a new base socket. This is a basic constructor for converting any valid socket to a Socket::Connection. /// \param sockNo Integer representing the socket to convert. @@ -69,6 +74,27 @@ Socket::Connection::Connection(std::string address, bool nonblock){ } }//Socket::Connection Unix Contructor +/// Calls poll() on the socket, checking if data is available. +/// This function may return true even if there is no data, but never returns false when there is. +bool Socket::Connection::canRead(){ + struct pollfd PFD; + PFD.fd = sock; + PFD.events = POLLIN; + PFD.revents = 0; + poll(&PFD, 1, 5); + return (PFD.revents & POLLIN) == POLLIN; +} +/// Calls poll() on the socket, checking if data can be written. +bool Socket::Connection::canWrite(){ + struct pollfd PFD; + PFD.fd = sock; + PFD.events = POLLOUT; + PFD.revents = 0; + poll(&PFD, 1, 5); + return (PFD.revents & POLLOUT) == POLLOUT; +} + + /// Returns the ready-state for this socket. /// \returns 1 if data is waiting to be read, -1 if not connected, 0 otherwise. signed int Socket::Connection::ready(){ diff --git a/util/socket.h b/util/socket.h index 9aa754be..57aca183 100644 --- a/util/socket.h +++ b/util/socket.h @@ -27,6 +27,8 @@ namespace Socket{ Connection(); ///< Create a new disconnected base socket. Connection(int sockNo); ///< Create a new base socket. Connection(std::string adres, bool nonblock = false); ///< Create a new Unix Socket. + bool canRead(); ///< Calls poll() on the socket, checking if data is available. + bool canWrite(); ///< Calls poll() on the socket, checking if data can be written. bool Error; ///< Set to true if a socket error happened. bool Blocking; ///< Set to true if a socket is currently or wants to be blocking. signed int ready(); ///< Returns the ready-state for this socket. From 86e7d69e09fdab53f67a3dd53bdf692e099cfd5b Mon Sep 17 00:00:00 2001 From: Thulinma Date: Sun, 25 Sep 2011 22:44:55 +0200 Subject: [PATCH 2/4] Epoll removal tested and found working! :D --- util/socket.cpp | 24 ++++++++++++++++++++++++ util/socket.h | 2 ++ 2 files changed, 26 insertions(+) diff --git a/util/socket.cpp b/util/socket.cpp index b0046d02..425d2a70 100644 --- a/util/socket.cpp +++ b/util/socket.cpp @@ -495,3 +495,27 @@ bool Socket::Server::connected(){ /// Returns internal socket number. int Socket::Server::getSocket(){return sock;} + +/// Unescapes URLencoded C-strings to a std::string. +/// This function *will* destroy the incoming data! +std::string Socket::Connection::urlunescape(char *s){ + char *p; + for (p = s; *s != '\0'; ++s){ + if (*s == '%'){ + if (*++s != '\0'){ + *p = unhex(*s) << 4; + } + if (*++s != '\0'){ + *p++ += unhex(*s); + } + } else { + if (*s == '+'){*p++ = ' ';}else{*p++ = *s;} + } + } + *p = '\0'; + return std::string(s); +} + +int Socket::Connection::unhex(char c){ + return( c >= '0' && c <= '9' ? c - '0' : c >= 'A' && c <= 'F' ? c - 'A' + 10 : c - 'a' + 10 ); +} diff --git a/util/socket.h b/util/socket.h index 57aca183..456a162f 100644 --- a/util/socket.h +++ b/util/socket.h @@ -23,6 +23,7 @@ namespace Socket{ private: int sock; ///< Internally saved socket number. std::string remotehost; ///< Stores remote host address. + int unhex(char c); ///< Helper function for urlunescape. public: Connection(); ///< Create a new disconnected base socket. Connection(int sockNo); ///< Create a new base socket. @@ -44,6 +45,7 @@ namespace Socket{ bool swrite(std::string & buffer); ///< Read call that is compatible with std::string. bool iread(std::string & buffer); ///< Incremental write call that is compatible with std::string. bool iwrite(std::string & buffer); ///< Write call that is compatible with std::string. + std::string urlunescape(char *s); ///< Unescapes URLencoded C-strings to a std::string. void close(); ///< Close connection. std::string getHost(); ///< Gets hostname for connection, if available. int getSocket(); ///< Returns internal socket number. From 57b9866b4b1d2236cc0c6eccdcf940774560930d Mon Sep 17 00:00:00 2001 From: Thulinma Date: Mon, 26 Sep 2011 02:16:12 +0200 Subject: [PATCH 3/4] Added POST var parsing to HTTP lib, added WriteFile to JSON gearbox version, added real parsing of input to JSON gearbox version --- util/http_parser.cpp | 43 ++++++++++++++++++++++++++++++++++++++++++- util/http_parser.h | 2 ++ util/socket.cpp | 24 ------------------------ util/socket.h | 2 -- 4 files changed, 44 insertions(+), 27 deletions(-) diff --git a/util/http_parser.cpp b/util/http_parser.cpp index ec648a39..9a81c404 100644 --- a/util/http_parser.cpp +++ b/util/http_parser.cpp @@ -188,10 +188,25 @@ bool HTTP::Parser::parse(){ } if (seenHeaders){ if (length > 0){ - /// \todo Include POST variable parsing? if (HTTPbuffer.length() >= length){ body = HTTPbuffer.substr(0, length); HTTPbuffer.erase(0, length); + std::string tmppost = body; + std::string varname; + std::string varval; + while (tmppost.find('=') != std::string::npos){ + size_t found = tmppost.find('='); + varname = urlunescape(tmppost.substr(0, found).c_str()); + tmppost.erase(0, found+1); + size_t found = tmppost.find('&'); + varval = urlunescape(tmppost.substr(0, found).c_str()); + SetVar(varname, varval); + if (found == std::string::npos){ + tmppost.clear(); + }else{ + tmppost.erase(0, found+1); + } + } return true; }else{ return false; @@ -241,3 +256,29 @@ void HTTP::Parser::SendBodyPart(Socket::Connection & conn, std::string bodypart) conn.write(bodypart); } } + +/// Unescapes URLencoded C-strings to a std::string. +/// This function *will* destroy the input data! +std::string HTTP::Parser::urlunescape(char *s){ + char *p; + for (p = s; *s != '\0'; ++s){ + if (*s == '%'){ + if (*++s != '\0'){ + *p = unhex(*s) << 4; + } + if (*++s != '\0'){ + *p++ += unhex(*s); + } + } else { + if (*s == '+'){*p++ = ' ';}else{*p++ = *s;} + } + } + *p = '\0'; + return std::string(s); +} + +/// Helper function for urlunescape. +/// Takes a single char input and outputs its integer hex value. +int HTTP::Parser::unhex(char c){ + return( c >= '0' && c <= '9' ? c - '0' : c >= 'A' && c <= 'F' ? c - 'A' + 10 : c - 'a' + 10 ); +} diff --git a/util/http_parser.h b/util/http_parser.h index d7048eae..542c06e6 100644 --- a/util/http_parser.h +++ b/util/http_parser.h @@ -30,6 +30,7 @@ namespace HTTP{ void SendBodyPart(Socket::Connection & conn, std::string bodypart); void Clean(); bool CleanForNext(); + std::string urlunescape(char *s); ///< Unescapes URLencoded C-strings to a std::string. std::string body; std::string method; std::string url; @@ -43,5 +44,6 @@ namespace HTTP{ std::map headers; std::map vars; void Trim(std::string & s); + int unhex(char c); ///< Helper function for urlunescape. };//HTTP::Parser class };//HTTP namespace diff --git a/util/socket.cpp b/util/socket.cpp index 425d2a70..b0046d02 100644 --- a/util/socket.cpp +++ b/util/socket.cpp @@ -495,27 +495,3 @@ bool Socket::Server::connected(){ /// Returns internal socket number. int Socket::Server::getSocket(){return sock;} - -/// Unescapes URLencoded C-strings to a std::string. -/// This function *will* destroy the incoming data! -std::string Socket::Connection::urlunescape(char *s){ - char *p; - for (p = s; *s != '\0'; ++s){ - if (*s == '%'){ - if (*++s != '\0'){ - *p = unhex(*s) << 4; - } - if (*++s != '\0'){ - *p++ += unhex(*s); - } - } else { - if (*s == '+'){*p++ = ' ';}else{*p++ = *s;} - } - } - *p = '\0'; - return std::string(s); -} - -int Socket::Connection::unhex(char c){ - return( c >= '0' && c <= '9' ? c - '0' : c >= 'A' && c <= 'F' ? c - 'A' + 10 : c - 'a' + 10 ); -} diff --git a/util/socket.h b/util/socket.h index 456a162f..57aca183 100644 --- a/util/socket.h +++ b/util/socket.h @@ -23,7 +23,6 @@ namespace Socket{ private: int sock; ///< Internally saved socket number. std::string remotehost; ///< Stores remote host address. - int unhex(char c); ///< Helper function for urlunescape. public: Connection(); ///< Create a new disconnected base socket. Connection(int sockNo); ///< Create a new base socket. @@ -45,7 +44,6 @@ namespace Socket{ bool swrite(std::string & buffer); ///< Read call that is compatible with std::string. bool iread(std::string & buffer); ///< Incremental write call that is compatible with std::string. bool iwrite(std::string & buffer); ///< Write call that is compatible with std::string. - std::string urlunescape(char *s); ///< Unescapes URLencoded C-strings to a std::string. void close(); ///< Close connection. std::string getHost(); ///< Gets hostname for connection, if available. int getSocket(); ///< Returns internal socket number. From 592c1cfbd0285d0240c310d825e2ffa9d73bbf1c Mon Sep 17 00:00:00 2001 From: Thulinma Date: Mon, 26 Sep 2011 12:44:15 +0200 Subject: [PATCH 4/4] Added full IPv4 support --- util/http_parser.cpp | 6 +++--- util/socket.cpp | 42 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/util/http_parser.cpp b/util/http_parser.cpp index 9a81c404..274cb3c3 100644 --- a/util/http_parser.cpp +++ b/util/http_parser.cpp @@ -196,10 +196,10 @@ bool HTTP::Parser::parse(){ std::string varval; while (tmppost.find('=') != std::string::npos){ size_t found = tmppost.find('='); - varname = urlunescape(tmppost.substr(0, found).c_str()); + varname = urlunescape((char*)tmppost.substr(0, found).c_str()); tmppost.erase(0, found+1); - size_t found = tmppost.find('&'); - varval = urlunescape(tmppost.substr(0, found).c_str()); + found = tmppost.find('&'); + varval = urlunescape((char*)tmppost.substr(0, found).c_str()); SetVar(varname, varval); if (found == std::string::npos){ tmppost.clear(); diff --git a/util/socket.cpp b/util/socket.cpp index b0046d02..c585f7be 100644 --- a/util/socket.cpp +++ b/util/socket.cpp @@ -374,7 +374,47 @@ Socket::Server::Server(int port, std::string hostname, bool nonblock){ } }else{ #if DEBUG >= 1 - fprintf(stderr, "Binding failed! Error: %s\n", strerror(errno)); + fprintf(stderr, "Binding failed, retrying as IPv4... (%s)\n", strerror(errno)); + #endif + close(); + } + sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0){ + #if DEBUG >= 1 + fprintf(stderr, "Could not create socket! Error: %s\n", strerror(errno)); + #endif + return; + } + on = 1; + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + if (nonblock){ + int flags = fcntl(sock, F_GETFL, 0); + flags |= O_NONBLOCK; + fcntl(sock, F_SETFL, flags); + } + struct sockaddr_in addr4; + addr4.sin_family = AF_INET; + addr4.sin_port = htons(port);//set port + if (hostname == "0.0.0.0"){ + addr4.sin_addr.s_addr = INADDR_ANY; + }else{ + inet_pton(AF_INET, hostname.c_str(), &addr4.sin_addr);//set interface, 0.0.0.0 (default) is all + } + ret = bind(sock, (sockaddr*)&addr4, sizeof(addr4));//do the actual bind + if (ret == 0){ + ret = listen(sock, 100);//start listening, backlog of 100 allowed + if (ret == 0){ + return; + }else{ + #if DEBUG >= 1 + fprintf(stderr, "Listen failed! Error: %s\n", strerror(errno)); + #endif + close(); + return; + } + }else{ + #if DEBUG >= 1 + fprintf(stderr, "IPv4 binding also failed, giving up. (%s)\n", strerror(errno)); #endif close(); return;