blob: 71fc3b4a2ca619d103fc8ebd4b79d958557b9f73 [file] [log] [blame]
/*
* Original author : tridge@samba.org, January 2002
*
* Copyright (c) 2005 Christophe Varoqui
* Copyright (c) 2005 Benjamin Marzinski, Redhat
*/
/*
* A simple domain socket listener
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdarg.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/poll.h>
#include <checkers.h>
#include <memory.h>
#include <debug.h>
#include <vector.h>
#include <structs.h>
#include <uxsock.h>
#include <defaults.h>
#include "cli.h"
#include "uxlsnr.h"
#define SLEEP_TIME 5000
struct client {
int fd;
struct client *next, *prev;
};
static struct client *clients;
static unsigned num_clients;
struct pollfd *polls;
/*
* handle a new client joining
*/
static void new_client(int ux_sock)
{
struct client *c;
struct sockaddr addr;
socklen_t len = sizeof(addr);
int fd;
fd = accept(ux_sock, &addr, &len);
if (fd == -1)
return;
/* put it in our linked list */
c = (struct client *)MALLOC(sizeof(*c));
memset(c, 0, sizeof(*c));
c->fd = fd;
c->next = clients;
if (c->next) c->next->prev = c;
clients = c;
num_clients++;
}
/*
* kill off a dead client
*/
static void dead_client(struct client *c)
{
close(c->fd);
if (c->prev) c->prev->next = c->next;
if (c->next) c->next->prev = c->prev;
if (c == clients) clients = c->next;
FREE(c);
num_clients--;
}
void free_polls (void)
{
if (polls)
FREE(polls);
}
void uxsock_cleanup(void *arg)
{
cli_exit();
free_polls();
}
/*
* entry point
*/
void * uxsock_listen(int (*uxsock_trigger)(char *, char **, int *, void *),
void * trigger_data)
{
int ux_sock;
size_t len;
int rlen;
char *inbuf;
char *reply;
ux_sock = ux_socket_listen(DEFAULT_SOCKET);
if (ux_sock == -1) {
condlog(0, "ux_socket_listen error");
exit(1);
}
pthread_cleanup_push(uxsock_cleanup, NULL);
polls = (struct pollfd *)MALLOC(0);
while (1) {
struct client *c;
int i, poll_count;
/* setup for a poll */
polls = REALLOC(polls, (1+num_clients) * sizeof(*polls));
polls[0].fd = ux_sock;
polls[0].events = POLLIN;
/* setup the clients */
for (i=1, c = clients; c; i++, c = c->next) {
polls[i].fd = c->fd;
polls[i].events = POLLIN;
}
/* most of our life is spent in this call */
poll_count = poll(polls, i, SLEEP_TIME);
if (poll_count == -1) {
if (errno == EINTR)
continue;
/* something went badly wrong! */
condlog(0, "poll");
pthread_exit(NULL);
}
if (poll_count == 0)
continue;
/* see if a client wants to speak to us */
for (i=1, c = clients; c; i++) {
struct client *next = c->next;
if (polls[i].revents & POLLIN) {
if (recv_packet(c->fd, &inbuf, &len) != 0) {
dead_client(c);
} else {
inbuf[len - 1] = 0;
condlog(4, "Got request [%s]", inbuf);
uxsock_trigger(inbuf, &reply, &rlen,
trigger_data);
if (reply) {
if (send_packet(c->fd, reply,
rlen) != 0) {
dead_client(c);
}
condlog(4, "Reply [%d bytes]",
rlen);
FREE(reply);
reply = NULL;
}
FREE(inbuf);
}
}
c = next;
}
/* see if we got a new client */
if (polls[0].revents & POLLIN) {
new_client(ux_sock);
}
}
pthread_cleanup_pop(1);
close(ux_sock);
return NULL;
}