summaryrefslogtreecommitdiff
path: root/src/net_server.c
diff options
context:
space:
mode:
authorReiner Herrmann <reiner@reiner-h.de>2011-01-15 17:28:08 +0100
committerReiner Herrmann <reiner@reiner-h.de>2011-01-15 17:28:08 +0100
commitd9b86b44ff96e7ca87af4c5dee7a61f61b55f603 (patch)
treef23f00a10c81fc5caf0eacdf8864859db7d7d372 /src/net_server.c
parent490e4ac6bbcdd431fd3cbe47f276b8d4ed66dd2b (diff)
splitted net.c into server/client files
Diffstat (limited to 'src/net_server.c')
-rw-r--r--src/net_server.c203
1 files changed, 203 insertions, 0 deletions
diff --git a/src/net_server.c b/src/net_server.c
new file mode 100644
index 0000000..39b6c51
--- /dev/null
+++ b/src/net_server.c
@@ -0,0 +1,203 @@
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <assert.h>
+#include "net.h"
+#include "player.h"
+
+/**
+ * Server side function; start server on specified port
+ * @param[in] port Port on which server should listen
+ * @return Listening socket
+ */
+int server_start(const char* port)
+{
+ int status;
+ int serversock;
+ struct addrinfo hints, *result, *tmp;
+
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = AF_UNSPEC; // IPv4 or IPv6
+ hints.ai_socktype = SOCK_STREAM; // TCP socket
+ hints.ai_flags = AI_PASSIVE; // wildcard IP
+ hints.ai_protocol = 0; // any protocol
+
+ status = getaddrinfo(NULL, port, &hints, &result);
+ if(status != 0)
+ {
+ printf("getaddrinfo: %s\n", gai_strerror(status));
+ exit(EXIT_FAILURE);
+ }
+
+ // iterate over linked addrinfo list and use first useable entry
+ for(tmp = result; tmp != NULL; tmp = tmp->ai_next)
+ {
+ int yes=1;
+
+ // create socket
+ serversock = socket(tmp->ai_family, tmp->ai_socktype, tmp->ai_protocol);
+ if(serversock == -1)
+ continue;
+
+ // try to reuse still open sockets in TIME_WAIT state
+ setsockopt(serversock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
+
+ // try to bind to address/port
+ if(bind(serversock, tmp->ai_addr, tmp->ai_addrlen) == 0)
+ break; // Success!
+
+ close(serversock);
+ }
+
+ if(tmp == NULL)
+ {
+ printf("failed to bind\n");
+ exit(EXIT_FAILURE);
+ }
+ freeaddrinfo(result);
+
+ // start listening
+ status = listen(serversock, 1);
+ if(status == -1)
+ {
+ printf("listen: %s\n", strerror(status));
+ exit(EXIT_FAILURE);
+ }
+
+ return serversock;
+}
+
+/**
+ * Server side function; accepts connections from clients
+ * @param[in] serversock Socket on which server is listening
+ * @param[in] count Number of clients that should connect
+ * @return List of $count open sockets with connections to clients
+ */
+int* server_get_players(int serversock, const uint8_t count)
+{
+ int* clientsocks;
+ int i;
+
+ assert(count < MAX_PLAYERS && count > 0);
+
+ clientsocks = malloc(count*sizeof(int));
+ if(clientsocks == NULL)
+ {
+ printf("server_get_players: Out of memory\n");
+ exit(EXIT_FAILURE);
+ }
+
+ // accept connections
+ for(i=0; i<count; i++)
+ {
+ int sock;
+ struct sockaddr_storage addr;
+ socklen_t addrlen = sizeof(addr);
+ sock = accept(serversock, (struct sockaddr*) &addr, &addrlen);
+ if(sock == -1)
+ {
+ printf("accept: %s\n", strerror(sock));
+ exit(EXIT_FAILURE);
+ }
+ //printf("new client connected: %s\n", inet_ntop(sock.ss_family, get_in_addr((struct sockaddr*)&sock), INET6_ADDRSTRLEN));
+ printf("new client connected (%d/%d)\n", i+1, count);
+ clientsocks[i] = sock;
+ }
+
+ return clientsocks;
+}
+
+void server_start_game(int* clients, const uint8_t clientcount, const struct player_list* players)
+{
+ uint8_t* buf;
+ uint8_t usercount = players->count;
+ uint32_t pos = 0;
+ uint32_t buflen = 2 + usercount; // type + usercount + (usercount * len)
+
+ for(int i=0; i<usercount; i++)
+ buflen += strlen(players->names[i]);
+
+ buf = malloc(buflen);
+ if(buf == NULL)
+ {
+ printf("server_start_game: Out of memory\n");
+ exit(EXIT_FAILURE);
+ }
+ buf[pos++] = msg_type_start_game;
+ buf[pos++] = players->count;
+ // copy usernames with length to buffer
+ for(int i=0; i<usercount; i++)
+ {
+ uint8_t len = strlen(players->names[i]);
+ buf[pos++] = len;
+ memcpy(buf+pos, players->names[i], len);
+ pos += len;
+ }
+
+ // send to all users
+ for(int i=0; i<clientcount; i++)
+ send(clients[i], buf, buflen, 0);
+
+ free(buf);
+}
+
+/**
+ * Server side function; receive hello message from client and read username
+ * @param[in] sock Socket to use
+ * @return Username of client
+ */
+static char* server_recv_hello(int sock)
+{
+ char buf[12], *name;
+ uint8_t namelen;
+
+ recv(sock, buf, 12, 0);
+
+ assert(buf[0] == msg_type_hello);
+
+ namelen = buf[1];
+ name = malloc(namelen+1);
+ if(name == NULL)
+ {
+ printf("sender_recv_hello: Out of memory\n");
+ exit(EXIT_FAILURE);
+ }
+
+ memcpy(name, buf+2, namelen);
+ name[namelen] = '\0';
+
+ return name;
+}
+
+/**
+ * Server side function; calls correct handler for incoming packet
+ * @param[in] sock Socket to use
+ * @param[in] wanted Packet type that should be handled
+ * @return Pointer to desired data or NULL if not in recv queue
+ */
+void* server_recv(int sock, uint8_t wanted)
+{
+ void* result = NULL;
+ uint8_t buf[10], type;
+ ssize_t len = recv(sock, buf, 10, MSG_PEEK); // just peek into packet to determine type
+
+ assert(len != -1);
+
+ type = buf[0];
+ if(type != wanted)
+ return NULL;
+
+ switch(type)
+ {
+ case msg_type_hello:
+ result = server_recv_hello(sock);
+ break;
+ }
+
+ return result;
+}
+