fence-virt/server/virt-sockets.c

237 lines
4.1 KiB
C
Raw Normal View History

#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
#include <list.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdlib.h>
#include <debug.h>
#include <simpleconfig.h>
#include <errno.h>
#include <fcntl.h>
#include "serial.h"
struct socket_list {
list_head();
char *domain_name;
char *socket_path;
int socket_fd;
};
static struct socket_list *socks = NULL;
static pthread_mutex_t sock_list_mutex = PTHREAD_MUTEX_INITIALIZER;
static int
connect_nb(int fd, struct sockaddr *dest, socklen_t len, int timeout)
{
int ret, flags, err;
unsigned l;
fd_set rfds, wfds;
struct timeval tv;
/*
Set up non-blocking connect
*/
flags = fcntl(fd, F_GETFL, 0);
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
ret = connect(fd, dest, len);
if ((ret < 0) && (errno != EINPROGRESS))
return -1;
if (ret == 0)
goto done;
FD_ZERO(&rfds);
FD_SET(fd, &rfds);
FD_ZERO(&wfds);
FD_SET(fd, &wfds);
tv.tv_sec = timeout;
tv.tv_usec = 0;
if (select(fd + 1, &rfds, &wfds, NULL, &tv) == 0) {
errno = ETIMEDOUT;
return -1;
}
if (!FD_ISSET(fd, &rfds) && !FD_ISSET(fd, &wfds)) {
errno = EIO;
return -1;
}
l = sizeof(err);
if (getsockopt(fd, SOL_SOCKET, SO_ERROR,
(void *)&err, &l) < 0) {
return -1;
}
if (err != 0) {
errno = err;
return -1;
}
done:
fcntl(fd, F_SETFL, flags);
return 0;
}
int
domain_sock_setup(const char *domain, const char *socket_path)
{
struct sockaddr_un *sun = NULL;
struct socket_list *node = NULL;
socklen_t sun_len;
int sock = -1;
sun_len = sizeof(*sun) + strlen(socket_path) + 1;
sun = malloc(sun_len);
if (!sun)
return -1;
memset((char *)sun, 0, sun_len);
sun->sun_family = PF_LOCAL;
strncpy(sun->sun_path, socket_path, sun_len - sizeof(*sun));
sock = socket(PF_LOCAL, SOCK_STREAM, 0);
if (sock < 0)
goto out_fail;
if (connect_nb(sock, (struct sockaddr *)sun, SUN_LEN(sun), 3) < 0)
goto out_fail;
free(sun);
sun = NULL;
node = calloc(1, sizeof(*node));
if (!node)
goto out_fail;
node->domain_name = strdup(domain);
if (!node->domain_name)
goto out_fail;
node->socket_path = strdup(socket_path);
if (!node->socket_path)
goto out_fail;
node->socket_fd = sock;
pthread_mutex_lock(&sock_list_mutex);
list_insert(&socks, node);
pthread_mutex_unlock(&sock_list_mutex);
dbg_printf(3, "Registered %s on %d\n", domain, sock);
return 0;
out_fail:
if (node) {
free(node->domain_name);
if (node->socket_path)
free(node->socket_path);
free(node);
}
free(sun);
if (sock >= 0)
close(sock);
return -1;
}
int
domain_sock_close(const char *domain)
{
struct socket_list *node = NULL;
struct socket_list *dead = NULL;
int x;
pthread_mutex_lock(&sock_list_mutex);
list_for(&socks, node, x) {
if (!strcasecmp(domain, node->domain_name)) {
list_remove(&socks, node);
dead = node;
break;
}
}
pthread_mutex_unlock(&sock_list_mutex);
if (dead) {
dbg_printf(3, "Unregistered %s, fd%d\n",
dead->domain_name,
dead->socket_fd);
close(dead->socket_fd);
free(dead->domain_name);
free(dead->socket_path);
free(dead);
}
return 0;
}
int
domain_sock_fdset(fd_set *fds, int *max)
{
struct socket_list *node = NULL;
int x = 0, _max = -1;
pthread_mutex_lock(&sock_list_mutex);
list_for(&socks, node, x) {
FD_SET(node->socket_fd, fds);
if (node->socket_fd > _max)
_max = node->socket_fd;
}
pthread_mutex_unlock(&sock_list_mutex);
if (max)
*max = _max;
return x;
}
int
domain_sock_name(int fd, char *outbuf, size_t buflen)
{
struct socket_list *node = NULL;
int ret = 1, x = 0;
pthread_mutex_lock(&sock_list_mutex);
list_for(&socks, node, x) {
if (node->socket_fd == fd) {
snprintf(outbuf, buflen, "%s", node->domain_name);
ret = 0;
break;
}
}
pthread_mutex_unlock(&sock_list_mutex);
return ret;
}
int
domain_sock_cleanup(void)
{
struct socket_list *dead= NULL;
pthread_mutex_lock(&sock_list_mutex);
while(socks) {
dead = socks;
list_remove(&socks, dead);
close(dead->socket_fd);
free(dead->domain_name);
free(dead->socket_path);
free(dead);
}
pthread_mutex_unlock(&sock_list_mutex);
return 0;
}