Skip to content

Instantly share code, notes, and snippets.

@guest271314
Last active March 29, 2023 07:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save guest271314/5f9e311184b85ca6f305acc7f319e4f0 to your computer and use it in GitHub Desktop.
Save guest271314/5f9e311184b85ca6f305acc7f319e4f0 to your computer and use it in GitHub Desktop.
C Web server
// webserver.c
// ./webserver "./script.sh"
//
// Copyright 2023 J.P.H. Bruins Slot
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the “Software”), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is furnished to do
// so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include <arpa/inet.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#define PORT 8080
#define BUFFER_SIZE 1024
int main(int argc, char* argv[]) {
char buffer[BUFFER_SIZE];
// man 7 tcp
// man socket
// man sys_socket.h
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
// man errno
// man 3 perror
perror("webserver (socket)");
return 1;
}
printf("socket created successfully\n");
// man 7 ip
struct sockaddr_in host_addr;
int host_addrlen = sizeof(host_addr);
// man htons
// man htonl
host_addr.sin_family = AF_INET;
host_addr.sin_port = htons(PORT);
host_addr.sin_addr.s_addr = htonl(INADDR_ANY);
struct sockaddr_in client_addr;
int client_addrlen = sizeof(client_addr);
// man bind
if (bind(sockfd, (struct sockaddr*)&host_addr, host_addrlen) != 0) {
perror("webserver (bind)");
return 1;
}
printf("socket successfully bound to address\n");
// man 2 listen
if (listen(sockfd, SOMAXCONN) != 0) {
perror("webserver (listen)");
return 1;
}
printf("server listening for connections\n");
for (;;) {
// man 2 accept
int request =
accept(sockfd, (struct sockaddr*)&host_addr, (socklen_t*)&host_addrlen);
if (request < 0) {
perror("webserver (accept)");
continue;
}
printf("connection accepted\n");
// man getsockname
int sockn = getsockname(request, (struct sockaddr*)&client_addr,
(socklen_t*)&client_addrlen);
if (sockn < 0) {
perror("webserver (getsockname)");
continue;
}
// man 2 read
int readable = read(request, buffer, BUFFER_SIZE);
if (readable < 0) {
perror("webserver (read)");
continue;
}
// man sscanf
// man inet_ntoa
// man ntohs
char method[BUFFER_SIZE], uri[BUFFER_SIZE], version[BUFFER_SIZE];
sscanf(buffer, "%s %s %s", method, uri, version);
printf("[%s:%u] %s %s %s\n", inet_ntoa(client_addr.sin_addr),
ntohs(client_addr.sin_port), method, version, uri);
// https://developer.chrome.com/blog/private-network-access-preflight/
// https://wicg.github.io/local-network-access/
char response[] =
"HTTP/1.1 200 OK\r\n"
"Server: webserver-c\r\n"
"Cache-Control: no-store\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-type: application/octet-stream\r\n"
"Access-Control-Allow-Private-Network: true\r\n\r\n";
// man 2 write
// man 3 strlen
int writer = write(request, response, strlen(response));
if (writer < 0) {
perror("webserver (write)");
continue;
}
// 441 * 4
uint8_t writable[1764];
// man popen
FILE* pipe = popen(argv[1], "r");
for (;;) {
// man fread
size_t count = fread(writable, 1, sizeof(writable), pipe);
int stream = write(request, writable, count);
if (stream < 0) {
perror("webserver (write)");
// man pclose
pclose(pipe);
break;
}
}
// man 2 close
close(request);
break;
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment