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/server/rccpp.cpp
|
||||||
src/impl/fs.cpp
|
src/impl/fs.cpp
|
||||||
src/impl/event.cpp
|
src/impl/event.cpp
|
||||||
|
src/impl/tcpsocket.cpp
|
||||||
)
|
)
|
||||||
add_executable(${SERVER_EXE_NAME} ${SERVER_SRCS})
|
add_executable(${SERVER_EXE_NAME} ${SERVER_SRCS})
|
||||||
TARGET_LINK_LIBRARIES(${SERVER_EXE_NAME}
|
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.
|
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 ~Server(){}
|
||||||
virtual void load_module(const ss_ &module_name, const ss_ &path) = 0;
|
virtual void load_module(const ss_ &module_name, const ss_ &path) = 0;
|
||||||
virtual ss_ get_modules_path() = 0;
|
virtual ss_ get_modules_path() = 0;
|
||||||
|
virtual ss_ get_builtin_modules_path() = 0;
|
||||||
virtual Module* get_module(const ss_ &module_name) = 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_ rccpp_build_path = "../cache/rccpp_build";
|
||||||
ss_ interface_path = "../src/interface";
|
ss_ interface_path = "../src/interface";
|
||||||
|
ss_ share_path = "../share";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,13 +12,14 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
std::string module_path;
|
std::string module_path;
|
||||||
|
|
||||||
const char opts[100] = "hm:r:i:";
|
const char opts[100] = "hm:r:i:S:";
|
||||||
const char usagefmt[1000] =
|
const char usagefmt[1000] =
|
||||||
"Usage: %s [OPTION]...\n"
|
"Usage: %s [OPTION]...\n"
|
||||||
" -h Show this help\n"
|
" -h Show this help\n"
|
||||||
" -m [module_path] Specify module path\n"
|
" -m [module_path] Specify module path\n"
|
||||||
" -r [rccpp_build_path]Specify runtime compiled C++ build path\n"
|
" -r [rccpp_build_path]Specify runtime compiled C++ build path\n"
|
||||||
" -i [interface_path] Specify path to interface headers\n"
|
" -i [interface_path] Specify path to interface headers\n"
|
||||||
|
" -S [share_path] Specify path to share/\n"
|
||||||
;
|
;
|
||||||
|
|
||||||
int c;
|
int c;
|
||||||
@ -41,6 +42,10 @@ int main(int argc, char *argv[])
|
|||||||
fprintf(stderr, "INFO: config.interface_path: %s\n", c55_optarg);
|
fprintf(stderr, "INFO: config.interface_path: %s\n", c55_optarg);
|
||||||
config.interface_path = c55_optarg;
|
config.interface_path = c55_optarg;
|
||||||
break;
|
break;
|
||||||
|
case 'S':
|
||||||
|
fprintf(stderr, "INFO: config.share_path: %s\n", c55_optarg);
|
||||||
|
config.share_path = c55_optarg;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "ERROR: Invalid command-line argument\n");
|
fprintf(stderr, "ERROR: Invalid command-line argument\n");
|
||||||
fprintf(stderr, usagefmt, argv[0]);
|
fprintf(stderr, usagefmt, argv[0]);
|
||||||
|
@ -57,6 +57,11 @@ struct CState: public State, public interface::Server
|
|||||||
return m_modules_path;
|
return m_modules_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ss_ get_builtin_modules_path()
|
||||||
|
{
|
||||||
|
return g_server_config.share_path+"/builtin";
|
||||||
|
}
|
||||||
|
|
||||||
interface::Module* get_module(const ss_ &module_name)
|
interface::Module* get_module(const ss_ &module_name)
|
||||||
{
|
{
|
||||||
auto it = m_modules.find(module_name);
|
auto it = m_modules.find(module_name);
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
#include "interface/server.h"
|
#include "interface/server.h"
|
||||||
#include "interface/fs.h"
|
#include "interface/fs.h"
|
||||||
#include "interface/event.h"
|
#include "interface/event.h"
|
||||||
//#include <cereal/archives/binary.hpp>
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
using interface::Event;
|
using interface::Event;
|
||||||
@ -35,10 +34,13 @@ struct Module: public interface::Module
|
|||||||
|
|
||||||
void load_modules()
|
void load_modules()
|
||||||
{
|
{
|
||||||
|
m_server->load_module("network", m_server->get_builtin_modules_path()+"/network");
|
||||||
|
|
||||||
sv_<ss_> load_list = {"test1", "test2"};
|
sv_<ss_> load_list = {"test1", "test2"};
|
||||||
for(const ss_ &name : load_list){
|
for(const ss_ &name : load_list){
|
||||||
m_server->load_module(name, m_server->get_modules_path()+"/"+name);
|
m_server->load_module(name, m_server->get_modules_path()+"/"+name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*// TODO: Dependencies
|
/*// TODO: Dependencies
|
||||||
auto list = interface::getGlobalFilesystem()->list_directory(m_server->get_modules_path());
|
auto list = interface::getGlobalFilesystem()->list_directory(m_server->get_modules_path());
|
||||||
for(const interface::Filesystem::Node &n : list){
|
for(const interface::Filesystem::Node &n : list){
|
||||||
|
Loading…
x
Reference in New Issue
Block a user