Added a list of running games.
[rlserver.git] / server.c
blob01f2c30e50724ca70a710c90c8c75ca9b23889d3
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <errno.h>
5 #include <string.h>
6 #include <sys/types.h>
7 #include <sys/socket.h>
8 #include <netinet/in.h>
9 #include <arpa/inet.h>
10 #include <sys/wait.h>
11 #include <signal.h>
12 #include <pthread.h>
13 #include <time.h>
14 #include "telnet.h"
15 #include "server.h"
17 #define MAXGAMES 256
18 #define MYPORT 3456
20 #define BACKLOG 3 // how many pending connections queue will hold
23 play_info *playlist = NULL;
24 int play_count = 0;
25 pthread_mutex_t playlist_mutex = PTHREAD_MUTEX_INITIALIZER;
28 play_info* add_play_session (const char *user_name, int game_id, int pty_master)
30 play_info *ps = (play_info*)malloc(sizeof(play_info));
31 if (ps == NULL) return NULL;
33 // fill data
34 ps->prev = NULL;
35 ps->next = NULL;
36 strcpy (ps->user_name, user_name);
37 ps->game_id = game_id;
38 ps->term_wid = 80;
39 ps->term_hgt = 24;
40 ps->pty_master = pty_master;
41 ps->observer_count = 0;
42 ps->observers = NULL;
43 pthread_mutex_init (&ps->mutex, NULL);
44 ps->last_activity = time(NULL);
47 pthread_mutex_lock (&playlist_mutex);
49 // add it to the list
50 if (playlist == NULL)
52 playlist = ps;
54 else
56 play_info *p = playlist;
57 while (p->next != NULL) p = p->next;
58 p->next = ps;
59 ps->prev = p;
61 play_count++;
63 pthread_mutex_unlock (&playlist_mutex);
65 return ps;
70 void remove_play_session (play_info *ps)
72 play_info *p;
74 pthread_mutex_lock (&playlist_mutex);
76 for (p = playlist; p != NULL; p = p->next)
78 if (p != ps) continue;
80 if (p->next) p->next->prev = p->prev;
81 if (p->prev) p->prev->next = p->next;
83 if (playlist == ps) playlist = ps->next;
84 play_count--;
86 free (ps);
88 break;
91 pthread_mutex_unlock (&playlist_mutex);
95 static void sigchld_handler (int s)
97 while (waitpid(-1, NULL, WNOHANG) > 0);
102 static void init_signals (void)
104 struct sigaction sa;
106 sa.sa_handler = sigchld_handler; // reap all dead processes
107 sigemptyset (&sa.sa_mask);
108 sa.sa_flags = SA_RESTART;
109 if (sigaction(SIGCHLD, &sa, NULL) == -1)
111 perror ("sigaction");
112 exit (1);
118 static int open_socket (int port)
120 int sockfd; // listen on sock_fd
121 struct sockaddr_in my_addr; // my address information
122 int yes = 1;
124 if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
126 perror ("socket");
127 return -1;
130 if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
132 perror ("setsockopt");
133 close (sockfd);
134 return -1;
137 my_addr.sin_family = AF_INET; // host byte order
138 my_addr.sin_port = htons(port); // short, network byte order
139 my_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP
140 memset (&(my_addr.sin_zero), 0, 8); // zero the rest of the struct
142 if (bind(sockfd, (struct sockaddr*)&my_addr, sizeof(struct sockaddr)) == -1)
144 perror ("bind");
145 close (sockfd);
146 return -1;
149 if (listen(sockfd, BACKLOG) == -1)
151 perror ("listen");
152 close (sockfd);
153 return -1;
156 return sockfd;
161 typedef struct
163 int sock;
164 } thread_data;
169 * Handle newly connected client in a thread
171 static void* connection_thread (void *data)
173 int r;
174 int sock = ((thread_data*)data)->sock;
175 free (data);
177 send_telnet_init (sock);
179 r = main_menu(sock);
180 printf("menu %d\n", r);
181 if (r == 1) run_game (sock);
183 close (sock);
184 return NULL;
189 static void handle_connect (int new_fd)
191 pthread_attr_t thread_attr;
192 thread_data *data;
193 pthread_t th; // XXX
195 if ((data = malloc(sizeof(thread_data))) == NULL)
197 close (new_fd);
198 // XXX
199 return;
202 data->sock = new_fd;
204 // init thread data
205 pthread_attr_init (&thread_attr);
206 pthread_attr_setdetachstate (&thread_attr, PTHREAD_CREATE_DETACHED);
207 pthread_attr_setscope (&thread_attr, PTHREAD_SCOPE_PROCESS);
209 // handle new connection in a thread
210 if (pthread_create(&th, &thread_attr, connection_thread, data) != 0)
212 free (data);
213 close (new_fd);
218 // socket used to listen for new connections
219 int server_socket = -1;
221 int main (void)
223 init_signals ();
225 server_socket = open_socket(MYPORT);
226 if (server_socket == -1) return 1;
228 while (1)
230 struct sockaddr_in their_addr; // connector's address information
231 socklen_t sin_size = sizeof(struct sockaddr_in);
232 int new_fd;
234 // got a new connection
235 if ((new_fd = accept(server_socket, (struct sockaddr*)&their_addr, &sin_size)) == -1)
237 perror ("accept");
238 continue;
241 printf("server: got connection from %s\n",inet_ntoa(their_addr.sin_addr));
242 handle_connect (new_fd);
245 close (server_socket);
246 pthread_mutex_destroy (&playlist_mutex);
247 return 0;