Simple echo client
This commit is contained in:
71
src/client.c
71
src/client.c
@ -7,12 +7,25 @@
|
|||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "necronda-server.h"
|
#include "necronda-server.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "net/http.h"
|
#include "net/http.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define out_1(fmt) fprintf(parent_stdout, "%s" fmt "\n", log_base_prefix)
|
||||||
|
#define out_2(fmt, args...) fprintf(parent_stdout, "%s" fmt "\n", log_base_prefix, args)
|
||||||
|
|
||||||
|
#define out_x(x, arg1, arg2, arg3, arg4, arg5, arg6, arg7, FUNC, ...) FUNC
|
||||||
|
|
||||||
|
#define print(...) out_x(, ##__VA_ARGS__, out_2(__VA_ARGS__), out_2(__VA_ARGS__), out_2(__VA_ARGS__), \
|
||||||
|
out_2(__VA_ARGS__), out_2(__VA_ARGS__), out_2(__VA_ARGS__), out_1(__VA_ARGS__))
|
||||||
|
|
||||||
|
|
||||||
|
char *client_addr_str, *client_addr_str_ptr, *server_addr_str, *server_addr_str_ptr, *log_base_prefix, *log_req_prefix;
|
||||||
|
|
||||||
|
|
||||||
int client_websocket_handler() {
|
int client_websocket_handler() {
|
||||||
// TODO implement client_websocket_handler
|
// TODO implement client_websocket_handler
|
||||||
return 0;
|
return 0;
|
||||||
@ -23,32 +36,58 @@ int client_request_handler() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int client_connection_handler() {
|
int client_connection_handler(int client) {
|
||||||
// TODO implement client_connection_handler
|
char buf[256];
|
||||||
|
print("Connection accepted from %s (%s) [%s]", client_addr_str, client_addr_str, "N/A");
|
||||||
|
|
||||||
|
sprintf(buf, "Hello World!\nYour address is: %s\n", client_addr_str);
|
||||||
|
send(client, buf, strlen(buf), 0);
|
||||||
|
close(client);
|
||||||
|
|
||||||
|
print("Connection closed");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pid_t client_handler(int socket) {
|
int client_handler(int socket, long client_num) {
|
||||||
struct sockaddr_in client_addr;
|
struct sockaddr_in6 client_addr, *server_addr;
|
||||||
|
struct sockaddr_storage server_addr_storage;
|
||||||
unsigned int client_addr_len = sizeof(client_addr);
|
unsigned int client_addr_len = sizeof(client_addr);
|
||||||
|
|
||||||
|
char *color_table[] = {"\x1B[31m", "\x1B[32m", "\x1B[33m", "\x1B[34m", "\x1B[35m", "\x1B[36m"};
|
||||||
|
|
||||||
int client = accept(socket, (struct sockaddr *) &client_addr, &client_addr_len);
|
int client = accept(socket, (struct sockaddr *) &client_addr, &client_addr_len);
|
||||||
if (client == -1) {
|
if (client == -1) {
|
||||||
fprintf(stderr, ERR_STR "Unable to accept connection: %s" CLR_STR "\n", strerror(errno));
|
fprintf(parent_stderr, ERR_STR "Unable to accept connection: %s" CLR_STR "\n", strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
pid_t pid = fork();
|
client_addr_str_ptr = malloc(INET6_ADDRSTRLEN);
|
||||||
if (pid == 0) {
|
inet_ntop(client_addr.sin6_family, (void *) &client_addr.sin6_addr, client_addr_str_ptr, INET6_ADDRSTRLEN);
|
||||||
// child
|
if (strncmp(client_addr_str_ptr, "::ffff:", 7) == 0) {
|
||||||
recv(client, NULL, 0, 0);
|
client_addr_str = client_addr_str_ptr + 7;
|
||||||
char buf[] = "Hello world!\n";
|
|
||||||
send(client, buf, strlen(buf), 0);
|
|
||||||
close(client);
|
|
||||||
return 0;
|
|
||||||
} else {
|
} else {
|
||||||
// parent
|
client_addr_str = client_addr_str_ptr;
|
||||||
close(client);
|
|
||||||
return pid;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
socklen_t len = sizeof(server_addr_storage);
|
||||||
|
getsockname(client, (struct sockaddr *) &server_addr_storage, &len);
|
||||||
|
server_addr = (struct sockaddr_in6 *) &server_addr_storage;
|
||||||
|
server_addr_str_ptr = malloc(INET6_ADDRSTRLEN);
|
||||||
|
inet_ntop(server_addr->sin6_family, (void *) &server_addr->sin6_addr, server_addr_str_ptr, INET6_ADDRSTRLEN);
|
||||||
|
if (strncmp(server_addr_str_ptr, "::ffff:", 7) == 0) {
|
||||||
|
server_addr_str = server_addr_str_ptr + 7;
|
||||||
|
} else {
|
||||||
|
server_addr_str = server_addr_str_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_base_prefix = malloc(256);
|
||||||
|
sprintf(log_base_prefix, "[%24s][%s%4i%s]%s[%*s][%5i]%s ",
|
||||||
|
server_addr_str, R_STR, ntohs(server_addr->sin6_port), CLR_STR,
|
||||||
|
color_table[client_num % 6], INET_ADDRSTRLEN, client_addr_str, ntohs(client_addr.sin6_port), CLR_STR);
|
||||||
|
|
||||||
|
int ret = client_connection_handler(client);
|
||||||
|
free(client_addr_str_ptr);
|
||||||
|
free(server_addr_str_ptr);
|
||||||
|
free(log_base_prefix);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -25,26 +25,22 @@ int main(int argc, const char *argv[]) {
|
|||||||
fd_set socket_fds, read_socket_fds;
|
fd_set socket_fds, read_socket_fds;
|
||||||
int max_socket_fd = 0;
|
int max_socket_fd = 0;
|
||||||
int ready_sockets_num = 0;
|
int ready_sockets_num = 0;
|
||||||
|
long client_num = 0;
|
||||||
|
|
||||||
const struct sockaddr_in addresses[2] = {
|
parent_stdout = stdout;
|
||||||
{.sin_family = AF_INET, .sin_addr.s_addr = INADDR_ANY, .sin_port = htons(8080)},
|
parent_stderr = stderr;
|
||||||
{.sin_family = AF_INET, .sin_addr.s_addr = INADDR_ANY, .sin_port = htons(4443)}
|
|
||||||
};
|
const struct sockaddr_in6 addresses[2] = {
|
||||||
const struct sockaddr_in6 addresses6[2] = {
|
|
||||||
{.sin6_family = AF_INET6, .sin6_addr = IN6ADDR_ANY_INIT, .sin6_port = htons(8080)},
|
{.sin6_family = AF_INET6, .sin6_addr = IN6ADDR_ANY_INIT, .sin6_port = htons(8080)},
|
||||||
{.sin6_family = AF_INET6, .sin6_addr = IN6ADDR_ANY_INIT, .sin6_port = htons(4443)}
|
{.sin6_family = AF_INET6, .sin6_addr = IN6ADDR_ANY_INIT, .sin6_port = htons(4443)}
|
||||||
};
|
};
|
||||||
|
|
||||||
printf("Necronda Web Server\n");
|
printf("Necronda Web Server\n");
|
||||||
|
|
||||||
SOCKETS[0] = socket(AF_INET, SOCK_STREAM, 0);
|
SOCKETS[0] = socket(AF_INET6, SOCK_STREAM, 0);
|
||||||
if (SOCKETS[0] == -1) goto socket_err;
|
if (SOCKETS[0] == -1) goto socket_err;
|
||||||
SOCKETS[1] = socket(AF_INET, SOCK_STREAM, 0);
|
SOCKETS[1] = socket(AF_INET6, SOCK_STREAM, 0);
|
||||||
if (SOCKETS[1] == -1) goto socket_err;
|
if (SOCKETS[1] == -1) {
|
||||||
SOCKETS[2] = socket(AF_INET6, SOCK_STREAM, 0);
|
|
||||||
if (SOCKETS[2] == -1) goto socket_err;
|
|
||||||
SOCKETS[3] = socket(AF_INET6, SOCK_STREAM, 0);
|
|
||||||
if (SOCKETS[3] == -1) {
|
|
||||||
socket_err:
|
socket_err:
|
||||||
fprintf(stderr, ERR_STR "Unable to create socket: %s" CLR_STR "\n", strerror(errno));
|
fprintf(stderr, ERR_STR "Unable to create socket: %s" CLR_STR "\n", strerror(errno));
|
||||||
return 1;
|
return 1;
|
||||||
@ -58,9 +54,7 @@ int main(int argc, const char *argv[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (bind(SOCKETS[0], (struct sockaddr *) &addresses[0], sizeof(addresses[0])) == -1) goto bind_err;
|
if (bind(SOCKETS[0], (struct sockaddr *) &addresses[0], sizeof(addresses[0])) == -1) goto bind_err;
|
||||||
if (bind(SOCKETS[1], (struct sockaddr *) &addresses[1], sizeof(addresses[1])) == -1) goto bind_err;
|
if (bind(SOCKETS[1], (struct sockaddr *) &addresses[1], sizeof(addresses[1])) == -1) {
|
||||||
if (bind(SOCKETS[2], (struct sockaddr *) &addresses6[0], sizeof(addresses6[0])) == -1) goto bind_err;
|
|
||||||
if (bind(SOCKETS[3], (struct sockaddr *) &addresses6[1], sizeof(addresses6[1])) == -1) {
|
|
||||||
bind_err:
|
bind_err:
|
||||||
fprintf(stderr, ERR_STR "Unable to bind socket to address: %s" CLR_STR "\n", strerror(errno));
|
fprintf(stderr, ERR_STR "Unable to bind socket to address: %s" CLR_STR "\n", strerror(errno));
|
||||||
return 1;
|
return 1;
|
||||||
@ -85,7 +79,7 @@ int main(int argc, const char *argv[]) {
|
|||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
read_socket_fds = socket_fds;
|
read_socket_fds = socket_fds;
|
||||||
ready_sockets_num = select(max_socket_fd, &read_socket_fds, NULL, NULL, NULL);
|
ready_sockets_num = select(max_socket_fd + 1, &read_socket_fds, NULL, NULL, NULL);
|
||||||
if (ready_sockets_num == -1) {
|
if (ready_sockets_num == -1) {
|
||||||
fprintf(stderr, ERR_STR "Unable to select sockets: %s" CLR_STR "\n", strerror(errno));
|
fprintf(stderr, ERR_STR "Unable to select sockets: %s" CLR_STR "\n", strerror(errno));
|
||||||
return 1;
|
return 1;
|
||||||
@ -93,15 +87,20 @@ int main(int argc, const char *argv[]) {
|
|||||||
|
|
||||||
for (int i = 0; i < NUM_SOCKETS; i++) {
|
for (int i = 0; i < NUM_SOCKETS; i++) {
|
||||||
if (FD_ISSET(SOCKETS[i], &read_socket_fds)) {
|
if (FD_ISSET(SOCKETS[i], &read_socket_fds)) {
|
||||||
pid_t child = client_handler(SOCKETS[i]);
|
pid_t pid = fork();
|
||||||
if (child == 0) {
|
if (pid == 0) {
|
||||||
return 0;
|
// child
|
||||||
} else if (child > 0) {
|
return client_handler(SOCKETS[i], client_num);
|
||||||
|
} else if (pid > 0) {
|
||||||
|
// parent
|
||||||
|
client_num++;
|
||||||
for (int j = 0; j < MAX_CHILDREN; j++) {
|
for (int j = 0; j < MAX_CHILDREN; j++) {
|
||||||
if (CHILDREN[j] == 0) {
|
if (CHILDREN[j] == 0) {
|
||||||
CHILDREN[j] = child;
|
CHILDREN[j] = pid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, ERR_STR "Unable to create child process: %s" CLR_STR "\n", strerror(errno));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,17 +9,22 @@
|
|||||||
#define NECRONDA_SERVER_NECRONDA_SERVER_H
|
#define NECRONDA_SERVER_NECRONDA_SERVER_H
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
|
||||||
#define NUM_SOCKETS 4
|
#define NUM_SOCKETS 2
|
||||||
#define MAX_CHILDREN 1024
|
#define MAX_CHILDREN 1024
|
||||||
#define LISTEN_BACKLOG 16
|
#define LISTEN_BACKLOG 16
|
||||||
|
|
||||||
#define ERR_STR "\x1B[1;31m"
|
#define ERR_STR "\x1B[1;31m"
|
||||||
#define CLR_STR "\x1B[0m"
|
#define CLR_STR "\x1B[0m"
|
||||||
|
#define R_STR "\x1B[31m"
|
||||||
|
#define G_STR "\x1B[32m"
|
||||||
|
|
||||||
int SOCKETS[NUM_SOCKETS];
|
int SOCKETS[NUM_SOCKETS];
|
||||||
pid_t CHILDREN[MAX_CHILDREN];
|
pid_t CHILDREN[MAX_CHILDREN];
|
||||||
|
|
||||||
|
FILE *parent_stdout, *parent_stderr;
|
||||||
|
|
||||||
|
|
||||||
#endif //NECRONDA_SERVER_NECRONDA_SERVER_H
|
#endif //NECRONDA_SERVER_NECRONDA_SERVER_H
|
||||||
|
Reference in New Issue
Block a user