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)
71 server.config.simulation_distance = 10;
74 pthread_rwlock_init(&server.clients_rwlck, NULL);
75 server.clients = list_create(NULL);
76 pthread_rwlock_init(&server.players_rwlck, NULL);
77 server.players = list_create(&list_compare_string);
80 server_map_init(&server);
81 server_map_prepare_spawn();
86 printf("Shutting down\n");
88 pthread_rwlock_wrlock(&server.clients_rwlck);
89 list_clear_func(&server.clients, &list_disconnect_client, NULL);
90 pthread_rwlock_unlock(&server.clients_rwlck);
92 pthread_rwlock_wrlock(&server.players_rwlck);
93 list_clear(&server.players);
94 pthread_rwlock_unlock(&server.players_rwlck);
96 pthread_rwlock_destroy(&server.clients_rwlck);
97 pthread_rwlock_destroy(&server.players_rwlck);
99 shutdown(server.sockfd, SHUT_RDWR);
100 close(server.sockfd);
110 // disconnect a client with various options an an optional detail message (flags: DiscoFlag bitmask)
111 void server_disconnect_client(Client *client, int flags, const char *detail)
113 client->state = CS_DISCONNECTED;
115 if (! (flags & DISCO_NO_REMOVE)) {
117 pthread_rwlock_wrlock(&server.players_rwlck);
118 list_delete(&server.players, client->name);
119 pthread_rwlock_unlock(&server.players_rwlck);
121 pthread_rwlock_wrlock(&server.clients_rwlck);
122 list_delete(&server.clients, client);
123 pthread_rwlock_unlock(&server.clients_rwlck);
126 if (! (flags & DISCO_NO_MESSAGE))
127 printf("Disconnected %s %s%s%s\n", client->name, INBRACES(detail));
129 if (! (flags & DISCO_NO_SEND))
130 send_command(client, CC_DISCONNECT);
132 pthread_mutex_lock(&client->mtx);
134 pthread_mutex_unlock(&client->mtx);
136 if (! (flags & DISCO_NO_JOIN))
137 pthread_join(client->net_thread, NULL);
139 if (client->name != client->address)
141 free(client->address);
143 pthread_mutex_destroy(&client->mtx);
147 // server entry point
148 int main(int argc, char **argv)
150 program_name = argv[0];
153 internal_error("missing port");
155 struct addrinfo hints = {
156 .ai_family = AF_INET6,
157 .ai_socktype = SOCK_STREAM,
159 .ai_flags = AI_NUMERICSERV | AI_PASSIVE,
162 struct addrinfo *info = NULL;
164 int gai_state = getaddrinfo(NULL, argv[1], &hints, &info);
167 internal_error(gai_strerror(gai_state));
169 int fd = socket(info->ai_family, info->ai_socktype, 0);
172 syscall_error("socket");
176 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)) == -1)
177 syscall_error("setsockopt");
179 if (bind(fd, info->ai_addr, info->ai_addrlen) == -1)
180 syscall_error("bind");
182 if (listen(fd, 3) == -1)
183 syscall_error("listen");
185 char *addrstr = address_string((struct sockaddr_in6 *) info->ai_addr);
186 printf("Listening on %s\n", addrstr);
191 signal_handlers_init();