Last active
February 14, 2022 03:41
-
-
Save SamuelMarks/3f386b61be78895ab8e93ad57b41e802 to your computer and use it in GitHub Desktop.
Experiments with simple HTTP socket server in C
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 "server_attempt_6.c" | |
/* just a hack for this gist^, for attempts 0-5 see revision <17 */ | |
int main(void) { | |
int code; | |
char *response = calloc(PIPE_BUF + 1, sizeof(char)); | |
if (response == NULL) { | |
const int _code = fputs("OOM", stderr); | |
if (_code == EOF) exit(_code); | |
exit(EAI_MEMORY); | |
} | |
puts("serve()"); | |
code = serve(&response); | |
fprintf(stderr, "serve::code: %d\n" | |
"serve::response: %s\n", | |
code, response); | |
puts("fin server()"); | |
if (code != EXIT_SUCCESS) | |
fputs("server() failed", stderr); | |
return code; | |
} |
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 "server_common.h" | |
int serve(char **response) { | |
#define STD_ERROR_HANDLER(code) \ | |
if((code) == -1) { \ | |
char _error_s_buf[BUFSIZ]; \ | |
strerror_r(code, _error_s_buf, BUFSIZ); \ | |
{ \ | |
const int _c = fputs(_error_s_buf, stderr); \ | |
if (_c == EOF) return _c; \ | |
} \ | |
return code == EXIT_SUCCESS? EXIT_FAILURE: (int)code; \ | |
} else | |
struct addrinfo hint = {0}, *p, *info = NULL; | |
int code; | |
#if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__) | |
unsigned long long | |
#else | |
int | |
#endif | |
sockfd; | |
size_t current_size = PIPE_BUF; | |
struct sockaddr_storage client_addr; | |
socklen_t addr_size = sizeof client_addr; | |
char pipe_buf[PIPE_BUF + 1]; | |
#if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__) | |
/* Initialize Winsock */ | |
WSADATA wsaData; | |
int iResult = WSAStartup(MAKEWORD(2,2), &wsaData); | |
if (iResult != 0) { | |
const int _code = fprintf(stderr, "WSAStartup failed: %d\n", iResult); | |
if (_code == EOF) return _code; | |
return _code == EXIT_SUCCESS? EXIT_FAILURE: _code; | |
} | |
#endif /* defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__) */ | |
hint.ai_family = AF_INET; | |
hint.ai_socktype = SOCK_STREAM; | |
hint.ai_flags = AI_PASSIVE | |
#if !defined(_WIN32) && !defined(__WIN32__) && !defined(__WINDOWS__) | |
| SOCK_NONBLOCK | |
#endif | |
; | |
code = getaddrinfo(NULL, PORT_TO_BIND_S, &hint, &info); | |
if (code != 0) { | |
fputs(gai_strerror(code), stderr); | |
return code == EXIT_SUCCESS ? EXIT_FAILURE : code; | |
} | |
for (p = info; p; p = p->ai_next) { | |
sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol); | |
if (sockfd == -1) { | |
continue; | |
} | |
code = bind(sockfd, p->ai_addr, (int)p->ai_addrlen); | |
if (code == -1) { | |
char error_s[BUFSIZ]; | |
strerror_r(code, error_s, BUFSIZ); | |
{ | |
const int _code = fputs(error_s, stderr); | |
if (_code == EOF) return _code; | |
} | |
#if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__) | |
STD_ERROR_HANDLER(closesocket(sockfd)); | |
#else | |
STD_ERROR_HANDLER(close(sockfd)); | |
#endif | |
continue; | |
} | |
break; | |
} | |
STD_ERROR_HANDLER(listen(sockfd, MSG_BACKLOG)); | |
/*if (*response == NULL) *response = malloc(sizeof(char)*PIPE_BUF+1);*/ | |
while (true) { | |
char *response_buf; | |
#if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__) | |
SOCKET | |
#else | |
ssize_t | |
#endif | |
bytes, total_bytes = 0; | |
const | |
#if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__) | |
SOCKET | |
#else | |
int | |
#endif | |
client_fd = accept(sockfd, (struct sockaddr *) &client_addr, &addr_size); | |
if (client_fd == -1) { | |
char error_s[BUFSIZ]; | |
strerror_r(code, error_s, BUFSIZ); | |
{ | |
const int _code = fputs(error_s, stderr); | |
if (_code == EOF) return _code; | |
} | |
continue; | |
} | |
puts("Running server on http://"SERVER_HOST ":" PORT_TO_BIND_S); | |
/* memset(pipe_buf, 0, PIPE_BUF); */ | |
do { | |
#if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__) | |
bytes = recv(client_fd, pipe_buf, PIPE_BUF, 0); | |
#else | |
bytes = read(client_fd, pipe_buf, PIPE_BUF); | |
#endif | |
printf("bytes: %"DEBUG_NUM_SEP"\n", bytes); | |
if (bytes == -1) { | |
char error_s[BUFSIZ]; | |
strerror_r(code, error_s, BUFSIZ); | |
{ | |
const int _code = fputs(error_s, stderr); | |
if (_code == EOF) return _code; | |
} | |
} else if (bytes > 0) { | |
const size_t new_size = total_bytes + bytes + 1; | |
printf("b4 current_size: %"DEBUG_NUM_SEP"\n" | |
"new_size: %"DEBUG_NUM_SEP"\n" | |
"b4 total_bytes: %"DEBUG_NUM_SEP"\n", | |
current_size, new_size, total_bytes); | |
if (new_size > current_size + 1) { | |
printf("b4 malloc_usable_size(*response): %"DEBUG_NUM_SEP"\n", malloc_usable_size(*response)); | |
response_buf = realloc(*response, new_size + 1); | |
printf("l8 malloc_usable_size(*response): %"DEBUG_NUM_SEP"\n", malloc_usable_size(*response)); | |
if (*response == NULL) { | |
const int _code = fputs("OOM", stderr); | |
if (_code == EOF) return _code; | |
return EXIT_FAILURE; | |
} else | |
*response = response_buf; | |
} | |
assert(response != NULL && *response != NULL); | |
memcpy(*response + total_bytes, pipe_buf, bytes); | |
total_bytes += bytes; | |
current_size = total_bytes; | |
printf("l8 current_size: %"DEBUG_NUM_SEP"\n" | |
"l8 total_bytes: %"DEBUG_NUM_SEP"\n", | |
current_size, total_bytes); | |
} | |
if (bytes < PIPE_BUF) | |
break; | |
/*printf("read bytes: %ld\n" | |
"buffer: %s\n", bytes, *response); | |
fflush(stdout);*/ | |
} while (bytes > 0); | |
if (response != NULL && *response != NULL) { | |
(*response)[total_bytes] = '\0'; | |
if (strncmp(STOP_ON_STARTSWITH, *response, strlen(STOP_ON_STARTSWITH)) == 0) { | |
STD_ERROR_HANDLER(write_and_close_socket((int)client_fd, responseOk, sizeof(responseOk) - 1)); | |
#if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__) | |
Sleep(1000* | |
#else | |
sleep( | |
#endif | |
50); | |
#if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__) | |
WSACleanup(); | |
#endif /* defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__) */ | |
return EXIT_SUCCESS; | |
} | |
} | |
STD_ERROR_HANDLER(write_and_close_socket((int)client_fd, responseErr, sizeof(responseErr) - 1)); | |
} | |
#undef STD_ERROR_HANDLER | |
} |
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 <stdlib.h> | |
#include <string.h> | |
#include <stdbool.h> | |
#include <assert.h> | |
#if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__) | |
#define NOWINBASEINTERLOCK | |
#include <intrin.h> | |
#include <ws2tcpip.h> | |
#include <winsock2.h> | |
#include <io.h> | |
#define DEBUG_NUM_SEP "zu" | |
#else | |
#define DEBUG_NUM_SEP "lu" | |
#include <malloc/malloc.h> | |
#include <unistd.h> | |
#include <sys/socket.h> | |
#include <netinet/in.h> | |
#include <err.h> | |
#include <ctype.h> | |
#include <netdb.h> | |
#define ERROR_EOM_OVERFLOW EXIT_FAILURE | |
#endif | |
#ifndef SOCK_NONBLOCK | |
#include <fcntl.h> | |
#include <errno.h> | |
# define SOCK_NONBLOCK O_NONBLOCK | |
#endif /* ! SOCK_NONBLOCK */ | |
#ifdef __clang__ | |
#define malloc_usable_size malloc_size | |
#endif /* __clang__ */ | |
#define SERVER_HOST "localhost" | |
#define PORT_TO_BIND_S "8080" | |
const static char responseOk[] = "HTTP/1.0 200 OK\r\n" | |
"Content-Type: text/plain\r\n" | |
"\r\n" | |
"Ok.\r\n"; | |
const static char responseErr[] = "HTTP/1.0 400 Bad Request\r\n" | |
"Content-Type: text/plain\r\n" | |
"\r\n" | |
"Bad Request\r\n"; | |
const static char STOP_ON_STARTSWITH[] = "GET /foo"; | |
int write_and_close_socket(int client_fd, const char responseMessage[], size_t messageSize) { | |
#if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__) | |
int wrote = send(client_fd, responseMessage, (int)messageSize - 1, 0 ); | |
int closed_code = closesocket(client_fd); | |
#else | |
ssize_t wrote = write(client_fd, responseMessage, messageSize - 1); | |
int closed_code = close(client_fd); | |
#endif | |
return wrote == -1 || closed_code == -1 ? -1 : 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment