Bind a socket but don't listen to it yet
This commit is contained in:
parent
72766206cb
commit
0287e82006
@ -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}
|
||||
|
@ -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.
|
||||
|
||||
|
||||
|
48
share/builtin/network/server/init.cpp
Normal file
48
share/builtin/network/server/init.cpp
Normal 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
295
src/impl/tcpsocket.cpp
Normal 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();
|
||||
}
|
||||
|
||||
}
|
@ -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
24
src/interface/tcpsocket.h
Normal 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();
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ namespace server
|
||||
{
|
||||
ss_ rccpp_build_path = "../cache/rccpp_build";
|
||||
ss_ interface_path = "../src/interface";
|
||||
ss_ share_path = "../share";
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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]);
|
||||
|
@ -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);
|
||||
|
@ -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){
|
||||
|
Loading…
x
Reference in New Issue
Block a user