Commit b13aa8b6 authored by Sebastian Schinzel's avatar Sebastian Schinzel

Ändere echo_server, so dass er auch Anfragen über stdin akzeptiert und...

Ändere echo_server, so dass er auch Anfragen über stdin akzeptiert und Antworten entsprechend auf stdout ausgibt. Das ist die Vorbereitung, um das Fuzzing von Servern zu erlauben.
parent b55e7bf6
......@@ -19,7 +19,7 @@ set(CMAKE_C_FLAGS
# Ausführbare Datei: echo_server
add_executable(echo_server
echo_server.c)
echo_server.c httplib.c httplib.h httplib-test.c)
set_property(TARGET echo_server
PROPERTY C_STANDARD 11)
install(TARGETS echo_server
......
/* Version: 2.1.2 */
#include <errno.h> // errno
#include <netinet/ip.h> // ^
#include <signal.h> // sigaction, struct sigaction, siginfo_t, SIGTERM
......@@ -8,59 +7,61 @@
#include <string.h> // memset, strerror
#include <sys/socket.h> // struct sockaddr_in, socket, setsockopt, bind, listen, socklen_t, accept
#include <unistd.h> // read, write, close
#include "httplib.h"
#define PORT 31337
#define BUFFER_SIZE 1024
#define BUFFER_SIZE 1024*1024
string* process(string *request);
/**
* Globale Variablen.
*/
static bool run = true;
/**
* Fehlerbehandlung.
* Gibt eine Fehlermeldung *msg* aus und beendet das Programm.
* @param msg Die Fehlermeldung.
*/
static void error(char *msg) {
fprintf(stderr, "%s", msg);
if (errno) {
fprintf(stderr, ", errno: %s", strerror(errno));
}
fprintf(stderr, "\n");
exit(1);
fprintf(stderr, "%s", msg);
if (errno) {
fprintf(stderr, ", errno: %s", strerror(errno));
}
fprintf(stderr, "\n");
exit(1);
}
/**
* Behandlung des SIGINT-Signals (Strg+C) um den Server zu beenden.
* Diese Funktion wird aufgerufen, wenn das Programm das *SIGINT*-Signal empfängt. Es beendet den Server.
* @param signum Die Signalnummer.
*/
static void handle_signal(int signum) {
if (signum != SIGINT) {
error("ERROR unexpected signal");
}
/*
* Beende den Server nach dem Abarbeiten des letzten Clients.
*/
run = false;
if (signum != SIGINT) {
error("ERROR unexpected signal");
}
/*
* Beende den Server nach dem Abarbeiten des letzten Clients.
*/
run = false;
}
/**
* Registriert das SIGINT-Signal (Strg+C) um den Server beenden zu können.
*/
static void register_signal() {
struct sigaction action;
/*
* Konfigurieren des Signal-Handlers.
*/
memset(&action, 0, sizeof(action));
action.sa_handler = handle_signal;
/*
* Registrierung des Signal-Handlers.
*/
if (sigaction(SIGINT, &action, NULL) < 0) {
error("ERROR registering signal handler");
}
struct sigaction action;
/*
* Konfigurieren des Signal-Handlers.
*/
memset(&action, 0, sizeof(action));
action.sa_handler = handle_signal;
/*
* Registrierung des Signal-Handlers.
*/
if (sigaction(SIGINT, &action, NULL) < 0) {
error("ERROR registering signal handler");
}
}
/**
......@@ -68,153 +69,179 @@ static void register_signal() {
* angenommen werden.
*/
static int setup_socket() {
#ifdef STDIN_ONLY
return STDOUT_FILENO;
#endif
int opt = 1;
int sockfd = 0;
struct sockaddr_in serv_addr;
/*
* Setzt Konfigurationsvariablen für den Socket, z.B. die Portnummer.
*/
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(PORT);
/*
* Erstelle den Socket.
*/
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
error("ERROR opening socket");
}
/*
* Verwende den Socket, selbst wenn er aus einer vorigen Ausführung
* im TIME_WAIT Status ist.
*/
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt,
sizeof(int)) < 0)
error("ERROR on setsockopt");
/*
* Melde, dass der Socket eingehende Verbindungen akzeptieren soll.
*/
if (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
error("ERROR on binding");
}
/*
* Horche auf dem Socket nach eingehenden Verbindungen. Es werden maximal
* fünf gleichzeitige Verbindungen erlaubt.
*/
if (listen(sockfd, 5) < 0) {
error("listen");
}
return sockfd;
}
int opt = 1;
int sockfd = 0;
struct sockaddr_in serv_addr;
/*
* Setzt Konfigurationsvariablen für den Socket, z.B. die Portnummer.
*/
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(PORT);
/*
* Erstelle den Socket.
*/
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
error("ERROR opening socket");
}
/*
* Verwende den Socket, selbst wenn er aus einer vorigen Ausführung
* im TIME_WAIT Status ist.
*/
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char *) &opt,
sizeof(int)) < 0)
error("ERROR on setsockopt");
/**
* Die Hauptschleife, in der eingehende Verbindungen angenommen werden.
*/
static void main_loop(int sockfd) {
int newsockfd;
ssize_t length;
#ifndef STDIN_ONLY
struct sockaddr_in cli_addr;
socklen_t clilen = sizeof(cli_addr);
#endif
void *const buffer = malloc(BUFFER_SIZE);
if (buffer == NULL) {
error("ERROR at malloc.");
}
/*
* Die Hauptshleife des Programms.
*/
while (run) {
#ifndef STDIN_ONLY
/*
* Der accept()-Aufruf blockiert, bis eine neue Verbindung rein kommt.
* Melde, dass der Socket eingehende Verbindungen akzeptieren soll.
*/
newsockfd = accept(sockfd, (struct sockaddr *)&cli_addr, &clilen);
if (newsockfd < 0) {
/*
* Wenn der Server mit dem SIGINT-Signal beendet wird, schlägt accept
* mit EINTR (interrupted) fehl.
*/
if (errno == EINTR) {
break;
}
error("ERROR on accept");
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
error("ERROR on binding");
}
/*
* Horche auf dem Socket nach eingehenden Verbindungen. Es werden maximal
* fünf gleichzeitige Verbindungen erlaubt.
*/
if (listen(sockfd, 5) < 0) {
error("listen");
}
return sockfd;
}
static void main_loop_stdin() {
void *const buffer = malloc(BUFFER_SIZE);
if (buffer == NULL) {
error("ERROR at malloc.");
}
#else
newsockfd = STDIN_FILENO;
#endif
/*
* Lies die ankommenden Daten von dem Socket in das Array buffer.
*/
memset(buffer, 0, BUFFER_SIZE);
length = read(newsockfd, buffer, BUFFER_SIZE - 1);
size_t length = read(STDIN_FILENO, buffer, BUFFER_SIZE - 1);
if (length < 0) {
if (errno == EINTR) {
break;
}
error("ERROR reading from socket");
if (errno != EINTR) {
error("ERROR reading from socket");
}
}
string *request = cpy_str(buffer, length);
string *response = process(request);
/*
* Schreibe die ausgehenden Daten auf den Socket.
size_t response_len = get_length(response);
char *response_char = get_char_str(response);
/*
* Schreibe die ausgehenden Daten auf stdout.
*/
if (write(STDOUT_FILENO, response_char, response_len) < 0) {
error("ERROR writing to STDOUT");
}
free(buffer);
}
/**
* Die Hauptschleife, in der eingehende Verbindungen angenommen werden.
*/
#ifndef STDIN_ONLY
length = write(newsockfd, buffer, (size_t)length);
if (length < 0) {
error("ERROR writing to socket");
static void main_loop() {
const int sockfd = setup_socket();
int newsockfd;
ssize_t length;
struct sockaddr_in cli_addr;
socklen_t clilen = sizeof(cli_addr);
void *const buffer = malloc(BUFFER_SIZE);
if (buffer == NULL) {
error("ERROR at malloc.");
}
#else
/*
* Gib die eingegangenen Daten auf der Kommandozeile aus.
* Die Hauptschleife des Programms.
*/
if (write(STDOUT_FILENO, buffer, length) < 0) {
error("ERROR writing to STDOUT");
while (run) {
/*
* Der accept()-Aufruf blockiert, bis eine neue Verbindung rein kommt.
*/
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0) {
/*
* Wenn der Server mit dem SIGINT-Signal beendet wird, schlägt accept
* mit EINTR (interrupted) fehl.
*/
if (errno == EINTR) {
break;
}
error("ERROR on accept");
}
/*
* Lies die ankommenden Daten von dem Socket in das Array buffer.
*/
memset(buffer, 0, BUFFER_SIZE);
length = read(newsockfd, buffer, BUFFER_SIZE - 1);
if (length < 0) {
if (errno == EINTR) {
break;
}
error("ERROR reading from socket");
}
string *request = cpy_str(buffer, length);
string *response = process(request);
/*
* Schreibe die ausgehenden Daten auf den Socket.
*/
size_t response_len = get_length(response);
char *response_char = get_char_str(response);
length = write(newsockfd, response_char, response_len);
if (length < 0) {
error("ERROR writing to socket");
}
/*
* Schließe die Verbindung.
*/
if (close(newsockfd) < 0) {
error("ERROR on close");
}
}
#endif
/*
* Schließe die Verbindung.
*/
#ifndef STDIN_ONLY
if (close(newsockfd) < 0) {
error("ERROR on close");
free(buffer);
if (close(sockfd) < 0) {
error("ERROR on close");
}
#endif
}
/*
* Lösche den Buffer und schließe den Socket. Dieser Aufruf sollte wegen der
* Endlosschleife niemals ausgeführt werden.
*/
free(buffer);
#ifndef STDIN_ONLY
if (close(sockfd) < 0) {
error("ERROR on close");
}
#endif
}
/**
* Die Funktion akzeptiert den eingehenden Request und gibt eine entsprechende Response zurück.
* @param request Der eingehende Request.
* @return Die ausgehende Response.
*/
string* process(string *request) {
/*
* Diese Funktion müssen Sie anpssen, so dass der request von Ihrem Code verarbeitet wird,
* die response generiert und zurück gibt.
*
* Für den Echo-Server wird der request einfach als response zurückgegeben, das Echo eben.
*/
string *response = request;
return response;
}
int main(int argc, char *argv[]) {
(void)argc;
(void)argv;
register_signal();
const int sockfd = setup_socket();
main_loop(sockfd);
register_signal();
if(argc == 2 && strcmp("stdin", argv[1]) == 0) {
main_loop_stdin();
} else {
main_loop();
}
return 0;
return 0;
}
#include "httplib.h"
void main1() {
const char* src1 = "Hallo ";
const char* src2 = "Welt!";
string* dest = cpy_str(src1, strlen(src1));
dest = str_cat(dest, src2, strlen(src2));
print_string(dest);
free_str(dest);
}
\ No newline at end of file
#include <assert.h>
#include "httplib.h"
string* str_cat(string* dest, const char* src, size_t len) {
printf("TODO!");
return dest;
}
string* new_string(size_t len) {
string* str = calloc(sizeof(string), 1);
if(str == NULL) {
exit(2);
}
str->str = calloc(len, 2);
if(str->str == NULL) {
exit(3);
}
str->len = len * 2;
str->pos = 0;
return str;
}
void print_string(string* str) {
for(int i=0; i < str->pos; i++) {
putchar(str->str[i]);
}
}
string* cpy_str(const char* src, size_t len) {
string* dest = new_string(len);
memcpy(dest->str, src, len);
dest->pos=len-1;
return dest;
}
void free_str(string* str) {
free(str->str);
free(str);
}
size_t get_length(string* str) {
assert(str != NULL);
return str->pos + 1;
}
char* get_char_str(string* str) {
assert(str != NULL);
return str->str;
}
//
// Created by Sebastian Schinzel on 25.03.20.
//
#ifndef ECHO_SERVER_HTTPLIB_H
#define ECHO_SERVER_HTTPLIB_H
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct string {
size_t len;
size_t pos;
char* str;
};
typedef struct string string;
string* str_cat(string* dest, const char* src, size_t len);
string* new_string(size_t );
void print_string(string* str);
string* cpy_str(const char* src, size_t len);
void free_str(string* str);
size_t get_length(string* str);
char* get_char_str(string* str);
#endif //ECHO_SERVER_HTTPLIB_H
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment