summaryrefslogtreecommitdiff
path: root/gdbremote.cpp
blob: a093192985a7a0a52ce372fe268de060be148f04 (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
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);
}