-
-
Save sehe/3173822 to your computer and use it in GitHub Desktop.
My prototype webserver-thing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "xeric-utils.h" | |
/* The main method. */ | |
int main(int argc, char * argv[]) { | |
int i; | |
int port = 80; | |
struct in_addr address = {0}; | |
/* Parse the arguments: */ | |
for(i = 1; i < argc; i++) { | |
if(strcmp(argv[i], "--port") == 0) { | |
i++; | |
if(i == argc) { | |
warn("Expected port number after --port option. Continuing with port 80."); | |
break; | |
} | |
port = strtoport(argv[i]); | |
if(!port) { | |
warn("Invalid port number specified. Continuing with port 80."); | |
port = 80; | |
} | |
} else if(strcmp(argv[i], "--address") == 0) { | |
i++; | |
if(i == argc) { | |
warn("Expected address after --address option. Continuing with address 0.0.0.0."); | |
break; | |
} | |
if(inet_pton(AF_INET, argv[i], &address) != 1) { | |
warn("Invalid address specified. Continuing with address 0.0.0.0."); | |
} | |
} else { | |
printf("Unrecognized option %s.\n", argv[i]); | |
} | |
} | |
int client; | |
socklen_t clilen = sizeof(struct sockaddr_in); | |
char buffer[1024]; | |
char str_address[16]; | |
struct sockaddr_in serv_addr, cli_addr; | |
int n; | |
/* Create the socket: */ | |
s = socket(AF_INET, SOCK_STREAM, 0); | |
if(s < 0) { | |
warn("Error opening socket."); | |
return 1; | |
} | |
/* Listen on the socket: */ | |
serv_addr.sin_family = AF_INET; | |
serv_addr.sin_port = htons(port); | |
serv_addr.sin_addr = address; | |
errno = 0; | |
if(bind(s, (struct sockaddr *) &serv_addr, sizeof serv_addr) < 0) { | |
if(errno == EADDRINUSE) | |
warn("Could not bind to port; already in use."); | |
else | |
warn("Could not bind to port due to an unknown error."); | |
return 1; | |
} | |
listen(s, 5); | |
success("Xeric 0.1.0 has started!"); | |
inet_ntop(AF_INET, &serv_addr.sin_addr, str_address, 15); | |
printf("Listening at %s:%d.\n", str_address, port); | |
/* Enable the Ctrl+C SIGINT handler so that the socket can be closed */ | |
signal(SIGINT, interrupted); | |
while(keepRunning) { | |
/* Accept a client: */ | |
client = accept(s, (struct sockaddr *)&cli_addr, &clilen); | |
if(client < 0) { | |
warn("Error on accept."); | |
return 1; | |
} | |
ip4_t r_addr = {cli_addr.sin_addr.s_addr}; | |
printf("Got client from %d.%d.%d.%d.\n", r_addr.components.p1, r_addr.components.p2, r_addr.components.p3, r_addr.components.p4); | |
/* Read data from the client: */ | |
bzero(buffer, 1024); | |
n = read(client, buffer, 1023); | |
if(n < 0) { | |
warn("Error reading from socket; breaking connection."); | |
goto close; | |
} | |
puts(buffer); | |
/* Write data to the client: */ | |
const char * output = "HTTP/1.1 200 OK\nContent-Type: text/html\n\n<h1>It works!</h1> <p>Welcome to Xeric, the tiny server.</p>"; | |
n = write(client, output, strlen(output)); | |
if(n < 0) { | |
warn("Error writing to socket; breaking connection."); | |
goto close; | |
} | |
close: | |
/* Close the connection: */ | |
close(client); | |
} | |
if(s >= 0) { | |
close(s); | |
} | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <errno.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <strings.h> | |
#include <signal.h> | |
#include <unistd.h> | |
#include <sys/types.h> | |
#include <sys/socket.h> | |
#include <netinet/in.h> | |
#include <arpa/inet.h> | |
/* Some message output methods. */ | |
#ifdef _WIN32 | |
#define warn puts | |
#define success puts | |
#else | |
void warn(const char * message) { | |
printf("\033[22;33m%s\n\033[22;0m", message); | |
} | |
void success(const char * message) { | |
printf("\033[22;32m%s\n\033[22;0m", message); | |
} | |
#endif | |
/* Represents an IPv4 address. * | |
* We use this to convert the `unsigned long` from sockaddr_in. */ | |
typedef union { | |
unsigned long address; | |
struct { | |
unsigned char p1; | |
unsigned char p2; | |
unsigned char p3; | |
unsigned char p4; | |
} components; | |
} ip4_t; | |
/* Handles interrupts gracefully. * | |
* Oddly, however, interrupting currently causes a segfault. * <-- Actually, it doesn't anymore... uh-oh. | |
* I have no idea where that comes from. */ | |
int keepRunning = 1; | |
int s; | |
void interrupted(int sig) { | |
/* Tell it to stop running: */ | |
keepRunning = 0; | |
/* Close the socket: */ | |
close(s); | |
s = -1; | |
/* Make it possible to "really kill": */ | |
signal(SIGINT, SIG_DFL); | |
} | |
/* Parses a port number, since strtoll isn't available in C89. */ | |
int strtoport(const char * str) { | |
int p = 0; | |
int v; | |
while(*str) { | |
v = *str++ - '0'; | |
if(v < 0 || v > 9) | |
return 0; | |
p = p * 10 + v; | |
if(p > 65535) | |
return 0; | |
} | |
return p; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment