Merging the savefile branch. I hope it works; I even don't remember it.
/*
Terminal Mixer - multi-point multi-user access to terminal applications
Copyright (C) 2007 LluĂs Batlle i Rossell
Please find the license in the provided COPYING file.
*/
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
#include <stdio.h>
#include <netinet/in.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/select.h>
#include "main.h"
#include "handlers.h"
static int served_sockets = 0;
static int listen_socket = -1; /* not listening */
static int connected_sockets = 0;
static int *conn_sockets = 0;
static void start_listening(int new)
{
int ls;
struct sockaddr_in addr;
int res;
assert(new > 0);
ls = socket(AF_INET, SOCK_STREAM, 0);
if (ls == -1)
error("Cannot create the tcp listen socket in the server");
{
int on = 1;
res = setsockopt(ls, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
if (res == -1)
error("Cannot set SO_REUSEADDR");
}
addr.sin_family = AF_INET;
addr.sin_port = htons(command_line.tcp_port);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
res = bind(ls, (struct sockaddr *) & addr, sizeof(addr));
if (res == -1)
error("Error binding tcp to port %i", command_line.tcp_port);
/* NUANCE: 0 backlog. Why should we assure future connections? */
res = listen(ls, 0);
if (res == -1)
error("Error listening on the binded tcp socket");
listen_socket = ls;
}
void s_tcp_update_served(int new)
{
if (new > served_sockets && new > 0 )
{
conn_sockets = realloc(conn_sockets, sizeof(*conn_sockets) * new);
if (listen_socket == -1) /* not listening */
{
start_listening(new);
}
served_sockets = new;
}
else if (new < served_sockets)
{
not_implemented("new < served_sockets at s_tcp_update_served");
}
}
void s_tcp_shutdown()
{
int i;
if (listen_socket != -1)
{
close(listen_socket);
}
for (i=0; i < connected_sockets; ++i)
{
close(conn_sockets[i]);
}
connected_sockets = 0;
served_sockets = 0;
}
void s_tcp_prepare_read_fdset(fd_set *read_set, int *maxfd)
{
int i;
FD_SET(listen_socket, read_set);
*maxfd = max(*maxfd, listen_socket);
for (i=0; i < connected_sockets; ++i)
{
/* We only accept if we don't have any
* connetion opened. */
FD_SET(conn_sockets[i], read_set);
*maxfd = max(*maxfd, conn_sockets[i]);
}
}
static void remove_conn_socket(int n)
{
int i;
assert(n >= 0);
for(i=n+1; i<connected_sockets; ++i)
{
conn_sockets[i-1] = conn_sockets[i];
}
connected_sockets -= 1;
/* We shrink the memory until we have an array for served_sockets */
if (served_sockets <= connected_sockets)
{
conn_sockets = realloc(conn_sockets, sizeof(*conn_sockets)
* connected_sockets);
}
}
static int accept_connection(int ls)
{
int cs;
cs = accept(ls, 0, 0);
if (cs == -1)
not_implemented("accept tcp socket error check");
/* TODO: Prepare unblocking sockets if needed */
return cs;
}
void s_tcp_process_read_fdset(fd_set *read_set)
{
int i;
/* Active streams */
for (i=0; i < connected_sockets; ++i)
{
if (FD_ISSET(conn_sockets[i], read_set))
{
int res;
res = read(conn_sockets[i], stream_buffer,
stream_buffer_size);
if (res == 0)
{
close(conn_sockets[i]);
remove_conn_socket(i);
} else
{
app_control_remote_send_to_stdin(stream_buffer, res);
}
}
}
/* Listen connection */
if (FD_ISSET(listen_socket, read_set))
{
if (served_sockets > connected_sockets)
{
int s;
s = accept_connection(listen_socket);
conn_sockets[connected_sockets++] = s;
welcome_new_client_socket(s);
} else
{
int s;
s = accept_connection(listen_socket);
close(s);
}
}
}
void s_tcp_send_to_connected(const char *buffer, size_t size)
{
int i;
for (i=0; i < connected_sockets; ++i)
{
write(conn_sockets[i], buffer, size);
}
}