Listening channels implemented
This commit is contained in:
@@ -22,6 +22,7 @@ public:
|
||||
bool engine_wakeup_;
|
||||
char console_line_[CONSOLE_MAX + 1];
|
||||
int console_len_;
|
||||
std::map<int, SOCKET> listen_sockets_;
|
||||
std::unique_ptr<char> chbuf;
|
||||
|
||||
static PADDRINFOA find_good_addr(PADDRINFOA addrinfo) {
|
||||
@@ -33,12 +34,17 @@ public:
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void set_nonblocking(SOCKET sock) {
|
||||
u_long mode = 1; // 1 to enable non-blocking socket
|
||||
int status = ioctlsocket(sock, FIONBIO, &mode);
|
||||
assert(status == 0);
|
||||
}
|
||||
|
||||
SOCKET open_connection(const std::string &target, std::string &err) {
|
||||
PADDRINFOA addrs = nullptr;
|
||||
PADDRINFOA goodaddr = nullptr;
|
||||
SOCKET sock = INVALID_SOCKET;
|
||||
std::string host, port;
|
||||
u_long mode = 1; // 1 to enable non-blocking socket
|
||||
|
||||
err = "";
|
||||
util::split_host_port(target, host, port);
|
||||
@@ -62,8 +68,7 @@ public:
|
||||
}
|
||||
sock = socket(goodaddr->ai_family, SOCK_STREAM, IPPROTO_TCP);
|
||||
assert(sock != INVALID_SOCKET);
|
||||
status = ioctlsocket(sock, FIONBIO, &mode);
|
||||
assert(status == 0);
|
||||
set_nonblocking(sock);
|
||||
status = connect(sock, goodaddr->ai_addr, goodaddr->ai_addrlen);
|
||||
if (status != 0) {
|
||||
int errcode = WSAGetLastError();
|
||||
@@ -83,6 +88,25 @@ public:
|
||||
return SOCKET_ERROR;
|
||||
}
|
||||
|
||||
SOCKET listen_on_port(int port, std::string &err) {
|
||||
int status;
|
||||
err = "";
|
||||
SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
assert(sock != INVALID_SOCKET);
|
||||
|
||||
struct sockaddr_in server;
|
||||
server.sin_family = AF_INET;
|
||||
server.sin_addr.s_addr = INADDR_ANY;
|
||||
server.sin_port = htons(port);
|
||||
|
||||
status = bind(sock, (struct sockaddr *)&server, sizeof(server));
|
||||
assert(status == 0);
|
||||
status = listen(sock, 10);
|
||||
assert(status == 0);
|
||||
set_nonblocking(sock);
|
||||
return sock;
|
||||
}
|
||||
|
||||
void init(DrivenEngine *de) {
|
||||
driven_ = de;
|
||||
for (int i = 0; i < MAX_CHAN; i++) {
|
||||
@@ -94,6 +118,20 @@ public:
|
||||
chbuf.reset(new char[65536]);
|
||||
}
|
||||
|
||||
void handle_listen_ports() {
|
||||
std::set<int> listenports;
|
||||
driven_->drv_get_listen_ports(listenports);
|
||||
for (int port : listenports) {
|
||||
if (listen_sockets_.find(port) == listen_sockets_.end()) {
|
||||
std::string err;
|
||||
SOCKET sock = listen_on_port(port, err);
|
||||
if (sock != INVALID_SOCKET) {
|
||||
listen_sockets_[port] = sock;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void handle_lua_source() {
|
||||
if (driven_->drv_get_rescan_lua_source()) {
|
||||
driven_->drv_set_lua_source(util::read_lua_source("lua"));
|
||||
@@ -190,11 +228,24 @@ public:
|
||||
void handle_clock() {
|
||||
}
|
||||
|
||||
void close_socket(int chid) {
|
||||
assert(socket_[chid] != INVALID_SOCKET);
|
||||
assert(closesocket(socket_[chid]) == 0);
|
||||
driven_->drv_notify_close(chid);
|
||||
socket_[chid] = INVALID_SOCKET;
|
||||
connected_[chid] = false;
|
||||
engine_wakeup_ = true;
|
||||
}
|
||||
|
||||
bool calc_select_sets(fd_set &rfds, fd_set &wfds, fd_set &efds) const {
|
||||
FD_ZERO(&rfds);
|
||||
FD_ZERO(&wfds);
|
||||
FD_ZERO(&efds);
|
||||
bool any = false;
|
||||
for (const auto &p : listen_sockets_) {
|
||||
FD_SET(p.second, &rfds);
|
||||
any = true;
|
||||
}
|
||||
for (int chid = 1; chid < MAX_CHAN; chid++) {
|
||||
SOCKET sock = socket_[chid];
|
||||
if (sock == INVALID_SOCKET) continue;
|
||||
@@ -207,13 +258,30 @@ public:
|
||||
return any;
|
||||
}
|
||||
|
||||
void close_socket(int chid) {
|
||||
assert(socket_[chid] != INVALID_SOCKET);
|
||||
assert(closesocket(socket_[chid]) == 0);
|
||||
driven_->drv_notify_close(chid);
|
||||
socket_[chid] = INVALID_SOCKET;
|
||||
connected_[chid] = false;
|
||||
engine_wakeup_ = true;
|
||||
void accept_connections(int port, SOCKET sock) {
|
||||
while (true) {
|
||||
SOCKET chsock = accept(sock, nullptr, nullptr);
|
||||
if (chsock != INVALID_SOCKET) {
|
||||
int chid = driven_->drv_notify_accept(port);
|
||||
socket_[chid] = chsock;
|
||||
connected_[chid] = true;
|
||||
engine_wakeup_ = true;
|
||||
continue;
|
||||
}
|
||||
int errcode = WSAGetLastError();
|
||||
if (errcode == WSAEWOULDBLOCK) {
|
||||
return;
|
||||
}
|
||||
if (errcode == WSAECONNRESET) {
|
||||
// The remote disconnected before we had a chance to accept.
|
||||
// Just pretend it never happened.
|
||||
continue;
|
||||
}
|
||||
// If a listening port fails in a non-transient way,
|
||||
// we don't really have any good way of handling
|
||||
// that.
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
void handle_socket_input_output(int mstimeout) {
|
||||
@@ -229,6 +297,13 @@ public:
|
||||
timeout.tv_usec = (mstimeout - (timeout.tv_sec*1000)) * 1000;
|
||||
int status = select(1, &rfds, &wfds, &efds, &timeout);
|
||||
assert(status != SOCKET_ERROR);
|
||||
|
||||
for (auto &p : listen_sockets_) {
|
||||
if (FD_ISSET(p.second, &rfds)) {
|
||||
accept_connections(p.first, p.second);
|
||||
}
|
||||
}
|
||||
|
||||
for (int chid = 1; chid < MAX_CHAN; chid++) {
|
||||
SOCKET sock = socket_[chid];
|
||||
if (sock == INVALID_SOCKET) continue;
|
||||
@@ -267,6 +342,7 @@ public:
|
||||
DrivenEngine::set(de);
|
||||
driven_->drv_set_lua_source(util::read_lua_source("lua"));
|
||||
driven_->drv_invoke_event_init();
|
||||
handle_listen_ports();
|
||||
while (!de->drv_get_stop_driver()) {
|
||||
engine_wakeup_ = false;
|
||||
handle_lua_source();
|
||||
|
||||
Reference in New Issue
Block a user