6 #include "server/database.h"
7 #include "server/server.h"
8 #include "server/server_map.h"
9 #include "signal_handlers.h"
14 // include handle_packets implementation
20 // pthread start routine for reciever thread
21 static void *reciever_thread(void *arg)
25 if (! handle_packets(client))
26 server_disconnect_client(client, DISCO_NO_SEND | DISCO_NO_JOIN, "network error");
31 // accept a new connection, initialize client and start reciever thread
32 static void accept_client()
34 struct sockaddr_storage client_address = {0};
35 socklen_t client_addrlen = sizeof(client_address);
37 int fd = accept(server.sockfd, (struct sockaddr *) &client_address, &client_addrlen);
45 Client *client = malloc(sizeof(Client));
47 pthread_mutex_init(&client->mtx, NULL);
48 client->state = CS_CREATED;
49 client->address = address_string((struct sockaddr_in6 *) &client_address);
50 client->name = client->address;
51 client->server = &server;
52 client->pos = (v3f64) {0.0f, 0.0f, 0.0f};
53 pthread_create(&client->net_thread, NULL, &reciever_thread, client);
55 pthread_rwlock_wrlock(&server.clients_rwlck);
56 list_put(&server.clients, client, NULL);
57 pthread_rwlock_unlock(&server.clients_rwlck);
59 printf("Connected %s\n", client->address);
62 // list_clear_func callback used on server shutdown to disconnect all clients properly
63 static void list_disconnect_client(void *key, unused void *value, unused void *arg)
65 server_disconnect_client(key, DISCO_NO_REMOVE | DISCO_NO_MESSAGE, "");
68 // start up the server after socket was created, then accept connections until interrupted, then shutdown server
69 static void server_run(int fd)
72 pthread_rwlock_init(&server.clients_rwlck, NULL);
73 server.clients = list_create(NULL);
74 pthread_rwlock_init(&server.players_rwlck, NULL);
75 server.players = list_create(&list_compare_string);
78 server_map_init(&server);
79 server_map_prepare_spawn();
84 printf("Shutting down\n");
86 pthread_rwlock_wrlock(&server.clients_rwlck);
87 list_clear_func(&server.clients, &list_disconnect_client, NULL);
88 pthread_rwlock_unlock(&server.clients_rwlck);
90 pthread_rwlock_wrlock(&server.players_rwlck);
91 list_clear(&server.players);
92 pthread_rwlock_unlock(&server.players_rwlck);
94 pthread_rwlock_destroy(&server.clients_rwlck);
95 pthread_rwlock_destroy(&server.players_rwlck);
97 shutdown(server.sockfd, SHUT_RDWR);
108 // disconnect a client with various options an an optional detail message (flags: DiscoFlag bitmask)
109 void server_disconnect_client(Client *client, int flags, const char *detail)
111 client->state = CS_DISCONNECTED;
113 if (! (flags & DISCO_NO_REMOVE)) {
115 pthread_rwlock_wrlock(&server.players_rwlck);
116 list_delete(&server.players, client->name);
117 pthread_rwlock_unlock(&server.players_rwlck);
119 pthread_rwlock_wrlock(&server.clients_rwlck);
120 list_delete(&server.clients, client);
121 pthread_rwlock_unlock(&server.clients_rwlck);
124 if (! (flags & DISCO_NO_MESSAGE))
125 printf("Disconnected %s %s%s%s\n", client->name, INBRACES(detail));
127 if (! (flags & DISCO_NO_SEND))
128 send_command(client, CC_DISCONNECT);
130 pthread_mutex_lock(&client->mtx);
132 pthread_mutex_unlock(&client->mtx);
134 if (! (flags & DISCO_NO_JOIN))
135 pthread_join(client->net_thread, NULL);
137 if (client->name != client->address)
139 free(client->address);
141 pthread_mutex_destroy(&client->mtx);
145 // server entry point
146 int main(int argc, char **argv)
148 program_name = argv[0];
151 internal_error("missing port");
153 struct addrinfo hints = {
154 .ai_family = AF_INET6,
155 .ai_socktype = SOCK_STREAM,
157 .ai_flags = AI_NUMERICSERV | AI_PASSIVE,
160 struct addrinfo *info = NULL;
162 int gai_state = getaddrinfo(NULL, argv[1], &hints, &info);
165 internal_error(gai_strerror(gai_state));
167 int fd = socket(info->ai_family, info->ai_socktype, 0);
170 syscall_error("socket");
174 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)) == -1)
175 syscall_error("setsockopt");
177 if (bind(fd, info->ai_addr, info->ai_addrlen) == -1)
178 syscall_error("bind");
180 if (listen(fd, 3) == -1)
181 syscall_error("listen");
183 char *addrstr = address_string((struct sockaddr_in6 *) info->ai_addr);
184 printf("Listening on %s\n", addrstr);
189 signal_handlers_init();