Aaro Saila 1 dzień temu
rodzic
commit
6a62c9f680
4 zmienionych plików z 137 dodań i 0 usunięć
  1. 25 0
      ch3/TCPEchoServer.c
  2. 93 0
      ch3/TCPServerUtility.c
  3. 5 0
      ch3/TCPServerUtility.h
  4. 14 0
      ch3/meson.build

+ 25 - 0
ch3/TCPEchoServer.c

@@ -0,0 +1,25 @@
+#include <unistd.h>
+
+#include "TCPServerUtility.h"
+#include "Practical.h"
+
+int main(int argc, char **argv) {
+    if (argc != 2) {
+        DieWithUserMessage("Parameter(s)", "<Server Service/Port>");
+    }
+
+    char *service = argv[1];
+
+    int serv_sock = setup_tcp_server_socket(service);
+    if (serv_sock == -1) {
+        DieWithUserMessage("setup_tcp_server_socket() failed", service);
+    }
+
+    while (true) {
+        const int client_sock = accept_tcp_connection(serv_sock);
+        HandleTCPClient(client_sock);
+        close(client_sock);
+    }
+
+    return 0;
+}

+ 93 - 0
ch3/TCPServerUtility.c

@@ -0,0 +1,93 @@
+#include <netdb.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "Practical.h"
+
+static const int MAX_PENDING = 5;
+
+int setup_tcp_server_socket(const char *service) {
+    struct addrinfo addr_criteria = { 0 };
+    addr_criteria.ai_family = AF_UNSPEC;
+    addr_criteria.ai_flags = AI_PASSIVE;
+    addr_criteria.ai_socktype = SOCK_STREAM;
+    addr_criteria.ai_protocol = proto_get_num("tcp");
+
+    struct addrinfo *serv_addr = nullptr;
+    int ret = getaddrinfo(nullptr, service, &addr_criteria, &serv_addr);
+    if (ret != 0) {
+        DieWithUserMessage("getaddrinfo() failed", gai_strerror(ret));
+    }
+
+    int serv_sock = -1;
+    for (struct addrinfo *addr = serv_addr; addr != nullptr; addr = addr->ai_next) {
+        serv_sock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
+        if (serv_sock < 0) {
+            continue;
+        }
+
+        if (
+            (bind(serv_sock, addr->ai_addr, addr->ai_addrlen) == 0)
+            && (listen(serv_sock, MAX_PENDING) == 0)
+        ) {
+            struct sockaddr_storage local_addr;
+            socklen_t addr_size = sizeof(local_addr);
+            if (getsockname(serv_sock, (struct sockaddr *) &local_addr, &addr_size) < 0) {
+                DieWithSystemMessage("getsockname() failed");
+            }
+            fputs("Binding to: ", stdout);
+            PrintSocketAddress((struct sockaddr *) &local_addr, stdout);
+            fputc('\n', stdout);
+            break;
+        } else {
+            close(serv_sock);
+            serv_sock = -1;
+        }
+    }
+
+    freeaddrinfo(serv_addr);
+
+    return serv_sock;
+}
+
+int accept_tcp_connection(const int serv_sock) {
+    struct sockaddr_storage client_addr;
+    socklen_t client_addr_len = sizeof(client_addr);
+
+    int client_sock = accept(serv_sock, (struct sockaddr *) &client_addr, &client_addr_len);
+    if (client_sock < 0) {
+        DieWithSystemMessage("accept() failed");
+    }
+
+    fputs("Handling client ", stdout);
+    PrintSocketAddress((struct sockaddr *) &client_addr, stdout);
+    fputc('\n', stdout);
+
+    return client_sock;
+}
+
+void HandleTCPClient(const int client_sock) {
+    char buffer[BUFSIZE];
+
+    ssize_t num_bytes_rcvd = recv(client_sock, buffer, BUFSIZE, 0);
+    if (num_bytes_rcvd < 0) {
+        DieWithSystemMessage("recv() failed");
+    }
+
+    while (num_bytes_rcvd > 0) {
+        ssize_t num_bytes_sent = send(client_sock, buffer, num_bytes_rcvd, 0);
+        if (num_bytes_sent < 0) {
+            DieWithSystemMessage("send() failed");
+        } else if (num_bytes_sent != num_bytes_rcvd) {
+            DieWithUserMessage("send()", "sent unexpected number of bytes");
+        }
+
+        num_bytes_rcvd = recv(client_sock, buffer, BUFSIZE, 0);
+        if (num_bytes_rcvd < 0) {
+            DieWithSystemMessage("recv() failed");
+        }
+    }
+
+    close(client_sock);
+}

+ 5 - 0
ch3/TCPServerUtility.h

@@ -0,0 +1,5 @@
+#pragma once
+
+int setup_tcp_server_socket(const char *service);
+int accept_tcp_connection(const int serv_sock);
+void HandleTCPClient(const int client_sock);

+ 14 - 0
ch3/meson.build

@@ -24,3 +24,17 @@ tcp_echo_client = executable(
     '-D_POSIX_C_SOURCE=200112L' # For getaddrinfo
   ]
 )
+
+tcp_echo_server = executable(
+  'tcp_echo_server',
+  'TCPEchoServer.c',
+  'TCPServerUtility.c',
+  common_src,
+  include_directories: [
+    common_include
+  ],
+  c_args: [
+    c_args,
+    '-D_POSIX_C_SOURCE=200112L' # For getaddrinfo
+  ]
+)