So, for context, I have started writing a small HTTP-Server for learning purposes. Currently, I have 2 modules: server, and Logger. The server module uses the logger I wrote internally for logging messages. I will add the 2 modules here as follows: server.h + server.c, then Logger.h and Logger.c
struct server {
int socket_fd;
struct addrinfo *serv_info;
char port[6];
char ip_str[INET6_ADDRSTRLEN];
int backlog;
};
server *server_init(server *serv, char *addr, char *port) {
int status = 0;
struct addrinfo hints = {0};
if (serv == NULL)
return NULL;
if (port == NULL) {
log_msg(COMMUNICATION, ERROR, "Please provide a non-null port to bind to");
return NULL;
}
hints.ai_socktype = SOCK_STREAM;
hints.ai_family = AF_UNSPEC;
hints.ai_flags = AI_PASSIVE;
status = getaddrinfo(addr, port, &hints, &serv->serv_info);
if (status != 0) {
log_msg(COMMUNICATION, ERROR, "GetAddrInfo error: [%d]", status);
return NULL;
}
struct addrinfo *p;
for (p = serv->serv_info; p != NULL; p = p->ai_next) {
serv->socket_fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if (serv->socket_fd < 0) continue;
int yes = 1;
setsockopt(serv->socket_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
status = bind(serv->socket_fd, p->ai_addr, p->ai_addrlen);
if (status < 0) {
log_msg(COMMUNICATION, ERROR, "Could not bind to port: [%s]", port);
goto err_cleanup;
}
/* finish up initializing the structure */
serv->backlog = BACKLOG;
memcpy(serv->port, port, strlen(port));
serv->port[strlen(port)] = '\0';
inet_pton(
serv->serv_info->ai_family,
serv->serv_info->ai_addr->sa_data,
serv->ip_str
);
break;
}
if (p == NULL) {
log_msg(COMMUNICATION, ERROR, "Failed to bind to any socket");
goto err_cleanup;
}
status = listen(serv->socket_fd, serv->backlog);
if (status < 0) {
log_msg(COMMUNICATION, ERROR, "Failed to listen on socket");
goto err_cleanup;
}
return serv;
err_cleanup:
freeaddrinfo(serv->serv_info);
return NULL;
}
And for the Logger:
#include
typedef enum {
INFORMATION,
DEBUG,
WARNING,
ERROR,
CRITICAL
} eLogLevel;
#define LOG_SUBS_COUNT 4
typedef enum {
COMMUNICATION,
DISPLAY,
SYSTEM,
SENSOR
} eLogSubSystem;
typedef struct s_log_struct {
eLogLevel subs_levels[LOG_SUBS_COUNT];
int fd;
int enabled;
void (*output_func)(const char *msg);
} Logger;
void log_msg(eLogSubSystem system, eLogLevel level, const char *fmt, ...);
void log_msg(eLogSubSystem system, eLogLevel level, const char *fmt, ...) {
pthread_mutex_lock(&lock);
if (!gLogData || !gLogData->enabled || level < gLogData->subs_levels[system]) {
pthread_mutex_unlock(&lock);
return;
}
char buffer[1024];
int offset = 0;
rfc8601_timespec(buffer, 64);
offset = strlen(buffer);
offset += snprintf(buffer + offset, sizeof(buffer) - offset,
"[%s][%s] ",
subsystem_to_str(system),
level_to_str(level));
if (offset < sizeof(buffer) - 1) {
va_list args;
va_start(args, fmt);
offset += vsnprintf(buffer + offset, sizeof(buffer) - offset, fmt, args);
va_end(args);
}
if (offset >= sizeof(buffer)) {
offset = sizeof(buffer) - 2;
}
buffer[offset] = '\n';
buffer[offset + 1] = '\0';
gLogData->output_func(buffer);
pthread_mutex_unlock(&lock);
}
I have included the only 2 relevant functions, I believe
The thing is: on the line:
if (port == NULL) {
log_msg(COMMUNICATION, ERROR, "Please provide a non-null port to bind to");
return NULL;
}
When I send back a dummy GET-response in my main:
client_fd = accept(
server.socket_fd,
(struct sockaddr *) &client_addr,
&client_size
);
if (client_fd < 0) {
log_msg(COMMUNICATION, DEBUG, "Could not accept client");
continue;
}
log_msg(COMMUNICATION, DEBUG, "Accepted client: [%d]", client_fd);
response = "HTTP/1.0 200 OK \r\n"
"\r\n"
"Hello world\n";
write(client_fd, response, 256);
close(client_fd);
The output comes as:
HTTP/1.0 200 OK
Hello world Please provide a non-null port to bind tot\Llh8,Lh(|h(x0xd|^C
Now, I know that I need to write the exact amount of characters I have in the response, that is not the question. The question is why does the log_msg get appeneded to the end of the response buffer? How do the 2 interact?