1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
/* SPDX-License-Identifier: Unlicense
*/
#include "gdbremote_parser.hpp"
#include <cstdlib>
#include <cstdio>
#include <cstdint>
#include <cstring>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#define MESSAGE_BUFFER_SIZE 1
char msg_buf[MESSAGE_BUFFER_SIZE];
static int set_socket_reuseaddr(int socket_fd)
{
const int val = 1;
const socklen_t len = sizeof(val);
return setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, (void*)&val, len);
}
static inline struct sockaddr_in sockaddr_in_any_ip_with_port(uint16_t port) {
struct sockaddr_in server{};
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(port);
return server;
}
static int setup_socket(uint16_t port)
{
// This creates the socket - or quits
const int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
if (socket_fd == -1) {
perror("Could not create socket");
return -1;
}
// Make TCP port reusable in case of kill or crash.
// Deliberate explanation: https://stackoverflow.com/a/3233022
if (set_socket_reuseaddr(socket_fd) == -1) {
perror("setsockopt failed");
close(socket_fd);
return -1;
}
puts("Socket created");
const struct sockaddr_in server = sockaddr_in_any_ip_with_port(port);
if (bind(socket_fd, (struct sockaddr *)&server, sizeof(server)) == -1) {
perror("Bind failed");
close(socket_fd);
return -1;
}
printf("Binding to 0.0.0.0:%u done\n", port);
return socket_fd;
}
int main(int argc, char *argv[])
{
const int port = argc > 1 ? atoi(argv[1]) : 3333;
const int socket_fd = setup_socket(port);
if (socket_fd == -1)
return EXIT_FAILURE;
printf("Listening TCP 0.0.0.0:%u\n", port);
listen(socket_fd, 4); // Mark socket as listener
struct sockaddr client_address;
socklen_t address_len;
const int conn_fd = accept(socket_fd, &client_address, &address_len);
if (conn_fd == -1) {
perror("Accept failed");
close(socket_fd);
return EXIT_FAILURE;
}
puts("Connection accepted");
GDBRemote::ExchangeContext exchange_ctx{};
ssize_t read_size;
while ((read_size = recv(conn_fd, msg_buf, MESSAGE_BUFFER_SIZE, 0)) > 0) {
for (size_t i = 0; i < static_cast<size_t>(read_size); i++) {
const auto res = exchange_ctx.Consume(msg_buf[i]);
if (res == nullptr) continue;
if (res->packet.length() > 0) {
if (0) printf("<- \"%s\"\n", res->packet.c_str());
printf("<- \"%s\"\n", exchange_ctx.GetLastPacket().c_str());
const auto packet = GDBRemote::Packet::Parse(res->packet);
printf(
" Packet type: \"%s\"\n",
GDBRemote::Packet::PacketTypeToString(packet.type));
}
if (res->ack.length() > 0) {
printf("-> \"%s\"\n", res->ack.c_str());
if (send(conn_fd, &res->ack[0], res->ack.length(), 0) == -1)
perror("Send failed (ack/nak)");
}
if (res->packet.length() > 0) {
const auto packet = GDBRemote::Packet::Parse(res->packet);
(void) packet;
const auto response = exchange_ctx.WrapDataToSend();
printf("-> \"%s\"\n", response.c_str());
if (send(conn_fd, &response[0], response.length(), 0) == -1)
perror("Send failed (response)");
}
}
memset(msg_buf, '\0', MESSAGE_BUFFER_SIZE);
}
if (read_size == 0) {
puts("Client disconnected");
} else if (read_size == -1) {
perror("Recv failed");
}
close(socket_fd);
}
|