Initial import
authorfatbob313 <martin@fatbob.nu>
Wed, 26 Aug 2009 20:00:32 +0000 (20:00 +0000)
committerfatbob313 <martin@fatbob.nu>
Wed, 26 Aug 2009 20:00:32 +0000 (20:00 +0000)
30 files changed:
Makefile [new file with mode: 0644]
files/umurmur.conf [new file with mode: 0644]
files/umurmur.init [new file with mode: 0644]
src/Makefile [new file with mode: 0644]
src/channel.c [new file with mode: 0644]
src/channel.h [new file with mode: 0644]
src/client.c [new file with mode: 0644]
src/client.h [new file with mode: 0644]
src/conf.c [new file with mode: 0644]
src/conf.h [new file with mode: 0644]
src/crypt.c [new file with mode: 0644]
src/crypt.h [new file with mode: 0644]
src/depend.mak [new file with mode: 0644]
src/list.h [new file with mode: 0644]
src/log.c [new file with mode: 0644]
src/log.h [new file with mode: 0644]
src/main.c [new file with mode: 0644]
src/messagehandler.c [new file with mode: 0644]
src/messagehandler.h [new file with mode: 0644]
src/messages.c [new file with mode: 0644]
src/messages.h [new file with mode: 0644]
src/pds.c [new file with mode: 0644]
src/pds.h [new file with mode: 0644]
src/server.c [new file with mode: 0644]
src/server.h [new file with mode: 0644]
src/ssl.c [new file with mode: 0644]
src/ssl.h [new file with mode: 0644]
src/timer.c [new file with mode: 0644]
src/timer.h [new file with mode: 0644]
src/types.h [new file with mode: 0644]

diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..e2ed946
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,53 @@
+include $(TOPDIR)/rules.mk
+
+# Name and release number of this package
+PKG_NAME:=umurmur
+PKG_VERSION:=0.1.1
+PKG_RELEASE:=4
+
+
+PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
+
+include $(INCLUDE_DIR)/package.mk
+
+
+define Package/umurmur
+       SECTION:=net
+       CATEGORY:=Network
+       TITLE:=uMurmur
+       DEPENDS:=+libopenssl +libconfig
+endef
+
+
+# Uncomment portion below for Kamikaze and delete DESCRIPTION variable above
+define Package/umurmur/description
+       Minimalistic Mumble server daemon.
+endef
+
+TARGET_CFLAGS := \
+        -DWRT_TARGET \
+        $(TARGET_CFLAGS)
+
+define Build/Prepare
+       mkdir -p $(PKG_BUILD_DIR)
+       $(CP) ./src/* $(PKG_BUILD_DIR)/
+endef
+
+define Build/CompileTarget
+       CFLAGS="$(TARGET_CFLAGS)" LDFLAGS="$(TARGET_LDFLAGS)"\
+       $(MAKE) -C $(PKG_BUILD_DIR)/umurmur.$(1)/umurmur \
+               all
+endef
+
+define Package/umurmur/install
+       $(INSTALL_DIR) $(1)/usr/bin
+       $(INSTALL_BIN) $(PKG_BUILD_DIR)/umurmurd $(1)/usr/bin/
+       $(INSTALL_DIR) $(1)/etc
+       $(INSTALL_BIN) ./files/umurmur.conf $(1)/etc/umurmur.conf
+       $(INSTALL_DIR) $(1)/etc/init.d
+       $(INSTALL_BIN) ./files/umurmur.init $(1)/etc/init.d/umurmur
+       $(INSTALL_DIR) $(1)/etc/umurmur
+endef
+
+$(eval $(call BuildPackage,umurmur))
+
diff --git a/files/umurmur.conf b/files/umurmur.conf
new file mode 100644 (file)
index 0000000..42b5e99
--- /dev/null
@@ -0,0 +1,31 @@
+max_bandwidth = 5000;
+welcometext = "Welcome to uMurmur!";
+certificate = "/etc/umurmur/cert.crt";
+private_key = "/etc/umurmur/key.key";
+password = "";
+max_users = 10;
+
+# Root channel must always be defined first.
+# If a channel has a parent, the parent must be defined before the child channel(s).
+channels = ( {
+        name = "Root";
+        parent = "";
+        description = "The Root of all channels";
+        },
+        {
+        name = "Lobby";
+        parent = "Root";
+        description = "Lobby channel";
+        },
+        {
+        name = "Red team";
+        parent = "Lobby";
+        description = "The Red team channel";
+        },
+        {
+        name = "Blue team";
+        parent = "Lobby";
+        description = "The Blue team channel";
+        }
+);
+default_channel = "COH";
diff --git a/files/umurmur.init b/files/umurmur.init
new file mode 100644 (file)
index 0000000..44d7802
--- /dev/null
@@ -0,0 +1,15 @@
+#!/bin/sh /etc/rc.common
+# Copyright (C) 2006-2008 OpenWrt.org
+
+START=90
+
+PIDFILE="/var/run/umurmurd.pid"
+
+start() {
+        stop
+        /usr/bin/umurmurd -p $PIDFILE
+}
+
+stop() {
+        [ -f "$PIDFILE" ] && kill $(cat "$PIDFILE") 2>/dev/null >/dev/null
+}
\ No newline at end of file
diff --git a/src/Makefile b/src/Makefile
new file mode 100644 (file)
index 0000000..e66f475
--- /dev/null
@@ -0,0 +1,22 @@
+# build helloworld executable when user executes "make" 
+
+SRCS:=client.c main.c messages.c pds.c server.c ssl.c log.c conf.c crypt.c timer.c messagehandler.c channel.c
+OBJS:=$(patsubst %.c, %.o, $(SRCS))
+CFLAGS:=$(CFLAGS) -Wall -Os -g
+LDFLAGS:=$(LDFLAGS) -lcrypto -lssl -lconfig
+
+umurmurd:$(OBJS) depend.mak
+       $(CC) $(LDFLAGS) $(OBJS) -o umurmurd
+
+# remove object files and executable when user executes "make clean"
+clean:
+       rm *.o umurmurd 
+
+all: umurmur
+
+$(OBJS): Makefile
+
+depend.mak:
+       $(CC) -M $(SRCS) > depend.mak
+
+include depend.mak
\ No newline at end of file
diff --git a/src/channel.c b/src/channel.c
new file mode 100644 (file)
index 0000000..e4ec9ad
--- /dev/null
@@ -0,0 +1,217 @@
+/* Copyright (C) 2009, Martin Johansson <martin@fatbob.nu>
+   Copyright (C) 2005-2009, Thorvald Natvig <thorvald@natvig.com>
+
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+   - 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.
+   - Neither the name of the Developers nor the names of its contributors may
+     be used to endorse or promote products derived from this software without
+     specific prior written permission.
+
+   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 FOUNDATION 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 "log.h"
+#include "list.h"
+#include "client.h"
+#include "channel.h"
+#include "conf.h"
+
+
+static int nextchanId;
+static channel_t *rootChan;
+channel_t *defaultChan;
+declare_list(channels); /* A flat list of the channels */
+
+static channel_t *createChannel(int id, const char *name, const char *desc)
+{
+       channel_t *ch;
+
+       ch = malloc(sizeof(channel_t));
+       if (ch == NULL)
+               Log_fatal("out of memory");
+       memset(ch, 0, sizeof(channel_t));
+       ch->id = id;
+       strncpy(ch->name, name, MAX_TEXT);
+       strncpy(ch->desc, desc, MAX_TEXT);
+       init_list_entry(&ch->subs);
+       init_list_entry(&ch->node);
+       init_list_entry(&ch->clients);
+       init_list_entry(&ch->flatlist_node);
+       return ch;
+}
+
+#if 0
+/* Might be used when tree travesal becomes neccessary */
+static channel_t *first_subchannel(channel_t *ch)
+{
+       if (list_empty(&ch->subs))
+               return NULL;
+       else
+               return list_get_entry(list_get_first(&ch->subs), channel_t, node);
+}
+
+static channel_t *next_channel(channel_t *ch)
+{
+       if (list_get_next(&ch->node) == &list_get_entry(&ch->node, channel_t, node)->parent->subs)
+               return NULL;
+       else
+               return list_get_entry(list_get_next(&ch->node), channel_t, node);       
+}
+#endif
+
+void Chan_iterate(channel_t **channelpptr)
+{
+       channel_t *ch = *channelpptr;
+
+       if (!list_empty(&channels)) {
+               if (ch == NULL)
+                       ch = list_get_entry(list_get_first(&channels), channel_t, flatlist_node);
+               else {
+                       if (list_get_next(&ch->flatlist_node) == &channels)
+                               ch = NULL;
+                       else
+                               ch = list_get_entry(list_get_next(&ch->flatlist_node), channel_t, flatlist_node);
+               }
+               if (ch)
+                       Log_debug("Channel %d", ch->id);
+       }
+
+       *channelpptr = ch;
+}
+                       
+void Chan_init()
+{
+       int i;
+       conf_channel_t chdesc;
+       const char *defaultChannelName;
+
+       defaultChannelName = getStrConf(DEAFULT_CHANNEL);
+       
+       for (i = 0; ; i++) {
+               if (Conf_getNextChannel(&chdesc, i) < 0) {
+                       if (i == 0)
+                               Log_fatal("No valid channels found in configuration file. Exiting.");
+                       break;
+               }
+               if (i == 0) {
+                       rootChan = createChannel(0, chdesc.name, chdesc.description);
+                       list_add_tail(&rootChan->flatlist_node, &channels);
+                       if (strcmp(defaultChannelName, chdesc.name) == 0)
+                               defaultChan = rootChan;
+               }
+               else {
+                       channel_t *ch, *ch_itr = NULL;
+                       ch = Chan_createChannel(chdesc.name, chdesc.description);
+                       
+                       if (strcmp(defaultChannelName, chdesc.name) == 0) {
+                               Log_info("Setting default channel %s", ch->name); 
+                               defaultChan = ch;
+                       }
+                       
+                       do {
+                               Chan_iterate(&ch_itr);
+                       } while (ch_itr != NULL && strcmp(ch_itr->name, chdesc.parent) != 0);
+                       
+                       if (ch_itr == NULL)
+                               Log_fatal("Error in channel configuration: parent not found");
+                       else {
+                               Chan_addChannel(ch_itr, ch);
+                               Log_info("Adding channel %s parent %s", ch->name, chdesc.parent);
+                       }
+               }
+       }
+       if (defaultChan == NULL)
+               defaultChan = rootChan;
+}
+
+void Chan_free()
+{
+       struct dlist *itr, *save;
+       
+       list_iterate_safe(itr, save, &channels) {
+               Log_debug("Free channel %s", list_get_entry(itr, channel_t, flatlist_node)->name);
+               free(list_get_entry(itr, channel_t, flatlist_node));
+       }
+}
+
+channel_t *Chan_createChannel(const char *name, const char *desc)
+{
+       /* Get an ID */
+       nextchanId += 1; 
+       return createChannel(nextchanId, name, desc);
+}
+
+void Chan_freeChannel(channel_t *ch)
+{
+       list_del(&ch->node);
+       list_del(&ch->flatlist_node);
+       free(ch);
+}
+
+void Chan_addChannel(channel_t *parent, channel_t *ch)
+{
+       list_add_tail(&ch->node, &parent->subs);
+       ch->parent = parent;
+       list_add_tail(&ch->flatlist_node, &channels);
+}
+
+
+void Chan_playerJoin(channel_t *ch, client_t *client)
+{
+       /* Only allowed in one channel at a time */
+       Log_debug("Add player %s to channel %s", client->playerName, ch->name); 
+
+       if (client->channel)
+               list_del(&client->chan_node);
+       list_add_tail(&client->chan_node, &ch->clients);
+       client->channel = (void *)ch;
+       
+}
+
+void Chan_playerJoin_id(int channelid, client_t *client)
+{
+       channel_t *ch_itr = NULL;
+       do {
+               Chan_iterate(&ch_itr);
+       } while (ch_itr != NULL && ch_itr->id != channelid);
+       if (ch_itr == NULL)
+               Log_warn("Channel id %d not found - ignoring.", channelid);
+       else
+               Chan_playerJoin(ch_itr, client);
+       
+}
+
+void Chan_addChannel_id(int parentId, channel_t *ch)
+{
+       channel_t *ch_itr = NULL;
+       do {
+               Chan_iterate(&ch_itr);
+       } while (ch_itr != NULL && ch_itr->id != parentId);
+       if (ch_itr == NULL)
+               Log_warn("Channel id %d not found - ignoring.", parentId);
+       else
+               list_add_tail(&ch->node, &ch_itr->subs);
+}
+
+void Chan_removeChannel(channel_t *ch)
+{
+       list_del(&ch->node);
+}
diff --git a/src/channel.h b/src/channel.h
new file mode 100644 (file)
index 0000000..3fdd940
--- /dev/null
@@ -0,0 +1,61 @@
+/* Copyright (C) 2009, Martin Johansson <martin@fatbob.nu>
+   Copyright (C) 2005-2009, Thorvald Natvig <thorvald@natvig.com>
+
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+   - 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.
+   - Neither the name of the Developers nor the names of its contributors may
+     be used to endorse or promote products derived from this software without
+     specific prior written permission.
+
+   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 FOUNDATION 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 CHANNEL_H_8939873
+#define CHANNEL_H_8939873
+
+#include "log.h"
+#include "list.h"
+#include "client.h"
+
+typedef struct channel {
+       int id;
+       char name[MAX_TEXT];
+       char desc[MAX_TEXT];
+       struct channel *parent;
+       struct dlist node;
+       struct dlist subs;
+       struct dlist clients;
+       struct dlist flatlist_node;
+} channel_t;
+
+void Chan_init();
+void Chan_free();
+void Chan_addChannel(channel_t *parent, channel_t *sub);
+void Chan_removeChannel(channel_t *c);
+void Chan_addClient(channel_t *c, client_t *client);
+void Chan_removeClient(channel_t *c, client_t *client);
+void Chan_playerJoin(channel_t *ch, client_t *client);
+void Chan_playerJoin_id(int channelid, client_t *client);
+void Chan_iterate(channel_t **channelpptr);
+channel_t *Chan_createChannel(const char *name, const char *desc);
+void Chan_freeChannel(channel_t *ch);
+
+#endif
diff --git a/src/client.c b/src/client.c
new file mode 100644 (file)
index 0000000..94da524
--- /dev/null
@@ -0,0 +1,619 @@
+/* Copyright (C) 2009, Martin Johansson <martin@fatbob.nu>
+   Copyright (C) 2005-2009, Thorvald Natvig <thorvald@natvig.com>
+
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+   - 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.
+   - Neither the name of the Developers nor the names of its contributors may
+     be used to endorse or promote products derived from this software without
+     specific prior written permission.
+
+   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 FOUNDATION 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 <sys/poll.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include "log.h"
+#include "list.h"
+#include "client.h"
+#include "ssl.h"
+#include "messages.h"
+#include "messagehandler.h"
+#include "pds.h"
+#include "conf.h"
+#include "channel.h"
+
+
+
+static int Client_read(client_t *client);
+static int Client_write(client_t *client);
+static int Client_voiceMsg(client_t *client, pds_t *pds);
+static int Client_send_udp(client_t *client, uint8_t *data, int len);
+static void Client_voiceMsg_tunnel(client_t *client, message_t *msg);
+
+declare_list(clients);
+static int clientcount; /* = 0 */
+static int session = 1;
+static int maxBandwidth;
+
+extern int udpsock;
+
+void Client_init()
+{
+       maxBandwidth = getIntConf(MAX_BANDWIDTH);
+}
+
+int Client_count()
+{
+       return clientcount;
+}
+
+int Client_getfds(struct pollfd *pollfds)
+{
+       struct dlist *itr;
+       int i = 0;
+       list_iterate(itr, &clients) {
+               client_t *c;
+               c = list_get_entry(itr, client_t, node);
+               pollfds[i].fd = c->tcpfd;
+               pollfds[i].events = POLLIN | POLLHUP | POLLERR;
+               if (c->txsize > 0 || c->readBlockedOnWrite) /* Data waiting to be sent? */
+                       pollfds[i].events |= POLLOUT;
+               i++;
+       }
+       return i;
+}
+
+void Client_janitor()
+{
+       struct dlist *itr;
+       int bwTop = maxBandwidth + maxBandwidth / 4;
+       list_iterate(itr, &clients) {
+               client_t *c;
+               c = list_get_entry(itr, client_t, node);
+               Log_debug("Client %s BW available %d", c->playerName, c->availableBandwidth);
+               c->availableBandwidth += maxBandwidth;
+               if (c->availableBandwidth > bwTop)
+                       c->availableBandwidth = bwTop;
+               
+               if (Timer_isElapsed(&c->lastActivity, 1000000LL * INACTICITY_TIMEOUT))
+                       Client_close(c);
+       }
+}
+
+int Client_add(int fd, struct sockaddr_in *remote)
+{
+       client_t *newclient;
+
+       newclient = malloc(sizeof(client_t));
+       if (newclient == NULL)
+               Log_fatal("Out of memory");
+       memset(newclient, 0, sizeof(client_t));
+
+       newclient->tcpfd = fd;
+       memcpy(&newclient->remote_tcp, remote, sizeof(struct sockaddr_in));
+       newclient->ssl = SSL_newconnection(newclient->tcpfd, &newclient->SSLready);
+       if (newclient->ssl == NULL) {
+               Log_warn("SSL negotiation failed");
+               free(newclient);
+               return -1;
+       }
+       newclient->availableBandwidth = maxBandwidth;
+       Timer_init(&newclient->lastActivity);
+       newclient->sessionId = session++; /* XXX - more elaborate? */
+       
+       init_list_entry(&newclient->txMsgQueue);
+       init_list_entry(&newclient->chan_node);
+       init_list_entry(&newclient->node);
+       
+       list_add_tail(&newclient->node, &clients);
+       clientcount++;
+       return 0;
+}
+
+void Client_free(client_t *client)
+{
+       struct dlist *itr, *save;
+       message_t *sendmsg;
+
+       Log_info("Disconnect client ID %d addr %s port %d", client->sessionId,
+                        inet_ntoa(client->remote_tcp.sin_addr),
+                        ntohs(client->remote_tcp.sin_port));
+
+       if (client->authenticated) {
+               sendmsg = Msg_create(ServerLeave);
+               sendmsg->sessionId = client->sessionId;
+               Client_send_message_except(client, sendmsg);
+       }
+       list_iterate_safe(itr, save, &client->txMsgQueue) {
+               list_del(&list_get_entry(itr, message_t, node)->node);
+               Msg_free(list_get_entry(itr, message_t, node));
+       }
+               
+       list_del(&client->node);
+       list_del(&client->chan_node);
+       if (client->ssl)
+               SSL_free(client->ssl);
+       close(client->tcpfd);
+       clientcount--;
+       free(client);
+}
+
+void Client_close(client_t *client)
+{
+       SSL_shutdown(client->ssl);
+       client->shutdown_wait = true;
+}
+
+void Client_disconnect_all()
+{
+       struct dlist *itr, *save;
+       
+       list_iterate_safe(itr, save, &clients) {
+               Client_free(list_get_entry(itr, client_t, node));
+       }
+}
+
+int Client_read_fd(int fd)
+{
+       struct dlist *itr;
+       client_t *client = NULL;
+       
+       list_iterate(itr, &clients) {
+               if(fd == list_get_entry(itr, client_t, node)->tcpfd) {
+                       client = list_get_entry(itr, client_t, node);
+                       break;
+               }
+       }
+       if (client == NULL)
+               Log_fatal("No client found for fd %d", fd);
+       
+       return Client_read(client);
+}
+
+int Client_read(client_t *client)
+{
+       int rc;
+
+       Timer_restart(&client->lastActivity);
+       
+       if (client->writeBlockedOnRead) {
+               client->writeBlockedOnRead = false;
+               Log_debug("Client_read: writeBlockedOnRead == true");
+               return Client_write(client);
+       }
+       
+       if (client->shutdown_wait) {
+               Client_free(client);
+               return 0;
+       }
+       if (!client->SSLready) {
+               int rc;
+               rc = SSL_nonblockaccept(client->ssl, &client->SSLready);
+               if (rc < 0) {
+                       Client_free(client);
+                       return -1;
+               }
+       }
+
+       do {
+               errno = 0;
+               if (!client->msgsize) 
+                       rc = SSL_read(client->ssl, client->rxbuf, 3 - client->rxcount);
+               else if (client->drainleft > 0)
+                       rc = SSL_read(client->ssl, client->rxbuf, client->drainleft > BUFSIZE ? BUFSIZE : client->drainleft);
+               else
+                       rc = SSL_read(client->ssl, &client->rxbuf[client->rxcount], client->msgsize);
+               if (rc > 0) {
+                       message_t *msg;
+                       if (client->drainleft > 0)
+                               client->drainleft -= rc;
+                       else {
+                               client->rxcount += rc;
+                               if (!client->msgsize && rc >= 3)
+                                       client->msgsize = ((client->rxbuf[0] & 0xff) << 16) |
+                                               ((client->rxbuf[1] & 0xff) << 8) |
+                                               (client->rxbuf[2] & 0xff);
+                               if (client->msgsize > BUFSIZE - 3 && client->drainleft == 0) {
+                                       Log_warn("Too big message received (%d). Discarding.", client->msgsize);
+                                       client->rxcount = client->msgsize = 0;
+                                       client->drainleft = client->msgsize;
+                               }
+                               else if (client->rxcount == client->msgsize + 3) { /* Got all of the message */
+                                       msg = Msg_networkToMessage(&client->rxbuf[3], client->msgsize);
+                                       /* pass messsage to handler */
+                                       if (msg) {
+                                               if (msg->messageType == Speex) /* Tunneled voice message */
+                                                       Client_voiceMsg_tunnel(client, msg);
+                                               else 
+                                                       Mh_handle_message(client, msg);
+                                       }
+                                       client->rxcount = client->msgsize = 0;
+                               }
+                       }
+               } else /* rc <= 0 */ {
+                       if (SSL_get_error(client->ssl, rc) == SSL_ERROR_WANT_READ) {
+                               return 0;
+                       }
+                       else if (SSL_get_error(client->ssl, rc) == SSL_ERROR_WANT_WRITE) {
+                               client->readBlockedOnWrite = true;
+                               return 0;
+                       }
+                       else if (SSL_get_error(client->ssl, rc) == SSL_ERROR_ZERO_RETURN) {
+                               Log_warn("Error: Zero return - closing");
+                               if (!client->shutdown_wait)
+                                       Client_close(client);
+                       }
+                       else {
+                               if (SSL_get_error(client->ssl, rc) == SSL_ERROR_SYSCALL) {
+                                       /* Hmm. This is where we end up when the client closes its connection.
+                                        * Kind of strange...
+                                        */
+                                       Log_info("Connection closed by peer");
+                               }
+                               else {
+                                       Log_warn("SSL error: %d - Closing connection.", SSL_get_error(client->ssl, rc));
+                               }
+                               Client_free(client);
+                               return -1;
+                       }
+               }
+       } while (SSL_pending(client->ssl));
+       return 0;       
+}
+
+int Client_write_fd(int fd)
+{
+       struct dlist *itr;
+       client_t *client = NULL;
+       
+       list_iterate(itr, &clients) {
+               if(fd == list_get_entry(itr, client_t, node)->tcpfd) {
+                       client = list_get_entry(itr, client_t, node);
+                       break;
+               }
+       }
+       if (client == NULL)
+               Log_fatal("No client found for fd %d", fd);
+       Client_write(client);
+       return 0;
+}
+
+int Client_write(client_t *client)
+{
+       int rc;
+       
+       if (client->readBlockedOnWrite) {
+               client->readBlockedOnWrite = false;
+               Log_debug("Client_write: readBlockedOnWrite == true");
+               return Client_read(client);
+       }
+       rc = SSL_write(client->ssl, &client->txbuf[client->txcount], client->txsize - client->txcount);
+       if (rc > 0) {
+               client->txcount += rc;
+               if (client->txcount == client->txsize)
+                       client->txsize = client->txcount = 0;
+       }
+       else if (rc < 0) {
+               if (SSL_get_error(client->ssl, rc) == SSL_ERROR_WANT_READ) {
+                       client->writeBlockedOnRead = true;
+                       return 0;
+               }
+               else if (SSL_get_error(client->ssl, rc) == SSL_ERROR_WANT_WRITE) {
+                       return 0;
+               }
+               else {
+                       if (SSL_get_error(client->ssl, rc) == SSL_ERROR_SYSCALL)
+                               Log_warn("Client_write: Error: %s  - Closing connection", strerror(errno));
+                       else
+                               Log_warn("Client_write: SSL error: %d - Closing connection.", SSL_get_error(client->ssl, rc));
+                       Client_free(client);
+                       return -1;
+               }
+       }
+       if (client->txsize == 0 && !list_empty(&client->txMsgQueue)) {
+               message_t *msg;
+               msg = list_get_entry(list_get_first(&client->txMsgQueue), message_t, node);
+               list_del(list_get_first(&client->txMsgQueue));
+               client->txQueueCount--;
+               Client_send_message(client, msg);
+       }
+       return 0;
+}
+
+int Client_send_message(client_t *client, message_t *msg)
+{
+       if (!client->authenticated || !client->SSLready) {
+               Msg_free(msg);
+               return 0;
+       }
+       if (client->txsize != 0) {
+               /* Queue message */
+               if ((client->txQueueCount > 5 &&  msg->messageType == Speex) ||
+                       client->txQueueCount > 30) {
+                       Msg_free(msg);
+                       return -1;
+               }
+               client->txQueueCount++;
+               list_add_tail(&msg->node, &client->txMsgQueue);
+       } else {
+               int len;
+               memset(client->txbuf, 0, BUFSIZE);
+               len = Msg_messageToNetwork(msg, &client->txbuf[3], BUFSIZE - 3);
+               doAssert(len < BUFSIZE - 3);
+
+               client->txbuf[0] =  (len >> 16) & 0xff;
+               client->txbuf[1] =  (len >> 8) & 0xff;
+               client->txbuf[2] =  len & 0xff;
+               client->txsize = len + 3;
+               client->txcount = 0;
+               Client_write(client);
+               Msg_free(msg);
+       }
+       return 0;
+}
+
+client_t *Client_iterate(client_t **client_itr)
+{
+       client_t *c = *client_itr;
+       
+       if (c == NULL && !list_empty(&clients)) {
+               c = list_get_entry(list_get_first(&clients), client_t, node);
+       } else {
+               if (list_get_next(&c->node) == &clients)
+                       c = NULL;
+               else
+                       c = list_get_entry(list_get_next(&c->node), client_t, node);
+       }
+       *client_itr = c;
+       return c;
+}
+
+
+int Client_send_message_except(client_t *client, message_t *msg)
+{
+       client_t *itr = NULL;
+       int count = 0;
+       
+       Msg_inc_ref(msg); /* Make sure a reference is held during the whole iteration. */
+       while (Client_iterate(&itr) != NULL) {
+               if (itr != client) {
+                       if (count++ > 0)
+                               Msg_inc_ref(msg); /* One extra reference for each new copy */
+                       Log_debug("Msg %d to %s refcount %d",  msg->messageType, itr->playerName, msg->refcount);
+                       Client_send_message(itr, msg);
+               }
+       }
+       Msg_free(msg); /* Free our reference to the message */
+       
+       if (count == 0)
+               Msg_free(msg); /* If only 1 client is connected then no message is passed
+                                               * to Client_send_message(). Free it here. */
+               
+       return 0;
+}
+
+static bool_t checkDecrypt(client_t *client, const uint8_t *encrypted, uint8_t *plain, unsigned int len)
+{
+       if (CryptState_isValid(&client->cryptState) &&
+               CryptState_decrypt(&client->cryptState, encrypted, plain, len))
+               return true;
+
+       if (Timer_elapsed(&client->cryptState.tLastGood) > 5000000ULL) {
+               if (Timer_elapsed(&client->cryptState.tLastRequest) > 5000000ULL) {
+                       message_t *sendmsg;
+                       Timer_restart(&client->cryptState.tLastRequest);
+                       
+                       sendmsg = Msg_create(CryptSync);
+                       sendmsg->sessionId = client->sessionId;
+                       sendmsg->payload.cryptSync.empty = true;
+                       Log_info("Requesting voice channel crypt resync");
+                       Client_send_message(client, sendmsg);
+               }
+       }
+       return false;
+}
+
+int Client_read_udp()
+{
+       int len;
+       struct sockaddr_in from;
+       socklen_t fromlen = sizeof(struct sockaddr_in);
+       uint64_t key;
+       client_t *itr;
+       int msgType = 0;
+       uint32_t sessionId = 0;
+       pds_t *pds;
+       
+#if defined(__LP64__)
+       uint8_t encbuff[512 + 8];
+       uint8_t *encrypted = encbuff + 4;
+#else
+       uint8_t encrypted[512];
+#endif
+       uint8_t buffer[512];
+       
+       len = recvfrom(udpsock, encrypted, 512, MSG_TRUNC, (struct sockaddr *)&from, &fromlen);
+       if (len == 0) {
+               return -1;
+       } else if (len < 0) {
+               return -1;
+       } else if (len < 6) {
+               // 4 bytes crypt header + type + session
+               return 0;
+       } else if (len > 512) {
+               return 0;
+       }
+       
+       key = (((uint64_t)from.sin_addr.s_addr) << 16) ^ from.sin_port;
+       pds = Pds_create(buffer, len - 4);
+       itr = NULL;
+       
+       while (Client_iterate(&itr) != NULL) {
+               if (itr->key == key) {
+                       if (!checkDecrypt(itr, encrypted, buffer, len))
+                               goto out;
+                       msgType = Pds_get_numval(pds);
+                       sessionId = Pds_get_numval(pds);
+                       if (itr->sessionId != sessionId)
+                               goto out;
+                       break;
+               }
+       }       
+       if (itr == NULL) { /* Unknown peer */
+               while (Client_iterate(&itr) != NULL) {
+                       pds->offset = 0;
+                       if (itr->remote_tcp.sin_addr.s_addr == from.sin_addr.s_addr) {
+                               if (checkDecrypt(itr, encrypted, buffer, len)) {
+                                       msgType = Pds_get_numval(pds);
+                                       sessionId = Pds_get_numval(pds);
+                                       if (itr->sessionId == sessionId) { /* Found matching client */
+                                               itr->key = key;
+                                               Log_info("New UDP connection from %s port %d sessionId %d", inet_ntoa(from.sin_addr), ntohs(from.sin_port), sessionId);
+                                               memcpy(&itr->remote_udp, &from, sizeof(struct sockaddr_in));
+                                               break;
+                                       }
+                               }
+                               else Log_warn("Bad cryptstate from peer");
+                       }
+               } /* while */
+       }
+       if (itr == NULL) {
+               goto out;
+       }
+       len -= 4;
+       if (msgType != Speex && msgType != Ping)
+               goto out;
+       
+       if (msgType == Ping) {
+               Client_send_udp(itr, buffer, len);
+       }
+       else {
+               Client_voiceMsg(itr, pds);
+       }
+       
+out:
+       Pds_free(pds);
+       return 0;
+}
+
+static void Client_voiceMsg_tunnel(client_t *client, message_t *msg)
+{
+       uint8_t buf[512];
+       pds_t *pds = Pds_create(buf, 512);
+
+       Pds_add_numval(pds, msg->messageType);
+       Pds_add_numval(pds, msg->sessionId);
+       Pds_add_numval(pds, msg->payload.speex.seq);
+       Pds_append_data_nosize(pds, msg->payload.speex.data, msg->payload.speex.size);
+       if (!pds->bOk)
+               Log_warn("Large Speex message from TCP"); /* XXX - pds resize? */
+       pds->maxsize = pds->offset;
+       Client_voiceMsg(client, pds);
+       Pds_free(pds);
+}
+
+static int Client_voiceMsg(client_t *client, pds_t *pds)
+{
+       int seq, flags, msgType, sessionId, packetsize;
+       channel_t *ch = (channel_t *)client->channel;
+       struct dlist *itr;
+       
+       if (!client->authenticated || client->mute)
+               return 0;
+
+       
+       pds->offset = 0;
+       msgType = Pds_get_numval(pds);
+       sessionId = Pds_get_numval(pds);
+       seq = Pds_get_numval(pds);
+       flags = Pds_get_numval(pds);
+
+       packetsize = 20 + 8 + 4 + pds->maxsize - pds->offset;
+       if (client->availableBandwidth - packetsize < 0)
+               return 0; /* Discard */
+       
+       client->availableBandwidth -= packetsize;
+       
+       pds->offset = 0;
+       
+       if (flags & LoopBack) {
+               Client_send_udp(client, pds->data, pds->maxsize);
+               return 0;
+       }
+       if (ch == NULL)
+               return 0;
+       
+       list_iterate(itr, &ch->clients) {
+               client_t *c;
+               c = list_get_entry(itr, client_t, chan_node);
+               if (c != client && !c->deaf) {
+                       Client_send_udp(c, pds->data, pds->maxsize);
+               }
+       }
+       return 0;
+}
+
+
+static int Client_send_udp(client_t *client, uint8_t *data, int len)
+{
+       uint8_t *buf, *mbuf;
+       message_t *sendmsg;
+
+       if (client->remote_udp.sin_port != 0 && CryptState_isValid(&client->cryptState)) {
+#if defined(__LP64__)
+               buf = mbuf = malloc(len + 4 + 16);
+               buf += 4;
+#else
+               mbuf = buf = malloc(len + 4);
+#endif
+               if (mbuf == NULL)
+                       Log_fatal("Out of memory");
+               
+               CryptState_encrypt(&client->cryptState, data, buf, len);
+               
+               sendto(udpsock, buf, len + 4, 0, (struct sockaddr *)&client->remote_udp, sizeof(struct sockaddr_in));
+               
+               free(mbuf);
+       } else {
+               pds_t *pds = Pds_create(data, len);
+               
+               sendmsg = Msg_create(Pds_get_numval(pds));
+               sendmsg->sessionId = Pds_get_numval(pds);
+               
+               if (sendmsg->messageType == Speex || sendmsg->messageType == Ping) {
+                       if (sendmsg->messageType == Speex) {
+                               sendmsg->payload.speex.seq = Pds_get_numval(pds);
+                               sendmsg->payload.speex.size = pds->maxsize - pds->offset;
+                               doAssert(pds->maxsize - pds->offset <= SPEEX_DATA_SIZE);
+                               memcpy(sendmsg->payload.speex.data, data + pds->offset, pds->maxsize - pds->offset);
+                       } else { /* Ping */
+                               sendmsg->payload.ping.timestamp = Pds_get_numval(pds);
+                       }
+                       Client_send_message(client, sendmsg);
+               } else {
+                       Log_warn("TCP fallback: Unsupported message type %d", sendmsg->messageType);
+                       Msg_free(sendmsg);
+               }
+               Pds_free(pds);
+       }
+       return 0;
+}
diff --git a/src/client.h b/src/client.h
new file mode 100644 (file)
index 0000000..b7460b6
--- /dev/null
@@ -0,0 +1,98 @@
+/* Copyright (C) 2009, Martin Johansson <martin@fatbob.nu>
+   Copyright (C) 2005-2009, Thorvald Natvig <thorvald@natvig.com>
+
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+   - 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.
+   - Neither the name of the Developers nor the names of its contributors may
+     be used to endorse or promote products derived from this software without
+     specific prior written permission.
+
+   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 FOUNDATION 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 CLIENT_H_45786678
+#define CLIENT_H_45786678
+
+#include <openssl/ssl.h>
+#include <stdint.h>
+#include <unistd.h>             /* close() */
+#include <sys/types.h>
+#include <sys/socket.h>         /* socket() */
+#include <netinet/in.h>         /* IPPROTO_TCP */
+#include <arpa/inet.h>          /* inet_addr() */
+#include <errno.h>              /* errno */
+#include <sys/poll.h>
+
+#include "list.h"
+#include "types.h"
+#include "messages.h"
+#include "crypt.h"
+#include "timer.h"
+
+#define BUFSIZE 2048
+#define UDP_BUFSIZE 512
+#define INACTICITY_TIMEOUT 15 /* Seconds */
+
+#define IS_AUTH(_a_) ((_a_)->authenticated)
+
+typedef struct {
+       int tcpfd;
+       SSL *ssl;
+       bool_t SSLready;
+       bool_t shutdown_wait;
+       cryptState_t cryptState;
+       bool_t readBlockedOnWrite, writeBlockedOnRead;
+       
+       struct sockaddr_in remote_tcp;
+       struct sockaddr_in remote_udp; 
+       uint8_t rxbuf[BUFSIZE], txbuf[BUFSIZE];
+       uint32_t rxcount, msgsize, drainleft, txcount, txsize;
+       int sessionId;
+       uint64_t key;
+       char playerName[MAX_TEXT];
+       int playerId;
+       bool_t authenticated, deaf, mute;
+       int availableBandwidth;
+       etimer_t lastActivity;
+       struct dlist node;
+       struct dlist txMsgQueue;
+       int txQueueCount;
+       /* Channel */
+       void *channel; /*Ugly... */
+       struct dlist chan_node;
+} client_t;
+
+
+void Client_init();
+int Client_getfds(struct pollfd *pollfds);
+void Client_janitor();
+int Client_add(int fd, struct sockaddr_in *remote);
+int Client_read_fd(int fd);
+int Client_write_fd(int fd);
+int Client_send_message(client_t *client, message_t *msg);
+int Client_count(void);
+void Client_close(client_t *client);
+client_t *Client_iterate(client_t **client);
+int Client_send_message_except(client_t *client, message_t *msg);
+int Client_read_udp(void);
+void Client_disconnect_all();
+
+#endif
diff --git a/src/conf.c b/src/conf.c
new file mode 100644 (file)
index 0000000..540928b
--- /dev/null
@@ -0,0 +1,214 @@
+/* Copyright (C) 2009, Martin Johansson <martin@fatbob.nu>
+   Copyright (C) 2005-2009, Thorvald Natvig <thorvald@natvig.com>
+
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+   - 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.
+   - Neither the name of the Developers nor the names of its contributors may
+     be used to endorse or promote products derived from this software without
+     specific prior written permission.
+
+   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 FOUNDATION 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef WRT_TARGET
+#include <libconfig/libconfig.h>
+#else
+#include <libconfig.h>
+#endif
+
+#include "types.h"
+#include "conf.h"
+#include "log.h"
+
+static config_t configuration;
+
+#define DEFAULT_CONFIG "/etc/umurmur.conf"
+#define DEFAULT_WELCOME "Welcome to uMurmur!"
+#define DEFAULT_MAX_CLIENTS 10
+#define DEFAULT_MAX_BANDWIDTH 5000
+#define DEFAULT_BINDPORT 64738
+
+const char defaultconfig[] = DEFAULT_CONFIG;
+
+int Conf_init(const char *conffile)
+{
+       const char *conf;
+       
+       config_init(&configuration);
+       if (conffile == NULL)
+               conf = defaultconfig;
+       else
+               conf = conffile;
+       if (config_read_file(&configuration, conf) != CONFIG_TRUE) {
+               fprintf(stderr, "Error in config file %s: %s at line %d\n", conffile,
+                               config_error_text(&configuration), config_error_line(&configuration));
+               exit(1);
+       }
+       return 0;
+}
+
+void Conf_deinit()
+{
+       config_destroy(&configuration);
+}
+
+const char *getStrConf(param_t param)
+{
+       config_setting_t *setting = NULL;
+       const char *strsetting = NULL;
+       
+       switch (param) {
+       case CERTIFICATE:
+               setting = config_lookup(&configuration, "certificate");
+               if (!setting)
+                       return "/etc/umurmur/certificate.crt";
+               else {
+                       if ((strsetting = config_setting_get_string(setting)) != NULL)
+                               return strsetting;
+                       else
+                               return "/etc/umurmur/certificate.crt";
+               }
+               break;
+       case KEY:
+               setting = config_lookup(&configuration, "private_key");
+               if (!setting)
+                       return "/etc/umurmur/private_key.key";
+               else {
+                       if ((strsetting = config_setting_get_string(setting)) != NULL)
+                               return strsetting;
+                       else
+                               return "/etc/umurmur/private_key.key";
+               }
+               break;
+       case PASSPHRASE:
+               setting = config_lookup(&configuration, "password");
+               if (!setting)
+                       return "";
+               else {
+                       if ((strsetting = config_setting_get_string(setting)) != NULL)
+                               return strsetting;
+                       else
+                               return "";
+               }
+               break;
+       case BINDADDR:
+               setting = config_lookup(&configuration, "bindaddr");
+               if (!setting)
+                       return "";
+               else {
+                       if ((strsetting = config_setting_get_string(setting)) != NULL)
+                               return strsetting;
+                       else
+                               return "";
+               }
+               break;
+       case WELCOMETEXT:
+               setting = config_lookup(&configuration, "welcometext");
+               if (!setting)
+                       return DEFAULT_WELCOME;
+               else {
+                       if ((strsetting = config_setting_get_string(setting)) != NULL)
+                               return strsetting;
+                       else
+                       return DEFAULT_WELCOME;
+               }
+               break;
+       case DEAFULT_CHANNEL:
+               setting = config_lookup(&configuration, "default_channel");
+               if (!setting)
+                       return "";
+               else {
+                       if ((strsetting = config_setting_get_string(setting)) != NULL)
+                               return strsetting;
+                       else
+                       return "";
+               }
+               break;
+       default:
+               doAssert(false);
+               break;
+       }
+       return NULL;
+}
+
+int getIntConf(param_t param)
+{
+       config_setting_t *setting = NULL;
+       
+       switch (param) {
+       case BINDPORT:
+               setting = config_lookup(&configuration, "bindport");
+               if (!setting)
+                       return DEFAULT_BINDPORT;
+               else {
+                       return config_setting_get_int(setting);
+               }
+               break;
+       case MAX_BANDWIDTH:
+               setting = config_lookup(&configuration, "max_bandwidth");
+               if (!setting)
+                       return DEFAULT_MAX_BANDWIDTH;
+               else {
+                       return config_setting_get_int(setting);
+               }
+               break;
+       case MAX_CLIENTS:
+               setting = config_lookup(&configuration, "max_users");
+               if (!setting)
+                       return DEFAULT_MAX_CLIENTS;
+               else {
+                       return config_setting_get_int(setting);
+               }
+               break;
+       default:
+               doAssert(false);
+       }
+}
+
+int Conf_getNextChannel(conf_channel_t *chdesc, int index)
+{
+       config_setting_t *setting = NULL;
+       char configstr[64];
+       
+       sprintf(configstr, "channels.[%d].name", index);
+       setting = config_lookup(&configuration, configstr);
+       if (setting == NULL)
+               return -1;
+       strncpy(chdesc->name, config_setting_get_string(setting), MAX_TEXT);
+       
+       sprintf(configstr, "channels.[%d].parent", index);
+       setting = config_lookup(&configuration, configstr);
+       if (setting == NULL)
+               return -1;
+       strncpy(chdesc->parent, config_setting_get_string(setting), MAX_TEXT);
+       
+       sprintf(configstr, "channels.[%d].description", index);
+       setting = config_lookup(&configuration, configstr);
+       if (setting == NULL)
+               return -1;
+       strncpy(chdesc->description, config_setting_get_string(setting), MAX_TEXT);
+
+       return 0;
+}
diff --git a/src/conf.h b/src/conf.h
new file mode 100644 (file)
index 0000000..a42daad
--- /dev/null
@@ -0,0 +1,61 @@
+/* Copyright (C) 2009, Martin Johansson <martin@fatbob.nu>
+   Copyright (C) 2005-2009, Thorvald Natvig <thorvald@natvig.com>
+
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+   - 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.
+   - Neither the name of the Developers nor the names of its contributors may
+     be used to endorse or promote products derived from this software without
+     specific prior written permission.
+
+   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 FOUNDATION 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 CONF_H_24564356
+#define CONF_H_24564356
+
+#include "messages.h"
+
+typedef enum param {
+       CERTIFICATE,
+       KEY,
+       PASSPHRASE,
+       BINDPORT,
+       BINDADDR,
+       WELCOMETEXT,
+       MAX_BANDWIDTH,
+       MAX_CLIENTS,
+       DEAFULT_CHANNEL,
+} param_t;
+
+typedef struct {
+       char parent[MAX_TEXT];
+       char name[MAX_TEXT];
+       char description[MAX_TEXT];
+} conf_channel_t;
+
+int Conf_init(const char *conffile);
+void Conf_deinit();
+
+const char *getStrConf(param_t param);
+int getIntConf(param_t param);
+int Conf_getNextChannel(conf_channel_t *chdesc, int index);
+
+#endif
diff --git a/src/crypt.c b/src/crypt.c
new file mode 100644 (file)
index 0000000..a7eda57
--- /dev/null
@@ -0,0 +1,329 @@
+/* Copyright (C) 2009, Martin Johansson <martin@fatbob.nu>
+   Copyright (C) 2005-2009, Thorvald Natvig <thorvald@natvig.com>
+
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+   - 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.
+   - Neither the name of the Developers nor the names of its contributors may
+     be used to endorse or promote products derived from this software without
+     specific prior written permission.
+
+   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 FOUNDATION 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.
+*/
+
+/*
+ * This code implements OCB-AES128.
+ * In the US, OCB is covered by patents. The inventor has given a license
+ * to all programs distributed under the GPL.
+ * uMurmur is BSD (revised) licensed, meaning you can use the code in a
+ * closed-source program. If you do, you'll have to either replace
+ * OCB with something else or get yourself a license.
+ */
+
+#include <string.h>
+#include <arpa/inet.h>
+#include "crypt.h"
+#include "log.h"
+static void CryptState_ocb_encrypt(cryptState_t *cs, const unsigned char *plain, unsigned char *encrypted, unsigned int len, const unsigned char *nonce, unsigned char *tag);
+static void CryptState_ocb_decrypt(cryptState_t *cs, const unsigned char *encrypted, unsigned char *plain, unsigned int len, const unsigned char *nonce, unsigned char *tag);
+
+void CryptState_init(cryptState_t *cs)
+{
+       memset(cs->decrypt_history, 0, 0xff);
+       memset(cs->raw_key, 0, AES_BLOCK_SIZE);
+       memset(cs->encrypt_iv, 0, AES_BLOCK_SIZE);
+       memset(cs->decrypt_iv, 0, AES_BLOCK_SIZE);
+       cs->bInit = false;
+       cs->uiGood = cs->uiLate = cs->uiLost = cs->uiResync = 0;
+       cs->uiRemoteGood = cs->uiRemoteLate = cs->uiRemoteLost = cs->uiRemoteResync = 0;
+       Timer_init(&cs->tLastGood);
+       Timer_init(&cs->tLastRequest);
+}
+
+bool_t CryptState_isValid(cryptState_t *cs)
+{
+       return cs->bInit;
+}
+
+void CryptState_genKey(cryptState_t *cs) {
+       RAND_bytes(cs->raw_key, AES_BLOCK_SIZE);
+       RAND_bytes(cs->encrypt_iv, AES_BLOCK_SIZE);
+       RAND_bytes(cs->decrypt_iv, AES_BLOCK_SIZE);
+       AES_set_encrypt_key(cs->raw_key, 128, &cs->encrypt_key);
+       AES_set_decrypt_key(cs->raw_key, 128, &cs->decrypt_key);
+       cs->bInit = true;
+}
+
+void CryptState_setKey(cryptState_t *cs, const unsigned char *rkey, const unsigned char *eiv, const unsigned char *div)
+{
+       memcpy(cs->raw_key, rkey, AES_BLOCK_SIZE);
+       memcpy(cs->encrypt_iv, eiv, AES_BLOCK_SIZE);
+       memcpy(cs->decrypt_iv, div, AES_BLOCK_SIZE);
+       AES_set_encrypt_key(cs->raw_key, 128, &cs->encrypt_key);
+       AES_set_decrypt_key(cs->raw_key, 128, &cs->decrypt_key);
+       cs->bInit = true;
+}
+
+void CryptState_setDecryptIV(cryptState_t *cs, const unsigned char *iv)
+{
+       memcpy(cs->decrypt_iv, iv, AES_BLOCK_SIZE);
+}
+
+void CryptState_encrypt(cryptState_t *cs, const unsigned char *source, unsigned char *dst, unsigned int plain_length)
+{
+       unsigned char tag[AES_BLOCK_SIZE];
+       int i;
+       // First, increase our IV.
+       for (i = 0; i < AES_BLOCK_SIZE; i++)
+               if (++cs->encrypt_iv[i])
+                       break;
+
+       CryptState_ocb_encrypt(cs, source, dst+4, plain_length, cs->encrypt_iv, tag);
+
+       dst[0] = cs->encrypt_iv[0];
+       dst[1] = tag[0];
+       dst[2] = tag[1];
+       dst[3] = tag[2];
+}
+
+bool_t CryptState_decrypt(cryptState_t *cs, const unsigned char *source, unsigned char *dst, unsigned int crypted_length)
+{
+       if (crypted_length < 4)
+               return false;
+
+       unsigned int plain_length = crypted_length - 4;
+
+       unsigned char saveiv[AES_BLOCK_SIZE];
+       unsigned char ivbyte = source[0];
+       bool_t restore = false;
+       unsigned char tag[AES_BLOCK_SIZE];
+
+       int lost = 0;
+       int late = 0;
+
+       memcpy(saveiv, cs->decrypt_iv, AES_BLOCK_SIZE);
+
+       if (((cs->decrypt_iv[0] + 1) & 0xFF) == ivbyte) {
+               // In order as expected.
+               if (ivbyte > cs->decrypt_iv[0]) {
+                       cs->decrypt_iv[0] = ivbyte;
+               } else if (ivbyte < cs->decrypt_iv[0]) {
+                       int i;
+                       cs->decrypt_iv[0] = ivbyte;
+                       for (i = 1; i < AES_BLOCK_SIZE; i++)
+                               if (++cs->decrypt_iv[i])
+                                       break;
+               } else {
+                       return false;
+               }
+       } else {
+               // This is either out of order or a repeat.
+
+               int diff = ivbyte - cs->decrypt_iv[0];
+               if (diff > 128)
+                       diff = diff-256;
+               else if (diff < -128)
+                       diff = diff+256;
+
+               if ((ivbyte < cs->decrypt_iv[0]) && (diff > -30) && (diff < 0)) {
+                       // Late packet, but no wraparound.
+                       late = 1;
+                       lost = -1;
+                       cs->decrypt_iv[0] = ivbyte;
+                       restore = true;
+               } else if ((ivbyte > cs->decrypt_iv[0]) && (diff > -30) && (diff < 0)) {
+                       int i;
+                       // Last was 0x02, here comes 0xff from last round
+                       late = 1;
+                       lost = -1;
+                       cs->decrypt_iv[0] = ivbyte;
+                       for (i = 1; i < AES_BLOCK_SIZE; i++)
+                               if (cs->decrypt_iv[i]--)
+                                       break;
+                       restore = true;
+               } else if ((ivbyte > cs->decrypt_iv[0]) && (diff > 0)) {
+                       // Lost a few packets, but beyond that we're good.
+                       lost = ivbyte - cs->decrypt_iv[0] - 1;
+                       cs->decrypt_iv[0] = ivbyte;
+               } else if ((ivbyte < cs->decrypt_iv[0]) && (diff > 0)) {
+                       int i;
+                       // Lost a few packets, and wrapped around
+                       lost = 256 - cs->decrypt_iv[0] + ivbyte - 1;
+                       cs->decrypt_iv[0] = ivbyte;
+                       for (i = 1; i < AES_BLOCK_SIZE; i++)
+                               if (++cs->decrypt_iv[i])
+                                       break;
+               } else {
+                       return false;
+               }
+
+               if (cs->decrypt_history[cs->decrypt_iv[0]] == cs->decrypt_iv[1]) {
+                       memcpy(cs->decrypt_iv, saveiv, AES_BLOCK_SIZE);
+                       return false;
+               }
+       }
+
+       CryptState_ocb_decrypt(cs, source+4, dst, plain_length, cs->decrypt_iv, tag);
+
+       if (memcmp(tag, source+1, 3) != 0) {
+               memcpy(cs->decrypt_iv, saveiv, AES_BLOCK_SIZE);
+               return false;
+       }
+       cs->decrypt_history[cs->decrypt_iv[0]] = cs->decrypt_iv[1];
+
+       if (restore)
+               memcpy(cs->decrypt_iv, saveiv, AES_BLOCK_SIZE);
+
+       cs->uiGood++;
+       cs->uiLate += late;
+       cs->uiLost += lost;
+
+       Timer_restart(&cs->tLastGood);
+       return true;
+}
+
+#if defined(__LP64__)
+#define BLOCKSIZE 2
+#define SHIFTBITS 63
+typedef uint64_t subblock;
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define SWAPPED(x) (x)
+#else
+#ifdef __x86_64__
+#define SWAPPED(x) ({register uint64_t __out, __in = (x); __asm__("bswap %q0" : "=r"(__out) : "0"(__in)); __out;})
+#else
+#include <byteswap.h>
+#define SWAPPED(x) bswap_64(x)
+#endif
+#endif
+
+#else
+
+#define BLOCKSIZE 4
+#define SHIFTBITS 31
+typedef uint32_t subblock;
+#define SWAPPED(x) htonl(x)
+
+#endif
+
+#define HIGHBIT (1<<SHIFTBITS);
+
+
+static void inline XOR(subblock *dst, const subblock *a, const subblock *b) {
+       int i;
+       for (i=0;i<BLOCKSIZE;i++) {
+               dst[i] = a[i] ^ b[i];
+       }
+}
+
+static void inline S2(subblock *block) {
+       subblock carry = SWAPPED(block[0]) >> SHIFTBITS;
+       int i;
+       for (i=0;i<BLOCKSIZE-1;i++)
+               block[i] = SWAPPED((SWAPPED(block[i]) << 1) | (SWAPPED(block[i+1]) >> SHIFTBITS));
+       block[BLOCKSIZE-1] = SWAPPED((SWAPPED(block[BLOCKSIZE-1]) << 1) ^(carry * 0x87));
+}
+
+static void inline S3(subblock *block) {
+       subblock carry = SWAPPED(block[0]) >> SHIFTBITS;
+       int i;
+       for (i=0;i<BLOCKSIZE-1;i++)
+               block[i] ^= SWAPPED((SWAPPED(block[i]) << 1) | (SWAPPED(block[i+1]) >> SHIFTBITS));
+       block[BLOCKSIZE-1] ^= SWAPPED((SWAPPED(block[BLOCKSIZE-1]) << 1) ^(carry * 0x87));
+}
+
+static void inline ZERO(subblock *block) {
+       int i;
+       for (i=0;i<BLOCKSIZE;i++)
+               block[i]=0;
+}
+
+#define AESencrypt(src,dst,key) AES_encrypt((unsigned char *)(src),(unsigned char *)(dst), key);
+#define AESdecrypt(src,dst,key) AES_decrypt((unsigned char *)(src),(unsigned char *)(dst), key);
+
+void CryptState_ocb_encrypt(cryptState_t *cs, const unsigned char *plain, unsigned char *encrypted, unsigned int len, const unsigned char *nonce, unsigned char *tag) {
+       subblock checksum[BLOCKSIZE], delta[BLOCKSIZE], tmp[BLOCKSIZE], pad[BLOCKSIZE];
+
+       // Initialize
+       AESencrypt(nonce, delta, &cs->encrypt_key);
+       ZERO(checksum);
+
+       while (len > AES_BLOCK_SIZE) {
+               S2(delta);
+               XOR(tmp, delta, (const subblock *)(plain));
+               AESencrypt(tmp, tmp, &cs->encrypt_key);
+               XOR((subblock *)(encrypted), delta, tmp);
+               XOR(checksum, checksum, (subblock *)(plain));
+               len -= AES_BLOCK_SIZE;
+               plain += AES_BLOCK_SIZE;
+               encrypted += AES_BLOCK_SIZE;
+       }
+
+       S2(delta);
+       ZERO(tmp);
+       tmp[BLOCKSIZE - 1] = SWAPPED(len * 8);
+       XOR(tmp, tmp, delta);
+       AESencrypt(tmp, pad, &cs->encrypt_key);
+       memcpy(tmp, plain, len);
+       memcpy((unsigned char *)tmp + len, (unsigned char *)pad + len, AES_BLOCK_SIZE - len);
+       XOR(checksum, checksum, tmp);
+       XOR(tmp, pad, tmp);
+       memcpy(encrypted, tmp, len);
+
+       S3(delta);
+       XOR(tmp, delta, checksum);
+       AESencrypt(tmp, tag, &cs->encrypt_key);
+}
+
+void CryptState_ocb_decrypt(cryptState_t *cs, const unsigned char *encrypted, unsigned char *plain, unsigned int len, const unsigned char *nonce, unsigned char *tag) {
+       subblock checksum[BLOCKSIZE], delta[BLOCKSIZE], tmp[BLOCKSIZE], pad[BLOCKSIZE];
+
+       // Initialize
+       AESencrypt(nonce, delta, &cs->encrypt_key);
+       ZERO(checksum);
+
+       while (len > AES_BLOCK_SIZE) {
+               S2(delta);
+               XOR(tmp, delta, (const subblock *)(encrypted));
+               AESdecrypt(tmp, tmp, &cs->decrypt_key);
+               XOR((subblock *)(plain), delta, tmp);
+               XOR(checksum, checksum, (const subblock *)(plain));
+               len -= AES_BLOCK_SIZE;
+               plain += AES_BLOCK_SIZE;
+               encrypted += AES_BLOCK_SIZE;
+       }
+
+       S2(delta);
+       ZERO(tmp);
+       tmp[BLOCKSIZE - 1] = SWAPPED(len * 8);
+       XOR(tmp, tmp, delta);
+       AESencrypt(tmp, pad, &cs->encrypt_key);
+       memset(tmp, 0, AES_BLOCK_SIZE);
+       memcpy(tmp, encrypted, len);
+       XOR(tmp, tmp, pad);
+       XOR(checksum, checksum, tmp);
+       memcpy(plain, tmp, len);
+
+       S3(delta);
+       XOR(tmp, delta, checksum);
+       AESencrypt(tmp, tag, &cs->encrypt_key);
+}
diff --git a/src/crypt.h b/src/crypt.h
new file mode 100644 (file)
index 0000000..e227ed2
--- /dev/null
@@ -0,0 +1,71 @@
+/* Copyright (C) 2009, Martin Johansson <martin@fatbob.nu>
+   Copyright (C) 2005-2009, Thorvald Natvig <thorvald@natvig.com>
+
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+   - 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.
+   - Neither the name of the Developers nor the names of its contributors may
+     be used to endorse or promote products derived from this software without
+     specific prior written permission.
+
+   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 FOUNDATION 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 _CRYPTSTATE_H
+#define _CRYPTSTATE_H
+
+#include <openssl/rand.h>
+#include <openssl/aes.h>
+#include <stdint.h>
+#include "timer.h"
+#include "types.h"
+
+typedef struct CryptState {
+       uint8_t raw_key[AES_BLOCK_SIZE];
+       uint8_t encrypt_iv[AES_BLOCK_SIZE];
+       uint8_t decrypt_iv[AES_BLOCK_SIZE];
+       uint8_t decrypt_history[0x100];
+       
+       unsigned int uiGood;
+       unsigned int uiLate;
+       unsigned int uiLost;
+       unsigned int uiResync;
+       
+       unsigned int uiRemoteGood;
+       unsigned int uiRemoteLate;
+       unsigned int uiRemoteLost;
+       unsigned int uiRemoteResync;
+       
+       AES_KEY encrypt_key;
+       AES_KEY decrypt_key;
+       etimer_t tLastGood;
+       etimer_t tLastRequest;
+       bool_t bInit;   
+} cryptState_t;
+
+void CryptState_init(cryptState_t *cs);
+bool_t CryptState_isValid(cryptState_t *cs);
+void CryptState_genKey(cryptState_t *cs);
+void CryptState_setKey(cryptState_t *cs, const unsigned char *rkey, const unsigned char *eiv, const unsigned char *div);
+void CryptState_setDecryptIV(cryptState_t *cs, const unsigned char *iv);
+
+bool_t CryptState_decrypt(cryptState_t *cs, const unsigned char *source, unsigned char *dst, unsigned int crypted_length);
+void CryptState_encrypt(cryptState_t *cs, const unsigned char *source, unsigned char *dst, unsigned int plain_length);
+#endif
diff --git a/src/depend.mak b/src/depend.mak
new file mode 100644 (file)
index 0000000..7243217
--- /dev/null
@@ -0,0 +1,418 @@
+client.o: client.c /usr/include/sys/poll.h /usr/include/features.h \
+  /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \
+  /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \
+  /usr/include/bits/poll.h /usr/include/sys/socket.h \
+  /usr/include/sys/uio.h /usr/include/sys/types.h \
+  /usr/include/bits/types.h /usr/include/bits/typesizes.h \
+  /usr/include/time.h \
+  /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/stddef.h \
+  /usr/include/endian.h /usr/include/bits/endian.h \
+  /usr/include/bits/byteswap.h /usr/include/sys/select.h \
+  /usr/include/bits/select.h /usr/include/bits/sigset.h \
+  /usr/include/bits/time.h /usr/include/sys/sysmacros.h \
+  /usr/include/bits/pthreadtypes.h /usr/include/bits/uio.h \
+  /usr/include/bits/socket.h /usr/include/bits/sockaddr.h \
+  /usr/include/asm/socket.h /usr/include/asm/sockios.h \
+  /usr/include/errno.h /usr/include/bits/errno.h \
+  /usr/include/linux/errno.h /usr/include/asm/errno.h \
+  /usr/include/asm-generic/errno.h /usr/include/asm-generic/errno-base.h \
+  log.h types.h list.h client.h /usr/include/openssl/ssl.h \
+  /usr/include/openssl/e_os2.h /usr/include/openssl/opensslconf.h \
+  /usr/include/openssl/opensslconf-x86_64.h /usr/include/openssl/comp.h \
+  /usr/include/openssl/crypto.h /usr/include/stdlib.h \
+  /usr/include/alloca.h /usr/include/stdio.h /usr/include/libio.h \
+  /usr/include/_G_config.h /usr/include/wchar.h \
+  /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/stdarg.h \
+  /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
+  /usr/include/openssl/stack.h /usr/include/openssl/safestack.h \
+  /usr/include/openssl/opensslv.h /usr/include/openssl/ossl_typ.h \
+  /usr/include/openssl/symhacks.h /usr/include/openssl/bio.h \
+  /usr/include/openssl/x509.h /usr/include/openssl/buffer.h \
+  /usr/include/openssl/evp.h /usr/include/openssl/objects.h \
+  /usr/include/openssl/obj_mac.h /usr/include/openssl/asn1.h \
+  /usr/include/openssl/bn.h /usr/include/openssl/rsa.h \
+  /usr/include/openssl/dsa.h /usr/include/openssl/dh.h \
+  /usr/include/openssl/sha.h /usr/include/openssl/x509_vfy.h \
+  /usr/include/openssl/lhash.h /usr/include/openssl/pkcs7.h \
+  /usr/include/openssl/pem.h /usr/include/openssl/pem2.h \
+  /usr/include/openssl/kssl.h /usr/include/ctype.h /usr/include/krb5.h \
+  /usr/include/krb5/krb5.h \
+  /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/limits.h \
+  /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/syslimits.h \
+  /usr/include/limits.h /usr/include/bits/posix1_lim.h \
+  /usr/include/bits/local_lim.h /usr/include/linux/limits.h \
+  /usr/include/bits/posix2_lim.h /usr/include/et/com_err.h \
+  /usr/include/openssl/ssl2.h /usr/include/openssl/ssl3.h \
+  /usr/include/openssl/pq_compat.h /usr/include/openssl/tls1.h \
+  /usr/include/openssl/dtls1.h /usr/include/openssl/pqueue.h \
+  /usr/include/string.h /usr/include/openssl/ssl23.h \
+  /usr/include/stdint.h /usr/include/bits/wchar.h /usr/include/unistd.h \
+  /usr/include/bits/posix_opt.h /usr/include/bits/confname.h \
+  /usr/include/getopt.h /usr/include/netinet/in.h /usr/include/bits/in.h \
+  /usr/include/arpa/inet.h messages.h /usr/include/openssl/aes.h crypt.h \
+  /usr/include/openssl/rand.h timer.h ssl.h /usr/include/openssl/x509v3.h \
+  /usr/include/openssl/conf.h messagehandler.h pds.h conf.h channel.h
+main.o: main.c /usr/include/stdio.h /usr/include/features.h \
+  /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \
+  /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \
+  /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/stddef.h \
+  /usr/include/bits/types.h /usr/include/bits/typesizes.h \
+  /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \
+  /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/stdarg.h \
+  /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
+  /usr/include/unistd.h /usr/include/bits/posix_opt.h \
+  /usr/include/bits/confname.h /usr/include/getopt.h \
+  /usr/include/sys/types.h /usr/include/time.h /usr/include/endian.h \
+  /usr/include/bits/endian.h /usr/include/bits/byteswap.h \
+  /usr/include/sys/select.h /usr/include/bits/select.h \
+  /usr/include/bits/sigset.h /usr/include/bits/time.h \
+  /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \
+  /usr/include/sys/stat.h /usr/include/bits/stat.h /usr/include/fcntl.h \
+  /usr/include/bits/fcntl.h /usr/include/signal.h \
+  /usr/include/bits/signum.h /usr/include/bits/siginfo.h \
+  /usr/include/bits/sigaction.h /usr/include/bits/sigcontext.h \
+  /usr/include/bits/sigstack.h /usr/include/bits/sigthread.h \
+  /usr/include/sched.h /usr/include/bits/sched.h /usr/include/errno.h \
+  /usr/include/bits/errno.h /usr/include/linux/errno.h \
+  /usr/include/asm/errno.h /usr/include/asm-generic/errno.h \
+  /usr/include/asm-generic/errno-base.h server.h ssl.h \
+  /usr/include/openssl/x509v3.h /usr/include/openssl/bio.h \
+  /usr/include/openssl/e_os2.h /usr/include/openssl/opensslconf.h \
+  /usr/include/openssl/opensslconf-x86_64.h /usr/include/openssl/crypto.h \
+  /usr/include/stdlib.h /usr/include/alloca.h \
+  /usr/include/openssl/stack.h /usr/include/openssl/safestack.h \
+  /usr/include/openssl/opensslv.h /usr/include/openssl/ossl_typ.h \
+  /usr/include/openssl/symhacks.h /usr/include/openssl/x509.h \
+  /usr/include/openssl/buffer.h /usr/include/openssl/evp.h \
+  /usr/include/openssl/objects.h /usr/include/openssl/obj_mac.h \
+  /usr/include/openssl/asn1.h /usr/include/openssl/bn.h \
+  /usr/include/openssl/rsa.h /usr/include/openssl/dsa.h \
+  /usr/include/openssl/dh.h /usr/include/openssl/sha.h \
+  /usr/include/openssl/x509_vfy.h /usr/include/openssl/lhash.h \
+  /usr/include/openssl/pkcs7.h /usr/include/openssl/conf.h \
+  /usr/include/openssl/ssl.h /usr/include/openssl/comp.h \
+  /usr/include/openssl/pem.h /usr/include/openssl/pem2.h \
+  /usr/include/openssl/kssl.h /usr/include/ctype.h /usr/include/krb5.h \
+  /usr/include/krb5/krb5.h \
+  /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/limits.h \
+  /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/syslimits.h \
+  /usr/include/limits.h /usr/include/bits/posix1_lim.h \
+  /usr/include/bits/local_lim.h /usr/include/linux/limits.h \
+  /usr/include/bits/posix2_lim.h /usr/include/et/com_err.h \
+  /usr/include/openssl/ssl2.h /usr/include/openssl/ssl3.h \
+  /usr/include/openssl/pq_compat.h /usr/include/openssl/tls1.h \
+  /usr/include/openssl/dtls1.h /usr/include/openssl/pqueue.h \
+  /usr/include/string.h /usr/include/openssl/ssl23.h types.h channel.h \
+  log.h list.h client.h /usr/include/stdint.h /usr/include/bits/wchar.h \
+  /usr/include/sys/socket.h /usr/include/sys/uio.h \
+  /usr/include/bits/uio.h /usr/include/bits/socket.h \
+  /usr/include/bits/sockaddr.h /usr/include/asm/socket.h \
+  /usr/include/asm/sockios.h /usr/include/netinet/in.h \
+  /usr/include/bits/in.h /usr/include/arpa/inet.h /usr/include/sys/poll.h \
+  /usr/include/bits/poll.h messages.h /usr/include/openssl/aes.h crypt.h \
+  /usr/include/openssl/rand.h timer.h conf.h
+messages.o: messages.c /usr/include/stdlib.h /usr/include/features.h \
+  /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \
+  /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \
+  /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/stddef.h \
+  /usr/include/sys/types.h /usr/include/bits/types.h \
+  /usr/include/bits/typesizes.h /usr/include/time.h /usr/include/endian.h \
+  /usr/include/bits/endian.h /usr/include/bits/byteswap.h \
+  /usr/include/sys/select.h /usr/include/bits/select.h \
+  /usr/include/bits/sigset.h /usr/include/bits/time.h \
+  /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \
+  /usr/include/alloca.h /usr/include/stdio.h /usr/include/libio.h \
+  /usr/include/_G_config.h /usr/include/wchar.h \
+  /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/stdarg.h \
+  /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
+  /usr/include/string.h messages.h /usr/include/stdint.h \
+  /usr/include/bits/wchar.h /usr/include/openssl/aes.h \
+  /usr/include/openssl/opensslconf.h \
+  /usr/include/openssl/opensslconf-x86_64.h list.h types.h pds.h log.h
+pds.o: pds.c /usr/include/string.h /usr/include/features.h \
+  /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \
+  /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \
+  /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/stddef.h \
+  /usr/include/stdlib.h /usr/include/sys/types.h \
+  /usr/include/bits/types.h /usr/include/bits/typesizes.h \
+  /usr/include/time.h /usr/include/endian.h /usr/include/bits/endian.h \
+  /usr/include/bits/byteswap.h /usr/include/sys/select.h \
+  /usr/include/bits/select.h /usr/include/bits/sigset.h \
+  /usr/include/bits/time.h /usr/include/sys/sysmacros.h \
+  /usr/include/bits/pthreadtypes.h /usr/include/alloca.h pds.h \
+  /usr/include/stdint.h /usr/include/bits/wchar.h types.h log.h
+server.o: server.c /usr/include/stdio.h /usr/include/features.h \
+  /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \
+  /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \
+  /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/stddef.h \
+  /usr/include/bits/types.h /usr/include/bits/typesizes.h \
+  /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \
+  /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/stdarg.h \
+  /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
+  /usr/include/sys/time.h /usr/include/time.h /usr/include/bits/time.h \
+  /usr/include/sys/select.h /usr/include/bits/select.h \
+  /usr/include/bits/sigset.h /usr/include/sys/poll.h \
+  /usr/include/bits/poll.h /usr/include/netinet/tcp.h \
+  /usr/include/sys/types.h /usr/include/endian.h \
+  /usr/include/bits/endian.h /usr/include/bits/byteswap.h \
+  /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \
+  /usr/include/sys/socket.h /usr/include/sys/uio.h \
+  /usr/include/bits/uio.h /usr/include/bits/socket.h \
+  /usr/include/bits/sockaddr.h /usr/include/asm/socket.h \
+  /usr/include/asm/sockios.h /usr/include/errno.h \
+  /usr/include/bits/errno.h /usr/include/linux/errno.h \
+  /usr/include/asm/errno.h /usr/include/asm-generic/errno.h \
+  /usr/include/asm-generic/errno-base.h /usr/include/string.h \
+  /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/limits.h \
+  /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/syslimits.h \
+  /usr/include/limits.h /usr/include/bits/posix1_lim.h \
+  /usr/include/bits/local_lim.h /usr/include/linux/limits.h \
+  /usr/include/bits/posix2_lim.h /usr/include/unistd.h \
+  /usr/include/bits/posix_opt.h /usr/include/bits/confname.h \
+  /usr/include/getopt.h /usr/include/fcntl.h /usr/include/bits/fcntl.h \
+  client.h /usr/include/openssl/ssl.h /usr/include/openssl/e_os2.h \
+  /usr/include/openssl/opensslconf.h \
+  /usr/include/openssl/opensslconf-x86_64.h /usr/include/openssl/comp.h \
+  /usr/include/openssl/crypto.h /usr/include/stdlib.h \
+  /usr/include/alloca.h /usr/include/openssl/stack.h \
+  /usr/include/openssl/safestack.h /usr/include/openssl/opensslv.h \
+  /usr/include/openssl/ossl_typ.h /usr/include/openssl/symhacks.h \
+  /usr/include/openssl/bio.h /usr/include/openssl/x509.h \
+  /usr/include/openssl/buffer.h /usr/include/openssl/evp.h \
+  /usr/include/openssl/objects.h /usr/include/openssl/obj_mac.h \
+  /usr/include/openssl/asn1.h /usr/include/openssl/bn.h \
+  /usr/include/openssl/rsa.h /usr/include/openssl/dsa.h \
+  /usr/include/openssl/dh.h /usr/include/openssl/sha.h \
+  /usr/include/openssl/x509_vfy.h /usr/include/openssl/lhash.h \
+  /usr/include/openssl/pkcs7.h /usr/include/openssl/pem.h \
+  /usr/include/openssl/pem2.h /usr/include/openssl/kssl.h \
+  /usr/include/ctype.h /usr/include/krb5.h /usr/include/krb5/krb5.h \
+  /usr/include/et/com_err.h /usr/include/openssl/ssl2.h \
+  /usr/include/openssl/ssl3.h /usr/include/openssl/pq_compat.h \
+  /usr/include/openssl/tls1.h /usr/include/openssl/dtls1.h \
+  /usr/include/openssl/pqueue.h /usr/include/openssl/ssl23.h \
+  /usr/include/stdint.h /usr/include/bits/wchar.h \
+  /usr/include/netinet/in.h /usr/include/bits/in.h \
+  /usr/include/arpa/inet.h list.h types.h messages.h \
+  /usr/include/openssl/aes.h crypt.h /usr/include/openssl/rand.h timer.h \
+  conf.h log.h
+ssl.o: ssl.c /usr/include/openssl/x509v3.h /usr/include/openssl/bio.h \
+  /usr/include/openssl/e_os2.h /usr/include/openssl/opensslconf.h \
+  /usr/include/openssl/opensslconf-x86_64.h /usr/include/stdio.h \
+  /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \
+  /usr/include/gnu/stubs-64.h \
+  /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/stddef.h \
+  /usr/include/bits/types.h /usr/include/bits/typesizes.h \
+  /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \
+  /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/stdarg.h \
+  /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
+  /usr/include/openssl/crypto.h /usr/include/stdlib.h \
+  /usr/include/sys/types.h /usr/include/time.h /usr/include/endian.h \
+  /usr/include/bits/endian.h /usr/include/bits/byteswap.h \
+  /usr/include/sys/select.h /usr/include/bits/select.h \
+  /usr/include/bits/sigset.h /usr/include/bits/time.h \
+  /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \
+  /usr/include/alloca.h /usr/include/openssl/stack.h \
+  /usr/include/openssl/safestack.h /usr/include/openssl/opensslv.h \
+  /usr/include/openssl/ossl_typ.h /usr/include/openssl/symhacks.h \
+  /usr/include/openssl/x509.h /usr/include/openssl/buffer.h \
+  /usr/include/openssl/evp.h /usr/include/openssl/objects.h \
+  /usr/include/openssl/obj_mac.h /usr/include/openssl/asn1.h \
+  /usr/include/openssl/bn.h /usr/include/openssl/rsa.h \
+  /usr/include/openssl/dsa.h /usr/include/openssl/dh.h \
+  /usr/include/openssl/sha.h /usr/include/openssl/x509_vfy.h \
+  /usr/include/openssl/lhash.h /usr/include/openssl/pkcs7.h \
+  /usr/include/openssl/conf.h /usr/include/openssl/ssl.h \
+  /usr/include/openssl/comp.h /usr/include/openssl/pem.h \
+  /usr/include/openssl/pem2.h /usr/include/openssl/kssl.h \
+  /usr/include/ctype.h /usr/include/krb5.h /usr/include/krb5/krb5.h \
+  /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/limits.h \
+  /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/syslimits.h \
+  /usr/include/limits.h /usr/include/bits/posix1_lim.h \
+  /usr/include/bits/local_lim.h /usr/include/linux/limits.h \
+  /usr/include/bits/posix2_lim.h /usr/include/et/com_err.h \
+  /usr/include/openssl/ssl2.h /usr/include/openssl/ssl3.h \
+  /usr/include/openssl/pq_compat.h /usr/include/openssl/tls1.h \
+  /usr/include/openssl/dtls1.h /usr/include/openssl/pqueue.h \
+  /usr/include/string.h /usr/include/openssl/ssl23.h \
+  /usr/include/openssl/err.h /usr/include/errno.h \
+  /usr/include/bits/errno.h /usr/include/linux/errno.h \
+  /usr/include/asm/errno.h /usr/include/asm-generic/errno.h \
+  /usr/include/asm-generic/errno-base.h conf.h messages.h \
+  /usr/include/stdint.h /usr/include/bits/wchar.h \
+  /usr/include/openssl/aes.h list.h types.h log.h ssl.h
+log.o: log.c /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/stdarg.h \
+  /usr/include/stdio.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \
+  /usr/include/gnu/stubs-64.h \
+  /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/stddef.h \
+  /usr/include/bits/types.h /usr/include/bits/typesizes.h \
+  /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \
+  /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
+  /usr/include/stdlib.h /usr/include/sys/types.h /usr/include/time.h \
+  /usr/include/endian.h /usr/include/bits/endian.h \
+  /usr/include/bits/byteswap.h /usr/include/sys/select.h \
+  /usr/include/bits/select.h /usr/include/bits/sigset.h \
+  /usr/include/bits/time.h /usr/include/sys/sysmacros.h \
+  /usr/include/bits/pthreadtypes.h /usr/include/alloca.h \
+  /usr/include/syslog.h /usr/include/sys/syslog.h \
+  /usr/include/bits/syslog-path.h /usr/include/string.h log.h types.h
+conf.o: conf.c /usr/include/stdio.h /usr/include/features.h \
+  /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \
+  /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \
+  /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/stddef.h \
+  /usr/include/bits/types.h /usr/include/bits/typesizes.h \
+  /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \
+  /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/stdarg.h \
+  /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
+  /usr/include/stdlib.h /usr/include/sys/types.h /usr/include/time.h \
+  /usr/include/endian.h /usr/include/bits/endian.h \
+  /usr/include/bits/byteswap.h /usr/include/sys/select.h \
+  /usr/include/bits/select.h /usr/include/bits/sigset.h \
+  /usr/include/bits/time.h /usr/include/sys/sysmacros.h \
+  /usr/include/bits/pthreadtypes.h /usr/include/alloca.h \
+  /usr/include/string.h /usr/include/libconfig.h types.h conf.h \
+  messages.h /usr/include/stdint.h /usr/include/bits/wchar.h \
+  /usr/include/openssl/aes.h /usr/include/openssl/opensslconf.h \
+  /usr/include/openssl/opensslconf-x86_64.h list.h log.h
+crypt.o: crypt.c /usr/include/string.h /usr/include/features.h \
+  /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \
+  /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \
+  /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/stddef.h \
+  /usr/include/arpa/inet.h /usr/include/netinet/in.h \
+  /usr/include/stdint.h /usr/include/bits/wchar.h \
+  /usr/include/sys/socket.h /usr/include/sys/uio.h \
+  /usr/include/sys/types.h /usr/include/bits/types.h \
+  /usr/include/bits/typesizes.h /usr/include/time.h /usr/include/endian.h \
+  /usr/include/bits/endian.h /usr/include/bits/byteswap.h \
+  /usr/include/sys/select.h /usr/include/bits/select.h \
+  /usr/include/bits/sigset.h /usr/include/bits/time.h \
+  /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \
+  /usr/include/bits/uio.h /usr/include/bits/socket.h \
+  /usr/include/bits/sockaddr.h /usr/include/asm/socket.h \
+  /usr/include/asm/sockios.h /usr/include/bits/in.h crypt.h \
+  /usr/include/openssl/rand.h /usr/include/stdlib.h /usr/include/alloca.h \
+  /usr/include/openssl/ossl_typ.h /usr/include/openssl/e_os2.h \
+  /usr/include/openssl/opensslconf.h \
+  /usr/include/openssl/opensslconf-x86_64.h /usr/include/openssl/aes.h \
+  timer.h types.h log.h
+timer.o: timer.c /usr/include/sys/time.h /usr/include/features.h \
+  /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \
+  /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \
+  /usr/include/bits/types.h /usr/include/bits/typesizes.h \
+  /usr/include/time.h /usr/include/bits/time.h /usr/include/sys/select.h \
+  /usr/include/bits/select.h /usr/include/bits/sigset.h \
+  /usr/include/stdint.h /usr/include/bits/wchar.h /usr/include/stdio.h \
+  /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/stddef.h \
+  /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \
+  /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/stdarg.h \
+  /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h timer.h \
+  types.h
+messagehandler.o: messagehandler.c /usr/include/string.h \
+  /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \
+  /usr/include/gnu/stubs-64.h \
+  /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/stddef.h \
+  /usr/include/openssl/aes.h /usr/include/openssl/opensslconf.h \
+  /usr/include/openssl/opensslconf-x86_64.h log.h types.h list.h client.h \
+  /usr/include/openssl/ssl.h /usr/include/openssl/e_os2.h \
+  /usr/include/openssl/comp.h /usr/include/openssl/crypto.h \
+  /usr/include/stdlib.h /usr/include/sys/types.h \
+  /usr/include/bits/types.h /usr/include/bits/typesizes.h \
+  /usr/include/time.h /usr/include/endian.h /usr/include/bits/endian.h \
+  /usr/include/bits/byteswap.h /usr/include/sys/select.h \
+  /usr/include/bits/select.h /usr/include/bits/sigset.h \
+  /usr/include/bits/time.h /usr/include/sys/sysmacros.h \
+  /usr/include/bits/pthreadtypes.h /usr/include/alloca.h \
+  /usr/include/stdio.h /usr/include/libio.h /usr/include/_G_config.h \
+  /usr/include/wchar.h \
+  /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/stdarg.h \
+  /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
+  /usr/include/openssl/stack.h /usr/include/openssl/safestack.h \
+  /usr/include/openssl/opensslv.h /usr/include/openssl/ossl_typ.h \
+  /usr/include/openssl/symhacks.h /usr/include/openssl/bio.h \
+  /usr/include/openssl/x509.h /usr/include/openssl/buffer.h \
+  /usr/include/openssl/evp.h /usr/include/openssl/objects.h \
+  /usr/include/openssl/obj_mac.h /usr/include/openssl/asn1.h \
+  /usr/include/openssl/bn.h /usr/include/openssl/rsa.h \
+  /usr/include/openssl/dsa.h /usr/include/openssl/dh.h \
+  /usr/include/openssl/sha.h /usr/include/openssl/x509_vfy.h \
+  /usr/include/openssl/lhash.h /usr/include/openssl/pkcs7.h \
+  /usr/include/openssl/pem.h /usr/include/openssl/pem2.h \
+  /usr/include/openssl/kssl.h /usr/include/ctype.h /usr/include/krb5.h \
+  /usr/include/krb5/krb5.h \
+  /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/limits.h \
+  /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/syslimits.h \
+  /usr/include/limits.h /usr/include/bits/posix1_lim.h \
+  /usr/include/bits/local_lim.h /usr/include/linux/limits.h \
+  /usr/include/bits/posix2_lim.h /usr/include/et/com_err.h \
+  /usr/include/openssl/ssl2.h /usr/include/openssl/ssl3.h \
+  /usr/include/openssl/pq_compat.h /usr/include/openssl/tls1.h \
+  /usr/include/openssl/dtls1.h /usr/include/openssl/pqueue.h \
+  /usr/include/openssl/ssl23.h /usr/include/stdint.h \
+  /usr/include/bits/wchar.h /usr/include/unistd.h \
+  /usr/include/bits/posix_opt.h /usr/include/bits/confname.h \
+  /usr/include/getopt.h /usr/include/sys/socket.h /usr/include/sys/uio.h \
+  /usr/include/bits/uio.h /usr/include/bits/socket.h \
+  /usr/include/bits/sockaddr.h /usr/include/asm/socket.h \
+  /usr/include/asm/sockios.h /usr/include/netinet/in.h \
+  /usr/include/bits/in.h /usr/include/arpa/inet.h /usr/include/errno.h \
+  /usr/include/bits/errno.h /usr/include/linux/errno.h \
+  /usr/include/asm/errno.h /usr/include/asm-generic/errno.h \
+  /usr/include/asm-generic/errno-base.h /usr/include/sys/poll.h \
+  /usr/include/bits/poll.h messages.h crypt.h /usr/include/openssl/rand.h \
+  timer.h channel.h conf.h
+channel.o: channel.c log.h types.h list.h client.h \
+  /usr/include/openssl/ssl.h /usr/include/openssl/e_os2.h \
+  /usr/include/openssl/opensslconf.h \
+  /usr/include/openssl/opensslconf-x86_64.h /usr/include/openssl/comp.h \
+  /usr/include/openssl/crypto.h /usr/include/stdlib.h \
+  /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \
+  /usr/include/gnu/stubs-64.h \
+  /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/stddef.h \
+  /usr/include/sys/types.h /usr/include/bits/types.h \
+  /usr/include/bits/typesizes.h /usr/include/time.h /usr/include/endian.h \
+  /usr/include/bits/endian.h /usr/include/bits/byteswap.h \
+  /usr/include/sys/select.h /usr/include/bits/select.h \
+  /usr/include/bits/sigset.h /usr/include/bits/time.h \
+  /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \
+  /usr/include/alloca.h /usr/include/stdio.h /usr/include/libio.h \
+  /usr/include/_G_config.h /usr/include/wchar.h \
+  /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/stdarg.h \
+  /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
+  /usr/include/openssl/stack.h /usr/include/openssl/safestack.h \
+  /usr/include/openssl/opensslv.h /usr/include/openssl/ossl_typ.h \
+  /usr/include/openssl/symhacks.h /usr/include/openssl/bio.h \
+  /usr/include/openssl/x509.h /usr/include/openssl/buffer.h \
+  /usr/include/openssl/evp.h /usr/include/openssl/objects.h \
+  /usr/include/openssl/obj_mac.h /usr/include/openssl/asn1.h \
+  /usr/include/openssl/bn.h /usr/include/openssl/rsa.h \
+  /usr/include/openssl/dsa.h /usr/include/openssl/dh.h \
+  /usr/include/openssl/sha.h /usr/include/openssl/x509_vfy.h \
+  /usr/include/openssl/lhash.h /usr/include/openssl/pkcs7.h \
+  /usr/include/openssl/pem.h /usr/include/openssl/pem2.h \
+  /usr/include/openssl/kssl.h /usr/include/ctype.h /usr/include/krb5.h \
+  /usr/include/krb5/krb5.h \
+  /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/limits.h \
+  /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/syslimits.h \
+  /usr/include/limits.h /usr/include/bits/posix1_lim.h \
+  /usr/include/bits/local_lim.h /usr/include/linux/limits.h \
+  /usr/include/bits/posix2_lim.h /usr/include/et/com_err.h \
+  /usr/include/openssl/ssl2.h /usr/include/openssl/ssl3.h \
+  /usr/include/openssl/pq_compat.h /usr/include/openssl/tls1.h \
+  /usr/include/openssl/dtls1.h /usr/include/openssl/pqueue.h \
+  /usr/include/string.h /usr/include/openssl/ssl23.h \
+  /usr/include/stdint.h /usr/include/bits/wchar.h /usr/include/unistd.h \
+  /usr/include/bits/posix_opt.h /usr/include/bits/confname.h \
+  /usr/include/getopt.h /usr/include/sys/socket.h /usr/include/sys/uio.h \
+  /usr/include/bits/uio.h /usr/include/bits/socket.h \
+  /usr/include/bits/sockaddr.h /usr/include/asm/socket.h \
+  /usr/include/asm/sockios.h /usr/include/netinet/in.h \
+  /usr/include/bits/in.h /usr/include/arpa/inet.h /usr/include/errno.h \
+  /usr/include/bits/errno.h /usr/include/linux/errno.h \
+  /usr/include/asm/errno.h /usr/include/asm-generic/errno.h \
+  /usr/include/asm-generic/errno-base.h /usr/include/sys/poll.h \
+  /usr/include/bits/poll.h messages.h /usr/include/openssl/aes.h crypt.h \
+  /usr/include/openssl/rand.h timer.h channel.h conf.h
diff --git a/src/list.h b/src/list.h
new file mode 100644 (file)
index 0000000..37ec739
--- /dev/null
@@ -0,0 +1,57 @@
+#ifndef LIST_H_87698769870987
+#define LIST_H_87698769870987
+
+struct dlist {
+       struct dlist *next, *prev;
+};
+
+#define init_list_entry(ptr) \
+        do { \
+            (ptr)->prev = ptr; (ptr)->next = ptr; } \
+        while(0);
+#define declare_list(_name_) struct dlist _name_ = {&(_name_), &(_name_) }
+
+static inline void list_add_head(struct dlist *new, struct dlist *list)
+{
+       list->next->prev = new;
+       new->prev = list;
+       new->next = list->next;
+       list->next = new;
+}
+
+static inline void list_add_tail(struct dlist *new, struct dlist *list)
+{
+       list->prev->next = new;
+       new->prev = list->prev;
+       new->next = list;
+       list->prev = new;
+}
+static inline void list_del(struct dlist *entry)
+{
+       entry->next->prev = entry->prev;
+       entry->prev->next = entry->next;
+}
+
+static inline int list_empty(struct dlist *list)
+{
+       return list->next == list;
+}
+
+#define list_get_first(listhead) \
+        ((listhead)->next)
+
+#define list_get_next(_entry_) \
+        ((_entry_)->next)
+
+#define list_get_entry(entry, type, structmember) \
+        ((type *) ((char *)(entry) - (unsigned long)(&((type *)0)->structmember)))
+
+#define list_iterate(entry, listhead) \
+        for(entry = (listhead)->next; entry != (listhead); entry = entry->next)
+
+#define list_iterate_safe(entry, save, listhead) \
+        for(entry = (listhead)->next, save = entry->next; entry != (listhead); \
+            entry = save, save = save->next)
+
+
+#endif /* #ifndef LIST_H_87698769870987 */
diff --git a/src/log.c b/src/log.c
new file mode 100644 (file)
index 0000000..f3bfea6
--- /dev/null
+++ b/src/log.c
@@ -0,0 +1,141 @@
+/* Copyright (C) 2009, Martin Johansson <martin@fatbob.nu>
+   Copyright (C) 2005-2009, Thorvald Natvig <thorvald@natvig.com>
+
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+   - 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.
+   - Neither the name of the Developers nor the names of its contributors may
+     be used to endorse or promote products derived from this software without
+     specific prior written permission.
+
+   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 FOUNDATION 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 <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <string.h>
+
+#include "log.h"
+
+#define BUFSIZE 254
+
+static bool_t termprint;
+
+void Log_init(bool_t terminal)
+{
+       termprint = terminal;
+       if (!termprint)
+               openlog("uMurmud", LOG_PID, LOG_DAEMON);
+}
+
+void Log_free()
+{
+       if (!termprint)
+               closelog();
+}
+               
+
+void logthis(const char *logstring, ...)
+{
+       va_list argp;
+       char buf[BUFSIZE + 2];
+       
+       va_start(argp, logstring);
+       vsnprintf(&buf[0], BUFSIZE, logstring, argp);
+       va_end(argp);
+       strcat(buf, "\n");
+       if (termprint)
+               fprintf(stderr, "%s", buf); /* XXX - other targets for logging */
+       else
+               syslog(LOG_INFO, buf);
+}
+
+void Log_warn(const char *logstring, ...)
+{
+       va_list argp;
+       char buf[BUFSIZE + 2];
+       int offset = 0;
+       
+       va_start(argp, logstring);
+       offset = sprintf(buf, "WARN: ");
+       vsnprintf(&buf[offset], BUFSIZE - offset, logstring, argp);
+       va_end(argp);
+       strcat(buf, "\n");
+       if (termprint)
+               fprintf(stderr, "%s", buf); /* XXX - other targets for logging */
+       else
+               syslog(LOG_ALERT, buf);
+}
+
+void Log_info(const char *logstring, ...)
+{
+       va_list argp;
+       char buf[BUFSIZE + 2];
+       int offset = 0;
+       
+       va_start(argp, logstring);
+       offset = sprintf(buf, "INFO: ");
+       vsnprintf(&buf[offset], BUFSIZE - offset, logstring, argp);
+       va_end(argp);
+       strcat(buf, "\n");
+       if (termprint)
+               fprintf(stderr, "%s", buf); /* XXX - other targets for logging */
+       else
+               syslog(LOG_ALERT, buf);
+}
+
+#ifdef DEBUG
+void Log_debug(const char *logstring, ...)
+{
+       va_list argp;
+       char buf[BUFSIZE + 2];
+       int offset = 0;
+       
+       va_start(argp, logstring);
+       offset = sprintf(buf, "DEBUG: ");
+       vsnprintf(&buf[offset], BUFSIZE - offset, logstring, argp);
+       va_end(argp);
+       strcat(buf, "\n");
+       if (termprint)
+               fprintf(stderr, "%s", buf); /* XXX - other targets for logging */
+       else
+               syslog(LOG_INFO, buf);
+}
+#endif
+
+void Log_fatal(const char *logstring, ...)
+{
+       va_list argp;
+       char buf[BUFSIZE + 2];
+       int offset = 0;
+       va_start(argp, logstring);
+       offset = sprintf(buf, "FATAL: ");
+       vsnprintf(&buf[offset], BUFSIZE - offset, logstring, argp);
+       va_end(argp);
+       strcat(buf, "\n");
+       if (termprint)
+               fprintf(stderr, "%s", buf); /* XXX - other targets for logging */
+       else
+               syslog(LOG_INFO, buf);
+       exit(1);
+}
diff --git a/src/log.h b/src/log.h
new file mode 100644 (file)
index 0000000..66a2949
--- /dev/null
+++ b/src/log.h
@@ -0,0 +1,60 @@
+/* Copyright (C) 2009, Martin Johansson <martin@fatbob.nu>
+   Copyright (C) 2005-2009, Thorvald Natvig <thorvald@natvig.com>
+
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+   - 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.
+   - Neither the name of the Developers nor the names of its contributors may
+     be used to endorse or promote products derived from this software without
+     specific prior written permission.
+
+   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 FOUNDATION 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 LOG_H_2435642356
+#define LOG_H_2435642356
+
+#include "types.h"
+
+#define doAssert(_cond_) do {                                  \
+               if (!(_cond_)) {                                                                                                \
+                       logthis("Assertion failed in %s: Line: %d Function: %s", __FILE__, __LINE__, __FUNCTION__); \
+                       abort();                                                                                                        \
+               }                                                                                                                               \
+       } while (0)
+
+
+void logthis(const char *logstring, ...);
+
+#ifdef DEBUG
+void Log_debug(const char *logstring, ...);
+#else
+#define Log_debug(_args_, ...) ((void)0)
+#endif
+
+void Log_warn(const char *logstring, ...);
+void Log_info(const char *logstring, ...);
+void Log_fatal(const char *logstring, ...);
+
+void Log_init(bool_t terminal);
+void Log_free();
+
+#endif
+
diff --git a/src/main.c b/src/main.c
new file mode 100644 (file)
index 0000000..6892907
--- /dev/null
@@ -0,0 +1,197 @@
+/* Copyright (C) 2009, Martin Johansson <martin@fatbob.nu>
+   Copyright (C) 2005-2009, Thorvald Natvig <thorvald@natvig.com>
+
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+   - 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.
+   - Neither the name of the Developers nor the names of its contributors may
+     be used to endorse or promote products derived from this software without
+     specific prior written permission.
+
+   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 FOUNDATION 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 <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sched.h>
+#include <errno.h>
+
+#include "server.h"
+#include "ssl.h"
+#include "channel.h"
+#include "log.h"
+#include "client.h"
+#include "conf.h"
+
+#define UMURMUR_VERSION "0.1.0"
+
+void lockfile(const char *pidfile)
+{
+       int lfp;
+       char str[16];
+       
+       lfp = open(pidfile, O_RDWR|O_CREAT, 0640);
+       
+       if (lfp < 0)
+               Log_fatal("Cannot open PID-file %s for writing", pidfile);
+       sprintf(str,"%d\n",getpid());
+       write(lfp, str, strlen(str)); /* record pid to lockfile */
+       Log_info("PID-file: %s", pidfile);
+}
+
+
+void signal_handler(int sig)
+{
+       switch(sig) {
+       case SIGHUP:
+               /* XXX - do stuff? */
+               Log_info("HUP signal");
+               break;
+       case SIGTERM:
+               Log_info("TERM signal. Shutting down.");
+               Server_shutdown();
+               break;
+       }
+}
+
+void daemonize()
+{
+       int i;
+       
+       if (getppid() == 1)
+               return; /* already a daemon */
+       i = fork();
+       if ( i < 0) {
+               fprintf(stderr, "Fork error. Exiting\n");
+               exit(1); /* fork error */
+       }
+       if ( i > 0)
+               exit(0); /* parent exits */
+       
+       /* child (daemon) continues */
+       setsid(); /* obtain a new process group */
+       for (i = getdtablesize(); i >= 0; --i)
+               close(i); /* close all descriptors */
+       
+       i = open("/dev/null",O_RDWR);
+       dup(i);
+       dup(i);
+       
+       umask(027); /* set newly created file permissions */
+       chdir("/");
+               
+}
+
+void setscheduler()
+{
+       int rc;
+       struct sched_param sp;
+
+       sp.sched_priority = sched_get_priority_min(SCHED_RR); /* Should suffice */
+       Log_info("Setting SCHED_RR prio %d", sp.sched_priority);
+       rc = sched_setscheduler(0, SCHED_RR, &sp);
+       if (rc < 0)
+               Log_warn("Failed to set scheduler: %s", strerror(errno));
+}
+
+void printhelp()
+{
+       printf("uMurmur version %s. Mumble protocol %d\n", UMURMUR_VERSION, MESSAGE_STREAM_VERSION);
+       printf("Usage: umurmurd [-d] [-p <pidfile>] [-c <conf file>] [-h]\n");
+       printf("       -d             - Do not deamonize\n");
+       printf("       -p <pidfile>   - Write PID to this file\n");
+       printf("       -c <conf file> - Specify configuration file\n");
+       printf("       -h             - Print this help\n");
+       exit(0);
+}
+
+int main(int argc, char **argv)
+{
+       bool_t nodaemon = false;
+       char *conffile = NULL, *pidfile = NULL;
+       int c;
+       
+       /* Arguments */
+       while ((c = getopt(argc, argv, "dp:c:h")) != EOF) {
+               switch(c) {
+               case 'c':
+                       conffile = optarg;
+                       break;
+               case 'p':
+                       pidfile = optarg;
+                       break;
+               case 'd':
+                       nodaemon = true;
+                       break;
+               case 'h':
+                       printhelp();
+                       break;
+               default:
+                       fprintf(stderr, "Unrecognized option\n");
+                       printhelp();
+                       break;
+               }
+       }
+       
+       if (Conf_init(conffile) != 0) {
+               fprintf(stderr, "Configuration error\n");
+               exit(1);
+       }
+               
+       if (!nodaemon) {
+               Log_init(false);
+               daemonize();
+               if (pidfile != NULL)
+                       lockfile(pidfile);
+       }
+       else
+               Log_init(true);
+       
+       signal(SIGCHLD, SIG_IGN); /* ignore child */
+       signal(SIGTSTP, SIG_IGN); /* ignore tty signals */
+       signal(SIGTTOU, SIG_IGN);
+       signal(SIGTTIN, SIG_IGN);
+       signal(SIGHUP, signal_handler); /* catch hangup signal */
+       signal(SIGTERM, signal_handler); /* catch kill signal */
+
+       /* Initializing */
+       SSL_init();
+       Chan_init();
+       Client_init();
+
+       setscheduler();
+       Server_run();
+       
+       SSL_deinit();
+       Chan_free();
+       Log_free();
+       Conf_deinit();
+       
+       if (pidfile != NULL)
+               unlink(pidfile);
+       
+       return 0;
+}
diff --git a/src/messagehandler.c b/src/messagehandler.c
new file mode 100644 (file)
index 0000000..8cca053
--- /dev/null
@@ -0,0 +1,351 @@
+/* Copyright (C) 2009, Martin Johansson <martin@fatbob.nu>
+   Copyright (C) 2005-2009, Thorvald Natvig <thorvald@natvig.com>
+
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+   - 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.
+   - Neither the name of the Developers nor the names of its contributors may
+     be used to endorse or promote products derived from this software without
+     specific prior written permission.
+
+   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 FOUNDATION 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 <string.h>
+#include <openssl/aes.h>
+
+#include "log.h"
+#include "list.h"
+#include "client.h"
+#include "messages.h"
+#include "crypt.h"
+#include "channel.h"
+#include "conf.h"
+
+extern channel_t *defaultChan;
+
+static void sendServerReject(client_t *client, const char *reason, rejectType_t type)
+{
+       message_t *msg = Msg_create(ServerReject);
+       msg->sessionId = client->sessionId;
+       strcpy(msg->payload.serverReject.reason, reason);
+       msg->payload.serverReject.type = type;
+       Client_send_message(client, msg);
+}
+
+static void sendPermissionDenied(client_t *client, const char *reason)
+{
+       message_t *msg = Msg_create(PermissionDenied);
+       msg->sessionId = client->sessionId;
+       strncpy(msg->payload.permissionDenied.reason, reason, MAX_TEXT);
+       Client_send_message(client, msg);
+}
+
+void Mh_handle_message(client_t *client, message_t *msg)
+{
+       message_t *sendmsg;
+       channel_t *ch_itr = NULL;
+       client_t *client_itr;
+       
+       switch (msg->messageType) {
+       case ServerAuthenticate:
+               /*
+                * 1. Check stuff, Serverreject if not ok
+                * 2. Setup UDP encryption -> MessageCryptSetup
+                * 3. (Enter channel)
+                * 4. MessageChannelAdd + MessageChannelDescUpdate for all channels
+                * 5. (MessageChannelLink)
+                * 6. MessageServerJoin
+                * 7. MessagePlayerMove
+                * 8. MessageServerJoin for all connected users
+                * 9. PlayerDeaf/PlayerMute/PlayerSelfMuteDeaf for all users it applies to
+                * 10. MessageServerSync
+                */
+               if (msg->payload.serverAuthenticate.version != MESSAGE_STREAM_VERSION) {
+                       char buf[64];
+                       sprintf(buf, "Wrong version of mumble protocol (client: %d, server: %d)",
+                                       msg->payload.serverAuthenticate.version, MESSAGE_STREAM_VERSION);
+                       sendServerReject(client, buf, WrongVersion);
+                       goto disconnect;
+               }
+                               
+               client_itr = NULL;
+               while (Client_iterate(&client_itr) != NULL) {
+                       if (!IS_AUTH(client_itr))
+                               continue;
+                       if (strncmp(client_itr->playerName, msg->payload.serverAuthenticate.userName, MAX_TEXT) == 0) {
+                               char buf[64];
+                               sprintf(buf, "Username already in use");
+                               sendServerReject(client, buf, UsernameInUse);
+                               goto disconnect;
+                       }                               
+               }
+               
+               if (strncmp(getStrConf(PASSPHRASE), msg->payload.serverAuthenticate.password, MAX_TEXT) != 0) {
+                       char buf[64];
+                       sprintf(buf, "Wrong server password");
+                       sendServerReject(client, buf, WrongServerPW);
+                       goto disconnect;
+               }                               
+
+               if (strlen(msg->payload.serverAuthenticate.userName) == 0) { /* XXX - other invalid names? */
+                       char buf[64];
+                       sprintf(buf, "Invalid username");
+                       sendServerReject(client, buf, InvalidUsername);
+                       goto disconnect;
+               }                               
+
+               if (Client_count() >= getIntConf(MAX_CLIENTS)) {
+                       char buf[64];
+                       sprintf(buf, "Server is full (max %d users)", getIntConf(MAX_CLIENTS));
+                       sendServerReject(client, buf, ServerFull);
+                       goto disconnect;
+               }
+               
+               /* Name & password */
+               strncpy(client->playerName, msg->payload.serverAuthenticate.userName, MAX_TEXT);
+               client->playerId = client->sessionId;
+
+               client->authenticated = true;
+               
+               /* XXX - Kick ghost */
+               
+               /* Setup UDP encryption */
+               CryptState_init(&client->cryptState);
+               CryptState_genKey(&client->cryptState);
+               sendmsg = Msg_create(CryptSetup);
+               sendmsg->sessionId = client->sessionId;
+               memcpy(sendmsg->payload.cryptSetup.key, client->cryptState.raw_key, AES_BLOCK_SIZE);
+               memcpy(sendmsg->payload.cryptSetup.serverNonce, client->cryptState.encrypt_iv, AES_BLOCK_SIZE);
+               memcpy(sendmsg->payload.cryptSetup.clientNonce, client->cryptState.decrypt_iv, AES_BLOCK_SIZE);
+               Client_send_message(client, sendmsg);
+
+               /* Channel stuff */
+               Chan_playerJoin(defaultChan, client); /* Join default channel */
+
+               /* Iterate channels and send channel info */
+               ch_itr = NULL;
+               Chan_iterate(&ch_itr);
+               do {
+                       sendmsg = Msg_create(ChannelAdd);
+                       sendmsg->sessionId = 0;
+                       sendmsg->payload.channelAdd.id = ch_itr->id;
+                       if (ch_itr->id == 0)
+                               sendmsg->payload.channelAdd.parentId = -1;
+                       else
+                               sendmsg->payload.channelAdd.parentId = ch_itr->parent->id;
+                       strcpy(sendmsg->payload.channelAdd.name, ch_itr->name);
+                       Client_send_message(client, sendmsg);
+                       
+                       sendmsg = Msg_create(ChannelDescUpdate);
+                       sendmsg->sessionId = 0;
+                       sendmsg->payload.channelDescUpdate.id = ch_itr->id;
+                       strcpy(sendmsg->payload.channelDescUpdate.desc, ch_itr->desc);
+                       Client_send_message(client, sendmsg);
+                       
+                       Chan_iterate(&ch_itr);
+               } while (ch_itr != NULL);
+
+               /* Not supporting channel link for now */
+
+               /* Server join for connecting user */
+               sendmsg = Msg_create(ServerJoin);
+               sendmsg->sessionId = client->sessionId;
+               sendmsg->payload.serverJoin.id = client->playerId;
+               strcpy(sendmsg->payload.serverJoin.playerName, client->playerName);
+               Client_send_message_except(client, sendmsg);
+
+               /* Player move for connecting user */
+               if (((channel_t *)client->channel)->id != 0) {
+                       sendmsg = Msg_create(PlayerMove);
+                       sendmsg->sessionId = client->sessionId;
+                       sendmsg->payload.playerMove.victim = client->playerId;
+                       sendmsg->payload.playerMove.channel = ((channel_t *)client->channel)->id;
+                       Client_send_message_except(client, sendmsg);
+               }
+               client_itr = NULL;
+               while (Client_iterate(&client_itr) != NULL) {
+                       if (!IS_AUTH(client_itr))
+                               continue;
+                       sendmsg = Msg_create(ServerJoin);
+                       sendmsg->sessionId = client_itr->sessionId;
+                       sendmsg->payload.serverJoin.id = client_itr->playerId;
+                       strncpy(sendmsg->payload.serverJoin.playerName, client_itr->playerName, MAX_TEXT);
+                       Client_send_message(client, sendmsg);
+                       
+                       sendmsg = Msg_create(PlayerMove);
+                       sendmsg->sessionId = client_itr->sessionId;
+                       sendmsg->payload.playerMove.victim = client_itr->playerId;
+                       sendmsg->payload.playerMove.channel = ((channel_t *)client_itr->channel)->id;
+                       Client_send_message(client, sendmsg);
+               }
+               
+               sendmsg = Msg_create(ServerSync);
+               sendmsg->sessionId = client->sessionId;
+               strcpy(sendmsg->payload.serverSync.welcomeText, getStrConf(WELCOMETEXT));
+               sendmsg->payload.serverSync.maxBandwidth = getIntConf(MAX_BANDWIDTH);
+               Client_send_message(client, sendmsg);
+               
+               Log_info("Player %s authenticated", client->playerName);
+               
+               break;
+               
+       case PingStats:
+               client->cryptState.uiRemoteGood = msg->payload.pingStats.good;
+               client->cryptState.uiRemoteLate = msg->payload.pingStats.late;
+               client->cryptState.uiRemoteLost = msg->payload.pingStats.lost;
+               client->cryptState.uiRemoteResync = msg->payload.pingStats.resync;
+
+               Log_debug("Pingstats <-: %d %d %d %d",
+                                 client->cryptState.uiRemoteGood, client->cryptState.uiRemoteLate,
+                                 client->cryptState.uiRemoteLost, client->cryptState.uiRemoteResync);
+               
+               /* Ignoring the double values since they don't seem to be used */
+               sendmsg = Msg_create(PingStats);
+               sendmsg->sessionId = client->sessionId;
+               sendmsg->payload.pingStats.timestamp = msg->payload.pingStats.timestamp;
+               
+               sendmsg->payload.pingStats.good = client->cryptState.uiGood;
+               sendmsg->payload.pingStats.late = client->cryptState.uiLate;
+               sendmsg->payload.pingStats.lost = client->cryptState.uiLost;
+               sendmsg->payload.pingStats.resync = client->cryptState.uiResync;
+               
+               Client_send_message(client, sendmsg);
+               Log_debug("Pingstats ->: %d %d %d %d",
+                                 client->cryptState.uiGood, client->cryptState.uiLate,
+                                 client->cryptState.uiLost, client->cryptState.uiResync);
+
+               break;
+       case Ping:
+               sendmsg = Msg_create(Ping);
+               sendmsg->sessionId = client->sessionId;
+               sendmsg->payload.ping.timestamp = msg->payload.ping.timestamp;
+               Client_send_message(client, sendmsg);
+               break;
+       case CryptSync:
+               Log_debug("Voice channel crypt resync requested");
+               if (msg->payload.cryptSync.empty) {
+                       sendmsg = Msg_create(CryptSync);
+                       sendmsg->sessionId = msg->sessionId;
+                       sendmsg->payload.cryptSync.empty = false;
+                       memcpy(sendmsg->payload.cryptSync.nonce, client->cryptState.decrypt_iv, AES_BLOCK_SIZE);
+                       Client_send_message(client, sendmsg);
+               } else {
+                       memcpy(client->cryptState.decrypt_iv, msg->payload.cryptSync.nonce, AES_BLOCK_SIZE);
+                       client->cryptState.uiResync++;
+               }
+               break;
+       case PlayerMute:
+               if (msg->payload.playerMute.victim != client->playerId) {
+                       sendPermissionDenied(client, "Permission denied");
+               } else {
+                       Log_debug("Player ID %d muted", msg->payload.playerMute.victim);
+                       client->mute = msg->payload.playerMute.bMute;                   
+               }
+               break;
+       case PlayerDeaf:
+               if (msg->payload.playerDeaf.victim != client->playerId) {
+                       sendPermissionDenied(client, "Permission denied");
+               } else {
+                       Log_debug("Player ID %d deaf", msg->payload.playerDeaf.victim);
+                       client->deaf = msg->payload.playerDeaf.bDeaf;
+               }
+               break;
+       case TextMessage:
+               if (msg->payload.textMessage.bTree)
+                       sendPermissionDenied(client, "Tree message not supported");
+               else if (msg->payload.textMessage.channel != -1) { /* To channel */
+                       channel_t *ch_itr = NULL;
+                       do {
+                               Chan_iterate(&ch_itr);
+                       } while (ch_itr != NULL && ch_itr->id != msg->payload.textMessage.channel);
+                       if (ch_itr == NULL)
+                               Log_warn("Channel id %d not found - ignoring.", msg->payload.textMessage.channel);
+                       else {
+                               struct dlist *itr;
+                               list_iterate(itr, &ch_itr->clients) {
+                                       client_t *c;
+                                       c = list_get_entry(itr, client_t, chan_node);
+                                       if (c != client && !c->deaf) {
+                                               Msg_inc_ref(msg);
+                                               Client_send_message(c, msg);
+                                               Log_debug("Text message to player ID %d", c->playerId);
+                                       }
+                               }
+                       }
+               } else { /* To player */
+                       client_t *itr = NULL;
+                       while (Client_iterate(&itr) != NULL) {
+                               if (!IS_AUTH(itr))
+                                       continue;
+                               if (itr->playerId == msg->payload.textMessage.victim) {
+                                       if (!itr->deaf) {
+                                               Msg_inc_ref(msg);
+                                               Client_send_message(itr, msg);
+                                       }
+                                       break;
+                               }
+                       }
+                       if (itr == NULL)
+                               Log_warn("TextMessage: Player ID %d not found", msg->payload.textMessage.victim);
+               }
+               break;
+       case PlayerSelfMuteDeaf:
+               client->deaf = msg->payload.playerSelfMuteDeaf.bDeaf;
+               client->mute = msg->payload.playerSelfMuteDeaf.bMute;
+               Log_debug("Player ID %d %s and %s", client->playerId, client->deaf ? "deaf": "not deaf",
+                                 client->mute ? "mute" : "not mute");
+               break;
+       case PlayerMove:
+               Msg_inc_ref(msg); /* Re-use message */
+               Client_send_message_except(NULL, msg);
+               Chan_playerJoin_id(msg->payload.playerMove.channel, client);            
+               break;
+
+               /* Permission denied for all these messages. Not implemented. */
+       case PlayerRename:
+       case ChannelAdd:
+       case ChannelDescUpdate:
+       case ContextAction:
+       case ContextAddAction:
+       case ServerBanList:
+       case PlayerKick:
+       case PlayerBan:
+       case ChannelRemove:
+       case ChannelMove:
+       case ChannelLink:
+       case ChannelRename:
+       case EditACL:
+               sendPermissionDenied(client, "Not supported by uMurmur");
+               break;
+               
+       case PlayerTexture: /* Ignore */
+               break;
+               
+       default:
+               Log_warn("Message %d not handled", msg->messageType);
+               break;
+       }
+       Msg_free(msg);
+       return;
+disconnect:
+       Msg_free(msg);
+       Client_close(client);
+}
diff --git a/src/messagehandler.h b/src/messagehandler.h
new file mode 100644 (file)
index 0000000..cd46cd7
--- /dev/null
@@ -0,0 +1,36 @@
+/* Copyright (C) 2009, Martin Johansson <martin@fatbob.nu>
+   Copyright (C) 2005-2009, Thorvald Natvig <thorvald@natvig.com>
+
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+   - 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.
+   - Neither the name of the Developers nor the names of its contributors may
+     be used to endorse or promote products derived from this software without
+     specific prior written permission.
+
+   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 FOUNDATION 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 MESSAGEHANDLER_H_8907
+#define MESSAGEHANDLER_H_8907
+
+void Mh_handle_message(client_t *client, message_t *msg);
+
+#endif
diff --git a/src/messages.c b/src/messages.c
new file mode 100644 (file)
index 0000000..42f1fa9
--- /dev/null
@@ -0,0 +1,353 @@
+/* Copyright (C) 2009, Martin Johansson <martin@fatbob.nu>
+   Copyright (C) 2005-2009, Thorvald Natvig <thorvald@natvig.com>
+
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+   - 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.
+   - Neither the name of the Developers nor the names of its contributors may
+     be used to endorse or promote products derived from this software without
+     specific prior written permission.
+
+   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 FOUNDATION 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 <string.h>
+
+#include "messages.h"
+#include "pds.h"
+#include "log.h"
+
+
+void dumpmsg(uint8_t *data, int size);
+
+int Msg_messageToNetwork(message_t *msg, uint8_t *buffer, int bufsize)
+{
+       pds_t *pds = Pds_create(buffer, bufsize);
+       int len;
+       
+       Pds_add_numval(pds, msg->messageType);
+       Pds_add_numval(pds, msg->sessionId);
+       
+       switch (msg->messageType) {
+               case Speex:
+                       Pds_add_numval(pds, msg->payload.speex.seq);
+                       Pds_append_data_nosize(pds, msg->payload.speex.data, msg->payload.speex.size);
+                       break;
+               case ServerReject:
+                       Pds_add_string(pds, msg->payload.serverReject.reason);
+                       Pds_add_numval(pds, msg->payload.serverReject.type);
+                       break;
+               case ServerSync:
+                       Pds_add_numval(pds, msg->payload.serverSync.maxBandwidth);
+                       Pds_add_string(pds, msg->payload.serverSync.welcomeText);
+                       break;
+               case ServerJoin:
+                       Pds_add_string(pds, msg->payload.serverJoin.playerName);                        
+                       Pds_add_numval(pds, msg->payload.serverJoin.id);
+                       break;
+               case ChannelDescUpdate:
+                       Pds_add_numval(pds, msg->payload.channelDescUpdate.id);
+                       Pds_add_string(pds, msg->payload.channelDescUpdate.desc);                       
+                       break;
+               case ChannelAdd:
+                       Pds_add_numval(pds, msg->payload.channelAdd.id);
+                       Pds_add_numval(pds, msg->payload.channelAdd.parentId);
+                       Pds_add_string(pds, msg->payload.channelAdd.name);
+                       break;
+               case PlayerMove:
+                       Pds_add_numval(pds, msg->payload.playerMove.victim);
+                       Pds_add_numval(pds, msg->payload.playerMove.channel);
+                       break;
+               case QueryUsers:
+                       break;
+               case Ping:
+                       Pds_add_numval(pds, msg->payload.ping.timestamp);
+                       break;
+               case PingStats:
+                       Pds_add_numval(pds, msg->payload.pingStats.timestamp);
+                       Pds_add_numval(pds, msg->payload.pingStats.good);
+                       Pds_add_numval(pds, msg->payload.pingStats.late);
+                       Pds_add_numval(pds, msg->payload.pingStats.lost);
+                       Pds_add_numval(pds, msg->payload.pingStats.resync);
+                       Pds_add_double(pds, msg->payload.pingStats.dUDPPingAvg);
+                       Pds_add_double(pds, msg->payload.pingStats.dUDPPingVar);
+                       Pds_add_numval(pds, msg->payload.pingStats.UDPPackets);
+                       Pds_add_double(pds, msg->payload.pingStats.dTCPPingAvg);
+                       Pds_add_double(pds, msg->payload.pingStats.dTCPPingVar);
+                       Pds_add_numval(pds, msg->payload.pingStats.TCPPackets);                 
+                       break;
+               case PlayerMute:
+                       break;
+               case PlayerDeaf:
+                       break;
+               case PlayerSelfMuteDeaf:
+                       break;
+               case TextMessage:
+                       Pds_add_numval(pds, msg->payload.textMessage.victim);                   
+                       Pds_add_numval(pds, msg->payload.textMessage.channel);                  
+                       Pds_add_numval(pds, msg->payload.textMessage.bTree);                    
+                       Pds_add_string(pds, msg->payload.textMessage.message);
+                       break;
+               case PermissionDenied:
+                       Pds_add_string(pds, msg->payload.permissionDenied.reason);
+                       break;
+               case CryptSetup:
+                       Pds_append_data(pds, msg->payload.cryptSetup.key, AES_BLOCK_SIZE);
+                       Pds_append_data(pds, msg->payload.cryptSetup.serverNonce, AES_BLOCK_SIZE);
+                       Pds_append_data(pds, msg->payload.cryptSetup.clientNonce, AES_BLOCK_SIZE);
+                       break;
+               case CryptSync:
+                       if (!msg->payload.cryptSync.empty)
+                               Pds_append_data(pds, msg->payload.cryptSync.nonce, AES_BLOCK_SIZE);                     
+                       break;
+               case ServerLeave:
+                       /* No info to add */
+                       break;
+
+       default:
+               Log_warn("Unsupported message %d", msg->messageType);
+               break;
+       }
+       len = pds->offset;
+       Pds_free(pds);
+       return len;
+}
+
+message_t *Msg_create(messageType_t messageType)
+{
+       message_t *msg = malloc(sizeof(message_t));
+
+       if (msg == NULL)
+               Log_fatal("Out of memory");
+       memset(msg, 0, sizeof(message_t));
+       msg->refcount = 1;
+       msg->messageType = messageType;
+       init_list_entry(&msg->node);
+       
+       if (msg->messageType == Speex) {
+               msg->payload.speex.data = malloc(SPEEX_DATA_SIZE);
+               if (msg->payload.speex.data == NULL)
+                       Log_fatal("Out of memory");
+       }
+       return msg;
+}
+
+void Msg_inc_ref(message_t *msg)
+{
+       msg->refcount++;
+}
+
+void Msg_free(message_t *msg)
+{
+       if (msg->refcount) msg->refcount--;
+       if (msg->refcount > 0)
+               return;
+       if (msg->messageType == Speex)
+               free(msg->payload.speex.data);
+       free(msg);
+}
+
+void dumpmsg(uint8_t *data, int size)
+{
+       int i, r = 0, offset = 0;
+       char buf[512];
+       
+       while (r * 8 + i < size) {
+               for (i = 0; i < 8 && r * 8 + i < size; i++) {
+                       offset += sprintf(buf + offset, "%x ", data[r * 8 + i]);
+               }
+               sprintf(buf + offset, "\n");
+               printf(buf);
+               offset = 0;
+               r++;
+               i = 0;
+       } 
+}
+
+message_t *Msg_networkToMessage(uint8_t *data, int size)
+{
+       message_t *msg = NULL;
+       int messageType;
+       int sessionId;
+       pds_t *pds;
+
+       pds = Pds_create(data, size);
+       messageType = Pds_get_numval(pds);
+       sessionId = Pds_get_numval(pds);
+       
+       switch (messageType) {
+               case Speex:
+                       msg = Msg_create(Speex);
+                       msg->payload.speex.seq = Pds_get_numval(pds);
+                       msg->payload.speex.size = pds->maxsize - pds->offset;
+                       memcpy(msg->payload.speex.data, &pds->data[pds->offset], pds->maxsize - pds->offset);
+                       break;
+               case ServerAuthenticate:
+                       msg = Msg_create(ServerAuthenticate);
+                       msg->payload.serverAuthenticate.version = Pds_get_numval(pds);
+                       Pds_get_string(pds, msg->payload.serverAuthenticate.userName, MAX_TEXT);
+                       Pds_get_string(pds, msg->payload.serverAuthenticate.password, MAX_TEXT);
+                       break;
+               case ServerReject:
+                       msg = Msg_create(ServerReject);
+                       break;
+               case ServerSync:
+                       msg = Msg_create(ServerSync);
+                       break;
+               case ServerJoin:
+                       msg = Msg_create(ServerJoin);
+                       break;
+               case ServerLeave:
+                       msg = Msg_create(ServerLeave);
+                       break;
+               case QueryUsers:
+                       msg = Msg_create(QueryUsers);
+                       break;
+               case Ping:
+                       msg = Msg_create(Ping);
+                       msg->payload.ping.timestamp = Pds_get_numval(pds);
+                       break;
+               case PingStats:
+                       msg = Msg_create(PingStats);
+                       msg->payload.pingStats.timestamp = Pds_get_numval(pds);
+                       msg->payload.pingStats.good = Pds_get_numval(pds);
+                       msg->payload.pingStats.late = Pds_get_numval(pds);
+                       msg->payload.pingStats.lost = Pds_get_numval(pds);
+                       msg->payload.pingStats.resync = Pds_get_numval(pds);
+                       msg->payload.pingStats.dUDPPingAvg = Pds_get_double(pds);
+                       msg->payload.pingStats.dUDPPingVar = Pds_get_double(pds);
+                       msg->payload.pingStats.UDPPackets = Pds_get_numval(pds);
+                       msg->payload.pingStats.dTCPPingAvg = Pds_get_double(pds);
+                       msg->payload.pingStats.dTCPPingVar = Pds_get_double(pds);
+                       msg->payload.pingStats.TCPPackets = Pds_get_numval(pds);
+                       break;
+               case PlayerMute:
+                       msg = Msg_create(PlayerMute);
+                       msg->payload.playerMute.victim = Pds_get_numval(pds);
+                       msg->payload.playerMute.bMute = Pds_get_numval(pds);
+                       break;
+               case PlayerDeaf:
+                       msg = Msg_create(PlayerDeaf);
+                       msg->payload.playerDeaf.victim = Pds_get_numval(pds);
+                       msg->payload.playerDeaf.bDeaf = Pds_get_numval(pds);
+                       break;
+               case PlayerSelfMuteDeaf:
+                       msg = Msg_create(PlayerSelfMuteDeaf);
+                       msg->payload.playerSelfMuteDeaf.bMute = Pds_get_numval(pds);
+                       msg->payload.playerSelfMuteDeaf.bDeaf = Pds_get_numval(pds);
+                       break;
+               case TextMessage:
+                       msg = Msg_create(TextMessage);
+                       msg->payload.textMessage.victim = Pds_get_numval(pds);
+                       msg->payload.textMessage.channel = Pds_get_numval(pds);
+                       msg->payload.textMessage.bTree = Pds_get_numval(pds);
+                       Pds_get_string(pds, msg->payload.textMessage.message, MAX_TEXT);
+                       break;
+               case PermissionDenied:
+                       Log_warn("Ignoring message PermissionDenied - not supported");
+                       break;
+               case CryptSetup:
+                       Log_warn("Ignoring message CryptSetup - not supported");
+                       break;
+               case CryptSync:
+                       msg = Msg_create(CryptSync);
+                       if (Pds_get_data(pds, msg->payload.cryptSync.nonce, AES_BLOCK_SIZE) == 0)
+                               msg->payload.cryptSync.empty = true;
+                       else
+                               msg->payload.cryptSync.empty = false;                           
+                       break;
+               case PlayerMove:
+                       msg = Msg_create(PlayerMove);
+                       msg->payload.playerMove.victim = Pds_get_numval(pds);
+                       msg->payload.playerMove.channel = Pds_get_numval(pds);
+                       break;
+                       
+                       /* The commands below are not supported -> no need to read the parameters */
+               case PlayerRename:
+                       msg = Msg_create(PlayerRename);
+                       break;                  
+               case ChannelAdd:
+                       msg = Msg_create(ChannelAdd);
+                       break;
+               case ChannelDescUpdate:
+                       msg = Msg_create(ChannelDescUpdate);
+                       break;
+               case ContextAction:
+                       msg = Msg_create(ContextAction);
+                       break;
+               case ContextAddAction:
+                       msg = Msg_create(ContextAddAction);
+                       break;
+               case ServerBanList:
+                       msg = Msg_create(ServerBanList);
+                       break;
+               case PlayerKick:
+                       msg = Msg_create(PlayerKick);
+                       break;
+               case PlayerBan:
+                       msg = Msg_create(PlayerBan);
+                       break;
+               case ChannelRemove:
+                       msg = Msg_create(ChannelRemove);
+                       break;
+               case ChannelMove:
+                       msg = Msg_create(ChannelMove);
+                       break;
+               case ChannelLink:
+                       msg = Msg_create(ChannelLink);
+                       break;
+               case ChannelRename:
+                       msg = Msg_create(ChannelRename);
+                       break;
+               case EditACL:
+                       msg = Msg_create(EditACL);
+                       break;
+               case PlayerTexture:
+                       msg = Msg_create(PlayerTexture);
+                       break;
+               default:
+                       Log_warn("Message: Type %d (session %d) is unknown type", messageType, sessionId);
+       }
+       if (msg) {
+               msg->sessionId = sessionId;
+#if 0
+               if (!pds->bOk) {
+                       Msg_free(msg);
+                       msg = NULL;
+                       Log_warn("Message: Type %d (session %d, size %d) corrupt or short packet",
+                                        messageType, sessionId, pds->offset);
+               } else if (pds->maxsize - pds->offset != 0) {
+                       Msg_free(msg);
+                       msg = NULL;
+                       Log_warn("Message: Type %d (session %d) Long packet: %d/%d leftover bytes",
+                                        messageType, sessionId, pds->overshoot, pds->offset);
+               } else if (!pds->bOk) {
+                       Msg_free(msg);
+                       msg = NULL;
+                       Log_warn("Message: Type %d (session %d, size %d) failed to validate", messageType, sessionId, pds->maxsize);
+               }
+#endif
+       }
+       Pds_free(pds);
+       return msg;
+}
diff --git a/src/messages.h b/src/messages.h
new file mode 100644 (file)
index 0000000..5283222
--- /dev/null
@@ -0,0 +1,238 @@
+/* Copyright (C) 2009, Martin Johansson <martin@fatbob.nu>
+   Copyright (C) 2005-2009, Thorvald Natvig <thorvald@natvig.com>
+
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+   - 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.
+   - Neither the name of the Developers nor the names of its contributors may
+     be used to endorse or promote products derived from this software without
+     specific prior written permission.
+
+   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 FOUNDATION 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 MESSAGES_H_89768
+#define MESSAGES_H_89768
+
+#include <stdint.h>
+#include <openssl/aes.h>
+#include "list.h"
+#include "types.h"
+
+#define MAX_TEXT 64
+#define SPEEX_DATA_SIZE 1024
+#define MESSAGE_STREAM_VERSION 4
+
+typedef enum {
+       ServerReject,
+       ServerAuthenticate,
+       Speex,
+       ServerSync,
+       ServerJoin,
+       ServerLeave,
+       ServerBanList,
+       PlayerMute,
+       PlayerDeaf,
+       PlayerKick,
+       PlayerRename, /*10 */
+       PlayerBan,
+       PlayerMove,
+       PlayerSelfMuteDeaf,
+       ChannelAdd,
+       ChannelRemove,
+       ChannelMove,
+       ChannelLink,
+       ChannelRename,
+       PermissionDenied,
+       EditACL, /* 20 */
+       QueryUsers,
+       Ping,
+       TextMessage,
+       PlayerTexture,
+       CryptSetup,
+       CryptSync,
+       PingStats,
+       ContextAction,
+       ContextAddAction,
+       ChannelDescUpdate,
+} messageType_t;
+
+
+typedef enum {
+       AltSpeak = 0x01,
+       LoopBack = 0x02,
+       EndSpeech = 0x04,
+       FrameCountMask = 0x30
+} speexflag_t;
+
+typedef struct {
+       int speexflag;
+       int seq;
+       uint8_t *data;
+       int size;
+} speex_t;
+
+typedef struct {
+       int maxBandwidth;
+       char welcomeText[MAX_TEXT];
+} serverSync_t;
+
+typedef struct {
+       char playerName[MAX_TEXT];
+       int id;
+} serverLeave_t;
+
+typedef enum {
+       None,
+       WrongVersion,
+       InvalidUsername,
+       WrongUserPW,
+       WrongServerPW,
+       UsernameInUse,
+       ServerFull
+} rejectType_t;
+
+typedef struct {
+       char reason[MAX_TEXT];
+       rejectType_t type;
+} serverReject_t;
+
+typedef struct {
+       int version;
+       char userName[MAX_TEXT];
+       char password[MAX_TEXT];
+} serverAuthenticate_t;
+
+typedef struct {
+       int id;
+       int parentId;
+       char name[MAX_TEXT];
+} channelAdd_t;
+
+typedef struct {
+       int id;
+       char desc[MAX_TEXT];
+} channelDescUpdate_t;
+
+typedef struct {
+       char playerName[MAX_TEXT];
+       int id;
+} serverJoin_t;
+
+typedef struct {
+       int victim;
+       int channel;
+} playerMove_t;
+
+typedef struct {
+       uint8_t key[AES_BLOCK_SIZE];
+       uint8_t clientNonce[AES_BLOCK_SIZE];
+       uint8_t serverNonce[AES_BLOCK_SIZE];
+} cryptSetup_t;
+
+typedef struct {
+       bool_t empty;
+       uint8_t nonce[AES_BLOCK_SIZE];
+} cryptSync_t;
+
+typedef struct {
+       uint64_t timestamp;
+} ping_t;
+
+typedef struct {
+       uint64_t timestamp;
+       uint32_t good;
+       uint32_t late;
+       uint32_t lost;
+       uint32_t resync;
+       double dUDPPingAvg;
+       double dUDPPingVar;
+       uint32_t UDPPackets;
+       double dTCPPingAvg;
+       double dTCPPingVar;
+       uint32_t TCPPackets;
+} pingStats_t;
+
+typedef struct {
+       char reason[MAX_TEXT];
+} permissionDenied_t;
+
+typedef struct {
+       uint32_t victim;
+       bool_t bMute;
+} playerMute_t;
+
+typedef struct {
+       uint32_t victim;
+       bool_t bDeaf;
+} playerDeaf_t;
+
+typedef struct {
+       bool_t bMute;
+       bool_t bDeaf;
+} playerSelfMuteDeaf_t;
+
+typedef struct {
+       int32_t victim;
+       int32_t channel;
+       bool_t bTree;
+       char message[MAX_TEXT];
+} textMessage_t;
+
+typedef union payload {
+       speex_t speex;
+       serverSync_t serverSync;
+       serverJoin_t serverJoin;
+       serverLeave_t serverLeave;
+       serverReject_t serverReject;
+       serverAuthenticate_t serverAuthenticate;
+       cryptSetup_t cryptSetup;
+       cryptSync_t cryptSync;
+       pingStats_t pingStats;
+       ping_t ping;
+       channelAdd_t channelAdd;
+       channelDescUpdate_t channelDescUpdate;
+       playerMove_t playerMove;
+       permissionDenied_t permissinDenied;
+       playerMute_t playerMute;
+       playerDeaf_t playerDeaf;
+       playerSelfMuteDeaf_t playerSelfMuteDeaf;
+       permissionDenied_t permissionDenied;
+       textMessage_t textMessage;
+} payload_t;
+
+typedef struct message {
+       messageType_t messageType;
+       uint32_t sessionId;
+       int refcount;
+       struct dlist node;
+       payload_t payload;
+} message_t;
+
+
+
+int Msg_messageToNetwork(message_t *msg, uint8_t *buffer, int bufsize);
+message_t *Msg_networkToMessage(uint8_t *data, int size);
+void Msg_free(message_t *msg);
+void Msg_inc_ref(message_t *msg);
+
+message_t *Msg_create(messageType_t messageType);
+
+#endif
diff --git a/src/pds.c b/src/pds.c
new file mode 100644 (file)
index 0000000..7db1e7a
--- /dev/null
+++ b/src/pds.c
@@ -0,0 +1,249 @@
+/* Copyright (C) 2009, Martin Johansson <martin@fatbob.nu>
+   Copyright (C) 2005-2009, Thorvald Natvig <thorvald@natvig.com>
+
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+   - 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.
+   - Neither the name of the Developers nor the names of its contributors may
+     be used to endorse or promote products derived from this software without
+     specific prior written permission.
+
+   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 FOUNDATION 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 <string.h>
+#include <stdlib.h>
+#include "pds.h"
+#include "log.h"
+
+/*
+ * Data serialization functions below
+ */
+
+typedef union double64u {
+       uint64_t u64;
+       double dval;
+} double64u_t;
+
+static inline void append_val(pds_t *pds, uint64_t val)
+{
+       if (pds->offset < pds->maxsize)
+               pds->data[pds->offset++] = ((uint8_t)(val));
+       else {
+               pds->bOk = false;
+               pds->overshoot++;
+       }
+}
+
+void Pds_append_data(pds_t *pds, const uint8_t *data, uint32_t len)
+{
+       int left;
+       Pds_add_numval(pds, len);
+       left = pds->maxsize - pds->offset;
+       if (left >= len) {
+               memcpy(&pds->data[pds->offset], data, len);
+               pds->offset += len;
+       } else {
+               memset(&pds->data[pds->offset], 0, left);
+               pds->offset += left;
+               pds->overshoot += len - left;
+               pds->bOk = false;
+       }
+}
+
+void Pds_append_data_nosize(pds_t *pds, const uint8_t *data, uint32_t len)
+{
+       int left;
+       left = pds->maxsize - pds->offset;
+       if (left >= len) {
+               memcpy(&pds->data[pds->offset], data, len);
+               pds->offset += len;
+       } else {
+               memset(&pds->data[pds->offset], 0, left);
+               pds->offset += left;
+               pds->overshoot += len - left;
+               pds->bOk = false;
+       }
+}
+
+static inline uint64_t next(pds_t *pds)
+{
+       if (pds->offset < pds->maxsize)
+               return pds->data[pds->offset++];
+       else {
+               pds->bOk = false;
+               return 0;
+       }
+}
+
+pds_t *Pds_create(uint8_t *buf, int size)
+{
+       pds_t *pds = malloc(sizeof(pds_t));
+       if (pds == NULL)
+               Log_fatal("Out of memory");
+       pds->data = buf;
+       pds->offset = pds->overshoot = 0;
+       pds->maxsize = size;
+       pds->bOk = true;
+       return pds;
+}
+
+void Pds_free(pds_t *pds)
+{
+       free(pds);
+}
+
+void Pds_add_double(pds_t *pds, double value)
+{
+       double64u_t u;
+       
+       u.dval = value;
+       
+       Pds_add_numval(pds, u.u64);
+}
+
+double Pds_get_double(pds_t *pds)
+{
+       double64u_t u;
+       u.u64 = Pds_get_numval(pds);
+       return u.dval;
+}
+void Pds_add_numval(pds_t *pds, const uint64_t value)
+{
+       uint64_t i = value;
+       
+       if ((i & 0x8000000000000000LL) && (~i < 0x100000000LL)) {
+               // Signed number.
+               i = ~i;
+               if (i <= 0x3) {
+                       // Shortcase for -1 to -4
+                       append_val(pds, 0xFC | i);
+                       return;
+               } else {
+                       append_val(pds, 0xF8);
+               }
+       }
+       if (i < 0x80) {
+               // Need top bit clear
+               append_val(pds, i);
+       } else if (i < 0x4000) {
+               // Need top two bits clear
+               append_val(pds, (i >> 8) | 0x80);
+               append_val(pds, i & 0xFF);
+       } else if (i < 0x200000) {
+               // Need top three bits clear
+               append_val(pds, (i >> 16) | 0xC0);
+               append_val(pds, (i >> 8) & 0xFF);
+               append_val(pds, i & 0xFF);
+       } else if (i < 0x10000000) {
+               // Need top four bits clear
+               append_val(pds, (i >> 24) | 0xE0);
+               append_val(pds, (i >> 16) & 0xFF);
+               append_val(pds, (i >> 8) & 0xFF);
+               append_val(pds, i & 0xFF);
+       } else if (i < 0x100000000LL) {
+               // It's a full 32-bit integer.
+               append_val(pds, 0xF0);
+               append_val(pds, (i >> 24) & 0xFF);
+               append_val(pds, (i >> 16) & 0xFF);
+               append_val(pds, (i >> 8) & 0xFF);
+               append_val(pds, i & 0xFF);
+       } else {
+               // It's a 64-bit value.
+               append_val(pds, 0xF4);
+               append_val(pds, (i >> 56) & 0xFF);
+               append_val(pds, (i >> 48) & 0xFF);
+               append_val(pds, (i >> 40) & 0xFF);
+               append_val(pds, (i >> 32) & 0xFF);
+               append_val(pds, (i >> 24) & 0xFF);
+               append_val(pds, (i >> 16) & 0xFF);
+               append_val(pds, (i >> 8) & 0xFF);
+               append_val(pds, i & 0xFF);
+       }
+}
+       
+uint64_t Pds_get_numval(pds_t *pds)
+{
+       uint64_t i = 0;
+       uint64_t v = next(pds);
+       
+       if ((v & 0x80) == 0x00) {
+               i=(v & 0x7F);
+       } else if ((v & 0xC0) == 0x80) {
+               i=(v & 0x3F) << 8 | next(pds);
+       } else if ((v & 0xF0) == 0xF0) {
+               switch (v & 0xFC) {
+               case 0xF0:
+                       i=next(pds) << 24 | next(pds) << 16 | next(pds) << 8 | next(pds);
+                       break;
+               case 0xF4:
+                       i=next(pds) << 56 | next(pds) << 48 | next(pds) << 40 | next(pds) << 32 | next(pds) << 24 | next(pds) << 16 | next(pds) << 8 | next(pds);
+                       break;
+               case 0xF8:
+                       i = Pds_get_numval(pds);
+                       i = ~i;
+                       break;
+               case 0xFC:
+                       i=v & 0x03;
+                       i = ~i;
+                       break;
+               default:
+                       //ok = false;
+                       i = 0;
+                       break;
+               }
+       } else if ((v & 0xF0) == 0xE0) {
+               i=(v & 0x0F) << 24 | next(pds) << 16 | next(pds) << 8 | next(pds);
+       } else if ((v & 0xE0) == 0xC0) {
+               i=(v & 0x1F) << 16 | next(pds) << 8 | next(pds);
+       }
+       return i;
+}
+
+void Pds_add_string(pds_t *pds, const char *str)
+{
+       Pds_append_data(pds, (uint8_t *)str, strlen(str));
+}
+
+void Pds_get_string(pds_t *pds, char *str, int maxlen)
+{
+       int len = Pds_get_numval(pds);
+       if (len < maxlen) {
+               memcpy(str, &pds->data[pds->offset], len);
+               str[len] = '\0';
+               pds->offset += len;
+       } else {
+               Log_warn("Too long string from network");
+               strcpy(str, "N/A");
+       }
+}
+
+int Pds_get_data(pds_t *pds, uint8_t *data, int maxlen)
+{
+       int len = Pds_get_numval(pds);
+       if (len < maxlen) {
+               memcpy(data, &pds->data[pds->offset], len);
+               pds->offset += len;
+               return len;
+       } else {
+               Log_warn("Pds_get_data: Too much data from network");
+               return -1;
+       }
+}
diff --git a/src/pds.h b/src/pds.h
new file mode 100644 (file)
index 0000000..e5be19b
--- /dev/null
+++ b/src/pds.h
@@ -0,0 +1,58 @@
+/* Copyright (C) 2009, Martin Johansson <martin@fatbob.nu>
+   Copyright (C) 2005-2009, Thorvald Natvig <thorvald@natvig.com>
+
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+   - 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.
+   - Neither the name of the Developers nor the names of its contributors may
+     be used to endorse or promote products derived from this software without
+     specific prior written permission.
+
+   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 FOUNDATION 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 PDS_H_457865876
+#define PDS_H_457865876
+
+#include <stdint.h>
+#include "types.h"
+
+typedef struct {
+       uint8_t *data;
+       uint32_t maxsize;
+       uint32_t offset;
+       uint32_t overshoot;
+       bool_t bOk;
+} pds_t;
+
+void Pds_append_data(pds_t *pds, const uint8_t *data, uint32_t len);
+void Pds_append_data_nosize(pds_t *pds, const uint8_t *data, uint32_t len);
+uint64_t Pds_get_numval(pds_t *pds);
+void Pds_add_numval(pds_t *pds, const uint64_t value);
+pds_t *Pds_create(uint8_t *buf, int size);
+void Pds_free(pds_t *pds);
+void Pds_add_string(pds_t *pds, const char *str);
+void Pds_get_string(pds_t *pds, char *str, int maxlen);
+void Pds_add_double(pds_t *pds, double value);
+double Pds_get_double(pds_t *pds);
+int Pds_get_data(pds_t *pds, uint8_t *data, int maxlen);
+
+
+#endif
diff --git a/src/server.c b/src/server.c
new file mode 100644 (file)
index 0000000..7cabfb3
--- /dev/null
@@ -0,0 +1,173 @@
+/* Copyright (C) 2009, Martin Johansson <martin@fatbob.nu>
+   Copyright (C) 2005-2009, Thorvald Natvig <thorvald@natvig.com>
+
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+   - 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.
+   - Neither the name of the Developers nor the names of its contributors may
+     be used to endorse or promote products derived from this software without
+     specific prior written permission.
+
+   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 FOUNDATION 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 <stdio.h>
+#include <sys/time.h>
+#include <sys/poll.h>
+#include <netinet/tcp.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <string.h>
+#include <limits.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "client.h"
+#include "conf.h"
+#include "log.h"
+#include "timer.h"
+
+#define LISTEN_SOCK 0
+#define TCP_SOCK 0
+#define UDP_SOCK 1
+
+int udpsock; /* XXX restructure! */
+bool_t shutdown_server;
+
+void Server_run()
+{
+       int timeout = 1000, rc;
+       struct pollfd *pollfds;
+       int tcpsock, sockopt = 1;
+       struct sockaddr_in sin;
+       int val, clientcount;
+       etimer_t janitorTimer;
+
+       /* max clients + listen sock + udp sock + client connecting that will be disconnected */
+       pollfds = malloc((getIntConf(MAX_CLIENTS) + 3) * sizeof(struct pollfd));
+       if (pollfds == NULL)
+               Log_fatal("out of memory");
+       
+       /* Prepare TCP socket */
+       memset(&sin, 0, sizeof(sin));
+       tcpsock = socket(PF_INET, SOCK_STREAM, 0);
+       if (tcpsock < 0)
+               Log_fatal("socket");
+       if (setsockopt(tcpsock, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(int)) != 0)
+               Log_fatal("setsockopt: %s", strerror(errno));
+       sin.sin_family = AF_INET;
+       sin.sin_port = htons(getIntConf(BINDPORT));
+       sin.sin_addr.s_addr = inet_addr(getStrConf(BINDADDR)) ==  -1 ? inet_addr("0.0.0.0") : inet_addr(getStrConf(BINDADDR));
+       rc = bind(tcpsock, (struct sockaddr *) &sin, sizeof (struct sockaddr_in));
+       if (rc < 0) Log_fatal("bind: %s", strerror(errno));
+       rc = listen(tcpsock, 3);
+       if (rc < 0) Log_fatal("listen");
+       fcntl(tcpsock, F_SETFL, O_NONBLOCK);
+       
+       pollfds[LISTEN_SOCK].fd = tcpsock;
+       pollfds[LISTEN_SOCK].events = POLLIN;
+
+       /* Prepare UDP socket */
+       memset(&sin, 0, sizeof(sin));
+       udpsock = socket(PF_INET, SOCK_DGRAM, 0);
+       sin.sin_family = AF_INET;
+       sin.sin_port = htons(getIntConf(BINDPORT));
+       sin.sin_addr.s_addr = inet_addr(getStrConf(BINDADDR)) ==  -1 ? inet_addr("0.0.0.0") : inet_addr(getStrConf(BINDADDR));
+       rc = bind(udpsock, (struct sockaddr *) &sin, sizeof (struct sockaddr_in));
+       if (rc < 0)
+               Log_fatal("bind %d %s: %s", getIntConf(BINDPORT), getStrConf(BINDADDR), strerror(errno));
+       val = 0xe0;
+       rc = setsockopt(udpsock, IPPROTO_IP, IP_TOS, &val, sizeof(val));
+       if (rc < 0)
+               Log_fatal("Server: Failed to set TOS for UDP Socket");
+       val = 0x80;
+       rc = setsockopt(udpsock, IPPROTO_IP, IP_TOS, &val, sizeof(val));
+       if (rc < 0)
+               Log_fatal("Server: Failed to set TOS for UDP Socket");
+       
+       fcntl(udpsock, F_SETFL, O_NONBLOCK);
+       pollfds[UDP_SOCK].fd = udpsock;
+       pollfds[UDP_SOCK].events = POLLIN | POLLHUP | POLLERR;
+       
+       Timer_init(&janitorTimer);
+       
+       /* Main server loop */
+       while (!shutdown_server) {
+               struct sockaddr_in remote;
+               int i;
+               
+               pollfds[UDP_SOCK].revents = 0;
+               pollfds[TCP_SOCK].revents = 0;
+               clientcount = Client_getfds(&pollfds[2]);
+               
+               timeout = (int)(1000000LL - (int64_t)Timer_elapsed(&janitorTimer)) / 1000LL;
+               if (timeout <= 0) {
+                       Client_janitor();
+                       Timer_restart(&janitorTimer);
+                       timeout = (int)(1000000LL - (int64_t)Timer_elapsed(&janitorTimer)) / 1000LL;
+               }
+               rc = poll(pollfds, clientcount + 2, timeout);
+               if (rc == 0) { /* Timeout */
+                       /* Do maintenance */
+                       Timer_restart(&janitorTimer);
+                       Client_janitor();
+                       continue;
+               }
+               if (rc < 0) {
+                       if (errno == EINTR) /* signal */
+                               continue;
+                       else
+                               Log_fatal("poll: error %d", errno);
+               }
+               if (pollfds[LISTEN_SOCK].revents) { /* New tcp connection */
+                       int tcpfd, flag = 1;
+                       uint32_t addrlen;
+                       addrlen = sizeof(struct sockaddr_in);
+                       tcpfd = accept(pollfds[LISTEN_SOCK].fd, (struct sockaddr*)&remote, &addrlen);
+                       fcntl(tcpfd, F_SETFL, O_NONBLOCK);
+                       setsockopt(tcpfd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int));
+                       Log_info("Connection from %s port %d\n", inet_ntoa(remote.sin_addr),
+                                        ntohs(remote.sin_port));
+                       Client_add(tcpfd, &remote);
+               }
+
+               if (pollfds[UDP_SOCK].revents) {
+                       Client_read_udp();
+               }
+               for (i = 0; i < clientcount; i++) {
+                       if (pollfds[i + 2].revents & POLLIN) {
+                               Client_read_fd(pollfds[i + 2].fd);
+                       }
+                       if (pollfds[i + 2].revents & POLLOUT) {
+                               Client_write_fd(pollfds[i + 2].fd);
+                       }
+               }
+       }       
+
+       /* Disconnect clients */
+       Client_disconnect_all();
+       free(pollfds);
+}
+
+void Server_shutdown()
+{
+       shutdown_server = true;
+}
diff --git a/src/server.h b/src/server.h
new file mode 100644 (file)
index 0000000..aa48482
--- /dev/null
@@ -0,0 +1,38 @@
+/* Copyright (C) 2009, Martin Johansson <martin@fatbob.nu>
+   Copyright (C) 2005-2009, Thorvald Natvig <thorvald@natvig.com>
+
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+   - 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.
+   - Neither the name of the Developers nor the names of its contributors may
+     be used to endorse or promote products derived from this software without
+     specific prior written permission.
+
+   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 FOUNDATION 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 SERVER_H_347563
+#define SERVER_H_347563
+
+void Server_run();
+void Server_shutdown();
+
+#endif
diff --git a/src/ssl.c b/src/ssl.c
new file mode 100644 (file)
index 0000000..42f9610
--- /dev/null
+++ b/src/ssl.c
@@ -0,0 +1,368 @@
+/* Copyright (C) 2009, Martin Johansson <martin@fatbob.nu>
+   Copyright (C) 2005-2009, Thorvald Natvig <thorvald@natvig.com>
+
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+   - 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.
+   - Neither the name of the Developers nor the names of its contributors may
+     be used to endorse or promote products derived from this software without
+     specific prior written permission.
+
+   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 FOUNDATION 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 <openssl/x509v3.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include <openssl/safestack.h>
+#include <string.h>
+
+#include "conf.h"
+#include "log.h"
+#include "ssl.h"
+
+static X509 *x509;
+static RSA *rsa;
+static SSL_CTX *context;
+static EVP_PKEY *pkey;
+
+static int SSL_add_ext(X509 * crt, int nid, char *value) {
+       X509_EXTENSION *ex;
+       X509V3_CTX ctx;
+       X509V3_set_ctx_nodb(&ctx);
+       X509V3_set_ctx(&ctx, crt, crt, NULL, NULL, 0);
+       ex = X509V3_EXT_conf_nid(NULL, &ctx, nid, value);
+       if (!ex)
+               return 0;
+
+       X509_add_ext(crt, ex, -1);
+       X509_EXTENSION_free(ex);
+       return 1;
+}
+
+static X509 *SSL_readcert(char *certfile)
+{
+       FILE *fp;
+       X509 *x509;
+                       
+       /* open the private key file */
+       fp = fopen(certfile, "r");
+       if (fp == NULL) {
+               Log_warn("Unable to open the X509 file %s for reading.", certfile);
+               return NULL;
+       }
+       
+       /* allocate memory for the cert structure */    
+       x509 = X509_new();
+       
+       if (PEM_read_X509(fp, &x509, NULL, NULL) == 0) {
+               /* error reading the x509 information - check the error stack */
+               Log_warn("Error trying to read X509 info.");
+               fclose(fp);
+               X509_free(x509);
+               return NULL;
+       }
+       fclose(fp);
+       return x509;
+}
+
+static RSA *SSL_readprivatekey(char *keyfile)
+{
+       FILE *fp;
+       RSA *rsa;
+
+/* open the private key file for reading */
+       fp = fopen(keyfile, "r");
+       if (fp == NULL) {
+               Log_warn("Unable to open the private key file %s for reading.", keyfile);
+               return NULL;
+       }
+       
+/* allocate memory for the RSA structure */
+       rsa = RSA_new();
+       
+       /* assign a callback function for the password */
+       
+       /* read a private key from file */      
+       if (PEM_read_RSAPrivateKey(fp, &rsa, NULL, NULL) <= 0) {
+               /* error reading the key - check the error stack */
+               Log_warn("Error trying to read private key.");
+               RSA_free(rsa);
+               fclose(fp);
+               return NULL;
+       }
+       fclose(fp);
+       return rsa;
+}
+
+void SSL_writecert(char *certfile, X509 *x509)
+{
+       FILE *fp;
+       BIO *err_output;
+       
+       /* prepare a BIO for outputting error messages */
+       
+       err_output = BIO_new_fp(stderr,BIO_NOCLOSE);
+       
+       /* open the private key file */
+       fp = fopen(certfile, "w");
+       if (fp == NULL) {
+               BIO_printf(err_output, "Unable to open the X509 file for writing.\n");
+               BIO_free(err_output);
+               return;
+       }
+               
+       if (PEM_write_X509(fp, x509) == 0) {
+               BIO_printf(err_output, "Error trying to write X509 info.\n");
+               ERR_print_errors(err_output);
+       }
+       fclose(fp);
+}
+
+void SSL_writekey(char *keyfile, RSA *rsa)
+{
+       FILE *fp;
+       BIO *err_output;
+       /* prepare a BIO for outputing error messages */        
+       err_output = BIO_new_fp(stderr, BIO_NOCLOSE);
+       
+       /* open the private key file for reading */
+       fp = fopen(keyfile, "w");
+       if (fp == NULL) {
+               BIO_printf(err_output, "Unable to open the private key file %s for writing.\n", keyfile);
+               BIO_free(err_output);
+               return;
+       }
+       
+       if (PEM_write_RSAPrivateKey(fp, rsa, NULL, NULL, 0, NULL, NULL) == 0) {
+               /* error reading the key - check the error stack */
+               BIO_printf(err_output, "Error trying to write private key\n");
+               ERR_print_errors(err_output);
+       }
+       fclose(fp);
+}
+
+void SSL_initializeCert() {
+       char *crt, *key, *pass;
+       
+       crt = (char *)getStrConf(CERTIFICATE);
+       key = (char *)getStrConf(KEY);
+       pass = (char *)getStrConf(PASSPHRASE);
+
+       x509 = SSL_readcert(crt);
+       rsa = SSL_readprivatekey(key);
+       if (rsa != NULL) {
+               pkey = EVP_PKEY_new();
+               EVP_PKEY_assign_RSA(pkey, rsa);
+       }               
+       
+#if 0
+       /* Later ... */
+       if (key && !x509) {             
+               qscCert = QSslCertificate(key);
+               if (! qscCert.isNull()) {
+                       logthis("Using certificate from key.");
+               }
+       }
+
+       if (! qscCert.isNull()) {
+               QSsl::KeyAlgorithm alg = qscCert.publicKey().algorithm();
+               /* Fetch algorith from cert */
+               if (! key.isEmpty()) {
+                       /* get key */
+                       qskKey = QSslKey(key, alg, QSsl::Pem, QSsl::PrivateKey, pass);
+                       if (qskKey.isNull()) {
+                               logthis("Failed to parse key.");
+                       }
+               }
+
+               if (! crt.isEmpty() && qskKey.isNull()) {
+                       /* get key from certificate */
+                       qskKey = QSslKey(crt, alg, QSsl::Pem, QSsl::PrivateKey, pass);
+                       if (! qskKey.isNull()) {
+                               logthis("Using key from certificate.");
+                       }
+               }
+
+       }
+#endif
+       
+       if (!rsa || !x509) {
+               logthis("Generating new server certificate.");
+
+               BIO *bio_err;
+               
+               CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
+               
+               bio_err=BIO_new_fp(stderr, BIO_NOCLOSE);
+               
+               x509 = X509_new();
+               pkey = EVP_PKEY_new();
+               rsa = RSA_generate_key(1024,RSA_F4,NULL,NULL);
+               EVP_PKEY_assign_RSA(pkey, rsa);
+               
+               X509_set_version(x509, 2);
+               ASN1_INTEGER_set(X509_get_serialNumber(x509),1);
+               X509_gmtime_adj(X509_get_notBefore(x509),0);
+               X509_gmtime_adj(X509_get_notAfter(x509),60*60*24*365);
+               X509_set_pubkey(x509, pkey);
+               
+               X509_NAME *name=X509_get_subject_name(x509);
+               
+               X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, (const uint8_t *)"Murmur Autogenerated Certificate v2", -1, -1, 0);
+               X509_set_issuer_name(x509, name);
+               SSL_add_ext(x509, NID_basic_constraints, "critical,CA:FALSE");
+               SSL_add_ext(x509, NID_ext_key_usage, "serverAuth,clientAuth");
+               SSL_add_ext(x509, NID_subject_key_identifier, "hash");
+               SSL_add_ext(x509, NID_netscape_comment, "Generated from umurmur");
+               
+               X509_sign(x509, pkey, EVP_md5());
+               
+               SSL_writecert(crt, x509);
+               SSL_writekey(key, rsa);
+       }
+
+}
+
+void SSL_getdigest(char *s, int l)
+{
+       unsigned char md[EVP_MAX_MD_SIZE];
+       unsigned int n;
+       int j;
+       
+       if (!X509_digest (x509, EVP_md5(), md, &n))
+       {
+               snprintf (s, l, "[unable to calculate]");
+       }
+       else
+       {
+               for (j = 0; j < (int) n; j++)
+               {
+                       char ch[8];
+                       snprintf(ch, 8, "%02X%s", md[j], (j % 2 ? " " : ""));
+                       strcat(s, ch);
+               }
+       }
+}
+
+void SSL_init(void)
+{
+       SSL_METHOD *method;
+       SSL *ssl;
+       int i, offset = 0;
+       STACK_OF(SSL_CIPHER) *cipherlist = NULL, *cipherlist_new = NULL;
+       SSL_CIPHER *cipher;
+       char cipherstring[1024];
+               
+       SSL_library_init();
+    OpenSSL_add_all_algorithms();              /* load & register all cryptos, etc. */
+    SSL_load_error_strings();                  /* load all error messages */
+    ERR_load_crypto_strings();                 /* load all error messages */
+    method = SSLv23_server_method();           /* create new server-method instance */
+    context = SSL_CTX_new(method);                     /* create new context from method */
+    if (context == NULL)
+    {
+        ERR_print_errors_fp(stderr);
+        abort();
+    }
+       SSL_initializeCert();
+       if (SSL_CTX_use_certificate(context, x509) <= 0)
+               Log_fatal("Failed to initialize cert");
+       if (SSL_CTX_use_PrivateKey(context, pkey) <= 0) {
+               ERR_print_errors_fp(stderr);
+               Log_fatal("Failed to initialize private key");
+       }
+
+       /* Set cipher list */
+       ssl = SSL_new(context); 
+       cipherlist = (STACK_OF(SSL_CIPHER) *) SSL_get_ciphers(ssl);
+       cipherlist_new = (STACK_OF(SSL_CIPHER) *) sk_SSL_CIPHER_new_null();
+       
+       for ( i = 0; (cipher = sk_SSL_CIPHER_value(cipherlist, i)) != NULL; i++) {
+               if (SSL_CIPHER_get_bits(cipher, NULL) >= 128) {
+                       sk_SSL_CIPHER_push(cipherlist_new, cipher);
+               }
+       }
+       Log_info("List of ciphers:");
+       if (cipherlist_new) {
+               for ( i = 0; (cipher = sk_SSL_CIPHER_value(cipherlist_new, i)) != NULL; i++) {
+                       Log_info("%s", SSL_CIPHER_get_name(cipher));
+                       offset += snprintf(cipherstring + offset, 1024 - offset, "%s:", SSL_CIPHER_get_name(cipher));
+               }
+               cipherstring[offset - 1] = '\0';
+       }
+       
+       if (cipherlist_new)
+               sk_SSL_CIPHER_free(cipherlist_new);
+       
+       if (strlen(cipherstring) == 0)
+               Log_fatal("No suitable ciphers found!");
+       
+       if (SSL_CTX_set_cipher_list(context, cipherstring) == 0)
+               Log_fatal("Failed to set cipher list!");
+               
+       
+       SSL_free(ssl);
+}
+
+void SSL_deinit(void)
+{
+       SSL_CTX_free(context);
+       EVP_cleanup();
+}
+
+int SSL_nonblockaccept(SSL *ssl, bool_t *SSLready)
+{
+       int rc;
+       rc = SSL_accept(ssl);
+       if (rc < 0) {
+               if (SSL_get_error(ssl, rc) == SSL_ERROR_WANT_READ ||
+                       SSL_get_error(ssl, rc) == SSL_ERROR_WANT_WRITE) {
+                       Log_debug("SSL not ready");
+                       return 0;
+               } else {
+                       Log_warn("SSL error: %s", ERR_error_string(SSL_get_error(ssl, rc), NULL));
+                       return -1;
+               }
+       }
+       *SSLready = true;
+       return 0;
+}
+
+SSL *SSL_newconnection(int fd, bool_t *SSLready)
+{
+       SSL *ssl;
+       
+       *SSLready = false;
+       ssl = SSL_new(context);
+       SSL_set_fd(ssl, fd);
+       if (SSL_nonblockaccept(ssl, SSLready) < 0) {
+               SSL_free(ssl);
+               return NULL;
+       }
+       return ssl;
+}
+
+void SSL_closeconnection(SSL *ssl)
+{
+       SSL_free(ssl);
+}
+
+
diff --git a/src/ssl.h b/src/ssl.h
new file mode 100644 (file)
index 0000000..6c2a8ba
--- /dev/null
+++ b/src/ssl.h
@@ -0,0 +1,39 @@
+/* Copyright (C) 2009, Martin Johansson <martin@fatbob.nu>
+   Copyright (C) 2005-2009, Thorvald Natvig <thorvald@natvig.com>
+
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+   - 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.
+   - Neither the name of the Developers nor the names of its contributors may
+     be used to endorse or promote products derived from this software without
+     specific prior written permission.
+
+   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 FOUNDATION 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 <openssl/x509v3.h>
+#include <openssl/ssl.h>
+#include "types.h"
+
+void SSL_init(void);
+void SSL_deinit(void);
+SSL *SSL_newconnection(int fd, bool_t *SSLready);
+void SSL_closeconnection(SSL *ssl);
+int SSL_nonblockaccept(SSL *ssl, bool_t *SSLready);
diff --git a/src/timer.c b/src/timer.c
new file mode 100644 (file)
index 0000000..53542c1
--- /dev/null
@@ -0,0 +1,75 @@
+/* Copyright (C) 2009, Martin Johansson <martin@fatbob.nu>
+   Copyright (C) 2005-2009, Thorvald Natvig <thorvald@natvig.com>
+
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+   - 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.
+   - Neither the name of the Developers nor the names of its contributors may
+     be used to endorse or promote products derived from this software without
+     specific prior written permission.
+
+   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 FOUNDATION 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 <sys/time.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include "timer.h"
+
+static uint64_t Timer_now()
+{
+       struct timeval tv;
+       uint64_t e;
+       
+       gettimeofday(&tv, NULL);
+       e = tv.tv_sec * 1000000LL;
+       e += tv.tv_usec;
+       return e;
+}
+
+
+void Timer_init(etimer_t *t)
+{
+       *t = Timer_now();
+}
+
+bool_t Timer_isElapsed(etimer_t *t, uint64_t us)
+{
+       if (Timer_elapsed(t) > us) {
+               *t += us;
+               return true;
+       }
+       return false;
+
+}
+
+uint64_t Timer_elapsed(etimer_t *t)
+{
+       return Timer_now() - *t;
+}
+
+uint64_t Timer_restart(etimer_t *t)
+{
+       uint64_t n = Timer_now();
+       uint64_t e = n - *t;
+       *t = n;
+       return e;
+}
diff --git a/src/timer.h b/src/timer.h
new file mode 100644 (file)
index 0000000..bb7f9bc
--- /dev/null
@@ -0,0 +1,45 @@
+/* Copyright (C) 2009, Martin Johansson <martin@fatbob.nu>
+   Copyright (C) 2005-2009, Thorvald Natvig <thorvald@natvig.com>
+
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+   - 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.
+   - Neither the name of the Developers nor the names of its contributors may
+     be used to endorse or promote products derived from this software without
+     specific prior written permission.
+
+   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 FOUNDATION 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 TIMER_H_2766562
+#define TIMER_H_2766562
+
+#include <stdint.h>
+#include "types.h"
+
+typedef uint64_t etimer_t;
+
+void Timer_init(etimer_t *t);
+bool_t Timer_isElapsed(etimer_t *t, uint64_t us);
+uint64_t Timer_elapsed(etimer_t *t);
+uint64_t Timer_restart(etimer_t *t);
+
+#endif
+
diff --git a/src/types.h b/src/types.h
new file mode 100644 (file)
index 0000000..cd45146
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef TYPES_H_90878954
+#define TYPES_H_90878954
+
+typedef enum {
+       false,
+       true
+} bool_t;
+
+#endif
+