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