Selaa lähdekoodia

ch4 udp client and server

Aaro Saila 6 tuntia sitten
vanhempi
sitoutus
1af320e19b
7 muutettua tiedostoa jossa 222 lisäystä ja 0 poistoa
  1. 96 0
      ch4/UDPEchoClient.c
  2. 80 0
      ch4/UDPEchoServer.c
  3. 3 0
      ch4/ch4_common.h
  4. 25 0
      ch4/meson.build
  5. 16 0
      common/Practical.c
  6. 1 0
      common/Practical.h
  7. 1 0
      meson.build

+ 96 - 0
ch4/UDPEchoClient.c

@@ -0,0 +1,96 @@
+#include <sys/socket.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include "Practical.h"
+#include "ch4_common.h"
+
+int main(int argc, char **argv) {
+    if (argc < 3 || argc > 4) {
+        DieWithUserMessage("Parameter(s)", "<Server Address/Name> <Echo Word> [<Server Port/Service>]");
+    }
+
+    char *server = argv[1];
+    char *echo_str = argv[2];
+
+    const size_t echo_str_len = sizeof(echo_str);
+    if (echo_str_len > MAXSTRINGLENGTH) {
+        DieWithUserMessage(echo_str, "string too long");
+    }
+
+    char *server_port = (argc == 4) ? argv[3] : "echo";
+
+    struct addrinfo addr_criteria = { 0 };
+    addr_criteria.ai_family = AF_UNSPEC;
+    addr_criteria.ai_socktype = SOCK_DGRAM;
+    addr_criteria.ai_protocol = proto_get_num("udp");
+
+    struct addrinfo *serv_addr = nullptr;
+    int ret = getaddrinfo(server, server_port, &addr_criteria, &serv_addr);
+    if (ret != 0) {
+        DieWithUserMessage("getaddrinfo() failed", gai_strerror(ret));
+    }
+
+    int sock = socket(
+        serv_addr->ai_family,
+        serv_addr->ai_socktype,
+        serv_addr->ai_protocol
+    );
+    if (sock < 0) {
+        DieWithSystemMessage("socket() failed");
+    }
+
+    fputs("Sending to ", stdout);
+    PrintSocketAddress(serv_addr->ai_addr, stdout);
+    fputc('\n', stdout);
+
+    ssize_t num_bytes = sendto(
+        sock,
+        echo_str,
+        echo_str_len,
+        0,
+        serv_addr->ai_addr,
+        serv_addr->ai_addrlen
+    );
+    if (num_bytes < 0) {
+        DieWithSystemMessage("sendto() failed");
+    } else if (num_bytes != echo_str_len) {
+        DieWithUserMessage("sendto() error", "sent unexpected amount of bytes");
+    }
+
+    struct sockaddr_storage from_addr;
+    socklen_t from_addr_len = sizeof(from_addr);
+    char buf[MAXSTRINGLENGTH + 1];
+    num_bytes = recvfrom(
+        sock,
+        buf,
+        MAXSTRINGLENGTH,
+        0,
+        (struct sockaddr *) &from_addr,
+        &from_addr_len
+    );
+    if (num_bytes < 0) {
+        DieWithSystemMessage("recvfrom() failed");
+    } else if (num_bytes != echo_str_len) {
+        DieWithUserMessage("recvfrom() error", "received unexpected amount of bytes");
+    }
+
+    if (!sock_addrs_equal(serv_addr->ai_addr, (struct sockaddr *) &from_addr)) {
+        fputs("serv_addr: ", stdout);
+        PrintSocketAddress(serv_addr->ai_addr, stdout);
+        fputs("\nfrom_addr: ", stdout);
+        PrintSocketAddress((struct sockaddr *) &from_addr, stdout);
+        fputc('\n', stdout);
+        DieWithUserMessage("recvfrom()", "received a packet from unkown source");
+    }
+
+    freeaddrinfo(serv_addr);
+
+    buf[echo_str_len] = '\0';
+    printf("Received: %s\n", buf);
+
+    close(sock);
+
+    return 0;
+}

+ 80 - 0
ch4/UDPEchoServer.c

