diff --git a/src/common/multiio.c b/src/common/multiio.c
new file mode 100644
--- /dev/null
+++ b/src/common/multiio.c
@@ -0,0 +1,378 @@
+/*
+ Copyright 2010 Nathan Phillip Brink
+
+ This file is a part of DistRen.
+
+ DistRen is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ DistRen is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with DistRen. If not, see .
+
+*/
+
+#include "common/multiio.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+struct multiio_socket_info
+{
+ /* the type of socket */
+ multiio_socket_type_t socket_type;
+ /* to be passed to the socket handler */
+ void *socket_data;
+};
+
+struct multiio_socket_type_info
+{
+ /* type: struct multiio_socket_type_handler_info */
+ list_t type_handlers;
+};
+
+/*
+ The basic concept is that pollfds is an array. Thus, we have to
+ have another array reflecting that array to hold socket-specific
+ information.
+ */
+struct multiio_context
+{
+ /* the array passed to poll() */
+ struct pollfd *pollfds;
+ /* the number of entries pollfds could hold */
+ nfds_t pollfds_len;
+ /* the number of entries that pollfds does hold */
+ nfds_t nfds;
+
+ /*
+ an array whose order mirrors pollfds containing information
+ about the fd mentioned in pollfds.
+ */
+ struct multiio_socket_info *socket_infos;
+
+ /* the number of socket types registered (equivilent to the type ID of the next registered type) */
+ multiio_socket_type_t num_socket_types;
+ /* the information about each individual socket type keyed by the type ID */
+ struct multiio_socket_type_info *socket_types;
+};
+
+/*
+ stores information about a handler associated with a socket type/class.
+ */
+struct multiio_socket_type_handler_info
+{
+ /* the poll() event to which this handler responds */
+ short event;
+ /* the handler function to call when the event is matched */
+ multiio_event_handler_func_t handler;
+ /* the pointer passed to multiio_event_handler_register() */
+ void *handler_data;
+};
+
+/**
+ Finds the index in the context->pollfds array of a particular socket.
+
+ @param context the multiio context
+ @param fd the socket to search for
+ @param index a pointer which will be filled with the index of the socket if found
+ @return 0 if the pollfds entry is found, 1 if the entry is not found
+ */
+int multiio_pollfd_index_by_fd(const multiio_context_t context, int fd, size_t *index);
+
+multiio_context_t multiio_context_new()
+{
+ struct multiio_context *context;
+
+ context = malloc(sizeof(struct multiio_context));
+ if(!context)
+ return NULL;
+
+ context->pollfds = malloc(sizeof(struct pollfd) * 2);
+ if(!context->pollfds)
+ {
+ free(context);
+ return NULL;
+ }
+ context->pollfds_len = 2;
+ context->nfds = 0;
+ context->socket_infos = malloc(sizeof(struct multiio_socket_info) * 2);
+
+ context->num_socket_types = 0;
+ context->socket_types = NULL;
+
+ if(!context->pollfds
+ || !context->socket_infos)
+ {
+ free(context->pollfds);
+ free(context->socket_infos);
+ free(context);
+
+ return NULL;
+ }
+
+ return context;
+}
+
+int multiio_context_free(multiio_context_t context)
+{
+ size_t counter;
+ /*
+ clean up pollfds and socket_infos
+ */
+ free(context->pollfds);
+ free(context->socket_infos);
+
+ /*
+ wipe up the socket_types
+ */
+ for(counter = 0; counter < context->num_socket_types; counter ++)
+ list_free(context->socket_types[counter].type_handlers, LIST_DEALLOC);
+ free(context->socket_types);
+
+ /*
+ bye!
+ */
+ free(context);
+
+ return 0;
+}
+
+struct multiio_poll_travinfo
+{
+ multiio_context_t multiio;
+ struct multiio_socket_info *socket_info;
+ struct pollfd *pollfd;
+};
+/**
+ list traverser for multiio_poll()
+ */
+int mulitiio_poll_invoke_handlers(struct multiio_poll_travinfo *travinfo, struct multiio_socket_type_handler_info *handler_info)
+{
+ short event;
+
+ event = travinfo->pollfd->events & handler_info->event;
+ if(!event)
+ return TRUE;
+
+ handler_info->handler(travinfo->multiio,
+ travinfo->pollfd->fd,
+ event,
+ handler_info->handler_data,
+ travinfo->socket_info->socket_data);
+
+ return TRUE;
+}
+
+int multiio_poll(multiio_context_t context)
+{
+ size_t counter;
+ struct multiio_poll_travinfo travinfo;
+
+ poll(context->pollfds, context->nfds, -1);
+
+ for(counter = 0; counter < context->nfds; counter ++)
+ if(context->pollfds[counter].revents)
+ {
+ travinfo.multiio = context;
+ travinfo.socket_info = &context->socket_infos[counter];
+ travinfo.pollfd = &context->pollfds[counter];
+ list_traverse(context->socket_types[context->socket_infos[counter].socket_type].type_handlers,
+ &travinfo,
+ (list_traverse_func_t)&mulitiio_poll_invoke_handlers,
+ LIST_FRNT | LIST_SAVE);
+ }
+
+ return 0;
+}
+
+int multiio_socket_type_register(multiio_context_t context, multiio_socket_type_t *new_type)
+{
+ struct multiio_socket_type_info *new_socket_types;
+
+ new_socket_types = malloc(sizeof(struct multiio_socket_type_info) * (context->num_socket_types + 1));
+ if(!new_socket_types)
+ return 1;
+
+ *new_type = context->num_socket_types;
+ new_socket_types[*new_type].type_handlers = list_init();
+ if(!new_socket_types[*new_type].type_handlers)
+ {
+ free(new_socket_types);
+ return 2;
+ }
+
+
+ if(context->num_socket_types)
+ {
+ memcpy(new_socket_types, context->socket_types, sizeof(struct multiio_socket_type_info) * context->num_socket_types);
+ free(context->socket_types);
+ }
+
+ context->socket_types = new_socket_types;
+ context->num_socket_types ++;
+
+ return 0;
+}
+
+int multiio_event_handler_register(multiio_context_t context, multiio_socket_type_t socket_type, short event, multiio_event_handler_func_t handler_func, void *handler_data)
+{
+ struct multiio_socket_type_handler_info handler_info;
+
+ if(socket_type >= context->num_socket_types)
+ return 1;
+
+ if(!event)
+ return 2;
+
+ handler_info.event = event;
+ handler_info.handler = handler_func;
+ handler_info.handler_data = handler_data;
+
+ list_insert_after(context->socket_types[socket_type].type_handlers, &handler_info, sizeof(struct multiio_socket_type_handler_info));
+
+ return 0;
+}
+
+int multiio_socket_add(multiio_context_t context, int fd, multiio_socket_type_t socket_type, void *socket_data, short events)
+{
+ struct pollfd *pollfds;
+ struct multiio_socket_info *socket_infos;
+ size_t new_pollfds_len;
+
+ int fdstatus;
+ int tmp;
+
+ fdstatus = fcntl(fd, F_GETFL);
+ fdstatus |= O_NONBLOCK;
+ tmp = fcntl(fd, F_SETFL, fdstatus);
+ if(tmp == -1)
+ {
+ perror("fcntl");
+ return 1;
+ }
+
+ if(socket_type >= context->num_socket_types)
+ return 1;
+
+ /**
+ extend sockfds array
+ */
+ if(context->nfds >= context->pollfds_len)
+ {
+ new_pollfds_len = (context->pollfds_len + 1) * 2;
+
+ pollfds = malloc(sizeof(struct pollfd) * new_pollfds_len);
+ socket_infos = malloc(sizeof(struct multiio_socket_info) * new_pollfds_len);
+
+ if(!pollfds
+ || !socket_infos)
+ return 1;
+
+ memcpy(pollfds, context->pollfds, sizeof(struct pollfd) * context->pollfds_len);
+ memcpy(socket_infos, context->socket_infos, sizeof(struct multiio_socket_info) * context->pollfds_len);
+
+ free(context->pollfds);
+ free(context->socket_infos);
+
+ context->pollfds = pollfds;
+ context->socket_infos = socket_infos;
+ context->pollfds_len = new_pollfds_len;
+ }
+
+ pollfds = context->pollfds;
+ socket_infos = context->socket_infos;
+
+ pollfds[context->nfds].fd = fd;
+ pollfds[context->nfds].events = events;
+ socket_infos[context->nfds].socket_type = socket_type;
+ socket_infos[context->nfds].socket_data = socket_data;
+
+ context->nfds ++;
+
+ return 0;
+}
+
+int multiio_socket_del(multiio_context_t context, int fd)
+{
+ size_t index;
+ int tmp;
+
+ tmp = multiio_pollfd_index_by_fd(context, fd, &index);
+ if(tmp)
+ return 1;
+
+ /**
+ * Special case: one left, if we tried filling in holes... segfault ;-)
+ */
+ if(context->nfds == 1)
+ {
+ context->nfds --;
+ return 0;
+ }
+
+ /**
+ * For now we'll unconditionally fill in holes.
+ * In fact, it looks simple enough that this method
+ * may be what we always use ;-).
+ */
+ memcpy(&context->pollfds[index], &context->pollfds[context->nfds - 1], sizeof(struct pollfd));
+ memcpy(&context->socket_infos[index], &context->socket_infos[context->nfds - 1], sizeof(struct multiio_socket_info));
+ context->nfds --;
+
+ return 0;
+}
+
+int multiio_socket_event_enable(multiio_context_t context, int fd, short event)
+{
+ size_t index;
+ int tmp;
+
+ tmp = multiio_pollfd_index_by_fd(context, fd, &index);
+ if(tmp)
+ return 1;
+
+ context->pollfds[index].events |= event;
+
+ return 0;
+}
+
+int multiio_socket_event_disable(multiio_context_t context, int fd, short event)
+{
+ size_t index;
+ int tmp;
+
+ tmp = multiio_pollfd_index_by_fd(context, fd, &index);
+ if(tmp)
+ return 1;
+
+ context->pollfds[index].events &= ~event;
+
+ return 0;
+}
+
+
+
+int multiio_pollfd_index_by_fd(const multiio_context_t context, int fd, size_t *index)
+{
+ size_t counter;
+
+ for(counter = 0; counter < context->nfds; counter ++)
+ if(context->pollfds[counter].fd == fd)
+ {
+ *index = counter;
+ return 0;
+ }
+
+ return 1;
+}