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);
85 printf("Shutting down\n");
87 pthread_rwlock_wrlock(&server.clients_rwlck);
88 list_clear_func(&server.clients, &list_disconnect_client, NULL);
89 pthread_rwlock_unlock(&server.clients_rwlck);
91 pthread_rwlock_wrlock(&server.players_rwlck);
92 list_clear(&server.players);
93 pthread_rwlock_unlock(&server.players_rwlck);
95 pthread_rwlock_destroy(&server.clients_rwlck);
96 pthread_rwlock_destroy(&server.players_rwlck);
98 shutdown(server.sockfd, SHUT_RDWR);
109 // disconnect a client with various options an an optional detail message (flags: DiscoFlag bitmask)
110 void server_disconnect_client(Client *client, int flags, const char *detail)
112 client->state = CS_DISCONNECTED;
114 if (! (flags & DISCO_NO_REMOVE)) {
116 pthread_rwlock_wrlock(&server.players_rwlck);
117 list_delete(&server.players, client->name);
118 pthread_rwlock_unlock(&server.players_rwlck);
120 pthread_rwlock_wrlock(&server.clients_rwlck);
121 list_delete(&server.clients, client);
122 pthread_rwlock_unlock(&server.clients_rwlck);
125 if (! (flags & DISCO_NO_MESSAGE))
126 printf("Disconnected %s %s%s%s\n", client->name, INBRACES(detail));
128 if (! (flags & DISCO_NO_SEND))
129 send_command(client, CC_DISCONNECT);
131 pthread_mutex_lock(&client->mtx);
133 pthread_mutex_unlock(&client->mtx);
135 if (! (flags & DISCO_NO_JOIN))
136 pthread_join(client->net_thread, NULL);
138 if (client->name != client->address)
140 free(client->address);
142 pthread_mutex_destroy(&client->mtx);
146 // server entry point
147 int main(int argc, char **argv)
149 program_name = argv[0];
152 internal_error("missing port");
154 struct addrinfo hints = {
155 .ai_family = AF_INET6,
156 .ai_socktype = SOCK_STREAM,
158 .ai_flags = AI_NUMERICSERV | AI_PASSIVE,
161 struct addrinfo *info = NULL;
163 int gai_state = getaddrinfo(NULL, argv[1], &hints, &info);
166 internal_error(gai_strerror(gai_state));
168 int fd = socket(info->ai_family, info->ai_socktype, 0);
171 syscall_error("socket");
175 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)) == -1)
176 syscall_error("setsockopt");
178 if (bind(fd, info->ai_addr, info->ai_addrlen) == -1)
179 syscall_error("bind");
181 if (listen(fd, 3) == -1)
182 syscall_error("listen");
184 char *addrstr = address_string((struct sockaddr_in6 *) info->ai_addr);
185 printf("Listening on %s\n", addrstr);
190 signal_handlers_init();