From: Alberto Leiva Popper Date: Thu, 7 Feb 2019 16:32:17 +0000 (-0600) Subject: Code review X-Git-Tag: v0.0.2~52^2~69 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=2ae460ef60111e3d6561fc5d3b6e7155ba829b7d;p=thirdparty%2FFORT-validator.git Code review Patched some segfaults, removed some redundant code, added more sensible defaults. --- diff --git a/src/Makefile.am b/src/Makefile.am index 6fd1051a..00eca9af 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -4,18 +4,12 @@ AM_LDFLAGS = bin_PROGRAMS = rtr_server rtr_server_SOURCES = main.c -rtr_server_SOURCES += common.h -rtr_server_SOURCES += rtr/pdu.c -rtr_server_SOURCES += rtr/pdu.h -rtr_server_SOURCES += rtr/pdu_handler.c -rtr_server_SOURCES += rtr/pdu_handler.h -rtr_server_SOURCES += rtr/primitive_reader.c -rtr_server_SOURCES += rtr/primitive_reader.h -rtr_server_SOURCES += rtr/rtr.c -rtr_server_SOURCES += rtr/rtr.h -rtr_server_SOURCES += file.c -rtr_server_SOURCES += file.h -rtr_server_SOURCES += configuration.c -rtr_server_SOURCES += configuration.h +rtr_server_SOURCES += common.c common.h +rtr_server_SOURCES += configuration.c configuration.h + +rtr_server_SOURCES += rtr/pdu_handler.c rtr/pdu_handler.h +rtr_server_SOURCES += rtr/pdu.c rtr/pdu.h +rtr_server_SOURCES += rtr/primitive_reader.c rtr/primitive_reader.h +rtr_server_SOURCES += rtr/rtr.c rtr/rtr.h rtr_server_LDADD = ${JANSSON_LIBS} \ No newline at end of file diff --git a/src/common.c b/src/common.c new file mode 100644 index 00000000..1e748471 --- /dev/null +++ b/src/common.c @@ -0,0 +1,14 @@ +#include "common.h" + +#include +#include + +char * +str_clone(char const *original) +{ + char *result; + result = malloc(strlen(original) + 1); + if (result != NULL) + strcpy(result, original); + return result; +} diff --git a/src/common.h b/src/common.h index e4da13ff..7863baaf 100644 --- a/src/common.h +++ b/src/common.h @@ -1,9 +1,6 @@ #ifndef _SRC_COMMON_H_ #define _SRC_COMMON_H_ -#include -#include - /* __BEGIN_DECLS should be used at the beginning of your declarations, so that C++ compilers don't mangle their names. Use __END_DECLS at the end of C declarations. */ @@ -21,19 +18,12 @@ #define EUNIMPLEMENTED 566456 -#define warnxerror0(error, msg) \ - warnx(msg ": %s", strerror(error)) -#define warnxerrno0(msg) \ - warnxerror0(errno, msg) -#define warnxerror(error, msg, ...) \ - warnx(msg ": %s", ##__VA_ARGS__, strerror(error)) -#define warnxerrno(msg, ...) \ - warnxerror(errno, msg, ##__VA_ARGS__) - -#define pr_debug0(msg) printf("Debug: " msg "\n"); -#define pr_debug(msg, ...) printf("Debug: " msg "\n", ##__VA_ARGS__); +/* + * FYI: The error functions are warn() and warnx(). + * warn() automatically appends the errno string message (strerror()), warnx() + * does not. + */ -#define log_err(text, ...) fprintf(stderr, text "\n", ##__VA_ARGS__) -#define log_err0(text) fprintf(stderr, text "\n") +char *str_clone(char const *); #endif /* _SRC_COMMON_H_ */ diff --git a/src/configuration.c b/src/configuration.c index 0ebd6160..3c99482a 100644 --- a/src/configuration.c +++ b/src/configuration.c @@ -1,200 +1,155 @@ #include "configuration.h" -#include -#include -#include -#include -#include - -#include #include - +#include +#include #include +#include #include "common.h" -#include "file.h" - -#define OPTNAME_LISTEN "listen" -#define OPTNAME_LISTEN_SERVER "server_name" -#define OPTNAME_LISTEN_PORT "server_port" - -static int json_to_config(json_t *, struct rtr_config *); -static int handle_listen_config(json_t *, struct rtr_config *); -static json_t *load_json(const char *); - -void -free_rtr_config(struct rtr_config *config) -{ - if (!config) - return; - - if (config->host_address) - freeaddrinfo(config->host_address); - free(config); -} +#define OPTNAME_LISTEN "listen" +#define OPTNAME_LISTEN_ADDRESS "address" +#define OPTNAME_LISTEN_PORT "port" -static bool -endsWith(char *string, char *suffix) -{ - size_t strilen; - size_t suflen; - if (!string || !suffix) - return false; +#define DEFAULT_ADDR NULL +#define DEFAULT_PORT "323" - strilen = strlen(string); - suflen = strlen(suffix); +struct rtr_config { + /** The listener address of the RTR server. */ + struct addrinfo *address; + /** Stored aside only for printing purposes. */ + char *port; +} config; - return ((strilen >= suflen) && (0 == strcmp(string + strilen - suflen, suffix))); -} +static int handle_json(json_t *); +static int json_get_string(json_t *, char const *, char *, char const **); +static int init_addrinfo(char const *, char const *); int -read_config_from_file(char *json_file_path, struct rtr_config **result) +config_init(char const *json_file_path) { + json_t *json_root; + json_error_t json_error; int error; - int is_json_file; - json_t *root_json; - struct rtr_config *config; - struct file_contents fc; - - is_json_file = endsWith(json_file_path, ".json"); - if (!is_json_file) { - log_err("Invalid Json file extension for file '%s'", json_file_path); - return -EINVAL; - } - *result = NULL; - error = file_load(json_file_path, &fc); - if (error) - return error; + if (json_file_path == NULL) + return init_addrinfo(DEFAULT_ADDR, DEFAULT_PORT); - root_json = load_json(fc.buffer); - file_free(&fc); - if (!root_json) + json_root = json_load_file(json_file_path, JSON_REJECT_DUPLICATES, + &json_error); + if (json_root == NULL) { + warnx("JSON error on line %d, column %d: %s", + json_error.line, json_error.column, json_error.text); return -ENOENT; + } - config = malloc(sizeof(struct rtr_config)); - if (!config) - return -ENOMEM; - - error = json_to_config(root_json, config); - if (error) - free(config); + error = handle_json(json_root); - *result = config; - json_decref(root_json); + json_decref(json_root); return error; } -static void -check_duplicates(bool *found, char *section) +void +config_cleanup(void) { - if (*found) - log_err("Note: I found multiple '%s' sections.", section); - *found = true; + if (config.address != NULL) + freeaddrinfo(config.address); + if (config.port != NULL) + free(config.port); } static int -json_to_config(json_t *json, struct rtr_config *config) +handle_json(json_t *root) { - bool listen_found = false; - int error = 0; - const char *key; - json_t *value; + json_t *listen; + char const *address; + char const *port; + int error; - if (!json || json->type != JSON_OBJECT) { - log_err0("Invalid JSON config."); + if (!json_is_object(root)) { + warnx("The root of the JSON file is not a JSON object."); return -EINVAL; } - json_object_foreach(json, key, value) { - if(strcasecmp(OPTNAME_LISTEN, key) == 0) { - check_duplicates(&listen_found, OPTNAME_LISTEN); - error = handle_listen_config(value, config); + listen = json_object_get(root, OPTNAME_LISTEN); + if (listen != NULL) { + if (!json_is_object(listen)) { + warnx("The '%s' element is not a JSON object.", + OPTNAME_LISTEN); + return -EINVAL; } + + error = json_get_string(listen, OPTNAME_LISTEN_ADDRESS, + DEFAULT_ADDR, &address); + if (error) + return error; + + error = json_get_string(listen, OPTNAME_LISTEN_PORT, + DEFAULT_PORT, &port); + if (error) + return error; + + } else { + address = DEFAULT_ADDR; + port = DEFAULT_PORT; } - return error; + return init_addrinfo(address, port); } static int -hostname_to_ip(const char *hostname, struct addrinfo **result) +json_get_string(json_t *parent, char const *name, char *default_value, + char const **result) { - int rv; - struct addrinfo hints, *servinfo; - - memset(&hints, 0 , sizeof hints); - hints.ai_family = AF_UNSPEC; -// hints.ai_socktype = SOCK_DGRAM; - hints.ai_flags |= AI_CANONNAME; + json_t *child; + child = json_object_get(parent, name); + if (child == NULL) { + *result = default_value; + return 0; + } - if ((rv = getaddrinfo(hostname, NULL, &hints, &servinfo)) != 0){ - printf("getaddrinfo: [%d] - %s\n", rv, gai_strerror(rv)); // TODO change to print error or something like that + if (!json_is_string(child)) { + warnx("The '%s' element is not a JSON string.", name); return -EINVAL; } - *result = servinfo; - + *result = json_string_value(child); return 0; } static int -handle_listen_config(json_t *json, struct rtr_config *config) +init_addrinfo(char const *hostname, char const *service) { int error; - bool listen_servername_found = false; - bool listen_port_found = false; - const char *key; - json_t *value; - - if (!json || json->type != JSON_OBJECT) { - log_err0("Invalid JSON config."); - return -EINVAL; - } + struct addrinfo hints; - json_object_foreach(json, key, value) { - if (strcasecmp(OPTNAME_LISTEN_SERVER, key) == 0) { - check_duplicates(&listen_servername_found, OPTNAME_LISTEN_SERVER); - if (json_typeof(value) != JSON_STRING) { - log_err("Invalid value for key '%s'", key); - return -EINVAL; - } - - error = hostname_to_ip(json_string_value(value), &config->host_address); - if (error) - return error; - - } else if (strcasecmp(OPTNAME_LISTEN_PORT, key) == 0) { - check_duplicates(&listen_port_found, OPTNAME_LISTEN_PORT); - if (json_typeof(value) != JSON_INTEGER) { - log_err("Invalid value for key '%s'", key); - return -EINVAL; - } - - config->host_port = (__u16) json_integer_value(value); - } + memset(&hints, 0 , sizeof(hints)); + hints.ai_family = AF_UNSPEC; + /* hints.ai_socktype = SOCK_DGRAM; */ + hints.ai_flags |= AI_PASSIVE; + + error = getaddrinfo(hostname, service, &hints, &config.address); + if (error) { + warnx("Could not infer a bindable address out of address '%s' and port '%s': %s", + (hostname != NULL) ? hostname : "any", service, + gai_strerror(error)); + return error; } + config.port = str_clone(service); return 0; } - -/* - * Parse text into a JSON object. If text is valid JSON, returns a - * json_t structure, otherwise prints and error and returns null. - */ -static json_t *load_json(const char *text) { - json_t *root; - json_error_t error; - - root = json_loads(text, 0, &error); - - if (root) - return root; - else { - log_err("json error on line %d column %d: %s\n", error.line, error.column, error.text); - return (json_t *)0; - } +struct addrinfo const * +config_get_server_addrinfo(void) +{ + return config.address; } +char const * +config_get_server_port(void) +{ + return config.port; +} diff --git a/src/configuration.h b/src/configuration.h index 37980769..145143bf 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -1,18 +1,12 @@ #ifndef _SRC_CONFIGURATION_H_ #define _SRC_CONFIGURATION_H_ -#include "netdb.h" -#include +#include -struct rtr_config { - /** The listener address of the RTR server. */ - struct addrinfo *host_address; - /** The listener port of the RTR server. */ - __u16 host_port; -}; - -void free_rtr_config(struct rtr_config *); -int read_config_from_file(char *, struct rtr_config **); +int config_init(char const *); +void config_cleanup(void); +struct addrinfo const *config_get_server_addrinfo(void); +char const *config_get_server_port(void); #endif /* _SRC_CONFIGURATION_H_ */ diff --git a/src/file.c b/src/file.c deleted file mode 100644 index 72903a7f..00000000 --- a/src/file.c +++ /dev/null @@ -1,90 +0,0 @@ -#include "file.h" - -#include -#include -#include -#include - -#include "common.h" - -/* - * Will also rewind the file as a side effect. - * This is currently perfect for calling users. - */ -static int -get_file_size(FILE *file, long int *size) -{ - if (fseek(file, 0L, SEEK_END) == -1) - return errno ? errno : -EINVAL; - *size = ftell(file); - rewind(file); - return 0; -} - -int -file_load(const char *file_name, struct file_contents *fc) -{ - FILE *file; - long int file_size; - size_t fread_result; - int error; - - file = fopen(file_name, "rb"); - if (file == NULL) { - warnxerrno("Could not open file '%s'", file_name); - return errno; - } - - /* TODO if @file is a directory, this returns a very large integer. */ - error = get_file_size(file, &file_size); - if (error) { - warnxerror0(error, "Could not compute file size"); - fclose(file); - return error; - } - - fc->buffer_size = file_size; - fc->buffer = malloc(fc->buffer_size); - if (fc->buffer == NULL) { - warnx("Out of memory."); - fclose(file); - return -ENOMEM; - } - - fread_result = fread(fc->buffer, 1, fc->buffer_size, file); - if (fread_result < fc->buffer_size) { - error = ferror(file); - if (error) { - /* - * The manpage doesn't say that the result is an error - * code. It literally doesn't say how to obtain the - * error code. - */ - warnx("File read error. The errcode is presumably %d. (%s)", - error, strerror(error)); - free(fc->buffer); - fclose(file); - return error; - } - - /* - * As far as I can tell from the man page, feof() cannot return - * less bytes that requested like read() does. - */ - warnx("Likely programming error: fread() < file size"); - warnx("fr:%zu bs:%zu EOF:%d", fread_result, fc->buffer_size, - feof(file)); - free(fc->buffer); - fclose(file); - return -EINVAL; - } - - fclose(file); - return 0; -} - -void -file_free(struct file_contents *fc) -{ - free(fc->buffer); -} diff --git a/src/file.h b/src/file.h deleted file mode 100644 index 5affcf19..00000000 --- a/src/file.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef SRC_FILE_H_ -#define SRC_FILE_H_ - -#include - -/* - * The entire contents of the file, loaded into a buffer. - * - * Instances of this struct are expected to live on the stack. - */ -struct file_contents { - char *buffer; - size_t buffer_size; -}; - -int file_load(const char *, struct file_contents *); -void file_free(struct file_contents *); - -#endif /* SRC_FILE_H_ */ diff --git a/src/main.c b/src/main.c index 9fea1985..81998c04 100644 --- a/src/main.c +++ b/src/main.c @@ -1,9 +1,11 @@ +#include #include #include #include #include "rtr/rtr.h" #include "configuration.h" + /* * This program is an RTR server. * @@ -15,45 +17,27 @@ int main(int argc, char *argv[]) { - int err = 0; + int err; char *json_file = NULL; - struct rtr_config *config; int c; - int fflag=0; - static char usage[] = "usage: %s -f fname \n"; - - puts("!!!Hello World!!!"); - while ((c = getopt(argc, argv, "f:")) != -1) + while ((c = getopt(argc, argv, "f:")) != -1) { switch (c) { case 'f': - fflag = 1; json_file = optarg; break; case '?': - err = 1; - break; + fprintf(stdout, "usage: %s -f \n", argv[0]); + return 0; } - - if (fflag == 0) { /* -f was mandatory */ - fprintf(stderr, "%s: missing -f option\n", argv[0]); - fprintf(stderr, usage, argv[0]); - exit(1); - } else if (err) { - fprintf(stderr, usage, argv[0]); - exit(1); } - err = read_config_from_file(json_file, &config); + err = config_init(json_file); if (err) return err; - err = rtr_listen(config->host_address, config->host_port); - if (config) - free_rtr_config(config); - - if (err) - return err; + err = rtr_listen(); - return EXIT_SUCCESS; + config_cleanup(); + return err; } diff --git a/src/rtr/rtr.c b/src/rtr/rtr.c index 95622840..fcd0db2b 100644 --- a/src/rtr/rtr.c +++ b/src/rtr/rtr.c @@ -10,126 +10,42 @@ #include #include -#include "../common.h" +#include "configuration.h" #include "pdu.h" -static int -bind_server_socket6(int socket, struct sockaddr_in6 *host_addr, __u16 port) -{ - int err; - struct sockaddr_in6 address; - - memset(&address, 0, sizeof(address)); - address.sin6_family = AF_INET6; - address.sin6_addr.__in6_u = host_addr->sin6_addr.__in6_u; - address.sin6_port = htons(port); - - if (bind(socket, (struct sockaddr *)&address, sizeof(address)) < 0) { - err = errno; - warn("Could not bind the address. errno : %d", -abs(err)); - return -abs(err); - } - - return 0; -} - -static int -bind_server_socket4(int socket, struct sockaddr_in *host_addr, __u16 port) -{ - int err; - struct sockaddr_in address; - - memset(&address, 0, sizeof(address)); - address.sin_family = AF_INET; - address.sin_addr.s_addr = host_addr->sin_addr.s_addr; - address.sin_port = htons(port); - - if (bind(socket, (struct sockaddr *)&address, sizeof(address)) < 0) { - err = errno; - warn("Could not bind the address. errno : %d", -abs(err)); - return -abs(err); - } - - return 0; -} - -static void -log_binded_server_socket(struct addrinfo *host, __u16 port) -{ - char hostaddr[INET6_ADDRSTRLEN]; - struct sockaddr_in *h4; - struct sockaddr_in6 *h6; - - memset(&hostaddr, 0, INET6_ADDRSTRLEN); - switch(host->ai_family) { - case AF_INET: - h4 = (struct sockaddr_in *) host->ai_addr; - inet_ntop(host->ai_family, &h4->sin_addr, (char * restrict) &hostaddr, sizeof(hostaddr)); - pr_debug("Listening %s#%d", hostaddr, port); - break; - case AF_INET6: - h6 = (struct sockaddr_in6 *) host->ai_addr; - inet_ntop(host->ai_family, &h6->sin6_addr, (char * restrict) &hostaddr, sizeof(hostaddr)); - pr_debug("Listening [%s]#%d", hostaddr, port); - break; - default: - warn("Unknown AI_FAMILY type: %d", host->ai_family); - } -} - /* * Creates the socket that will stay put and wait for new connections started * from the clients. */ static int -create_server_socket(struct addrinfo *server_addr, __u16 port) +create_server_socket(void) { + struct addrinfo const *addr; int fd; /* "file descriptor" */ - struct addrinfo *tmp; - int err; - if (server_addr == NULL){ - warn("A server address must be present to bind a socket"); - return -EINVAL; - } + addr = config_get_server_addrinfo(); + for (; addr != NULL; addr = addr->ai_next) { + printf("Attempting to bind socket to address '%s', port '%s'.\n", + (addr->ai_canonname != NULL) ? addr->ai_canonname : "any", + config_get_server_port()); - for (tmp = server_addr; tmp != NULL; tmp = tmp->ai_next) { - err = 0; - fd = socket(tmp->ai_family, SOCK_STREAM, 0); + fd = socket(addr->ai_family, SOCK_STREAM, 0); if (fd < 0) { - err = errno; - err = -abs(err); - warn("Error opening socket. errno : %d", err); + warn("socket() failed"); continue; } - switch(tmp->ai_family) { - case AF_INET: - err = bind_server_socket4(fd, (struct sockaddr_in *) tmp->ai_addr, port); - if (err) - close(fd); - break; - case AF_INET6: - err = bind_server_socket6(fd, (struct sockaddr_in6 *) tmp->ai_addr, port); - if (err) - close(fd); - break; - default: - close(fd); - warn("Can't handle ai_family type: %d", tmp->ai_family); - err = -EINVAL; + if (bind(fd, addr->ai_addr, addr->ai_addrlen) < 0) { + warn("bind() failed"); + continue; } - if (!err) { - log_binded_server_socket(tmp, port); - break; - } + printf("Success.\n"); + return fd; /* Happy path */ } - if (err) - return err; - - return fd; + warnx("None of the addrinfo candidates could be bound."); + return -EINVAL; } /* @@ -197,7 +113,7 @@ client_thread_cb(void *param_void) int err; memcpy(¶m, param_void, sizeof(param)); - free(param_void); + free(param_void); /* Ha. */ while (true) { /* For each PDU... */ err = pdu_load(param.client_fd, &pdu, &meta); @@ -278,11 +194,11 @@ handle_client_connections(int server_fd) * This function blocks. */ int -rtr_listen(struct addrinfo *server_addr, __u16 port) +rtr_listen(void) { int server_fd; /* "file descriptor" */ - server_fd = create_server_socket(server_addr, port); + server_fd = create_server_socket(); if (server_fd < 0) return server_fd; diff --git a/src/rtr/rtr.h b/src/rtr/rtr.h index 6dc990ba..6cae8eab 100644 --- a/src/rtr/rtr.h +++ b/src/rtr/rtr.h @@ -1,13 +1,10 @@ #ifndef RTR_RTR_H_ #define RTR_RTR_H_ -#include -#include - -#include "../common.h" +#include "common.h" __BEGIN_DECLS -int rtr_listen(struct addrinfo *, __u16); +int rtr_listen(void); __END_DECLS #endif /* RTR_RTR_H_ */ diff --git a/test/rtr/stream.c b/test/rtr/stream.c index 808cc296..0902dc62 100644 --- a/test/rtr/stream.c +++ b/test/rtr/stream.c @@ -5,6 +5,8 @@ #include #include +#include "common.h" + /* * Writes exactly @length bytes from @buffer to the file descriptor @fd. * All or nothing. diff --git a/test/rtr/stream.h b/test/rtr/stream.h index 6f94337f..84f3212d 100644 --- a/test/rtr/stream.h +++ b/test/rtr/stream.h @@ -3,8 +3,6 @@ #include -#include "common.h" - __BEGIN_DECLS int write_exact(int, unsigned char *, size_t); int buffer2fd(unsigned char *, size_t);