rogue
Loading...
Searching...
No Matches
XvcServer.cpp
Go to the documentation of this file.
1
19
20#include "rogue/GilRelease.h"
21
22#include <arpa/inet.h>
23#include <netinet/in.h>
24#include <sys/select.h>
25#include <sys/socket.h>
26#include <unistd.h>
27
28#include <atomic>
29#include <cerrno>
30#include <cstdint>
31#include <cstring>
32
34
36
37rpx::XvcServer::XvcServer(uint16_t port, int wakeFd, JtagDriver* drv, unsigned maxMsgSize)
38 : sd_(-1),
39 wakeFd_(wakeFd),
40 drv_(drv),
41 maxMsgSize_(maxMsgSize),
42 port_(port) {
43 struct sockaddr_in a{};
44 int yes = 1;
45
46 a.sin_family = AF_INET;
47 a.sin_addr.s_addr = INADDR_ANY;
48 a.sin_port = htons(port);
49
50 if ((sd_ = ::socket(AF_INET, SOCK_STREAM, 0)) < 0)
51 throw(rogue::GeneralError::create("XvcServer::XvcServer()", "Failed to create socket"));
52
53 if (::setsockopt(sd_, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes))) {
54 ::close(sd_);
55 sd_ = -1;
56 throw(rogue::GeneralError::create("XvcServer::XvcServer()", "setsockopt(SO_REUSEADDR) failed"));
57 }
58
59 if (::bind(sd_, reinterpret_cast<struct sockaddr*>(&a), sizeof(a))) {
60 ::close(sd_);
61 sd_ = -1;
62 throw(rogue::GeneralError::create("XvcServer::XvcServer()", "Unable to bind Stream socket to local address"));
63 }
64
65 // Resolve kernel-assigned port when caller asked for 0.
66 if (port_ == 0) {
67 socklen_t len = sizeof(a);
68 if (::getsockname(sd_, reinterpret_cast<struct sockaddr*>(&a), &len) < 0) {
69 ::close(sd_);
70 sd_ = -1;
71 throw(rogue::GeneralError::create("XvcServer::XvcServer()", "getsockname failed"));
72 }
73 port_ = ntohs(a.sin_port);
74 }
75
76 if (::listen(sd_, 1)) {
77 ::close(sd_);
78 sd_ = -1;
79 throw(rogue::GeneralError::create("XvcServer::XvcServer()", "Unable to listen on socket"));
80 }
81}
82
83rpx::XvcServer::~XvcServer() {
84 if (sd_ >= 0) ::close(sd_);
85}
86
87uint32_t rpx::XvcServer::getPort() const {
88 return static_cast<uint32_t>(port_);
89}
90
91void rpx::XvcServer::run(std::atomic<bool>& threadEn, rogue::LoggingPtr log) {
92 if (sd_ < 0 || sd_ >= FD_SETSIZE || (wakeFd_ >= 0 && wakeFd_ >= FD_SETSIZE)) {
93 int badFd = (sd_ < 0 || sd_ >= FD_SETSIZE) ? sd_ : wakeFd_;
94 throw(rogue::GeneralError::create("XvcServer::run()", "fd %d invalid or exceeds FD_SETSIZE (%d)",
95 badFd, FD_SETSIZE));
96 }
97 fd_set rset;
98 int maxFd = sd_ + 1;
99 if (wakeFd_ >= 0 && wakeFd_ >= sd_) maxFd = wakeFd_ + 1;
100
101 while (threadEn.load(std::memory_order_acquire)) {
102 FD_ZERO(&rset);
103 FD_SET(sd_, &rset);
104 if (wakeFd_ >= 0) FD_SET(wakeFd_, &rset);
105
106 // NO timeout — block until accept-ready OR wakefd readable.
107 // Release the GIL across the blocking select() so that the outer
108 // rogue::ScopedGil held by Xvc::runThread (needed for tstate identity
109 // under nested Master::sendFrame callbacks into Python ris.Slave
110 // subclasses) does not starve Python worker threads.
111 int nready;
112 {
113 rogue::GilRelease noGil;
114 nready = ::select(maxFd, &rset, nullptr, nullptr, nullptr);
115 }
116 if (nready < 0) {
117 if (errno == EINTR) continue;
118 int savedErrno = errno;
119 log->warning("XvcServer::run(): select() failed: %s (errno %d)", strerror(savedErrno), savedErrno);
120 throw(rogue::GeneralError::create("XvcServer::run()", "select() failed: %s (errno %d)",
121 strerror(savedErrno), savedErrno));
122 }
123 if (wakeFd_ >= 0 && FD_ISSET(wakeFd_, &rset)) {
124 // Shutdown signaled by Xvc::stop(); break out of loop.
125 break;
126 }
127 if (FD_ISSET(sd_, &rset)) {
128 try {
129 // Forward the wake-fd so readTo() inside the connection
130 // wakes promptly on shutdown.
131 XvcConnection conn(sd_, wakeFd_, drv_, maxMsgSize_);
132 conn.run();
133 } catch (rogue::GeneralError& e) {
134 log->debug("Sub-connection closed: %s", e.what());
135 }
136 }
137 }
138}
Generic Rogue exception type.
char const * what() const
Returns exception text for standard exception handling.
static GeneralError create(std::string src, const char *fmt,...)
Creates a formatted error instance.
RAII helper that releases the Python GIL for a scope.
Definition GilRelease.h:36
Base transport driver for the AxisToJtag firmware protocol.
Definition JtagDriver.h:60
Manages one TCP client connection speaking the XVC protocol.
virtual void run()
Runs command processing loop for this connection.
std::shared_ptr< rogue::Logging > LoggingPtr
Shared pointer alias for Logging.
Definition Logging.h:205