@@ -0,0 +1,80 @@
+#include <sys/socket.h>
+#include <netdb.h>
+
+#include "Practical.h"
+#include "ch4_common.h"
+
+int main(int argc, char **argv) {
+    if (argc != 2) {
+        DieWithUserMessage("Parameter(s)", "<Server Port/Service");
+    }
+
+    char *service = argv[1];
+
+    struct addrinfo addr_criteria = { 0 };
+    addr_criteria.ai_family = AF_UNSPEC;
+    addr_criteria.ai_flags = AI_PASSIVE;
+    addr_criteria.ai_socktype = SOCK_DGRAM;
+    addr_criteria.ai_protocol = proto_get_num("udp");
+
+    struct addrinfo *serv_addr = nullptr;
+    int ret = getaddrinfo(nullptr, service, &addr_criteria, &serv_addr);
+    if (ret != 0) {
+        DieWithUserMessage("getaddrinfo() failed", gai_strerror(ret));
+    }
+
+    int sock = socket(
+        serv_addr->ai_family,
+        serv_addr->ai_socktype,
+        serv_addr->ai_protocol
+    );
+    if (sock < 0) {
+        DieWithSystemMessage("socket() failed");
+    }
+
+    if (bind(sock, serv_addr->ai_addr, serv_addr->ai_addrlen) < 0) {
+        DieWithSystemMessage("bind() failed");
+    }
+
+    fputs("Listening on ", stdout);
+    PrintSocketAddress(serv_addr->ai_addr, stdout);
+    fputc('\n', stdout);
+
+    freeaddrinfo(serv_addr);
+
+    while (true) {
+        struct sockaddr_storage client_addr;
+        socklen_t client_addr_len = sizeof(client_addr);
+
+        char buf[MAXSTRINGLENGTH];
+        const ssize_t num_bytes_recvd = recvfrom(
+            sock,
+            buf,
+            MAXSTRINGLENGTH,
+            0,
+            (struct sockaddr *) &client_addr,
+            &client_addr_len
+        );
+        if (num_bytes_recvd < 0) {
+            DieWithSystemMessage("recvfrom() failed");
+        }
+
+        fputs("Handling client ", stdout);
+        PrintSocketAddress((struct sockaddr *) &client_addr, stdout);
+        fputc('\n', stdout);
+
+        const ssize_t num_bytes_sent = sendto(
+            sock,
+            buf,
+            num_bytes_recvd,
+            0,
+            (struct sockaddr *) &client_addr,
+            client_addr_len
+        );
+        if (num_bytes_sent < 0) {
+            DieWithSystemMessage("sendto() failed");
+        } else if (num_bytes_sent != num_bytes_recvd) {
+            DieWithUserMessage("sendto()", "sent unexpected number of bytes");
+        }
+    }
+}

+ 3 - 0
ch4/ch4_common.h

@@ -0,0 +1,3 @@
+#pragma once
+
+#define MAXSTRINGLENGTH 255

+ 25 - 0
ch4/meson.build

@@ -0,0 +1,25 @@
+udp_echo_client = executable(
+  'udp_echo_client',
+  'UDPEchoClient.c',
+  common_src,
+  include_directories: [
+    common_include
+  ],
+  c_args: [
+    c_args,
+    '-D_POSIX_C_SOURCE=200112L' # For getaddrinfo
+  ]
+)
+
+udp_echo_server = executable(
+  'udp_echo_server',
+  'UDPEchoServer.c',
+  common_src,
+  include_directories: [
+    common_include
+  ],
+  c_args: [
+    c_args,
+    '-D_POSIX_C_SOURCE=200112L' # For getaddrinfo
+  ]
+)

+ 16 - 0
common/Practical.c

@@ -3,6 +3,7 @@
 #include <netinet/in.h>
 #include <stddef.h>
 #include <arpa/inet.h>
+#include <string.h>
 
 #include "Practical.h"
 
@@ -168,3 +169,18 @@ int AF_to_PF(const int af) {
     DieWithUserMessage("AF_to_PF", "Unkown AF_ value");
     return -1; // Unreachable, makes LSP shut up about not returning a value.
 }
+
+bool sock_addrs_equal(const struct sockaddr *const a1, const struct sockaddr *const a2) {
+    if (a1->sa_family != a2->sa_family) {
+        return false;
+    }
+    if (a1->sa_family != AF_INET && a1->sa_family != AF_INET6) {
+        DieWithUserMessage("Unsupported value for", "a1->sa_family");
+    }
+
+    const size_t addr_size = a1->sa_family == AF_INET
+        ? sizeof(struct in_addr)
+        : sizeof(struct in6_addr);
+
+    return memcmp(a1->sa_data, a2->sa_data, addr_size) == 0;
+}

+ 1 - 0
common/Practical.h

@@ -10,3 +10,4 @@ void DieWithSystemMessage(const char *msg);
 int proto_get_num(const char *name);
 void PrintSocketAddress(const struct sockaddr *address, FILE *stream);
 int AF_to_PF(const int af);
+bool sock_addrs_equal(const struct sockaddr *const a1, const struct sockaddr *const a2);

+ 1 - 0
meson.build

@@ -24,3 +24,4 @@ common_include = [
 
 subdir('ch2')
 subdir('ch3')
+subdir('ch4')