diff --git a/CMakeLists.txt b/CMakeLists.txt index c855f88..5bb56d9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,5 +3,4 @@ project(qotd C) set(CMAKE_C_STANDARD 99) -add_executable(server server/main.c server/quote.c server/quote.h server/server.c server/server.h) -add_executable(client client/main.c client/client.c client/client.h) \ No newline at end of file +add_executable(qotd main.c quote.c quote.h server.c server.h config.h) \ No newline at end of file diff --git a/README.md b/README.md index 8be92bc..a59a300 100644 --- a/README.md +++ b/README.md @@ -7,14 +7,14 @@ A [RFC 865](https://datatracker.ietf.org/doc/html/rfc865) compliant Quote of the * tcp client * udp server * udp client +* IPv6 compat ## Todo -* IPv6 -* t h r e a d s to accept several clients and/or run both udp and tcp servers from same executable +* t h r e a d s to accept several clients and/or run both udp and tcp servers from same executable and instance * macros (#define XXX yyy) for currently hard-coded values +* switches (-x) and options (--xxxx) ? * logging ? * conf files ? -* switches (-x) and options (--xxxx) ? ## Installation @@ -27,7 +27,7 @@ make ``` ## Use -A "quotes.txt" file in the same folder as the server containing one quote per line. Quotes are separated by the line feed ('\n') caracter. +A "quotes.txt" file in the same folder as the server containing one quote per line. Quotes are separated by the line feed `\n` character. Server as root (because port 17) ```sh diff --git a/client/client.c b/client/client.c deleted file mode 100644 index 0eabfe6..0000000 --- a/client/client.c +++ /dev/null @@ -1,90 +0,0 @@ -// -// Created by k0rb4k on 11/10/2021. -// - -#include "client.h" - -extern int errno; - -int tcp() { - struct sockaddr_in server; - int sock; - - int proto = IPPROTO_IP; - enum __socket_type socketType = SOCK_STREAM; - - server.sin_family = AF_INET; - server.sin_addr.s_addr = inet_addr("127.0.0.1"); - server.sin_port = htons(17); - - sock = socket(server.sin_family, socketType, proto); - if (sock == -1) { - puts("socket not created"); - return 1; - } - puts("socket created"); - - if (connect(sock, (const struct sockaddr *) &server, sizeof(server)) < 0) { - puts("connection failed"); - return 2; - } - puts("connected to server"); - - char *payload = "I dream of sushi"; - if (send(sock, payload, strlen(payload), 0) < 0) { - puts("error while sending payload"); - return 3; - } - puts("payload sent"); - - char response[2048]; - if (recv(sock, response, 2048, 0) < 0) { - puts("receive failed"); - return 4; - } - printf("server response : %s\n", response); - - close(sock); - - return 0; -} - -int udp() { - struct sockaddr_in server; - int sock; - unsigned long addressLength = sizeof server; - - int proto = IPPROTO_UDP; - enum __socket_type socketType = SOCK_DGRAM; - - server.sin_family = AF_INET; - server.sin_addr.s_addr = inet_addr("127.0.0.1"); - server.sin_port = htons(17); - - sock = socket(server.sin_family, socketType, proto); - if (sock == -1) { - puts("socket not created"); - return 1; - } - puts("socket created"); - - char *payload = "I dream of sushi"; - if (sendto(sock, payload, strlen(payload), 0, (const struct sockaddr *) &server, addressLength) < 0) { - puts("error while sending payload"); - perror("sendto"); - return 3; - } - puts("payload sent"); - - char response[2048]; - if (recvfrom(sock, response, 2048, 0, (struct sockaddr *) &server, (socklen_t *) &addressLength) < 0) { - puts("receive failed"); - perror("recvfrom"); - return 4; - } - printf("server response : %s\n", response); - - close(sock); - - return 0; -} \ No newline at end of file diff --git a/client/client.h b/client/client.h deleted file mode 100644 index 17bb0cd..0000000 --- a/client/client.h +++ /dev/null @@ -1,20 +0,0 @@ -// -// Created by k0rb4k on 11/10/2021. -// - -#ifndef QOTD_CLIENT_H -#define QOTD_CLIENT_H - -#include -#include -#include -#include -#include -#include -#include - -int tcp(); - -int udp(); - -#endif //QOTD_CLIENT_H diff --git a/client/main.c b/client/main.c deleted file mode 100644 index 0b9604f..0000000 --- a/client/main.c +++ /dev/null @@ -1,12 +0,0 @@ -// -// Created by k0rb4k on 22/04/2021. -// - -#include "client.h" - -int main(int argc, char *argv[]) { - // TODO: arg options for tcp or udp - tcp(); - - return 0; -} \ No newline at end of file diff --git a/config.h b/config.h new file mode 100644 index 0000000..9083199 --- /dev/null +++ b/config.h @@ -0,0 +1,12 @@ +// +// Created by k0rb4k on 26/11/2021. +// + +#ifndef QOTD_CONFIG_H +#define QOTD_CONFIG_H + +#define QUOTES_FILE "./quotes.txt" +#define MESSAGE_STRING_LENGTH 2048 +#define DEFAULT_LISTEN_PORT 17 // should be 17 to be RFC compliant + +#endif //QOTD_CONFIG_H diff --git a/main.c b/main.c new file mode 100644 index 0000000..4fcf290 --- /dev/null +++ b/main.c @@ -0,0 +1,8 @@ +#include "server.h" + +int main(int argc, char *argv[]) { + // TODO: shell args + server(1, 1); + + return 0; +} diff --git a/server/quote.c b/quote.c similarity index 98% rename from server/quote.c rename to quote.c index 5c746b4..9645269 100644 --- a/server/quote.c +++ b/quote.c @@ -3,6 +3,7 @@ // #include "quote.h" +#include "config.h" void getRandomQuote(char quote[2048]) { int lineCount; diff --git a/server/quote.h b/quote.h similarity index 90% rename from server/quote.h rename to quote.h index fba8603..b7deeda 100644 --- a/server/quote.h +++ b/quote.h @@ -11,8 +11,6 @@ #include #include -#define QUOTES_FILE "./quotes.txt" - void getRandomQuote(char quote[2048]); void getQuote(long line, char quote[2048]); diff --git a/server.c b/server.c new file mode 100644 index 0000000..9b54806 --- /dev/null +++ b/server.c @@ -0,0 +1,127 @@ +// +// Created by k0rb4k on 30/03/2021. +// + +#include "server.h" +#include "config.h" + +//TODO: object-like C + +extern int errno; + +_Noreturn void udpListen(int serverSocket, struct sockaddr * clientAddress, unsigned long addressLength) { + char clientMessage[MESSAGE_STRING_LENGTH], quote[MESSAGE_STRING_LENGTH]; + + for (;;) { + // receive data + + if (recvfrom(serverSocket, clientMessage, MESSAGE_STRING_LENGTH, 0, clientAddress, (socklen_t *) &addressLength) >= 0) { + printf("received: %s\n", clientMessage); + + // send data + getRandomQuote(quote); + printf("sending: %s\n", quote); + if (sendto(serverSocket, quote, strlen(quote), 0, clientAddress, addressLength) == -1) { + perror("udp: sendto"); + } + } else { + perror("udp: recvfrom"); + } + } +} + +void tcpListen(int serverSocket, struct sockaddr * clientAddress, unsigned long addressLength) { + int clientSocket; + char quote[MESSAGE_STRING_LENGTH] = "", clientMessage[MESSAGE_STRING_LENGTH] = ""; + + listen(serverSocket, 5); + puts("server listening"); + + // accept connections + //TODO: t h r e a d s + while ((clientSocket = accept(serverSocket, clientAddress, (socklen_t *) &addressLength)) >= 0) { + puts("client connected"); + + // receive data + if (recv(clientSocket, clientMessage, MESSAGE_STRING_LENGTH, 0) >= 0) { + printf("client says: %s\n", clientMessage); + + // send data + getRandomQuote(quote); + printf("responding: \"%s\"\n", quote); + if (send(clientSocket, quote, strlen(quote), 0) == -1) { + perror("tcp: send"); + } + } else { + perror("tcp: recv"); + } + + close(clientSocket); + + puts("closed connection"); + } + + if (clientSocket < 0) { + puts("client connection failed"); + exit(3); + } +} + +void server(int tcp, int ipv6) { + int serverSocket, socketType, socketProtocol; + unsigned long serverAddressLength, clientAddressLength; + struct sockaddr *serverAddress, *clientAddress; + struct sockaddr_in serverAddress4, clientAddress4; + struct sockaddr_in6 serverAddress6, clientAddress6; + + if (ipv6) { + serverAddress6.sin6_family = AF_INET6; + serverAddress6.sin6_addr = in6addr_any; + serverAddress6.sin6_port = htons(DEFAULT_LISTEN_PORT); + serverAddress = (struct sockaddr *) &serverAddress6; + serverAddressLength = sizeof serverAddress6; + + clientAddress6.sin6_family = AF_INET6; + clientAddress = (struct sockaddr *) &clientAddress6; + clientAddressLength = sizeof clientAddress6; + } else { + serverAddress4.sin_family = AF_INET; + serverAddress4.sin_addr.s_addr = INADDR_ANY; + serverAddress4.sin_port = htons(DEFAULT_LISTEN_PORT); + serverAddress = (struct sockaddr *) &serverAddress4; + serverAddressLength = sizeof serverAddress4; + + clientAddress4.sin_family = AF_INET; + clientAddress = (struct sockaddr *) &clientAddress4; + clientAddressLength = sizeof clientAddress4; + } + + if (tcp) { + socketType = SOCK_STREAM; + socketProtocol = IPPROTO_TCP; + } else { + socketType = SOCK_DGRAM; + socketProtocol = IPPROTO_UDP; + } + + // create sock + serverSocket = socket(serverAddress->sa_family, socketType, socketProtocol); + if (serverSocket == -1) { + puts("socket not created"); + exit(1); + } + puts("socket created"); + + // bind sock + if (bind(serverSocket, serverAddress, serverAddressLength) < 0) { + puts("bind failed"); + exit(2); + } + + // TODO: threads to run both at the same time + if (tcp) { + tcpListen(serverSocket, clientAddress, clientAddressLength); + } else { + udpListen(serverSocket, clientAddress, clientAddressLength); + } +} diff --git a/server/server.h b/server.h similarity index 54% rename from server/server.h rename to server.h index d42e0c6..5f4a381 100644 --- a/server/server.h +++ b/server.h @@ -6,7 +6,7 @@ #define QOTD_SERVER_H #include -//#include +#include #include #include #include @@ -17,10 +17,10 @@ #include "quote.h" -#define MESSAGE_STRING_LENGTH 2048 +void server(int tcp, int ipv6); -void tcpServer(); +void tcpListen(int serverSocket, struct sockaddr *clientAddress, unsigned long addressLength); -_Noreturn void udpServer(); +_Noreturn void udpListen(int serverSocket, struct sockaddr *clientAddress, unsigned long addressLength); #endif //QOTD_SERVER_H diff --git a/server/main.c b/server/main.c deleted file mode 100644 index 846bbf1..0000000 --- a/server/main.c +++ /dev/null @@ -1,10 +0,0 @@ -#include "server.h" - -int main(int argc, char *argv[]) { -// char quote[1024]; -// getRandomQuote(quote); -// printf("%s\n", quote); - tcpServer(); - - return 0; -} diff --git a/server/server.c b/server/server.c deleted file mode 100644 index b08e979..0000000 --- a/server/server.c +++ /dev/null @@ -1,129 +0,0 @@ -// -// Created by k0rb4k on 30/03/2021. -// - -#include "server.h" - -//TODO: refactor -//TODO: object-like C - -extern int errno; - -unsigned long addressLength = sizeof(struct sockaddr_in); - - -void tcpServer() { - int serverSocket, clientSocket; - long recvLen; -// unsigned long addressLength = sizeof(struct sockaddr_in); - struct sockaddr_in serverAddress, clientAddress; - char quote[MESSAGE_STRING_LENGTH] = ""; - char clientMessage[MESSAGE_STRING_LENGTH] = ""; - - /*initialize socket info*/ - serverAddress.sin_family = AF_INET; - serverAddress.sin_addr.s_addr = INADDR_ANY; - serverAddress.sin_port = htons(17); - - /*create socket*/ - serverSocket = socket(serverAddress.sin_family, SOCK_STREAM, IPPROTO_IP); - if (serverSocket == -1) { - puts("socket not created"); - exit(1); - } - puts("socket created"); - - /*bind socket to address:port*/ - if (bind(serverSocket, (const struct sockaddr *) &serverAddress, addressLength) < 0) { - puts("bind failed"); - exit(2); - } - puts("address bound"); - - /*start listening*/ - listen(serverSocket, 5); - puts("server listening"); - - /*accept connections*/ - //TODO: t h r e a d s - while ((clientSocket = accept(serverSocket, (struct sockaddr *) &clientAddress, (socklen_t *) &addressLength)) >= - 0) { - puts("client connected"); - - /*receive data*/ - while ((recvLen = recv(clientSocket, clientMessage, MESSAGE_STRING_LENGTH, 0))) { - if (recvLen < 0) { - puts("receive failed"); - } else { - printf("client says: %s\n", clientMessage); - - /*send data*/ - getRandomQuote(quote); - printf("responding: \"%s\"\n", quote); - send(clientSocket, quote, strlen(quote), 0); - } - } - - puts("client disconnected"); - } - - if (clientSocket < 0) { - puts("client connection failed"); - exit(3); - } -} - -_Noreturn void udpServer() { - int sock; -// unsigned long addressLength = sizeof(struct sockaddr_in); - struct sockaddr_in serverAddress, clientAddress; - char quote[MESSAGE_STRING_LENGTH] = ""; - char clientMessage[MESSAGE_STRING_LENGTH] = ""; - - /*initialize sock info*/ - memset(&serverAddress, 0, addressLength); - memset(&clientAddress, 0, addressLength); - - serverAddress.sin_family = AF_INET; - serverAddress.sin_addr.s_addr = INADDR_ANY; - serverAddress.sin_port = htons(17); - - /*create sock*/ - sock = socket(serverAddress.sin_family, SOCK_DGRAM, IPPROTO_UDP); - if (sock == -1) { - puts("sock not created"); - exit(1); - } - puts("sock created"); - - /*bind sock to address:port*/ - if (bind(sock, (const struct sockaddr *) &serverAddress, sizeof serverAddress) < 0) { - puts("bind failed"); - exit(2); - } - puts("address bound"); - - /*accept connections*/ - //TODO: t h r e a d s ? - while (1) { - /*receive data*/ - int recvLen = recvfrom(sock, clientMessage, MESSAGE_STRING_LENGTH, 0, - (struct sockaddr *) &clientAddress, (socklen_t *) &addressLength); - - uint16_t port = ntohs(clientAddress.sin_port); - char *ipv4 = inet_ntoa(clientAddress.sin_addr); - - printf("recvLen = %d from = %s:%d\nmsg = `%s`\n", recvLen, ipv4, port, clientMessage); - - perror("recvfrom"); - if (recvLen >= 0) { - printf("client says: %s\n", clientMessage); - - /*send data*/ - getRandomQuote(quote); - printf("responding: `%s`\n", quote); - sendto(sock, strcat(quote, "\n"), sizeof quote, 0, (struct sockaddr *) &clientAddress, addressLength); - perror("sendto"); - } - } -}