Open Model Railroad Network (OpenMRN)
Loading...
Searching...
No Matches
socket_listener.cxx
Go to the documentation of this file.
1
35#include "openmrn_features.h"
36
37#if OPENMRN_FEATURE_BSD_SOCKETS
38
39#ifndef _DEFAULT_SOURCE
40#define _DEFAULT_SOURCE
41#endif
42
44
45#include "nmranet_config.h"
46#include "utils/logging.h"
47#include "utils/macros.h"
48
49#ifndef ESP_PLATFORM
50// these don't exist on the ESP32 with LWiP
51#include <arpa/inet.h>
52#include <netinet/in.h>
53#include <netinet/tcp.h>
54#endif // ESP_PLATFORM
55#include <netdb.h>
56#include <sys/socket.h>
57#include <sys/types.h>
58#include <signal.h>
59#include <unistd.h>
60
61static void* accept_thread_start(void* arg)
62{
63 SocketListener* l = static_cast<SocketListener*>(arg);
65 return NULL;
66}
67
68SocketListener::SocketListener(int port, connection_callback_t callback,
69 const char *thread_name)
70 : startupComplete_(0),
71 shutdownRequested_(0),
72 shutdownComplete_(0),
73 port_(port),
74 callback_(callback),
75 accept_thread_(thread_name, 0, config_socket_listener_stack_size(),
76 accept_thread_start, this)
77{
78#if OPENMRN_FEATURE_BSD_SOCKETS_IGNORE_SIGPIPE
79 // We expect write failures to occur but we want to handle them where the
80 // error occurs rather than in a SIGPIPE handler.
81 signal(SIGPIPE, SIG_IGN);
82#endif // OPENMRN_FEATURE_BSD_SOCKETS_IGNORE_SIGPIPE
83}
84
85SocketListener::~SocketListener()
86{
88 {
89 shutdown();
90 }
91}
92
94{
96 while (!shutdownComplete_)
97 {
98 usleep(1000);
99 }
100}
101
103{
104 socklen_t namelen;
105 struct sockaddr_in addr;
106 int listenfd;
107
108 ERRNOCHECK("socket", listenfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP));
109
110 addr.sin_family = AF_INET;
111 addr.sin_addr.s_addr = INADDR_ANY;
112 addr.sin_port = htons(port_);
113 int val = 1;
114 ERRNOCHECK("setsockopt_reuseaddr",
115 setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)));
116
117 ERRNOCHECK("bind",
118 ::bind(listenfd, (struct sockaddr *) &addr, sizeof(addr)));
119
120#if OPENMRN_HAVE_BSD_SOCKETS_GETSOCKNAME
121 namelen = sizeof(addr);
122 ERRNOCHECK("getsockname",
123 getsockname(listenfd, (struct sockaddr *) &addr, &namelen));
124
125 // This is the actual port that got opened. We could check it against the
126 // requested port. listenport = ;
127#endif // OPENMRN_HAVE_BSD_SOCKETS_GETSOCKNAME
128
129 // FreeRTOS+TCP uses the parameter to listen to set the maximum number of
130 // connections to the given socket, so allow some room
131 ERRNOCHECK("listen", listen(listenfd, config_socket_listener_backlog()));
132
133 LOG(INFO, "Listening on port %d, fd %d", ntohs(addr.sin_port), listenfd);
134
135#if OPENMRN_HAVE_BSD_SOCKETS_RX_TIMEOUT
136 {
137 struct timeval tm;
138 tm.tv_sec = 0;
139 tm.tv_usec = MSEC_TO_USEC(100);
140 ERRNOCHECK("setsockopt_timeout",
141 setsockopt(listenfd, SOL_SOCKET, SO_RCVTIMEO, &tm, sizeof(tm)));
142 }
143#endif // OPENMRN_HAVE_BSD_SOCKETS_RX_TIMEOUT
144
145 int connfd;
146
148
149 while (!shutdownRequested_)
150 {
151 namelen = sizeof(addr);
152 connfd = accept(listenfd,
153 (struct sockaddr *)&addr,
154 &namelen);
155 if (connfd < 0)
156 {
157 if (errno == EINTR || errno == EAGAIN || errno == EMFILE)
158 {
159 continue;
160 }
161 else if (errno == ECONNABORTED)
162 {
163 break;
164 }
165 print_errno_and_exit("accept");
166 return;
167 }
168 int val = 1;
169 ERRNOCHECK("setsockopt(nodelay)",
171 &val, sizeof(val)));
172
173 LOG(INFO, "Incoming connection from %s, fd %d.", inet_ntoa(addr.sin_addr),
174 connfd);
175
176 callback_(connfd);
177 }
178 close(listenfd);
179 LOG(INFO, "Shutdown listening socket %d.", port_);
181}
182
183#endif // OPENMRN_FEATURE_BSD_SOCKETS
const char * inet_ntoa(struct in_addr addr)
Converts internet address into a dotted decimal string.
int getsockname(int socket, struct sockaddr &addr, socklen_t &namelen)
Get the socket name.
int accept(int socket, struct sockaddr *address, socklen_t *address_len)
Accept a new connection on a socket.
Definition Socket.cxx:194
int setsockopt(int socket, int level, int option_name, const void *option_value, socklen_t option_len)
Set the socket options.
Definition Socket.cxx:255
int bind(int socket, const struct sockaddr *address, socklen_t address_len)
Bind a name to a socket.
Definition Socket.cxx:159
int listen(int socket, int backlog)
Mark a connection-mode socket, specified by the socket argument, as accepting connections.
Definition Socket.cxx:174
int socket(int domain, int type, int protocol)
Create an unbound socket in a communications domain.
Definition Socket.cxx:144
volatile unsigned startupComplete_
1 if we have completed bind.
int port_
Port to listen on.
void shutdown()
Shuts down the socket listener.
connection_callback_t callback_
Callback to call with each incoming conneciton.
SocketListener(int port, connection_callback_t callback, const char *thread_name="accept_thread")
Constructor.
void AcceptThreadBody()
Implementation of the accept thread.
volatile unsigned shutdownRequested_
1 if shutting down.
volatile unsigned shutdownComplete_
1 if accept thread is exited.
void print_errno_and_exit(const char *where)
Prints an error message about errno to std error and terminates the current program.
Definition errno_exit.c:47
#define htons(x)
Converts a host endian short value to network endian.
Definition in.h:93
#define INADDR_ANY
Listen on all network interfaces for incoming connections.
Definition in.h:67
#define IPPROTO_TCP
TCP Raw Socket.
Definition in.h:70
#define ntohs(x)
Converts a network endian short value to host endian.
Definition in.h:89
#define ERRNOCHECK(where, x...)
Calls the function x, and if the return value is negative, prints errno as error message to stderr an...
Definition logging.h:174
#define LOG(level, message...)
Conditionally write a message to the logging output.
Definition logging.h:99
static const int INFO
Loglevel that is printed by default, reporting some status information.
Definition logging.h:57
#define MSEC_TO_USEC(_msec)
Convert a millisecond value to a microsecond value.
Definition os.h:274
#define SOCK_STREAM
TCP Socket.
Definition socket.h:45
uint32_t socklen_t
type of sockaddr lenth
Definition socket.h:89
#define SO_REUSEADDR
socket option to reuse address
Definition socket.h:67
#define SOL_SOCKET
socket option category
Definition socket.h:64
#define AF_INET
IPv4 Socket (UDP, TCP, etc...)
Definition socket.h:54
#define SO_RCVTIMEO
socket option receive timout
Definition socket.h:70
Structure describing an Internet socket address.
Definition in.h:56
IPv4 socket address.
Definition socket.h:83
#define TCP_NODELAY
don't delay send to coalesce packets
Definition tcp.h:42