basics for http

This commit is contained in:
darkrose 2013-07-07 13:12:57 +10:00
parent f38f6dadcc
commit aa90985303
5 changed files with 309 additions and 30 deletions

View File

@ -127,7 +127,8 @@ set(common_SRCS
test.cpp
sha1.cpp
base64.cpp
ban.cpp
ban.cpp
http.cpp
)
# This gives us the icon
@ -366,4 +367,4 @@ else (SQLITE3_FOUND)
add_subdirectory(sqlite)
endif (SQLITE3_FOUND)
#end
#end

29
src/http.cpp Normal file
View File

@ -0,0 +1,29 @@
/************************************************************************
* Minetest-c55
* Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
*
* http.cpp
* Copyright (C) Lisa 'darkrose' Milne 2013 <lisa@ltmnet.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
************************************************************************/
#include "socket.h"
#include "http.h"
#include "debug.h"
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <errno.h>
#include "utility.h"

48
src/http.h Normal file
View File

@ -0,0 +1,48 @@
/************************************************************************
* Minetest-c55
* Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
*
* http.h
* Copyright (C) Lisa 'darkrose' Milne 2013 <lisa@ltmnet.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
************************************************************************/
#ifndef HTTP_HEADER
#define HTTP_HEADER
#include "socket.h"
#include "common_irrlicht.h"
class HTTPServer
{
public:
HTTPServer();
~HTTPServer();
private:
TCPSocket &m_socket;
core::map<u16,TCPSocket&> m_peers;
};
class HTTPClient
{
public:
HTTPClient();
~HTTPClient();
private:
TCPSocket &m_socket;
};
#endif

View File

