Bind a socket but don't listen to it yet

This commit is contained in:
Perttu Ahola 2014-09-17 04:04:50 +03:00
parent 72766206cb
commit 0287e82006
10 changed files with 387 additions and 2 deletions

View File

@ -68,6 +68,7 @@ set(SERVER_SRCS
src/server/rccpp.cpp
src/impl/fs.cpp
src/impl/event.cpp
src/impl/tcpsocket.cpp
)
add_executable(${SERVER_EXE_NAME} ${SERVER_SRCS})
TARGET_LINK_LIBRARIES(${SERVER_EXE_NAME}

View File

@ -49,3 +49,6 @@ name->type registry is used for determining numeric packet types.
Data is freeform. Types 0...100 are reserved for initialization.
Core uses cereal's portable binary serialization.

View File

@ -0,0 +1,48 @@
#include "interface/module.h"
#include "interface/server.h"
#include "interface/event.h"
#include "interface/tcpsocket.h"
//#include "network/include/api.h"
#include <iostream>
using interface::Event;
namespace network {
struct Module: public interface::Module
{
interface::Server *m_server;
sp_<interface::TCPSocket> m_socket;
Module(interface::Server *server):
m_server(server),
m_socket(interface::createTCPSocket())
{
std::cout<<"network construct"<<std::endl;
ss_ address = "any";
ss_ port = "20000";
if(!m_socket->bind_fd(address, port)){
std::cerr<<"Failed to bind to "<<address<<":"<<port<<std::endl;
} else {
std::cerr<<"Listening at "<<address<<":"<<port<<std::endl;
}
}
~Module()
{
std::cout<<"network destruct"<<std::endl;
}
void event(const interface::Event &event)
{
}
};
extern "C" {
EXPORT void* createModule_network(interface::Server *server){
return (void*)(new Module(server));
}
}
}

295
src/impl/tcpsocket.cpp Normal file
View File

@ -0,0 +1,295 @@
#include "interface/tcpsocket.h"
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h> // strerror()
#include <netinet/in.h>
#include <iomanip>
#include <netdb.h>
namespace interface {
const unsigned char prefix[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xFF, 0xFF};
bool sockaddr_to_bytes(const sockaddr_storage* ptr, sv_<uchar>& to)
{
if(ptr->ss_family == AF_INET)
{
uchar* u = (uchar*)&((struct sockaddr_in*)ptr)->sin_addr.s_addr;
to.assign(u, u + 4);
return true;
}
else if(ptr->ss_family == AF_INET6)
{
uchar* u = (uchar*)&((struct sockaddr_in6*)ptr)->sin6_addr.s6_addr;
if(memcmp(prefix, u, sizeof(prefix)) == 0){
to.assign(u + 12, u + 16);
return true;
}
to.assign(u, u + 16);
return true;
}
return false;
};
std::string address_bytes_to_string(const sv_<uchar> &ip)
{
std::ostringstream os;
for(size_t i=0; i<ip.size(); i++){
if(ip.size() == 4){
os<<std::dec<<std::setfill('0')<<std::setw(0)
<<((uint32_t)ip[i]&0xff);
if(i < ip.size()-1)
os<<".";
} else {
os<<std::hex<<std::setfill('0')<<std::setw(2)
<<((uint32_t)ip[i]&0xff);
i++;
if(i < ip.size())
os<<std::hex<<std::setfill('0')<<std::setw(2)
<<((uint32_t)ip[i]&0xff);
if(i < ip.size()-1)
os<<":";
}
}
return os.str();
}
struct CTCPSocket: public TCPSocket
{
int m_fd = 0;
int fd() const
{
return m_fd;
}
bool good() const
{
return (m_fd != -1);
}
void close_fd()
{
if(m_fd != -1)
close(m_fd);
m_fd = -1;
}
bool listen_fd()
{
if(m_fd == -1)
return false;
if(listen(m_fd, 5) == -1){
std::cerr<<"TCPSocket::listen_fd(): "<<strerror(errno)<<std::endl;
return false;
}
return true;
}
bool connect_fd(const ss_ &address, const ss_ &port)
{
close_fd();
struct addrinfo hints;
struct addrinfo *res0 = NULL;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
if(address == "any")
hints.ai_flags = AI_PASSIVE; // Wildcard address
const char *address_c = (address == "any" ? NULL : address.c_str());
const char *port_c = (port == "any" ? NULL : port.c_str());
int err = getaddrinfo(address_c, port_c, &hints, &res0);
if(err){
std::cerr<<"getaddrinfo: "<<gai_strerror(err)<<std::endl;
return false;
}
if(res0 == NULL){
std::cerr<<"getaddrinfo: No results"<<std::endl;
return false;
}
// Try to use one of the results
int fd = -1;
int i=0;
for(struct addrinfo *res = res0; res != NULL; res = res->ai_next, i++)
{
std::cerr<<"Trying addrinfo #"<<i<<std::endl;
int try_fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if(try_fd == -1){
std::cerr<<"socket: "<<strerror(errno)<<std::endl;
continue;
}
if(connect(try_fd, res->ai_addr, res->ai_addrlen) == -1){
std::cerr<<"connect: "<<strerror(errno)<<std::endl;
close(try_fd);
continue;
}
fd = try_fd;
break;
}
freeaddrinfo(res0);
if(fd == -1){
std::cerr<<"Failed to create and connect socket"<<std::endl;
return false;
}
int val = 1;
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
// Set this so that forked child processes don't prevent re-opening the
// same port after crash
if(fcntl(fd, F_SETFD, FD_CLOEXEC) != 0){
std::cerr<<"Failed to set socket FD_CLOEXEC"<<std::endl;
return false;
}
m_fd = fd;
return true;
}
bool bind_fd(const ss_ &address, const ss_ &port)
{
close_fd();
struct addrinfo hints;
struct addrinfo *res0 = NULL;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
std::string address1 = address;
if(address1 == "any4"){
address1 = "any";
hints.ai_family = AF_INET;
}
if(address1 == "any6"){
address1 = "any";
hints.ai_family = AF_INET6;
}
if(address1 == "any"){
hints.ai_flags = AI_PASSIVE; // Wildcard address
}
const char *address_c = (address1 == "any" ? NULL : address1.c_str());
const char *port_c = (port == "any" ? NULL : port.c_str());
int err = getaddrinfo(address_c, port_c, &hints, &res0);
if(err){
std::cerr<<"getaddrinfo: "<<gai_strerror(err)<<std::endl;
return false;
}
if(res0 == NULL){
std::cerr<<"getaddrinfo: No results"<<std::endl;
return false;
}
// Try to use one of the results
int fd = -1;
int i=0;
for(struct addrinfo *res = res0; res != NULL; res = res->ai_next, i++)
{
//std::cerr<<"Trying addrinfo #"<<i<<std::endl;
int try_fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if(try_fd == -1){
//std::cerr<<"socket: "<<strerror(errno)<<std::endl;
continue;
}
int val = 1;
setsockopt(try_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
if(res->ai_family == AF_INET6){
int val = 1;
setsockopt(try_fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val));
}
if(bind(try_fd, res->ai_addr, res->ai_addrlen) == -1){
//std::cerr<<"bind: "<<strerror(errno)<<std::endl;
close(try_fd);
continue;
}
fd = try_fd;
break;
}
freeaddrinfo(res0);
if(fd == -1){
std::cerr<<"Failed to create and bind socket"<<std::endl;
return false;
}
// Set this so that forked child processes don't prevent re-opening the
// same port after crash
if(fcntl(fd, F_SETFD, FD_CLOEXEC) != 0){
std::cerr<<"Failed to set socket FD_CLOEXEC"<<std::endl;
return false;
}
m_fd = fd;
return true;
}
bool accept_fd(const TCPSocket &listener)
{
close_fd();
if(!listener.good())
return false;
struct sockaddr_storage pin;
socklen_t pin_len = sizeof(pin);
int fd_client = accept(listener.fd(), (struct sockaddr *) &pin, &pin_len);
if(fd_client == -1){
std::cerr<<"accept: "<<strerror(errno)<<std::endl;
return false;
}
int val = 1;
setsockopt(fd_client, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
m_fd = fd_client;
return true;
}
bool send_fd(const ss_ &data)
{
if(m_fd == -1)
return false;
if(send(m_fd, &data[0], data.size(), 0) == -1){
std::cerr<<"send: "<<strerror(errno)<<std::endl;
return false;
}
return true;
}
ss_ get_local_address() const
{
if(m_fd == -1)
return "";
struct sockaddr_storage sa;
socklen_t sa_len = sizeof(sa);
if(getpeername(m_fd, (sockaddr*)&sa, &sa_len) == -1)
return "";
sv_<uchar> a;
if(!sockaddr_to_bytes(&sa, a))
return "";
return address_bytes_to_string(a);
}
ss_ get_remote_address() const
{
if(m_fd == -1)
return "";
struct sockaddr_storage sa;
socklen_t sa_len = sizeof(sa);
if(getsockname(m_fd, (sockaddr*)&sa, &sa_len) == -1)
return "";
sv_<uchar> a;
if(!sockaddr_to_bytes(&sa, a))
return "";
return address_bytes_to_string(a);
}
};
TCPSocket* createTCPSocket()
{
return new CTCPSocket();
}
}

View File

@ -10,6 +10,7 @@ namespace interface
virtual ~Server(){}
virtual void load_module(const ss_ &module_name, const ss_ &path) = 0;
virtual ss_ get_modules_path() = 0;
virtual ss_ get_builtin_modules_path() = 0;
virtual Module* get_module(const ss_ &module_name) = 0;
};
}

