Skip to content

Commit 4b8838a

Browse files
committed
simulator: shutdown connection
TCP is fun. If the server initiates the closing of the TCP connection the socket needs to stay alive for some time according to the protocol so that out-of-order and delayed packets have a chance to arrive. When the simulator gets shut down those packets doesn't matter. Luckily there is a way around, by setting SO_LINGER on the socket the connection is closed with a "RESET" instead and the socket is immediately released in the OS. This commit also switches from signal(2) to sigaction(2) so that we can avoid setting SA_RESTART so that signals interrupt blocking syscalls like read. It also introduces support for "SIGHUP" that can be used to simply disconnect the client.
1 parent e74e3b8 commit 4b8838a

File tree

2 files changed

+57
-10
lines changed

2 files changed

+57
-10
lines changed

test/simulator/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Simulator
2+
3+
## Signals
4+
5+
The simulator can be forcefully shutdown with SIGTERM. It can also be told to
6+
disconnect from the client using SIGHUP.

test/simulator/simulator.c

Lines changed: 51 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ static const char* _simulator_version = "1.0.0";
4242
int data_len;
4343
int commfd;
4444

45-
static volatile sig_atomic_t sigint_called = false;
45+
static volatile sig_atomic_t quitting = false;
46+
static volatile sig_atomic_t hangup = false;
4647
static int sockfd;
4748

4849
static int get_usb_message_socket(uint8_t* input)
@@ -71,17 +72,28 @@ static void simulate_firmware_execution(const uint8_t* input)
7172
usb_processing_process(usb_processing_hww());
7273
}
7374

74-
static void _int_handler(int signum)
75+
static void _quit_handler(int signum)
7576
{
7677
(void)signum;
77-
sigint_called = true;
78-
close(sockfd);
78+
quitting = true;
79+
}
80+
81+
static void _hup_handler(int signum)
82+
{
83+
(void)signum;
84+
hangup = true;
7985
}
8086

8187
int main(int argc, char* argv[])
8288
{
83-
signal(SIGINT, _int_handler);
84-
// Default port number
89+
struct sigaction psa;
90+
memset(&psa, 0, sizeof(struct sigaction));
91+
psa.sa_handler = _quit_handler;
92+
sigaction(SIGINT, &psa, NULL);
93+
sigaction(SIGTERM, &psa, NULL);
94+
psa.sa_handler = _hup_handler;
95+
sigaction(SIGHUP, &psa, NULL);
96+
// Default port number
8597
int portno = 15423;
8698

8799
struct option long_options[] = {
@@ -162,11 +174,12 @@ int main(int argc, char* argv[])
162174
while (1) {
163175
if ((commfd = accept(sockfd, (struct sockaddr*)&serv_addr, (socklen_t*)&serv_addr_len)) <
164176
0) {
165-
if (sigint_called) {
166-
printf("\nGot Ctrl-C, exiting\n");
177+
if (quitting) {
178+
printf("\nGot signal, exiting\n");
179+
break;
167180
}
168181
perror("accept");
169-
return 1;
182+
break;
170183
}
171184
printf("Socket connection setup success\n");
172185

@@ -175,7 +188,33 @@ int main(int argc, char* argv[])
175188
int temp_len;
176189
while (1) {
177190
// Simulator polls for USB messages from client and then processes them
178-
if (!get_usb_message_socket(input)) break;
191+
if (get_usb_message_socket(input) < 1) {
192+
if (quitting) {
193+
printf("\nGot term/int signal, exiting\n");
194+
// Using LINGER we force a TCP RST instead of graceful shutdown. Without this
195+
// trick the port keeps being bound for 10s of seconds after the application has
196+
// died, hindering future executions.
197+
struct linger sol = {.l_onoff = 1, .l_linger = 0};
198+
int res = setsockopt(commfd, SOL_SOCKET, SO_LINGER, &sol, sizeof(sol));
199+
if (res) {
200+
perror("setsockopt");
201+
}
202+
shutdown(commfd, SHUT_RDWR);
203+
uint8_t buf[1024];
204+
while (read(commfd, buf, sizeof(buf)) > 0);
205+
close(commfd);
206+
goto after_main_loop;
207+
}
208+
if (hangup) {
209+
hangup = false;
210+
printf("\nGot hangup signal, disconnecting\n");
211+
shutdown(commfd, SHUT_RDWR);
212+
uint8_t buf[1024];
213+
while (read(commfd, buf, sizeof(buf)) > 0);
214+
close(commfd);
215+
}
216+
break;
217+
}
179218
simulate_firmware_execution(input);
180219

181220
// If the USB message to be sent from firmware is bigger than one packet,
@@ -196,5 +235,7 @@ int main(int argc, char* argv[])
196235
printf("Socket connection closed\n");
197236
printf("Waiting for new clients, CTRL+C to shut down the simulator\n");
198237
}
238+
after_main_loop:
239+
close(sockfd);
199240
return 0;
200241
}

0 commit comments

Comments
 (0)