Added filterdes.
/*
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 <sys/un.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 char *socket_path = 0;
static char default_path_prefix[] = "/tmp/tm-socket.";
void get_unix_path()
{
char *new;
new = getenv("TM_SOCKET");
if (new == 0) /* Compose the path from the default values */
{
char num[20]; /* enough for an int */
int len;
sprintf(num, "%i", (int) getuid());
len = strlen(default_path_prefix) + strlen(num) + 1;
command_line.unix_path = malloc(len);
sprintf(command_line.unix_path, "%s%s",
default_path_prefix, num);
} else
{
command_line.unix_path = malloc(strlen(new) + 1);
strcpy(command_line.unix_path, new);
}
}
static void start_listening(int new)
{
int ls;
struct sockaddr_un addr;
int res;
assert(new > 0);
assert(command_line.unix_path != 0);
socket_path = command_line.unix_path;
ls = socket(AF_UNIX, SOCK_STREAM, 0);
if (ls == -1)
error("Cannot create the unix listen socket in the server");
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path));
res = bind(ls, (struct sockaddr *) & addr, sizeof(addr));
if (res == -1)
error("Error binding to %s", socket_path);
/* NUANCE: 0 backlog. Why should we assure future connections? */
res = listen(ls, 0);
if (res == -1)
error("Error listening on the binded unix socket");
listen_socket = ls;
}
void s_unix_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 unix_update_served");
}
}
void s_unix_shutdown()
{
int i;
if (listen_socket != -1)
{
close(listen_socket);
unlink(socket_path);
}
for (i=0; i < connected_sockets; ++i)
{
close(conn_sockets[i]);
}
connected_sockets = 0;
served_sockets = 0;
}
void s_unix_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 unix socket error check");
/* TODO: Prepare unblocking sockets if needed */
return cs;
}
void s_unix_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_unix_send_to_connected(const char *buffer, size_t size)
{
int i;
for (i=0; i < connected_sockets; ++i)
{
write(conn_sockets[i], buffer, size);
}
}