summaryrefslogtreecommitdiff
path: root/gdbremote.cpp
diff options
context:
space:
mode:
authorOxore <oxore@protonmail.com>2022-08-27 15:12:08 +0300
committerOxore <oxore@protonmail.com>2022-08-27 15:13:13 +0300
commit9580a9a8daa4426914f396a694903ab880ecd3f2 (patch)
tree46394ea036316ffccf3357bcc35f1c18635ae890 /gdbremote.cpp
parent903b8dbcaad887f6e14cc8cffc22ddda08dc9f85 (diff)
Add initial gdbremote implementation
Diffstat (limited to 'gdbremote.cpp')
-rw-r--r--gdbremote.cpp100
1 files changed, 100 insertions, 0 deletions
diff --git a/gdbremote.cpp b/gdbremote.cpp
new file mode 100644
index 0000000..98a0e2a
--- /dev/null
+++ b/gdbremote.cpp
@@ -0,0 +1,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);
+}