@ -152,29 +152,15 @@ UDPSocket::UDPSocket()
if(g_sockets_initialized == false)
throw SocketException("Sockets not initialized");
m_handle = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
m_handle = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(DP)
dstream<<DPS<<"UDPSocket("<<(int)m_handle<<")::UDPSocket()"<<std::endl;
dstream<<DPS<<"UDPSocket("<<(int)m_handle<<")::UDPSocket()"<<std::endl;
if(m_handle <= 0)
{
if(m_handle <= 0)
{
throw SocketException("Failed to create socket");
}
/*#ifdef _WIN32
DWORD nonblocking = 0;
if(ioctlsocket(m_handle, FIONBIO, &nonblocking) != 0)
{
throw SocketException("Failed set non-blocking mode");
}
#else
int nonblocking = 0;
if(fcntl(m_handle, F_SETFL, O_NONBLOCK, nonblocking) == -1)
{
throw SocketException("Failed set non-blocking mode");
}
#endif*/
setTimeoutMs(0);
}
@ -197,18 +183,18 @@ void UDPSocket::Bind(unsigned short port)
dstream<<DPS<<"UDPSocket("<<(int)m_handle
<<")::Bind(): port="<<port<<std::endl;
sockaddr_in address;
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(port);
sockaddr_in address;
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(port);
if(bind(m_handle, (const sockaddr*)&address, sizeof(sockaddr_in)) < 0)
{
if(bind(m_handle, (const sockaddr*)&address, sizeof(sockaddr_in)) < 0)
{
#ifndef DISABLE_ERRNO
dstream<<(int)m_handle<<": Bind failed: "<<strerror(errno)<<std::endl;
#endif
throw SocketException("Failed to bind socket");
}
}
}
void UDPSocket::Send(const Address & destination, const void * data, int size)
@ -254,10 +240,10 @@ void UDPSocket::Send(const Address & destination, const void * data, int size)
int sent = sendto(m_handle, (const char*)data, size,
0, (sockaddr*)&address, sizeof(sockaddr_in));
if(sent != size)
{
if(sent != size)
{
throw SendFailedException("Failed to send packet");
}
}
}
int UDPSocket::Receive(Address & sender, void * data, int size)
@ -358,4 +344,199 @@ bool UDPSocket::WaitData(int timeout_ms)
return true;
}
/* TCPSocket */
TCPSocket::TCPSocket()
{
if (g_sockets_initialized == false)
throw SocketException("Sockets not initialized");
m_handle = socket(AF_INET, SOCK_STREAM, 0);
if (DP)
dstream<<DPS<<"TCPSocket("<<(int)m_handle<<")::TCPSocket()"<<std::endl;
if (m_handle <= 0) {
throw SocketException("Failed to create socket");
}
int a=1;
setsockopt(m_handle, SOL_SOCKET, SO_REUSEADDR, &a, sizeof(a));
setTimeoutMs(0);
}
TCPSocket::~TCPSocket()
{
if (DP)
dstream<<DPS<<"TCPSocket("<<(int)m_handle<<")::~TCPSocket()"<<std::endl;
#ifdef _WIN32
closesocket(m_handle);
#else
close(m_handle);
#endif
}
void TCPSocket::Bind(unsigned short port)
{
if(DP)
dstream<<DPS<<"TCPSocket("<<(int)m_handle<<")::Bind(): port="<<port<<std::endl;
sockaddr_in address;
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(port);
if (bind(m_handle, (const sockaddr*)&address, sizeof(sockaddr_in)) < 0) {
#ifndef DISABLE_ERRNO
dstream<<(int)m_handle<<": Bind failed: "<<strerror(errno)<<std::endl;
#endif
throw SocketException("Failed to bind socket");
}
if (listen(m_handle, 5) < 0) {
#ifndef DISABLE_ERRNO
dstream<<(int)m_handle<<": Listen failed: "<<strerror(errno)<<std::endl;
#endif
throw SocketException("Failed to set socket to listening mode");
}
}
bool TCPSocket::Connect(const Address &destination)
{
sockaddr_in address;
address.sin_family = AF_INET;
address.sin_addr.s_addr = htonl(destination.getAddress());
address.sin_port = htons(destination.getPort());
if (connect(m_handle, (sockaddr*)&address, sizeof(sockaddr_in)) < 0) {
#ifndef DISABLE_ERRNO
dstream<<(int)m_handle<<": Connect failed: "<<strerror(errno)<<std::endl;
#endif
return false;
}
return true;
}
void TCPSocket::Send(const void *data, int size)
{
int sent = send(m_handle, (const char*)data, size, 0);
if (sent != size)
throw SendFailedException("Failed to send data");
}
int TCPSocket::Receive(void *data, int size)
{
if (WaitData(m_timeout_ms) == false)
return -1;
sockaddr_in address;
socklen_t address_len = sizeof(address);
int received = recvfrom(
m_handle,
(char*)data,
size,
0,
(sockaddr*)&address,
&address_len
);
if (received < 0)
return -1;
unsigned int address_ip = ntohl(address.sin_addr.s_addr);
unsigned int address_port = ntohs(address.sin_port);
Address sender(address_ip, address_port);
if (DP) {
dstream<<DPS<<(int)m_handle<<" <- ";
dstream<<", size="<<received<<", data=";
for (int i=0; i<received && i<20; i++) {
if (i%2==0)
DEBUGPRINT(" ");
unsigned int a = ((const unsigned char*)data)[i];
DEBUGPRINT("%.2X", a);
}
if (received>20)
dstream<<"...";
dstream<<std::endl;
}
return received;
}
TCPSocket* TCPSocket::Accept()
{
sockaddr_in address;
socklen_t address_len = sizeof(address);
int client = accept(m_handle, (sockaddr*)&address, &address_len);
if (client < 0) {
#ifndef DISABLE_ERRNO
dstream<<(int)m_handle<<": Accept failed: "<<strerror(errno)<<std::endl;
#endif
throw SocketException("Failed to accept socket");
}
TCPSocket *socket = new TCPSocket();
socket->m_handle = client;
return socket;
}
int TCPSocket::GetHandle()
{
return m_handle;
}
void TCPSocket::setTimeoutMs(int timeout_ms)
{
m_timeout_ms = timeout_ms;
}
bool TCPSocket::WaitData(int timeout_ms)
{
fd_set readset;
int result;
// Initialize the set
FD_ZERO(&readset);
FD_SET(m_handle, &readset);
// Initialize time out struct
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = timeout_ms * 1000;
// select()
result = select(m_handle+1, &readset, NULL, NULL, &tv);
if (result == 0) {
return false;
}else if (result < 0 && errno == EINTR) {
return false;
}else if (result < 0) {
// Error
#ifndef DISABLE_ERRNO
dstream<<(int)m_handle<<": Select failed: "<<strerror(errno)<<std::endl;
#endif
#ifdef _WIN32
int e = WSAGetLastError();
dstream<<(int)m_handle<<": WSAGetLastError()="<<e<<std::endl;
if (e == 10004 /*=WSAEINTR*/) {
dstream<<"WARNING: Ignoring WSAEINTR."<<std::endl;
return false;
}
#endif
throw SocketException("Select failed");
}else if (FD_ISSET(m_handle, &readset) == false) {
// No data
return false;
}
// There is data
return true;
}

View File

@ -123,5 +123,25 @@ private:
int m_timeout_ms;
};
class TCPSocket
{
public:
TCPSocket();
~TCPSocket();
void Bind(unsigned short port);
bool Connect(const Address &destination);
void Send(const void *data, int size);
// Returns -1 if there is no data
int Receive(void *data, int size);
TCPSocket* Accept();
int GetHandle(); // For debugging purposes only
void setTimeoutMs(int timeout_ms);
// Returns true if there is data, false if timeout occurred
bool WaitData(int timeout_ms);
private:
int m_handle;
int m_timeout_ms;
};
#endif