diff --git a/.gitignore b/.gitignore index b883f1f..1feae78 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -*.exe +*.exe diff --git a/README.md b/README.md index 2fe4233..b42c245 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,20 @@ -# meownet 😺 -an awesome web server that meows at you - -## okay some more detail -i built this in c using `winsock2`. why? because i wanted to learn sockets! and my windows machine was the closest subject at the time. - -**Q:** is it very good? **A:** no! but i had fun making it, so idrc - -a fun little foire into getting even more familiar with how web services work. how fun!! - -### building -oh yeah you can compile this with `gcc` and a little `gcc -o ./meow.exe ./src/main.c -lws2_32`. i might make this work for mac/linux at some point if i somehow get even more bored :] +# meownet 😺 +an awesome web server that meows at you + +## okay some more detail +i originally built this in c using `winsock2`. why? because i wanted to learn sockets! and my windows machine was the closest subject at the time. now this runs the regular linux socket API by default (i left the old windows-specific code in `src/windows.c` if you want to use that!) + +**Q:** is it very good? **A:** no! but i had fun making it, so idrc + +a fun little foire into getting even more familiar with how web services work. how fun!! + +### building +oh yeah you can compile this with `gcc` and a little +```sh +# linux/macos (untested on macos) +gcc -o ./meow ./src/main.c +``` +```powershell +# windows +gcc -o ./meow.exe ./src/windows.c -lws2_32 +``` diff --git a/src/main.c b/src/main.c index dcc5437..2e1d4d8 100644 --- a/src/main.c +++ b/src/main.c @@ -1,166 +1,135 @@ -#include -#include -#include -#include - -#define BUFFER_SIZE (1024 * 1024) - -void simple_http_ok(char *response, size_t *response_len); - -int main() { - - printf("hello world!~\n"); - - int result = 0; - WSADATA wsaData = {0}; - struct sockaddr_in service; - - const char* address = "127.0.0.1"; - int port = 8080; - - result = WSAStartup(MAKEWORD(2, 2), &wsaData); - if (result != 0) { - printf("WSAStartup failed: %d\n", result); - return 1; - } - - SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (sock == INVALID_SOCKET) { - printf("failed to create socket! (%d)\n", WSAGetLastError()); - WSACleanup(); - return 1; - } - - printf("socket created successfully!\n"); - - service.sin_family = AF_INET; - service.sin_addr.s_addr = inet_addr(address); - service.sin_port = htons(port); - - if (bind(sock, (SOCKADDR*) &service, sizeof(service)) == SOCKET_ERROR) { - closesocket(sock); - printf("failed to bind to %s:%d: %ld\n", address, port, WSAGetLastError()); - WSACleanup(); - return 1; - } - - /* - result = connect(sock, (SOCKADDR*) &service, sizeof(client_service)); - if (result == SOCKET_ERROR) { - closesocket(sock); - printf("unable to connect to the server: %ld\n", WSAGetLastError()); - WSACleanup(); - return 1; - } - */ - - if (listen(sock, 1) == SOCKET_ERROR) { - closesocket(sock); - printf("failed to bind to %s:%d: %ld\n", address, port, WSAGetLastError()); - WSACleanup(); - return 1; - } - - /* - char address[INET_ADDRSTRLEN]; - InetNtop(AF_INET, &(service.sin_addr.s_addr), address, INET_ADDRSTRLEN); - ntohs(service.sin_port) - */ - printf("now listening on %s:%d!\n", address, port); - - char running = 1; - - do { - SOCKET accept_sock = accept(sock, NULL, NULL); - if (accept_sock == INVALID_SOCKET) { - closesocket(sock); - printf("failed to accept socket connection: %ld\n", WSAGetLastError()); - WSACleanup(); - return 1; - } else { - printf("client connected!\n"); - } - - char recvbuf[512]; - int received = 0; - do { - received = recv(accept_sock, recvbuf, 512, 0); - char end[] = "\r\n\r\n"; - char lastfour[4]; - - if (received > 0) { - printf("bytes received: %d\n", received); - printf("< "); - for (int i = 0; i < received; i++) { - printf("%c", recvbuf[i]); - if (recvbuf[i] == '\n') { - printf("< "); - } - for (int i = 0; i < 3; i++) { - lastfour[i] = lastfour[i + 1]; - } - lastfour[3] = recvbuf[i]; - } - - char matches = 1; - - for (int i = 0; i < 4; i++) { - if (lastfour[i] != end[i]) { - matches = 0; - break; - } - } - - if (matches) break; - } else if (received == 0) { - printf("connection closed.\n"); - } else { - printf("recv failed: %d\n", WSAGetLastError()); - } - } while (received > 0); - - char *response = (char *)malloc(BUFFER_SIZE * 2 * sizeof(char)); - size_t response_len; - simple_http_ok(response, &response_len); - - send(accept_sock, response, response_len, 0); - - free(response); - - result = closesocket(accept_sock); - if (result == SOCKET_ERROR) { - printf("failed to close socket properly: %d\n", WSAGetLastError()); - closesocket(sock); - WSACleanup(); - return 1; - } - } while (running); - - // close responsibly! <3 - result = closesocket(sock); - if (result == SOCKET_ERROR) { - printf("failed to close socket properly: %d\n", WSAGetLastError()); - WSACleanup(); - return 1; - } - - return 0; - -} - -void simple_http_ok(char *response, size_t *response_len) { - // build header - char *header = (char *)malloc(BUFFER_SIZE * sizeof(char)); - snprintf(header, BUFFER_SIZE, - "HTTP/1.1 200 OK\r\n" - "Content-Type: text/plain; charset=utf-8\r\n" - "Content-Length: 9\r\n" - "\r\n" - "meow 😺"); - - *response_len = 0; - memcpy(response, header, strlen(header)); - *response_len += strlen(header); - - free(header); -} +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BUFFER_SIZE (1024 * 1024) + +void simple_http_ok(char *response, size_t *response_len); + +int main() { + + printf("hello world!~\n"); + + int result = 0; + + const char* address = "0.0.0.0"; + int port = 8080; + + int sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock == -1) { + fprintf(stderr, "failed to create socket: %s\n", strerror(errno)); + return 1; + } + printf("socket created successfully!\n"); + + struct in_addr in_address; + inet_aton(address, &in_address); + struct sockaddr_in service = {AF_INET, htons(port), in_address}; + if (bind(sock, (struct sockaddr*) &service, sizeof(struct sockaddr_in)) == -1) { + close(sock); + fprintf(stderr, "failed to bind to %s:%d: %s\n", address, port, strerror(errno)); + return 1; + } + + if (listen(sock, 1) == -1) { + close(sock); + fprintf(stderr, "failed to bind to %s:%d: %s\n", address, port, strerror(errno)); + return 1; + } + + printf("now listening on %s:%d!\n", address, port); + + char running = 1; + + do { + int accept_sock = accept(sock, NULL, NULL); + if (accept_sock == -1) { + close(sock); + fprintf(stderr, "failed to accept socket connection: %s\n", strerror(errno)); + return 1; + } else { + printf("client connected!\n"); + } + + char recvbuf[512]; + int received = 0; + do { + received = recv(accept_sock, recvbuf, 512, 0); + char end[] = "\r\n\r\n"; + + if (received > 0) { + printf("bytes received: %d\n", received); + printf("< "); + for (int i = 0; i < received; i++) { + printf("%c", recvbuf[i]); + if (recvbuf[i] == '\n') { + printf("< "); + } + } + + if (received >= 4) { + char matches = 1; + for (int i = 0; i < 4; i++) { + if (recvbuf[received - 4 + i] != end[i]) { + matches = 0; + break; + } + } + if (matches) break; + } + } else if (received == 0) { + printf("connection closed.\n"); + } else { + printf("recv failed: %s\n", strerror(errno)); + } + } while (received > 0); + + char *response = (char *)malloc(BUFFER_SIZE * 2 * sizeof(char)); + size_t response_len; + simple_http_ok(response, &response_len); + + send(accept_sock, response, response_len, 0); + + free(response); + + result = close(accept_sock); + if (result == -1) { + fprintf(stderr, "failed to close socket properly: %s\n", strerror(errno)); + close(sock); + return 1; + } + } while (running); + + // close responsibly! <3 + result = close(sock); + if (result == -1) { + fprintf(stderr, "failed to close socket properly: %s\n", strerror(errno)); + return 1; + } + + return 0; + +} + +void simple_http_ok(char *response, size_t *response_len) { + // build header + char *header = (char *)malloc(BUFFER_SIZE * sizeof(char)); + snprintf(header, BUFFER_SIZE, + "HTTP/1.1 200 OK\r\n" + "Content-Type: text/plain; charset=utf-8\r\n" + "Content-Length: 10\r\n" + "\r\n" + "meow 😺\n"); + + *response_len = 0; + memcpy(response, header, strlen(header)); + *response_len += strlen(header); + + free(header); +} diff --git a/src/windows.c b/src/windows.c new file mode 100644 index 0000000..1dbcde4 --- /dev/null +++ b/src/windows.c @@ -0,0 +1,166 @@ +#include +#include +#include +#include + +#define BUFFER_SIZE (1024 * 1024) + +void simple_http_ok(char *response, size_t *response_len); + +int main() { + + printf("hello world!~\n"); + + int result = 0; + WSADATA wsaData = {0}; + struct sockaddr_in service; + + const char* address = "127.0.0.1"; + int port = 8080; + + result = WSAStartup(MAKEWORD(2, 2), &wsaData); + if (result != 0) { + printf("WSAStartup failed: %d\n", result); + return 1; + } + + SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (sock == INVALID_SOCKET) { + printf("failed to create socket! (%d)\n", WSAGetLastError()); + WSACleanup(); + return 1; + } + + printf("socket created successfully!\n"); + + service.sin_family = AF_INET; + service.sin_addr.s_addr = inet_addr(address); + service.sin_port = htons(port); + + if (bind(sock, (SOCKADDR*) &service, sizeof(service)) == SOCKET_ERROR) { + closesocket(sock); + printf("failed to bind to %s:%d: %ld\n", address, port, WSAGetLastError()); + WSACleanup(); + return 1; + } + + /* + result = connect(sock, (SOCKADDR*) &service, sizeof(client_service)); + if (result == SOCKET_ERROR) { + closesocket(sock); + printf("unable to connect to the server: %ld\n", WSAGetLastError()); + WSACleanup(); + return 1; + } + */ + + if (listen(sock, 1) == SOCKET_ERROR) { + closesocket(sock); + printf("failed to bind to %s:%d: %ld\n", address, port, WSAGetLastError()); + WSACleanup(); + return 1; + } + + /* + char address[INET_ADDRSTRLEN]; + InetNtop(AF_INET, &(service.sin_addr.s_addr), address, INET_ADDRSTRLEN); + ntohs(service.sin_port) + */ + printf("now listening on %s:%d!\n", address, port); + + char running = 1; + + do { + SOCKET accept_sock = accept(sock, NULL, NULL); + if (accept_sock == INVALID_SOCKET) { + closesocket(sock); + printf("failed to accept socket connection: %ld\n", WSAGetLastError()); + WSACleanup(); + return 1; + } else { + printf("client connected!\n"); + } + + char recvbuf[512]; + int received = 0; + do { + received = recv(accept_sock, recvbuf, 512, 0); + char end[] = "\r\n\r\n"; + char lastfour[4]; + + if (received > 0) { + printf("bytes received: %d\n", received); + printf("< "); + for (int i = 0; i < received; i++) { + printf("%c", recvbuf[i]); + if (recvbuf[i] == '\n') { + printf("< "); + } + for (int i = 0; i < 3; i++) { + lastfour[i] = lastfour[i + 1]; + } + lastfour[3] = recvbuf[i]; + } + + char matches = 1; + + for (int i = 0; i < 4; i++) { + if (lastfour[i] != end[i]) { + matches = 0; + break; + } + } + + if (matches) break; + } else if (received == 0) { + printf("connection closed.\n"); + } else { + printf("recv failed: %d\n", WSAGetLastError()); + } + } while (received > 0); + + char *response = (char *)malloc(BUFFER_SIZE * 2 * sizeof(char)); + size_t response_len; + simple_http_ok(response, &response_len); + + send(accept_sock, response, response_len, 0); + + free(response); + + result = closesocket(accept_sock); + if (result == SOCKET_ERROR) { + printf("failed to close socket properly: %d\n", WSAGetLastError()); + closesocket(sock); + WSACleanup(); + return 1; + } + } while (running); + + // close responsibly! <3 + result = closesocket(sock); + if (result == SOCKET_ERROR) { + printf("failed to close socket properly: %d\n", WSAGetLastError()); + WSACleanup(); + return 1; + } + + return 0; + +} + +void simple_http_ok(char *response, size_t *response_len) { + // build header + char *header = (char *)malloc(BUFFER_SIZE * sizeof(char)); + snprintf(header, BUFFER_SIZE, + "HTTP/1.1 200 OK\r\n" + "Content-Type: text/plain; charset=utf-8\r\n" + "Content-Length: 9\r\n" + "\r\n" + "meow 😺"); + + *response_len = 0; + memcpy(response, header, strlen(header)); + *response_len += strlen(header); + + free(header); +}