feat: strings and config modules
This commit is contained in:
commit
b9c9b21612
10 changed files with 576 additions and 0 deletions
79
.clang-format
Normal file
79
.clang-format
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
AccessModifierOffset: -4
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveAssignments: false
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlignEscapedNewlines: Right
|
||||
AlignOperands: false
|
||||
AlignTrailingComments: false
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: None
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BreakBeforeBraces: Custom
|
||||
BraceWrapping:
|
||||
AfterEnum: true
|
||||
AfterClass: true
|
||||
AfterControlStatement: true
|
||||
AfterFunction: true
|
||||
AfterNamespace: true
|
||||
AfterStruct: true
|
||||
AfterUnion: true
|
||||
AfterExternBlock: true
|
||||
BeforeCatch: true
|
||||
BeforeElse: true
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: false
|
||||
SplitEmptyRecord: false
|
||||
SplitEmptyNamespace: false
|
||||
BreakBeforeBinaryOperators: NonAssignment
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializers: BeforeComma
|
||||
BreakInheritanceList: BeforeComma
|
||||
BreakStringLiterals: true
|
||||
ColumnLimit: 80
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
Cpp11BracedListStyle: false
|
||||
DerivePointerAlignment: false
|
||||
FixNamespaceComments: true
|
||||
ForEachMacros: ['ILIST_FOREACH', 'ILIST_FOREACH_ENTRY']
|
||||
IncludeBlocks: Regroup
|
||||
IncludeCategories:
|
||||
- Regex: '<.*>'
|
||||
Priority: 1
|
||||
- Regex: '.*'
|
||||
Priority: 2
|
||||
IndentCaseLabels: false
|
||||
IndentPPDirectives: AfterHash
|
||||
IndentWidth: 4
|
||||
IndentWrappedFunctionNames: false
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
Language: Cpp
|
||||
NamespaceIndentation: All
|
||||
PointerAlignment: Right
|
||||
ReflowComments: true
|
||||
SortIncludes: true
|
||||
SortUsingDeclarations: false
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCpp11BracedList: false
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInContainerLiterals: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
TabWidth: 4
|
||||
UseTab: Never
|
||||
7
httpd/.gitignore
vendored
Normal file
7
httpd/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
*~
|
||||
*.swp
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
*.log
|
||||
*.core
|
||||
31
httpd/Makefile
Normal file
31
httpd/Makefile
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
CC = gcc
|
||||
CFLAGS = -std=c99 -Werror -Wall -Wextra -Wvla -pedantic
|
||||
LDFLAGS =
|
||||
LDLIBS =
|
||||
|
||||
LDFLAGS_DBG = -g
|
||||
ASAN_DBG_FLAGS = -fsanitize=address
|
||||
|
||||
UTILS_SRCS = src/utils/string/string.c
|
||||
CONFIG_SRCS = src/config/config.c
|
||||
SRCS = $(UTILS_SRCS) $(CONFIG_SRCS) src/main.c
|
||||
|
||||
UTILS_OBJS = ${UTILS_SRCS:.c=.o}
|
||||
CONFIG_OBJS = ${CONFIG_SRCS:.c=.o}
|
||||
OBJS = ${SRCS:.c=.o}
|
||||
|
||||
TARGET=httpd
|
||||
|
||||
$(TARGET): $(OBJS)
|
||||
$(CC) -o $@ $(OBJS) $(LDFLAGS) $(LDLIBS)
|
||||
|
||||
check:
|
||||
dash tests/run.sh
|
||||
|
||||
debug: LDFLAGS += LDFLAGS_DBG
|
||||
debug:
|
||||
$(CC) -o $(TARGET) $(OBJS) $(LDFLAGS) $(LDLIBS)
|
||||
|
||||
clean:
|
||||
$(RM) $(TARGET)
|
||||
$(RM) $(OBJS)
|
||||
9
httpd/config.txt
Normal file
9
httpd/config.txt
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
[global]
|
||||
log = true
|
||||
pid_file = /tmp/HTTPd.pid
|
||||
|
||||
[[vhosts]]
|
||||
server_name = my_server
|
||||
ip = 127.0.0.1
|
||||
port = 6996
|
||||
root_dir = .
|
||||
86
httpd/config_reader.sh
Executable file
86
httpd/config_reader.sh
Executable file
|
|
@ -0,0 +1,86 @@
|
|||
#!/bin/sh
|
||||
|
||||
usage() {
|
||||
echo "Usage: $0 --path-config <file> [--path-bin <bin>] [--daemon <options>]"
|
||||
echo
|
||||
echo "Options:"
|
||||
echo " --path-config <fichier> (mandatory) path to the config file"
|
||||
echo " --path-bin <chemin-binaire> (optional) path to the httpd binary, default is ./httpd"
|
||||
echo " --daemon <options> (optional) option passed to httpd"
|
||||
echo " -h, --help prints this help page"
|
||||
exit 1
|
||||
}
|
||||
|
||||
OPTIONS=$(getopt -o h --long path-config:,path-bin:,daemon:,help -- "$@")
|
||||
if [ $? -ne 0 ]; then
|
||||
usage
|
||||
fi
|
||||
|
||||
eval set -- "$OPTIONS"
|
||||
|
||||
PATH_CONFIG=""
|
||||
PATH_BIN="./httpd"
|
||||
DAEMON_OPTS=""
|
||||
|
||||
# Lecture des arguments
|
||||
while true; do
|
||||
case "$1" in
|
||||
--path-config)
|
||||
PATH_CONFIG="$2"
|
||||
shift 2
|
||||
;;
|
||||
--path-bin)
|
||||
PATH_BIN="$2"
|
||||
shift 2
|
||||
;;
|
||||
--daemon)
|
||||
DAEMON_OPTS="--daemon $2"
|
||||
shift 2
|
||||
;;
|
||||
-h|--help)
|
||||
usage
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
break
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# verify mandatory option
|
||||
if [ -z "$PATH_CONFIG" ]; then
|
||||
echo "error : --path-config is mandatory"
|
||||
echo
|
||||
usage
|
||||
fi
|
||||
|
||||
! [ -f "$PATH_CONFIG" ] && (echo "config file: $PATH_CONFIG is not a file"; exit 1;)
|
||||
PATH_BIN_TO_RUN="$PATH_BIN"
|
||||
|
||||
if [[ "$PATH_BIN_TO_RUN" != */* ]]; then
|
||||
PATH_BIN_TO_RUN="./$PATH_BIN_TO_RUN"
|
||||
fi
|
||||
|
||||
[ -x "$PATH_BIN_TO_RUN" ] || (echo "error: binary file: '$PATH_BIN_TO_RUN' is not executable or does not exist."; exit 1;)
|
||||
|
||||
PATH_BIN="$PATH_BIN_TO_RUN"
|
||||
|
||||
# main
|
||||
ARGS=""
|
||||
regex="([^ ]+) ?= ?([^ ]+)"
|
||||
|
||||
while IFS= read -r line || [[ -n "$line" ]];
|
||||
do
|
||||
[ "$line" = "[global]" ] || [ "$line" = "[[vhosts]]" ] && continue;
|
||||
|
||||
if [[ $line =~ $regex ]]; then
|
||||
ARGS="$ARGS --${BASH_REMATCH[1]} ${BASH_REMATCH[2]}"
|
||||
fi
|
||||
done < "$PATH_CONFIG"
|
||||
|
||||
# launch binary with correct args
|
||||
echo "command run is: $PATH_BIN $DAEMON_OPTS ${ARGS:1}"
|
||||
$PATH_BIN $DAEMON_OPTS ${ARGS:1}
|
||||
170
httpd/src/config/config.c
Normal file
170
httpd/src/config/config.c
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
#include "config.h"
|
||||
|
||||
#include <getopt.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../utils/string/string.h"
|
||||
|
||||
#define ARG_VALID 0
|
||||
#define ARG_INVALID 1
|
||||
#define ARG_HELP 2
|
||||
#define ARG_NOT_IMPLEMENTED 2
|
||||
|
||||
// == Static functions
|
||||
|
||||
// Returns 0 if the servers array is valid 1 otherwise
|
||||
// static int check_server_config(struct server_config *server)
|
||||
// {
|
||||
// if (server->server_name == NULL || server->port == NULL
|
||||
// || server->ip == NULL || server->root_dir == NULL)
|
||||
// {
|
||||
// return -1;
|
||||
// }
|
||||
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
static void print_help(char *program_name)
|
||||
{
|
||||
printf("Usage: %s [OPTION]\n", program_name);
|
||||
puts("");
|
||||
}
|
||||
|
||||
// Returns 0 if argument is valid, otherwise
|
||||
static int handle_opt(char **argv, char opt, struct config *cfg)
|
||||
{
|
||||
// Options without value
|
||||
switch (opt)
|
||||
{
|
||||
// Help
|
||||
case 'h':
|
||||
print_help(argv[0]);
|
||||
return ARG_HELP;
|
||||
}
|
||||
|
||||
if (optarg == NULL)
|
||||
return ARG_INVALID;
|
||||
|
||||
// Options with value
|
||||
switch (opt)
|
||||
{
|
||||
// Daemon
|
||||
case 'd':
|
||||
if (strcmp(optarg, "start") == 0)
|
||||
cfg->daemon = START;
|
||||
else if (strcmp(optarg, "stop") == 0)
|
||||
cfg->daemon = STOP;
|
||||
else if (strcmp(optarg, "restart") == 0)
|
||||
cfg->daemon = RESTART;
|
||||
else
|
||||
return ARG_INVALID;
|
||||
return ARG_VALID;
|
||||
|
||||
// Server name
|
||||
case 's':
|
||||
cfg->servers->server_name = string_create(optarg, strlen(optarg));
|
||||
break;
|
||||
|
||||
// Port
|
||||
case 'p':
|
||||
cfg->servers->port = optarg;
|
||||
break;
|
||||
|
||||
// IP
|
||||
case 'i':
|
||||
cfg->servers->ip = optarg;
|
||||
break;
|
||||
|
||||
// Root dir
|
||||
case 'r':
|
||||
cfg->servers->root_dir = optarg;
|
||||
break;
|
||||
|
||||
// Default file
|
||||
case 'D':
|
||||
cfg->servers->ip = optarg;
|
||||
break;
|
||||
|
||||
// PID file
|
||||
case 'P':
|
||||
cfg->pid_file = optarg;
|
||||
break;
|
||||
|
||||
// Log file
|
||||
case 'L':
|
||||
cfg->log_file = optarg;
|
||||
break;
|
||||
|
||||
// Logs
|
||||
case 'l':
|
||||
return ARG_NOT_IMPLEMENTED;
|
||||
|
||||
default:
|
||||
// TODO print full flags
|
||||
// printf("Unrecognized option '%s'", optstring);
|
||||
return ARG_INVALID;
|
||||
}
|
||||
|
||||
return ARG_VALID;
|
||||
}
|
||||
|
||||
// == Main functions
|
||||
|
||||
struct config *parse_configuration(int argc, char *argv[])
|
||||
{
|
||||
struct option options[] = { // Global
|
||||
{ "daemon", optional_argument, NULL, 'd' },
|
||||
{ "help", optional_argument, NULL, 'h' },
|
||||
// Vhosts
|
||||
{ "server_name", required_argument, NULL, 's' },
|
||||
{ "port", required_argument, NULL, 'p' },
|
||||
{ "ip", required_argument, NULL, 'i' },
|
||||
{ "root_dir", required_argument, NULL, 'r' },
|
||||
{ "defaut_file", optional_argument, NULL, 'D' },
|
||||
// Logging
|
||||
{ "pid_file", required_argument, NULL, 'P' },
|
||||
{ "log_file", optional_argument, NULL, 'L' },
|
||||
{ "log", optional_argument, NULL, 'l' },
|
||||
// End
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
struct config *config = calloc(1, sizeof(struct config));
|
||||
if (config == NULL)
|
||||
return NULL;
|
||||
|
||||
config->servers = calloc(1, sizeof(struct server_config));
|
||||
if (config->servers == NULL)
|
||||
{
|
||||
free(config);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char opt;
|
||||
int optindex;
|
||||
while ((opt = getopt_long(argc, argv, "*", options, &optindex)) != -1)
|
||||
{
|
||||
int err = handle_opt(argv, opt, config);
|
||||
if (err != ARG_VALID)
|
||||
{
|
||||
if (err == ARG_INVALID)
|
||||
printf("%s: Invalid argument '%s'", argv[0], argv[optindex]);
|
||||
if (err == ARG_NOT_IMPLEMENTED)
|
||||
printf("%s: This function is not implemented", argv[0]);
|
||||
|
||||
free(config->servers);
|
||||
free(config);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
void config_destroy(struct config *config)
|
||||
{
|
||||
free(config->servers);
|
||||
free(config);
|
||||
}
|
||||
73
httpd/src/config/config.h
Normal file
73
httpd/src/config/config.h
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
#ifndef CONFIG_H
|
||||
#define CONFIG_H
|
||||
|
||||
#define _XOPEN_SOURCE 500
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
/*
|
||||
** @brief Enum daemon
|
||||
** NO_OPTION if the '--daemon' option is not given
|
||||
** START, STOP, RESTART if option is "start", "stop" and "restart"
|
||||
*/
|
||||
enum daemon
|
||||
{
|
||||
NO_OPTION = 0,
|
||||
START,
|
||||
STOP,
|
||||
RESTART
|
||||
};
|
||||
|
||||
/*
|
||||
** @brief Configuration structure
|
||||
**
|
||||
** @param pid_file Path to the pid file
|
||||
** @param log_file Path to the log file
|
||||
** @param log Enable or disable logging
|
||||
** @param servers Array of vhosts
|
||||
** @daemon option for the daemon (START, STOP, RESTART)
|
||||
*/
|
||||
struct config
|
||||
{
|
||||
char *pid_file;
|
||||
char *log_file;
|
||||
bool log;
|
||||
|
||||
struct server_config *servers;
|
||||
enum daemon daemon;
|
||||
};
|
||||
|
||||
/*
|
||||
** @brief Vhost configuration structure
|
||||
**
|
||||
** @param server_name Server name
|
||||
** @param port Port to listen on
|
||||
** @param ip IP address
|
||||
** @param root_dir Root directory to serve
|
||||
** @param default_file Default file to serve
|
||||
*/
|
||||
struct server_config
|
||||
{
|
||||
struct string *server_name;
|
||||
char *port;
|
||||
char *ip;
|
||||
char *root_dir;
|
||||
char *default_file;
|
||||
};
|
||||
|
||||
/*
|
||||
** @brief Parse the given argv argument and returns a filled struct
|
||||
**
|
||||
** @param argc Number of arguments
|
||||
** @param argv A list of char * containing all the arguments
|
||||
*/
|
||||
struct config *parse_configuration(int argc, char *argv[]);
|
||||
|
||||
/*
|
||||
** @brief Free the config struct
|
||||
**
|
||||
** @param config The config struct to free
|
||||
*/
|
||||
void config_destroy(struct config *config);
|
||||
|
||||
#endif /* !CONFIG_H */
|
||||
4
httpd/src/main.c
Normal file
4
httpd/src/main.c
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
int main(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
70
httpd/src/utils/string/string.c
Normal file
70
httpd/src/utils/string/string.c
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
#include "string.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
struct string *string_create(const char *str, size_t size)
|
||||
{
|
||||
struct string *res = malloc(sizeof(struct string));
|
||||
if (res == NULL)
|
||||
return NULL;
|
||||
|
||||
res->data = malloc(size * sizeof(char));
|
||||
if (res->data == NULL)
|
||||
{
|
||||
free(res);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(res->data, str, size);
|
||||
res->size = size;
|
||||
return res;
|
||||
}
|
||||
|
||||
int string_compare_n_str(const struct string *str1, const char *str2, size_t n)
|
||||
{
|
||||
size_t i = 0;
|
||||
int res = 0;
|
||||
char reached_str2_end = 0;
|
||||
while (i < n)
|
||||
{
|
||||
if (i < str1->size)
|
||||
res += str1->data[i];
|
||||
|
||||
if (!reached_str2_end)
|
||||
{
|
||||
if (str2[i] == '\0')
|
||||
reached_str2_end = 1;
|
||||
else
|
||||
res -= str2[i];
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void string_concat_str(struct string *str, const char *to_concat, size_t size)
|
||||
{
|
||||
size_t new_size = str->size + size;
|
||||
size_t str_size = str->size;
|
||||
|
||||
if (new_size == 0)
|
||||
return;
|
||||
|
||||
str->data = realloc(str->data, new_size);
|
||||
if (str->data == NULL)
|
||||
return; // Handle ?
|
||||
|
||||
for (size_t i = 0; i < size; i++)
|
||||
{
|
||||
str->data[str_size + i] = to_concat[i];
|
||||
}
|
||||
}
|
||||
|
||||
void string_destroy(struct string *str)
|
||||
{
|
||||
free(str->data);
|
||||
free(str);
|
||||
}
|
||||
47
httpd/src/utils/string/string.h
Normal file
47
httpd/src/utils/string/string.h
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
#ifndef STRING_H
|
||||
#define STRING_H
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stddef.h>
|
||||
|
||||
struct string
|
||||
{
|
||||
size_t size;
|
||||
char *data;
|
||||
};
|
||||
|
||||
/*
|
||||
** @brief Create new string struct from char * and size
|
||||
** Be careful, the argument str will not be deallocated and thus you
|
||||
** can call this function with a static char *
|
||||
**
|
||||
** @param str
|
||||
** @param size
|
||||
**
|
||||
** @return the newly allocated string
|
||||
*/
|
||||
struct string *string_create(const char *str, size_t size);
|
||||
|
||||
/*
|
||||
** @brief Act like memcmp(3) but for struct string and char *
|
||||
**
|
||||
** @param str1
|
||||
** @param str2
|
||||
** @param n
|
||||
**
|
||||
** @return
|
||||
*/
|
||||
int string_compare_n_str(const struct string *str1, const char *str2, size_t n);
|
||||
|
||||
/*
|
||||
** @brief Concat a char * with its size in a struct string
|
||||
**
|
||||
** @param str
|
||||
** @param to_concat
|
||||
** @param size
|
||||
*/
|
||||
void string_concat_str(struct string *str, const char *to_concat, size_t size);
|
||||
|
||||
void string_destroy(struct string *str);
|
||||
|
||||
#endif /* ! STRING_H */
|
||||
Loading…
Add table
Add a link
Reference in a new issue