From 772d7ac6d85195e6dfa2b91632dcd23c2faeefeb Mon Sep 17 00:00:00 2001 From: Matt Godbolt Date: Fri, 13 Mar 2015 18:14:37 -0500 Subject: [PATCH] Expose the FD of seasocks, update test --- src/app/c/ws_test_poll.cpp | 55 +++++++++++++++++++++++++++++++++--- src/main/c/seasocks/Server.h | 5 ++++ 2 files changed, 56 insertions(+), 4 deletions(-) diff --git a/src/app/c/ws_test_poll.cpp b/src/app/c/ws_test_poll.cpp index 263eceaa..fd5805e1 100644 --- a/src/app/c/ws_test_poll.cpp +++ b/src/app/c/ws_test_poll.cpp @@ -29,7 +29,8 @@ // suspicious means of sending raw JavaScript commands to be executed on other // clients. -// Same as ws_test, but uses the poll() method. +// Same as ws_test, but uses the poll() method and a separate epoll set to +// demonstrate how Seasocks can be used with another polling system. #include "seasocks/PrintfLogger.h" #include "seasocks/Server.h" @@ -43,6 +44,9 @@ #include #include #include +#include +#include +#include using namespace seasocks; using namespace std; @@ -114,10 +118,53 @@ int main(int argc, const char* argv[]) { cerr << "couldn't start listening" << endl; return 1; } + int myEpoll = epoll_create(10); + epoll_event wakeSeasocks = { EPOLLIN|EPOLLOUT|EPOLLERR, { &server } }; + epoll_ctl(myEpoll, EPOLL_CTL_ADD, server.fd(), &wakeSeasocks); + + // Also poll stdin + epoll_event wakeStdin = { EPOLLIN, { nullptr } }; + epoll_ctl(myEpoll, EPOLL_CTL_ADD, STDIN_FILENO, &wakeStdin); + auto prevFlags = fcntl(STDIN_FILENO, F_GETFL, 0); + fcntl(STDIN_FILENO, F_SETFL, prevFlags | O_NONBLOCK); + + cout << "Will echo anything typed in stdin: " << flush; while (true) { - auto result = server.poll(100); - if (result == Server::PollResult::Terminated) return 0; - if (result == Server::PollResult::Error) return 1; + constexpr auto maxEvents = 2; + epoll_event events[maxEvents]; + auto res = epoll_wait(myEpoll, events, maxEvents, -1); + if (res < 0) { + cerr << "epoll returned an error" << endl; + return 1; + } + for (auto i = 0; i < res; ++i) { + if (events[i].data.ptr == &server) { + auto seasocksResult = server.poll(0); + if (seasocksResult == Server::PollResult::Terminated) return 0; + if (seasocksResult == Server::PollResult::Error) return 1; + } else if (events[i].data.ptr == nullptr) { + // Echo stdin to stdout to show we can read from that too. + for (;;) { + char buf[1024]; + auto numRead = ::read(STDIN_FILENO, buf, sizeof(buf)); + if (numRead < 0) { + if (errno != EWOULDBLOCK && errno != EAGAIN) { + cerr << "Error reading stdin" << endl; + return 1; + } + break; + } else if (numRead > 0) { + auto written = write(STDOUT_FILENO, buf, numRead); + if (written != numRead) { + cerr << "Truncated write" << endl; + } + } else if (numRead == 0) { + cerr << "EOF on stdin" << endl; + return 0; + } + } + } + } } return 0; } diff --git a/src/main/c/seasocks/Server.h b/src/main/c/seasocks/Server.h index aea16605..4629a432 100644 --- a/src/main/c/seasocks/Server.h +++ b/src/main/c/seasocks/Server.h @@ -99,6 +99,11 @@ class Server : private ServerImpl { }; PollResult poll(int millisToBlock); + // Returns a file descriptor that can be polled for changes (e.g. by + // placing it in an epoll set. The poll() method above only need be called + // when this file descriptor is readable. + int fd() const { return _epollFd; } + // Terminate any loop() or poll(). May be called from any thread. void terminate();