summaryrefslogtreecommitdiff
path: root/gdbremote.cpp
blob: 98a0e2a06df3d6f913943529e6e9e0ff6f072b71 (plain)
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
/* 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) {
                if (res->packet.length() > 0) {
                    printf("<- \"%s\"\n", res->packet.c_str());
                }
                if (res->response.length() > 0) {
                    printf("-> \"%s\"\n", res->response.c_str());
                    if (send(conn_fd, &res->response[0], res->response.length(), 0) == -1)
                        perror("Send failed");
                }
            }
        }
        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);
}