24
src/interface/tcpsocket.h Normal file
View File

@ -0,0 +1,24 @@
#pragma once
#include "core/types.h"
namespace interface
{
struct TCPSocket
{
virtual ~TCPSocket(){}
virtual int fd() const = 0;
virtual bool good() const = 0;
virtual void close_fd() = 0;
virtual bool listen_fd() = 0;
virtual bool connect_fd(const ss_ &address, const ss_ &port) = 0;
// Special values "any4", "any6" and "any"
virtual bool bind_fd(const ss_ &address, const ss_ &port) = 0;
virtual bool accept_fd(const TCPSocket &listener) = 0;
virtual bool send_fd(const ss_ &data) = 0;
virtual ss_ get_local_address() const = 0;
virtual ss_ get_remote_address() const = 0;
};
TCPSocket* createTCPSocket();
}

View File

@ -7,6 +7,7 @@ namespace server
{
ss_ rccpp_build_path = "../cache/rccpp_build";
ss_ interface_path = "../src/interface";
ss_ share_path = "../share";
};
}

View File

@ -12,13 +12,14 @@ int main(int argc, char *argv[])
std::string module_path;
const char opts[100] = "hm:r:i:";
const char opts[100] = "hm:r:i:S:";
const char usagefmt[1000] =
"Usage: %s [OPTION]...\n"
" -h Show this help\n"
" -m [module_path] Specify module path\n"
" -r [rccpp_build_path]Specify runtime compiled C++ build path\n"
" -i [interface_path] Specify path to interface headers\n"
" -S [share_path] Specify path to share/\n"
;
int c;
@ -41,6 +42,10 @@ int main(int argc, char *argv[])
fprintf(stderr, "INFO: config.interface_path: %s\n", c55_optarg);
config.interface_path = c55_optarg;
break;
case 'S':
fprintf(stderr, "INFO: config.share_path: %s\n", c55_optarg);
config.share_path = c55_optarg;
break;
default:
fprintf(stderr, "ERROR: Invalid command-line argument\n");
fprintf(stderr, usagefmt, argv[0]);

View File

@ -57,6 +57,11 @@ struct CState: public State, public interface::Server
return m_modules_path;
}
ss_ get_builtin_modules_path()
{
return g_server_config.share_path+"/builtin";
}
interface::Module* get_module(const ss_ &module_name)
{
auto it = m_modules.find(module_name);

View File

@ -2,7 +2,6 @@
#include "interface/server.h"
#include "interface/fs.h"
#include "interface/event.h"
//#include <cereal/archives/binary.hpp>
#include <iostream>
using interface::Event;
@ -35,10 +34,13 @@ struct Module: public interface::Module
void load_modules()
{
m_server->load_module("network", m_server->get_builtin_modules_path()+"/network");
sv_<ss_> load_list = {"test1", "test2"};
for(const ss_ &name : load_list){
m_server->load_module(name, m_server->get_modules_path()+"/"+name);
}
/*// TODO: Dependencies
auto list = interface::getGlobalFilesystem()->list_directory(m_server->get_modules_path());
for(const interface::Filesystem::Node &n : list){