linux version yippee
This commit is contained in:
parent
37f4a98791
commit
71fff37a40
12
README.md
12
README.md
|
@ -2,11 +2,19 @@
|
||||||
an awesome web server that meows at you
|
an awesome web server that meows at you
|
||||||
|
|
||||||
## okay some more detail
|
## 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.
|
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
|
**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!!
|
a fun little foire into getting even more familiar with how web services work. how fun!!
|
||||||
|
|
||||||
### building
|
### 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 :]
|
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
|
||||||
|
```
|
||||||
|
|
119
src/main.c
119
src/main.c
|
@ -1,7 +1,12 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <winsock2.h>
|
#include <stdlib.h>
|
||||||
#include <ws2tcpip.h>
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <netinet/ip.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
|
||||||
#define BUFFER_SIZE (1024 * 1024)
|
#define BUFFER_SIZE (1024 * 1024)
|
||||||
|
|
||||||
|
@ -12,70 +17,41 @@ int main() {
|
||||||
printf("hello world!~\n");
|
printf("hello world!~\n");
|
||||||
|
|
||||||
int result = 0;
|
int result = 0;
|
||||||
WSADATA wsaData = {0};
|
|
||||||
struct sockaddr_in service;
|
|
||||||
|
|
||||||
const char* address = "127.0.0.1";
|
const char* address = "0.0.0.0";
|
||||||
int port = 8080;
|
int port = 8080;
|
||||||
|
|
||||||
result = WSAStartup(MAKEWORD(2, 2), &wsaData);
|
int sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
if (result != 0) {
|
if (sock == -1) {
|
||||||
printf("WSAStartup failed: %d\n", result);
|
fprintf(stderr, "failed to create socket: %s\n", strerror(errno));
|
||||||
return 1;
|
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");
|
printf("socket created successfully!\n");
|
||||||
|
|
||||||
service.sin_family = AF_INET;
|
struct in_addr in_address;
|
||||||
service.sin_addr.s_addr = inet_addr(address);
|
inet_aton(address, &in_address);
|
||||||
service.sin_port = htons(port);
|
struct sockaddr_in service = {AF_INET, htons(port), in_address};
|
||||||
|
if (bind(sock, (struct sockaddr*) &service, sizeof(struct sockaddr_in)) == -1) {
|
||||||
if (bind(sock, (SOCKADDR*) &service, sizeof(service)) == SOCKET_ERROR) {
|
close(sock);
|
||||||
closesocket(sock);
|
fprintf(stderr, "failed to bind to %s:%d: %s\n", address, port, strerror(errno));
|
||||||
printf("failed to bind to %s:%d: %ld\n", address, port, WSAGetLastError());
|
|
||||||
WSACleanup();
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
if (listen(sock, 1) == -1) {
|
||||||
result = connect(sock, (SOCKADDR*) &service, sizeof(client_service));
|
close(sock);
|
||||||
if (result == SOCKET_ERROR) {
|
fprintf(stderr, "failed to bind to %s:%d: %s\n", address, port, strerror(errno));
|
||||||
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;
|
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);
|
printf("now listening on %s:%d!\n", address, port);
|
||||||
|
|
||||||
char running = 1;
|
char running = 1;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
SOCKET accept_sock = accept(sock, NULL, NULL);
|
int accept_sock = accept(sock, NULL, NULL);
|
||||||
if (accept_sock == INVALID_SOCKET) {
|
if (accept_sock == -1) {
|
||||||
closesocket(sock);
|
close(sock);
|
||||||
printf("failed to accept socket connection: %ld\n", WSAGetLastError());
|
fprintf(stderr, "failed to accept socket connection: %s\n", strerror(errno));
|
||||||
WSACleanup();
|
|
||||||
return 1;
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
printf("client connected!\n");
|
printf("client connected!\n");
|
||||||
|
@ -86,7 +62,6 @@ int main() {
|
||||||
do {
|
do {
|
||||||
received = recv(accept_sock, recvbuf, 512, 0);
|
received = recv(accept_sock, recvbuf, 512, 0);
|
||||||
char end[] = "\r\n\r\n";
|
char end[] = "\r\n\r\n";
|
||||||
char lastfour[4];
|
|
||||||
|
|
||||||
if (received > 0) {
|
if (received > 0) {
|
||||||
printf("bytes received: %d\n", received);
|
printf("bytes received: %d\n", received);
|
||||||
|
@ -96,26 +71,22 @@ int main() {
|
||||||
if (recvbuf[i] == '\n') {
|
if (recvbuf[i] == '\n') {
|
||||||
printf("< ");
|
printf("< ");
|
||||||
}
|
}
|
||||||
for (int i = 0; i < 3; i++) {
|
|
||||||
lastfour[i] = lastfour[i + 1];
|
|
||||||
}
|
|
||||||
lastfour[3] = recvbuf[i];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char matches = 1;
|
if (received >= 4) {
|
||||||
|
char matches = 1;
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
if (lastfour[i] != end[i]) {
|
if (recvbuf[received - 4 + i] != end[i]) {
|
||||||
matches = 0;
|
matches = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (matches) break;
|
||||||
if (matches) break;
|
}
|
||||||
} else if (received == 0) {
|
} else if (received == 0) {
|
||||||
printf("connection closed.\n");
|
printf("connection closed.\n");
|
||||||
} else {
|
} else {
|
||||||
printf("recv failed: %d\n", WSAGetLastError());
|
printf("recv failed: %s\n", strerror(errno));
|
||||||
}
|
}
|
||||||
} while (received > 0);
|
} while (received > 0);
|
||||||
|
|
||||||
|
@ -127,20 +98,18 @@ int main() {
|
||||||
|
|
||||||
free(response);
|
free(response);
|
||||||
|
|
||||||
result = closesocket(accept_sock);
|
result = close(accept_sock);
|
||||||
if (result == SOCKET_ERROR) {
|
if (result == -1) {
|
||||||
printf("failed to close socket properly: %d\n", WSAGetLastError());
|
fprintf(stderr, "failed to close socket properly: %s\n", strerror(errno));
|
||||||
closesocket(sock);
|
close(sock);
|
||||||
WSACleanup();
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
} while (running);
|
} while (running);
|
||||||
|
|
||||||
// close responsibly! <3
|
// close responsibly! <3
|
||||||
result = closesocket(sock);
|
result = close(sock);
|
||||||
if (result == SOCKET_ERROR) {
|
if (result == -1) {
|
||||||
printf("failed to close socket properly: %d\n", WSAGetLastError());
|
fprintf(stderr, "failed to close socket properly: %s\n", strerror(errno));
|
||||||
WSACleanup();
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,9 +123,9 @@ void simple_http_ok(char *response, size_t *response_len) {
|
||||||
snprintf(header, BUFFER_SIZE,
|
snprintf(header, BUFFER_SIZE,
|
||||||
"HTTP/1.1 200 OK\r\n"
|
"HTTP/1.1 200 OK\r\n"
|
||||||
"Content-Type: text/plain; charset=utf-8\r\n"
|
"Content-Type: text/plain; charset=utf-8\r\n"
|
||||||
"Content-Length: 9\r\n"
|
"Content-Length: 10\r\n"
|
||||||
"\r\n"
|
"\r\n"
|
||||||
"meow 😺");
|
"meow 😺\n");
|
||||||
|
|
||||||
*response_len = 0;
|
*response_len = 0;
|
||||||
memcpy(response, header, strlen(header));
|
memcpy(response, header, strlen(header));
|
||||||
|
|
166
src/windows.c
Normal file
166
src/windows.c
Normal file
|
@ -0,0 +1,166 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <winsock2.h>
|
||||||
|
#include <ws2tcpip.h>
|
||||||
|
|
||||||
|
#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);
|
||||||
|
}
|
Loading…
Reference in a new issue