aboutsummaryrefslogtreecommitdiff
path: root/src/server.c
diff options
context:
space:
mode:
authorFranklin Wei <git@fwei.tk>2015-12-03 17:57:36 -0500
committerFranklin Wei <git@fwei.tk>2015-12-03 17:57:36 -0500
commit1c795424fde9839ab6ebfd49ce7a84ac946be3c0 (patch)
tree2a33473d1ada10efe52b770ce9ec8ab2d452ec20 /src/server.c
downloadnetcosm-1c795424fde9839ab6ebfd49ce7a84ac946be3c0.zip
netcosm-1c795424fde9839ab6ebfd49ce7a84ac946be3c0.tar.gz
netcosm-1c795424fde9839ab6ebfd49ce7a84ac946be3c0.tar.bz2
netcosm-1c795424fde9839ab6ebfd49ce7a84ac946be3c0.tar.xz
initial commit
Diffstat (limited to 'src/server.c')
-rw-r--r--src/server.c142
1 files changed, 142 insertions, 0 deletions
diff --git a/src/server.c b/src/server.c
new file mode 100644
index 0000000..e727d19
--- /dev/null
+++ b/src/server.c
@@ -0,0 +1,142 @@
+/*
+ * NetCosm - a MUD server
+ * Copyright (C) 2015 Franklin Wei
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "netcosm.h"
+
+#define PORT 1234
+#define BACKLOG 16
+
+void __attribute__((noreturn)) error(const char *fmt, ...)
+{
+ char buf[128];
+ memset(buf, 0, sizeof(buf));
+ va_list ap;
+ va_start(ap, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+ va_end(ap);
+ perror(buf);
+ exit(EXIT_FAILURE);
+}
+
+void sigchld_handler(int s)
+{
+ // waitpid() might overwrite errno, so we save and restore it:
+ int saved_errno = errno;
+
+ while(waitpid(-1, NULL, WNOHANG) > 0);
+
+ errno = saved_errno;
+}
+
+int port;
+
+void handle_client(int fd, struct sockaddr_in *addr, int num_clients)
+{
+ client_main(fd, addr, num_clients);
+}
+
+int server_socket;
+
+void serv_cleanup(void)
+{
+ printf("Shutdown server.\n");
+ if(shutdown(server_socket, SHUT_RDWR) > 0)
+ error("shutdown");
+ close(server_socket);
+}
+
+void sigint_handler(int sig)
+{
+ serv_cleanup();
+}
+
+int main(int argc, char *argv[])
+{
+ port = PORT;
+ int sock = socket(AF_INET, SOCK_STREAM, 0);
+
+ if(sock<0)
+ error("socket");
+
+ int tmp = 1;
+
+ if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof tmp) < 0)
+ error("setsockopt");
+
+ struct sockaddr_in addr;
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+
+ addr.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ if(bind(sock, (struct sockaddr*) &addr, sizeof addr) < 0)
+ error("bind");
+
+ if(listen(sock, BACKLOG) < 0)
+ error("listen");
+
+ server_socket = sock;
+
+ struct sigaction sa;
+
+ sa.sa_handler = sigchld_handler; // reap all dead processes
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = SA_RESTART;
+ if (sigaction(SIGCHLD, &sa, NULL) == -1) {
+ perror("sigaction");
+ exit(1);
+ }
+
+ signal(SIGINT, sigint_handler);
+
+ int num_clients = 0;
+
+ if(access(USERFILE, F_OK) < 0)
+ first_run_setup();
+
+ printf("Listening on port %d\n", port);
+
+ while(1)
+ {
+ struct sockaddr_in client;
+ socklen_t client_len;
+ int new_sock = accept(sock, (struct sockaddr*) &client, &client_len);
+ if(new_sock < 0)
+ error("accept");
+
+ pid_t pid = fork();
+ if(pid < 0)
+ error("fork");
+ if(!pid)
+ {
+ close(sock);
+
+ server_socket = new_sock;
+
+ ++num_clients;
+
+ handle_client(new_sock, &client, num_clients);
+
+ --num_clients;
+
+ exit(0);
+ }
+ else
+ close(new_sock);
+ }
+}