Skip to content

Instantly share code, notes, and snippets.

@SamuelMarks
Last active February 14, 2022 03:41
Show Gist options
  • Save SamuelMarks/3f386b61be78895ab8e93ad57b41e802 to your computer and use it in GitHub Desktop.
Save SamuelMarks/3f386b61be78895ab8e93ad57b41e802 to your computer and use it in GitHub Desktop.
Experiments with simple HTTP socket server in C
#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;
}
#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
}
#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