|
@@ -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;
|
|
|
|
|
+}
|