From 40607b98aa9e138f45cb93c1776fe499dca877a4 Mon Sep 17 00:00:00 2001 From: socec Date: Thu, 6 Mar 2014 02:23:16 +0100 Subject: [PATCH] introducing files --- build.sh | 12 +++++ client.c | 48 ++++++++++++++++++ moxerver | Bin 0 -> 11318 bytes moxerver.c | 120 +++++++++++++++++++++++++++++++++++++++++++++ moxerver_include.h | 61 +++++++++++++++++++++++ server.c | 112 ++++++++++++++++++++++++++++++++++++++++++ tty.c | 26 ++++++++++ 7 files changed, 379 insertions(+) create mode 100755 build.sh create mode 100644 client.c create mode 100755 moxerver create mode 100644 moxerver.c create mode 100644 moxerver_include.h create mode 100644 server.c create mode 100644 tty.c diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..7c8ca4a --- /dev/null +++ b/build.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +# Builds MoxaNix project + +#TODO switch to Makefile :) + +name="moxerver" + +include_dir="." +src_list="$name.c server.c client.c tty.c" + +gcc $src_list -o $name -I $include_dir diff --git a/client.c b/client.c new file mode 100644 index 0000000..661e67b --- /dev/null +++ b/client.c @@ -0,0 +1,48 @@ +#include "moxerver_include.h" + + +/* Closes client connection. */ +int client_close(struct client_t *client) { + /* force closing in case of error */ + if (close(client->socket) == -1) { + close(client->socket); + } + client->socket = -1; + fprintf(stderr,"[%s]: socket closed for client %s\n", __func__, client->ip_string); + return 0; +} + +/* Reads incoming data from client to client data buffer. */ +int client_read(struct client_t *client) { + + int len; + + /* read client data */ + len = recv(client->socket, client->data, sizeof(client->data)-1, 0); + if (len == -1) { + fprintf(stderr, "[%s:%d] error %d: %s\n", __func__, __LINE__, errno, strerror(errno)); + return -errno; + } + /* null-terminate received data */ + client->data[len] = '\0'; + + //TODO how does a client disconnect? For now let's wait for QUIT command... + if (!strncmp(client->data, "QUIT", 4)) { + client_close(client); + } + + //TODO let's print the data during development phase... + fprintf(stderr, "client %s says: %s", client->ip_string, client->data); + + return 0; +} + +/* Sends data from a buffer to client. */ +int client_write(struct client_t *client, char *databuf, int datalen) { + /* send data to client */ + if (send(client->socket, databuf, datalen, 0) == -1) { + fprintf(stderr, "[%s:%d] error %d: %s\n", __func__, __LINE__, errno, strerror(errno)); + return -errno; + } + return 0; +} diff --git a/moxerver b/moxerver new file mode 100755 index 0000000000000000000000000000000000000000..7898d6d8c56e4c3cc169753d176dcebb11c1a7a9 GIT binary patch literal 11318 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 /* getopt() */ + + +#define SERVER_WAIT_TIMEOUT 5 /* seconds for select() timeout in server loop */ + +/* Prints help message. */ +void usage() { + //TODO maybe some styling should be done + fprintf(stderr, "Usage: moxerver -p port [-h]\n\n"); +} + +/* MoxaNix main program loop. */ +int main(int argc, char *argv[]) { + + int ret; + + struct server_t server; + struct client_t client; //TODO working with only 1 client, this can be expanded into a list + unsigned int port; + + fd_set read_fds; + int fdmax; + struct timeval tv; + + + /* grab argumments */ + while ((ret = getopt(argc, argv, ":p:h")) != -1) { + switch (ret) { + /* get server port number */ + case 'p': + port = (unsigned int) atoi(optarg); + /* check port range */ + if (port < 4001 || port > 4008) { + fprintf(stderr, "error: port number out of 4001-4008 range\n"); + return -1; + } + break; + /* print help and exit */ + case 'h': + usage(); + return 0; + default: + fprintf(stderr, "error parsing arguments\n"); + usage(); + return 0; + } + } + + /* introduction message */ + fprintf(stderr, "=== MoxaNix ===\n"); + + /* initialize */ + server_setup(&server, port); + client.socket = -1; + + //TODO this is a good place to create and start the TTY thread + + /* loop with timeouts waiting for client connection */ + while (1) { + + /* setup parameters for select() */ + tv.tv_sec = SERVER_WAIT_TIMEOUT; + tv.tv_usec = 0; + FD_ZERO(&read_fds); + FD_SET(server.socket, &read_fds); + if (client.socket != -1) { + FD_SET(client.socket, &read_fds); /* wait for client if connected */ + } + fdmax = (server.socket > client.socket) ? server.socket : client.socket; + + /* wait with select() */ + ret = select(fdmax+1, &read_fds, NULL, NULL, &tv); + if (ret == -1) { + //TODO do we really break and stop server when select returns an error? + fprintf(stderr, "[%s:%d] error %d: %s\n", __func__, __LINE__, errno, strerror(errno)); + break; + } + if (ret > 0) { + /* check server status */ + if (FD_ISSET(server.socket, &read_fds)) { + fprintf(stderr, "received client connection request\n"); + /* accept connection request if there is no client connected yet */ + if (client.socket == -1) { + ret = server_accept(&server, &client); + if ( ret != 0) { + /* print error but continue waiting for connection request */ + fprintf(stderr, "problem accepting client\n"); + continue; + } + } + /* reject connection request if a client is already connected */ + else { + server_reject(&server); + } + } + /* check client status if connected */ + if ( (client.socket != -1) && FD_ISSET(client.socket, &read_fds) ) { + /* read client data */ + ret = client_read(&client); + if ( ret != 0) { + /* print error but continue waiting for new data */ + fprintf(stderr, "problem reading client\n"); + continue; + } + //TODO we should send this data to TTY device + } + } + if (ret == 0) { + fprintf(stderr, "server waiting\n"); + } + + } /* END while loop */ + + /* close server and client */ + server_close(&server); + client_close(&client); + + return 0; +} \ No newline at end of file diff --git a/moxerver_include.h b/moxerver_include.h new file mode 100644 index 0000000..e79f63d --- /dev/null +++ b/moxerver_include.h @@ -0,0 +1,61 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DATA_BUFLEN 128 + + +struct server_t { + int socket; /* server socket */ + struct sockaddr_in address; /* server address information */ + unsigned int port; /* server port in host byte order, practical reference */ +}; + +struct client_t { + int socket; /* client socket */ + struct sockaddr_in address; /* client address information */ + char ip_string[INET_ADDRSTRLEN]; /* client IP address as a string */ + char data[DATA_BUFLEN]; /* buffer for data received from client */ +}; + +struct tty_t { + int fd; /* tty file descriptor */ + struct termios ttyset; /* tty termios settings */ + char data[DATA_BUFLEN]; /* buffer for data received from tty */ +}; + + +/* Sets up the server on specific port, binds to a socket and listens for client connections. */ +int server_setup(struct server_t *server, unsigned int port); +/* Closes the server. */ +int server_close(struct server_t *server); +/* Accepts incoming client connection. */ +int server_accept(struct server_t *server, struct client_t *accepted_client); +/* Rejects incoming client connection. */ +int server_reject(struct server_t *server); + + +/* Closes client connection. */ +int client_close(struct client_t *client); +/* Reads incoming data from client to client data buffer. */ +int client_read(struct client_t *client); +/* Sends data from a buffer to client. */ +int client_write(struct client_t *client, char *databuf, int datalen); + + +/* Opens the tty device and configures it. */ +int tty_open(struct tty_t *tty_dev); +/* Closes the tty device. */ +int tty_close(struct tty_t *tty_dev); +/* Reconfigures the tty device. */ +int tty_reconfigure(struct tty_t *tty_dev, struct termios newttyset); +/* Reads incoming data from tty device to tty data buffer. */ +int tty_read(struct tty_t *tty_dev); +/* Sends data from a buffer to tty device. */ +int tty_write(struct tty_t *tty_dev, char *databuf, int datalen); diff --git a/server.c b/server.c new file mode 100644 index 0000000..a8fb8b8 --- /dev/null +++ b/server.c @@ -0,0 +1,112 @@ +#include "moxerver_include.h" + + +/* Sets up the server on specific port, binds to a socket and listens for client connections. */ +int server_setup(struct server_t *server, unsigned int port) { + + int namelen, opt; + + /* set up server address information */ + server->address.sin_family = AF_INET; /* use IPv4 address family */ + server->address.sin_port = htons(port); /* set up port number, htons is for using network byte order */ + server->address.sin_addr.s_addr = INADDR_ANY; /* use local address */ + + /* create stream socket using TCP */ + server->socket = socket(AF_INET, SOCK_STREAM, 0); + if (server->socket == -1) { + fprintf(stderr, "[%s:%d] error %d: %s\n", __func__, __LINE__, errno, strerror(errno)); + return -errno; + } + fprintf(stderr,"[%s]: socket created\n", __func__); + + /* try to avoid "Address already in use" error */ + opt = 1; /* true value for setsockopt option */ + if (setsockopt(server->socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(int)) == -1) { + fprintf(stderr, "[%s:%d] error %d: %s\n", __func__, __LINE__, errno, strerror(errno)); + return -errno; + } + + /* bind server address to a socket */ + if (bind(server->socket, (struct sockaddr *) &server->address, sizeof(server->address)) == -1) { + fprintf(stderr, "[%s:%d] error %d: %s\n", __func__, __LINE__, errno, strerror(errno)); + return -errno; + } + fprintf(stderr,"[%s]: bind successful\n", __func__); + + /* check port assignment */ + namelen = sizeof(server->address); + if (getsockname(server->socket, (struct sockaddr *) &server->address, &namelen) == -1) { + fprintf(stderr, "[%s:%d] error %d: %s\n", __func__, __LINE__, errno, strerror(errno)); + return -errno; + } + if (ntohs(server->address.sin_port) != port) { + fprintf(stderr, "[%s:%d] error: could not assign port %u\n", __func__, __LINE__, port); + return -1; + } + /* save server port number */ + server->port = port; + fprintf(stderr,"[%s]: assigned port %u\n", __func__, server->port); //ntohs(server->address.sin_port) + + /* listen for a client connection, allow 2 connections in queue */ + if (listen(server->socket, 2) == -1) { + fprintf(stderr, "[%s:%d] error %d: %s\n", __func__, __LINE__, errno, strerror(errno)); + return -errno; + } + + fprintf(stderr,"[%s]: server is up, listening for client connection\n", __func__); + return 0; +} + +/* Closes the server. */ +int server_close(struct server_t *server) { + /* force closing in case of error */ + if (close(server->socket) == -1) { + close(server->socket); + } + fprintf(stderr,"[%s]: socket closed, server is down\n", __func__); + return 0; +} + +/* Accepts incoming client connection. */ +int server_accept(struct server_t *server, struct client_t *accepted_client) { + + int namelen; + + /* accept connection request */ + namelen = sizeof(accepted_client->address); + accepted_client->socket = accept(server->socket, (struct sockaddr *) &accepted_client->address, &namelen); + if (accepted_client->socket == -1) { + fprintf(stderr, "[%s:%d] error %d: %s\n", __func__, __LINE__, errno, strerror(errno)); + return -errno; + } + + /* get client IP address as human readable string */ + inet_ntop(accepted_client->address.sin_family, &accepted_client->address.sin_addr.s_addr, + accepted_client->ip_string, INET_ADDRSTRLEN); + + /* print client information */ + //TODO also print timestamp + fprintf(stderr, "[%s]: accepted client %s on port %u\n", __func__, + accepted_client->ip_string, server->port); + return 0; +} + +/* Rejects incoming client connection. */ +int server_reject(struct server_t *server) { + + int namelen; + struct client_t rclient; + char reject_msg[128]; + + /* accept connection request */ + namelen = sizeof(rclient.address); + rclient.socket = accept(server->socket, (struct sockaddr *) &rclient.address, &namelen); + /* send reject message */ + sprintf(reject_msg, "[%s]: port %u is already being used\n", __func__, server->port); + send(rclient.socket, reject_msg, strlen(reject_msg), 0); + /* close connection */ + close(rclient.socket); + + fprintf(stderr, "[%s]: rejected new client request, there is alredy a client connected\n", __func__, server->port); + return 0; +} diff --git a/tty.c b/tty.c new file mode 100644 index 0000000..b675f98 --- /dev/null +++ b/tty.c @@ -0,0 +1,26 @@ +#include "moxerver_include.h" + + +/* Opens the tty device and configures it. */ +int tty_open(struct tty_t *tty_dev) { + return 0; +} +/* Closes the tty device. */ +int tty_close(struct tty_t *tty_dev) { + return 0; +} + +/* Reconfigures the tty device. */ +int tty_reconfigure(struct tty_t *tty_dev, struct termios newttyset) { + return 0; +} + +/* Reads incoming data from tty device to tty data buffer. */ +int tty_read(struct tty_t *tty_dev) { + return 0; +} + +/* Sends data from a buffer to tty device. */ +int tty_write(struct tty_t *tty_dev, char *databuf, int datalen) { + return 0; +} \ No newline at end of file