diff --git a/include/Weather.h b/include/Weather.h new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/include/Weather.h @@ -0,0 +1 @@ + diff --git a/include/util.h b/include/util.h new file mode 100644 index 0000000..6d555e6 --- /dev/null +++ b/include/util.h @@ -0,0 +1,51 @@ +#include + +class Socket +{ +public: + Socket(); + ~Socket(); + int connect(const std::string& IPStr,int Port); + int send(const void* Buffer,int Length); + int recv(void* Buffer,int MaxToRecv); +private: + class _impl; + _impl* _pp; +}; + +/// forward declaration. +class HTTPResponse; + +class HTTPRequest +{ +public: + HTTPRequest(); + + enum class Method { Post,Get }; + enum class Connection { KeepAlive,Close }; + + Method method; + Connection connection; + + std::string url; + std::string host; + std::string user_agent; + + /// This value will only be evaluated when using POST method. + std::string content_type; + std::string content; + + /// This function will try to connect 'host':80 + int send(HTTPResponse& res); +}; + +class HTTPResponse +{ +public: + std::string protocol; + int status; + std::string content_type; + int content_length; + + std::string content; +}; diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..ee84630 --- /dev/null +++ b/main.cpp @@ -0,0 +1,25 @@ +#include "util.h" +#include +using namespace std; + +int main() +{ + cout<<"Program Start!"< +#include +#include +#include +#include +#include +#include + +#ifdef DEBUG +/// Debug Output API +#define dprintf(fmt,args...) printf(fmt,##args) +#else +/// Debug Output API +#define dprintf(fmt,args...) +#endif + +class _init_winsock2_2_class +{ +public: + _init_winsock2_2_class() + { + /// Windows Platform need WinSock2.DLL initialization. + WORD wd; + WSAData wdt; + wd=MAKEWORD(2,2); + if(WSAStartup(wd,&wdt)<0) + { + throw std::runtime_error("Unable to load winsock2.dll. "); + } + } + ~_init_winsock2_2_class() + { + /// Windows Platform need WinSock2.DLL clean up. + WSACleanup(); + } +}; + +static _init_winsock2_2_class _init_winsock2_2_obj; + +class Socket::_impl +{ +public: + int sfd; + sockaddr_in saddr; + bool created; +}; + +Socket::Socket() : _pp(new _impl) +{ + _pp->created=false; +} + +Socket::~Socket() +{ + if(_pp) + { + if(_pp->created) + { + closesocket(_pp->sfd); + } + + delete _pp; + } +} + +int Socket::connect(const std::string& IPStr,int Port) +{ + if(_pp->created) + { + return -2; + } + _pp->sfd=socket(AF_INET,SOCK_STREAM,0); + if(_pp->sfd<0) + { + return -3; + } + _pp->created=true; + + // refs + int& sfd=_pp->sfd; + sockaddr_in& saddr=_pp->saddr; + + memset(&saddr,0,sizeof(saddr)); + saddr.sin_addr.s_addr=inet_addr(IPStr.c_str()); + saddr.sin_port=htons(Port); + saddr.sin_family=AF_INET; + + return ::connect(sfd,(sockaddr*)&saddr,sizeof(saddr)); +} + +int Socket::send(const void* Buffer,int Length) +{ + return ::send(_pp->sfd,(const char*)Buffer,Length,0); +} + +int Socket::recv(void* Buffer,int MaxToRecv) +{ + return ::recv(_pp->sfd,(char*)Buffer,MaxToRecv,0); +} + +int DNSResolve(const std::string& HostName, std::string& _out_IPStr) +{ + /// Use getaddrinfo instead + struct addrinfo hints; + memset(&hints,0,sizeof(hints)); + hints.ai_family=AF_UNSPEC; + hints.ai_socktype=SOCK_STREAM; + hints.ai_protocol=IPPROTO_TCP; + + struct addrinfo* result=nullptr; + + int ret=getaddrinfo(HostName.c_str(),NULL,&hints,&result); + if(ret!=0) + { + return -1;/// API Call Failed. + } + for(struct addrinfo* ptr=result; ptr!=nullptr; ptr=ptr->ai_next) + { + switch(ptr->ai_family) + { + case AF_INET: + sockaddr_in* addr=(struct sockaddr_in*) (ptr->ai_addr) ; + _out_IPStr=inet_ntoa(addr->sin_addr); + return 0; + break; + } + } + /// Unknown error. + return -2; +} + +HTTPRequest::HTTPRequest() +{ + method=Method::Get; + connection=Connection::Close; + content_type="application/x-www-form-urlencoded"; +} + +int HTTPRequest::send(HTTPResponse& _out_res) +{ + if(host.empty()) + { + /// Host is empty + return -1; + } + if(url.empty()) + { + url="/"; + } + + switch(method) + { + case Method::Get: + case Method::Post: + break; + default: + method=Method::Get; + break; + } + + switch(connection) + { + case Connection::KeepAlive: + case Connection::Close: + break; + default: + connection=Connection::Close; + break; + } + + std::string ip; + int ret=DNSResolve(host,ip); + if(ret!=0) + { + /// DNS resolve error. + return -2; + } + + std::string result_str; + + std::ostringstream ostr; + if(method==Method::Post) + { + ostr<<"POST "; + } + else + { + ostr<<"GET "; + } + ostr<0) + { + response_str.append(std::string(buff,ret)); + } + + auto idx=response_str.find(target_str); + if(idx!=std::string::npos) + { + /// Found Content-Length + int tmp; + if(sscanf(response_str.c_str()+idx+target_str.size(),"%d",&tmp)!=1) + { + /// Failed to parse content-length. + /// Maybe it will success in next loop. + if(ret==0) + { + /// There is no next loop + /// Cannot find Content-Length. + return -7; + } + } + else + { + /// Parsed! + response_content_length=tmp; + break; + } + } + } + } + + /// Try to find header-content separator. + int last_flag=0; + while(true) + { + auto idx=response_str.find("\r\n\r\n"); + dprintf("ReceiveCheck 2: idx=%d\n",(int)idx); + if(idx==std::string::npos) + { + /// separator not found. Might not received. + if(last_flag==1) + { + /// No next loop. + /// Connection closed before separator received. + return -8; + } + memset(buff,0,1024); + int ret=s.recv(buff,1024); + dprintf("ReceiveLoop 2: ret=%d\n",ret); + if(ret<0) + { + /// Error while receiving response separator. + return -9; + } + else if(ret==0) + { + last_flag=1; + } + else + { + response_str.append(std::string(buff,ret)); + } + } + else break; + } + + int sidx=response_str.find("\r\n\r\n")+4; + + int received_content_length=response_str.size()-sidx; + + while(received_content_length