added (single) client / server architecture

Wed, 05 Feb 2014 14:07:43 +0100

author
Mike Becker <universe@uap-core.de>
date
Wed, 05 Feb 2014 14:07:43 +0100
changeset 1
e5fbb8f9edbe
parent 0
98034084033f
child 2
0a08f79c320d

added (single) client / server architecture

conf.mk file | annotate | diff | comparison | revisions
src/Makefile file | annotate | diff | comparison | revisions
src/main.c file | annotate | diff | comparison | revisions
src/network.c file | annotate | diff | comparison | revisions
src/network.h file | annotate | diff | comparison | revisions
src/terminal-chess.h file | annotate | diff | comparison | revisions
--- a/conf.mk	Thu Jan 23 14:45:34 2014 +0100
+++ b/conf.mk	Wed Feb 05 14:07:43 2014 +0100
@@ -31,7 +31,7 @@
 RM      = rm
 
 # build related
-BIN     = c2html
+BIN     = terminal-chess
 CC      = gcc
 CFLAGS  = -g -O2 -std=gnu99 -Wall -Werror -pedantic
 LD      = gcc
--- a/src/Makefile	Thu Jan 23 14:45:34 2014 +0100
+++ b/src/Makefile	Wed Feb 05 14:07:43 2014 +0100
@@ -29,6 +29,7 @@
 include ../conf.mk
 
 SRC  = main.c
+SRC += network.c
 
 OBJ = $(SRC:%.c=../build/%$(OBJ_EXT))
 
--- a/src/main.c	Thu Jan 23 14:45:34 2014 +0100
+++ b/src/main.c	Wed Feb 05 14:07:43 2014 +0100
@@ -27,9 +27,98 @@
  *
  */
 
-#include <stdlib.h>
+#include "terminal-chess.h"
+#include <string.h>
+
+int get_settings(int argc, char **argv, Settings *settings) {
+    char *valid;
+    
+    for (char opt ; (opt = getopt(argc, argv, "hp:")) != -1 ;) {
+        switch (opt) {
+            case 'p':
+                if (strtol(optarg, &valid, 10) < 1025 || *valid != '\0') {
+                    fprintf(stderr,
+                        "Invalid port number (%s) - choose a number > 1024\n",
+                        optarg);
+                    return 1;
+                } else {
+                    settings->port = optarg;
+                }
+                break;
+            case 'h':
+            case '?':
+                settings->printhelp = 1;
+                break;
+        }
+    }
+    
+    if (optind == argc - 1) {
+        settings->serverhost = argv[optind];
+    } else if (optind < argc - 1) {
+        fprintf(stderr, "Too many arguments\n");
+        return 1;
+    }
+    
+    return 0;
+}
+
+Settings default_settings() {
+    Settings settings;
+    memset(&settings, 0, sizeof(Settings));
+    settings.port = "27015";
+    return settings;
+}
+
+int cleanup(Settings *settings, int exitcode) {
+    if (settings->server) {
+        if (net_destroy(settings->server)) {
+            perror("Server shutdown failed");
+        }
+    }
+    
+    return exitcode;
+}
 
 int main(int argc, char **argv) {
-    return EXIT_SUCCESS;
+    
+    Settings settings = default_settings();
+    get_settings(argc, argv, &settings);
+    
+    if (settings.printhelp) {
+        printf(
+            "Usage: %s [OPTION]... [HOST]\n"
+            "Starts/joins a network chess game\n\n"
+            "  -h            This help page\n"
+            "  -p            TCP port to use (default: 27015)\n",
+            argv[0]);
+        return EXIT_SUCCESS;
+    }
+    
+    Server server;
+    settings.server = &server;
+    
+    if (is_server(&settings)) {
+        if (net_find(&server, settings.serverhost, settings.port)) {
+            perror("Can't find server");
+            return cleanup(&settings, EXIT_FAILURE);
+        }
+        
+        if (net_connect(&server)) {
+            perror("Can't connect to server");
+            return cleanup(&settings, EXIT_FAILURE);
+        }
+    } else {
+        if (net_create(&server, settings.port)) {
+            perror("Server creation failed");
+            return cleanup(&settings, EXIT_FAILURE);
+        }
+        
+        if (net_listen(&server)) {
+            perror("Listening for client failed");
+            return cleanup(&settings, EXIT_FAILURE);
+        }
+    }
+    
+    return cleanup(&settings, EXIT_SUCCESS);
 }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/network.c	Wed Feb 05 14:07:43 2014 +0100
@@ -0,0 +1,115 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2014 Mike Becker. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "network.h"
+
+int server_bind(Server *server) {
+    server->fd = socket(server->info->ai_family,
+        server->info->ai_socktype, server->info->ai_protocol);
+    if (server->fd > -1) {
+        int true = 1;
+        setsockopt(server->fd, SOL_SOCKET, SO_REUSEADDR, &true, sizeof(int));
+        if (bind(server->fd,
+                server->info->ai_addr, server->info->ai_addrlen)) {
+            server->fd = -1;
+            return 1;
+        } else {
+            return 0;
+        }
+    } else {
+        return 1;
+    }
+}
+
+int net_create(Server *server, char* port) {
+    return net_find(server, "localhost", port) || server_bind(server);
+}
+
+int getaddrinfo_intrnl(char *host, char *port, struct addrinfo **info) {
+    struct addrinfo hints;
+    memset(&hints, 0, sizeof(hints));
+    hints.ai_socktype = SOCK_STREAM;
+    hints.ai_protocol = IPPROTO_TCP;
+    
+    return getaddrinfo(host, port, &hints, info);
+}
+
+int net_find(Server *server, char *host, char* port) {
+    memset(server, 0, sizeof(Server));
+    server->fd = -1;
+    
+    return getaddrinfo_intrnl(host, port, &(server->info));
+}
+
+int net_listen(Server *server) {
+    listen(server->fd, 1);
+    Client* client = calloc(1, sizeof(Client));
+    client->fd = -1;
+    server->client = client;
+    
+    client->fd = accept(server->fd,
+        &(client->address), &(client->address_len));
+    
+    return client->fd == -1;
+}
+
+int net_connect(Server *server) {
+    struct addrinfo *info;
+    if (getaddrinfo_intrnl("localhost", NULL, &info)) {
+        return 1;
+    }
+    
+    Client* client = calloc(1, sizeof(Client));
+    client->fd = socket(info->ai_family, info->ai_socktype, info->ai_protocol);
+    server->client = client;
+    
+    freeaddrinfo(info);
+    if (client->fd == -1) {
+        return 1;
+    }
+    
+    return connect(client->fd, server->info->ai_addr, server->info->ai_addrlen);
+}
+
+int net_destroy(Server *server) {
+    if (server->info) {
+        freeaddrinfo(server->info);
+    }
+    if (server->client) {
+        shutdown(server->client->fd, SHUT_RDWR);
+        free(server->client);
+    }
+    if (server->fd > -1) {
+        return shutdown(server->fd, SHUT_RDWR);
+    }
+    
+    return EXIT_SUCCESS;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/network.h	Wed Feb 05 14:07:43 2014 +0100
@@ -0,0 +1,65 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2014 Mike Becker. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef TCHESS_NETWORK_H
+#define	TCHESS_NETWORK_H
+
+#include <sys/socket.h>
+#include <netdb.h>
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+    int fd;
+    struct sockaddr address;
+    socklen_t address_len;
+} Client;
+
+typedef struct {
+    int fd;
+    struct addrinfo* info;
+    Client *client;
+} Server;
+
+int net_create(Server *server, char* port);
+int net_find(Server *server, char* host, char* port);
+
+int net_listen(Server *server);
+int net_destroy(Server *server);
+int net_connect(Server *server);
+
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* TCHESS_NETWORK_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/terminal-chess.h	Wed Feb 05 14:07:43 2014 +0100
@@ -0,0 +1,56 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2014 Mike Becker. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <getopt.h>
+#include "network.h"
+
+#ifndef TERMINAL_CHESS_H
+#define	TERMINAL_CHESS_H
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+    int printhelp;
+    char* port;
+    char* serverhost; /* NULL, if we are about to start a server */
+    Server *server;
+} Settings;
+
+#define is_server(settings) ((settings)->serverhost)
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* TERMINAL_CHESS_H */
+

mercurial