Skip to content

Instantly share code, notes, and snippets.

@AdriDevelopsThings
Created February 4, 2024 01:18
Show Gist options
  • Save AdriDevelopsThings/efbf890256f6e7f51f07c53bfd39ee29 to your computer and use it in GitHub Desktop.
Save AdriDevelopsThings/efbf890256f6e7f51f07c53bfd39ee29 to your computer and use it in GitHub Desktop.
A http server written in c that responds to any request with a infinitely large file
#include <asm-generic/errno-base.h>
#include <asm-generic/errno.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#define RANDOM_BYTE_CHUNK_SIZE 256
// get random bytes and return a pointer to the random bytes of the length RANDOM_BYTE_CHUNK_SIZE
char* get_random_bytes() {
// allocate space for random bytes
char* random_bytes = malloc(RANDOM_BYTE_CHUNK_SIZE * sizeof(char));
if (random_bytes == NULL) {
perror("error while allocating space");
return NULL;
}
// open /dev/urandom as a file
FILE *file = fopen("/dev/urandom", "r");
// read RANDOM_BYTE_CHUNK_SIZE bytes into random_bytes
fgets(random_bytes, RANDOM_BYTE_CHUNK_SIZE, file);
fclose(file);
return random_bytes;
}
int main(int argc, char *argv[]) {
if (argc == 2 && strcmp(argv[1], "--help") == 0) {
printf("Usage: unlimited-download [port] [listen address]");
return 0;
}
// parse port
char *s_port = "8000";
if (argc > 1) {
s_port = argv[1];
}
int port = atoi(s_port);
// parse server address
char* server_address = "127.0.0.1";
if (argc == 3) {
server_address = argv[2];
}
// create socket
int server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd < 0) {
perror("error while creating socket");
return -1;
}
// set reuseaddr as socket option
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int)) < 0) {
perror("error while setting socket option");
return -1;
}
// build socket address
struct sockaddr_in address;
address.sin_family = AF_INET;
address.sin_port = htons(port);
if (inet_aton(server_address, &address.sin_addr) == 0) {
fprintf(stderr, "The server address %s seems to be invalid.\n", server_address);
return -1;
}
// bind socket to socket address
if (bind(server_fd, (struct sockaddr*)&address, sizeof(address)) < 0) {
perror("error while binding socket");
return -1;
}
// listen socket
if (listen(server_fd, 3) < 0) {
perror("error while listening");
return -1;
}
printf("Server listening on %s port %d\n", server_address, port);
// accept clients
while (1) {
// accept client
struct sockaddr_in client_address;
socklen_t client_size = sizeof(client_address);
int client_fd = accept(server_fd, (struct sockaddr*)&client_address, &client_size);
if (client_fd < 0) {
perror("error while accepting client");
continue;
}
// receive request from client (without parsing)
char client_buf[256];
if (recv(client_fd, client_buf, sizeof(client_buf), 0) < 0) {
perror("error while receiving from client");
close(client_fd);
continue;
}
// respond with http header
char* header = "HTTP/1.1 200 OK\r\nContent-Type: application/octet-stream\r\nContent-Disposition: attachment\r\n\r\n";
if (send(client_fd, header, strlen(header), 0) < 0) {
perror("error while sending http header");
close(client_fd);
continue;
}
// start responding with random bytes
while (1) {
// receive from client to check if the client closed the socket
char buffer[16];
int r = recv(client_fd, buffer, 16, MSG_DONTWAIT); // no blocking
if (r == 0 || (r < 0 && errno != EAGAIN && errno != EWOULDBLOCK)) { // error while receiving or client closed socket
break;
}
// generate random bytes
char* random_bytes = get_random_bytes();
if (random_bytes == NULL) {
break;
}
// send random bytes to client
if (send(client_fd, random_bytes, RANDOM_BYTE_CHUNK_SIZE, 0) < 0) {
free(random_bytes);
break;
}
free(random_bytes);
}
close(client_fd);
}
close(server_fd); // this close statement is obsolete because the loop will never break
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment