Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F4512375
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
22 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/config/example.conf b/config/example.conf
index 3af44df9..a79c6be4 100644
--- a/config/example.conf
+++ b/config/example.conf
@@ -1,28 +1,28 @@
fence_virtd {
debug ="99";
listener = "multicast";
backend = "libvirt";
+ name_mode = "name";
}
listeners {
multicast {
key_file = "/etc/cluster/fence_xvm.key";
ip_family = "ipv4";
multicast_address = "225.0.0.14";
interface = "virbr0";
hash = "sha256";
auth = "sha256";
}
serial {
directory = "/var/run/fence_virtd";
}
}
backends {
libvirt {
uri = "qemu:///system";
}
}
-name_mode = "name";
diff --git a/server/libvirt.c b/server/libvirt.c
index a26b47de..d1fea4df 100644
--- a/server/libvirt.c
+++ b/server/libvirt.c
@@ -1,435 +1,442 @@
/*
Copyright Red Hat, Inc. 2006
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
This program 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
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
MA 02139, USA.
*/
/*
* Author: Lon Hohberger <lhh at redhat.com>
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/un.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/time.h>
#include <fcntl.h>
#include <errno.h>
#include <pthread.h>
#include <virterror.h>
#include <nss.h>
#include <libgen.h>
#include <syslog.h>
#include <simpleconfig.h>
#include <server_plugin.h>
/* Local includes */
#include "xvm.h"
#include "simple_auth.h"
#include "options.h"
#include "mcast.h"
#include "tcp.h"
#include "virt.h"
#include "libcman.h"
#include "debug.h"
#define NAME "libvirt"
#define VERSION "0.1"
#define MAGIC 0x1e19317a
#define VALIDATE(arg) \
do {\
errno = EINVAL;\
return -1; \
} while(0)
struct libvirt_info {
int magic;
int use_uuid;
virConnectPtr vp;
};
static inline int
wait_domain(const char *vm_name, virConnectPtr vp,
int use_uuid, int timeout)
{
int tries = 0;
int response = 1;
virDomainPtr vdp;
virDomainInfo vdi;
if (use_uuid) {
vdp = virDomainLookupByUUID(vp, (const unsigned char *)vm_name);
} else {
vdp = virDomainLookupByName(vp, vm_name);
}
if (!vdp)
return 0;
/* Check domain liveliness. If the domain is still here,
we return failure, and the client must then retry */
/* XXX On the xen 3.0.4 API, we will be able to guarantee
synchronous virDomainDestroy, so this check will not
be necessary */
do {
sleep(1);
if (use_uuid) {
vdp = virDomainLookupByUUID(vp,
(const unsigned char *)vm_name);
} else {
vdp = virDomainLookupByName(vp, vm_name);
}
if (!vdp) {
dbg_printf(2, "Domain no longer exists\n");
response = 0;
break;
}
memset(&vdi, 0, sizeof(vdi));
virDomainGetInfo(vdp, &vdi);
virDomainFree(vdp);
if (vdi.state == VIR_DOMAIN_SHUTOFF) {
dbg_printf(2, "Domain has been shut off\n");
response = 0;
break;
}
dbg_printf(4, "Domain still exists (state %d) "
"after %d seconds\n",
vdi.state, tries);
if (++tries >= timeout)
break;
} while (1);
return response;
}
static int
libvirt_null(const char *vm_name, void *priv)
{
dbg_printf(5, "%s %s\n", __FUNCTION__, vm_name);
printf("NULL operation: returning failure\n");
return 1;
}
static int
libvirt_off(const char *vm_name, void *priv)
{
struct libvirt_info *info = (struct libvirt_info *)priv;
virDomainPtr vdp;
virDomainInfo vdi;
int ret = -1;
dbg_printf(5, "%s %s\n", __FUNCTION__, vm_name);
VALIDATE(info);
if (info->use_uuid) {
vdp = virDomainLookupByUUID(info->vp,
(const unsigned char *)vm_name);
} else {
vdp = virDomainLookupByName(info->vp, vm_name);
}
if (!vdp ||
((virDomainGetInfo(vdp, &vdi) == 0) &&
(vdi.state == VIR_DOMAIN_SHUTOFF))) {
dbg_printf(2, "Nothing to do - domain does not exist\n");
if (vdp)
virDomainFree(vdp);
return 0;
}
syslog(LOG_NOTICE, "Destroying domain %s\n", vm_name);
dbg_printf(2, "[OFF] Calling virDomainDestroy\n");
ret = virDomainDestroy(vdp);
if (ret < 0) {
syslog(LOG_NOTICE, "Failed to destroy domain: %d\n", ret);
printf("virDomainDestroy() failed: %d\n", ret);
return 1;
}
if (ret) {
syslog(LOG_NOTICE,
"Domain %s still exists; fencing failed\n",
vm_name);
printf("Domain %s still exists; fencing failed\n", vm_name);
return 1;
}
return 0;
}
static int
libvirt_on(const char *vm_name, void *priv)
{
dbg_printf(5, "%s %s\n", __FUNCTION__, vm_name);
return -ENOSYS;
}
static int
libvirt_devstatus(void *priv)
{
dbg_printf(5, "%s ---\n", __FUNCTION__);
if (priv)
return 0;
return 1;
}
static int
libvirt_status(const char *vm_name, void *priv)
{
struct libvirt_info *info = (struct libvirt_info *)priv;
virDomainPtr vdp;
virDomainInfo vdi;
int ret = 0;
dbg_printf(5, "%s %s\n", __FUNCTION__, vm_name);
VALIDATE(info);
if (info->use_uuid) {
vdp = virDomainLookupByUUID(info->vp,
(const unsigned char *)vm_name);
} else {
vdp = virDomainLookupByName(info->vp, vm_name);
}
if (!vdp || ((virDomainGetInfo(vdp, &vdi) == 0) &&
(vdi.state == VIR_DOMAIN_SHUTOFF))) {
ret = 1;
}
if (vdp)
virDomainFree(vdp);
return ret;
}
static int
libvirt_reboot(const char *vm_name, void *priv)
{
struct libvirt_info *info = (struct libvirt_info *)priv;
virDomainPtr vdp, nvdp;
virDomainInfo vdi;
char *domain_desc;
int ret;
//uuid_unparse(vm_uuid, uu_string);
dbg_printf(5, "%s %s\n", __FUNCTION__, vm_name);
VALIDATE(info);
if (info->use_uuid) {
vdp = virDomainLookupByUUID(info->vp,
(const unsigned char *)vm_name);
} else {
vdp = virDomainLookupByName(info->vp, vm_name);
}
if (!vdp || ((virDomainGetInfo(vdp, &vdi) == 0) &&
(vdi.state == VIR_DOMAIN_SHUTOFF))) {
dbg_printf(2, "[libvirt:REBOOT] Nothing to "
"do - domain does not exist\n");
if (vdp)
virDomainFree(vdp);
return 0;
}
syslog(LOG_NOTICE, "Rebooting domain %s\n", vm_name);
printf("Rebooting domain %s...\n", vm_name);
domain_desc = virDomainGetXMLDesc(vdp, 0);
if (!domain_desc) {
printf("Failed getting domain description from "
"libvirt\n");
}
dbg_printf(2, "[REBOOT] Calling virDomainDestroy(%p)\n", vdp);
ret = virDomainDestroy(vdp);
if (ret < 0) {
printf("virDomainDestroy() failed: %d/%d\n", ret, errno);
free(domain_desc);
virDomainFree(vdp);
return 1;
}
ret = wait_domain(vm_name, info->vp, info->use_uuid, 15);
if (ret) {
syslog(LOG_NOTICE, "Domain %s still exists; fencing failed\n",
vm_name);
printf("Domain %s still exists; fencing failed\n", vm_name);
if (domain_desc)
free(domain_desc);
return 1;
}
if (!domain_desc)
return 0;
/* 'on' is not a failure */
ret = 0;
dbg_printf(3, "[[ XML Domain Info ]]\n");
dbg_printf(3, "%s\n[[ XML END ]]\n", domain_desc);
dbg_printf(2, "Calling virDomainCreateLinux()...\n");
nvdp = virDomainCreateLinux(info->vp, domain_desc, 0);
if (nvdp == NULL) {
/* More recent versions of libvirt or perhaps the
* KVM back-end do not let you create a domain from
* XML if there is already a defined domain description
* with the same name that it knows about. You must
* then call virDomainCreate() */
dbg_printf(2, "Failed; Trying virDomainCreate()...\n");
if (virDomainCreate(vdp) < 0) {
syslog(LOG_NOTICE,
"Could not restart %s\n",
vm_name);
dbg_printf(1, "Failed to recreate guest"
" %s!\n", vm_name);
}
}
free(domain_desc);
return ret;
}
static int
libvirt_init(backend_context_t *c, config_object_t *config)
{
virConnectPtr vp;
char value[256];
- char *uri = NULL;
struct libvirt_info *info = NULL;
+ char *uri = NULL;
int use_uuid = 0;
info = malloc(sizeof(*info));
if (!info)
return -1;
memset(info, 0, sizeof(*info));
if (sc_get(config, "backends/libvirt/@uri",
value, sizeof(value)) == 0) {
- uri = value;
+ uri = strdup(value);
+ if (!uri) {
+ free(info);
+ return -1;
+ }
printf("Using %s\n", uri);
}
/* Naming scheme is a top-level configuration option */
- if ((sc_get(config, "@name_mode", value, sizeof(value)-1) == 0)) {
+ if (sc_get(config, "fence_virtd/@name_mode",
+ value, sizeof(value)-1) == 0) {
dbg_printf(1, "Got %s for name_mode\n", value);
if (!strcasecmp(value, "uuid")) {
use_uuid = 1;
} else if (!strcasecmp(value, "name")) {
use_uuid = 0;
} else {
dbg_printf(1, "Unsupported name_mode: %s\n", value);
}
}
/* We don't need to store the URI; we only use it once */
vp = virConnectOpen(uri);
if (!vp) {
+ free(uri);
free(info);
return -1;
}
+ free(uri);
info->magic = MAGIC;
info->vp = vp;
info->use_uuid = use_uuid;
*c = (void *)info;
return 0;
}
static int
libvirt_shutdown(backend_context_t c)
{
struct libvirt_info *info = (struct libvirt_info *)c;
VALIDATE(info);
if (virConnectClose(info->vp) < 0) {
return -errno;
}
return 0;
}
static fence_callbacks_t libvirt_callbacks = {
.null = libvirt_null,
.off = libvirt_off,
.on = libvirt_on,
.reboot = libvirt_reboot,
.status = libvirt_status,
.devstatus = libvirt_devstatus
};
static plugin_t libvirt_plugin = {
.name = NAME,
.version = VERSION,
.callbacks = &libvirt_callbacks,
.init = libvirt_init,
.cleanup = libvirt_shutdown,
};
#ifdef _MODULE
double
BACKEND_VER_SYM(void)
{
return PLUGIN_VERSION_BACKEND;
}
const plugin_t *
BACKEND_INFO_SYM(void)
{
return &libvirt_plugin;
}
#else
static void __attribute__((constructor))
libvirt_register_plugin(void)
{
plugin_register(&libvirt_plugin);
}
#endif
diff --git a/server/mcast.c b/server/mcast.c
index 73b7a45c..afe69ebb 100644
--- a/server/mcast.c
+++ b/server/mcast.c
@@ -1,540 +1,541 @@
/*
Copyright Red Hat, Inc. 2006
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
This program 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
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
MA 02139, USA.
*/
/*
* Author: Lon Hohberger <lhh at redhat.com>
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/un.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/time.h>
#include <fcntl.h>
#include <errno.h>
#include <pthread.h>
#include <nss.h>
#include <libgen.h>
#include <list.h>
#include <simpleconfig.h>
#include <server_plugin.h>
/* Local includes */
#include "xvm.h"
#include "simple_auth.h"
#include "options.h"
#include "mcast.h"
#include "tcp.h"
#include "debug.h"
#define MCAST_MAGIC 0xaabab1b34b911a
#define VALIDATE(info) \
do {\
if (!info || info->magic != MCAST_MAGIC)\
return -EINVAL;\
} while(0)
typedef struct _mcast_options {
char *addr;
char *key_file;
int ifindex;
int family;
unsigned int port;
unsigned int hash;
unsigned int auth;
unsigned int flags;
} mcast_options;
typedef struct _history_node {
list_head();
fence_req_t req;
time_t when;
} history_node;
typedef struct _mcast_info {
uint64_t magic;
void *priv;
history_node *history;
char key[MAX_KEY_LEN];
mcast_options args;
const fence_callbacks_t *cb;
ssize_t key_len;
int mc_sock;
int need_kill;
} mcast_info;
/*
* See if we fenced this node recently (successfully)
* If so, ignore the request for a few seconds.
*
* We purge our history when the entries time out.
*/
static int
check_history(history_node **list, fence_req_t *req)
{
history_node *entry = NULL;
time_t now;
int x;
now = time(NULL);
loop_again:
list_for(list, entry, x) {
if (entry->when < (now - 10)) {
list_remove(list, entry);
free(entry);
goto loop_again;
}
if (entry->req.request == req->request &&
!strcasecmp((const char *)entry->req.domain,
(const char *)req->domain)) {
return 1;
}
}
return 0;
}
static int
record_history(history_node **list, fence_req_t *req)
{
history_node *entry = NULL;
entry = malloc(sizeof(*entry));
if (!entry)
return -1; /* non-fatal */
memset(entry, 0, sizeof(*entry));
memcpy(&entry->req, req, sizeof(*req));
entry->when = time(NULL);
list_insert(list, entry);
return 0;
}
static int
connect_tcp(fence_req_t *req, fence_auth_type_t auth,
void *key, size_t key_len)
{
int fd = -1;
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
char buf[128];
switch(req->family) {
case PF_INET:
memset(&sin, 0, sizeof(sin));
memcpy(&sin.sin_addr, req->address,
sizeof(sin.sin_addr));
sin.sin_family = PF_INET;
fd = ipv4_connect(&sin.sin_addr, req->port,
5);
if (fd < 0) {
printf("Failed to call back\n");
return -1;
}
break;
case PF_INET6:
memset(&sin6, 0, sizeof(sin));
memcpy(&sin6.sin6_addr, req->address,
sizeof(sin6.sin6_addr));
sin.sin_family = PF_INET6;
fd = ipv6_connect(&sin6.sin6_addr, req->port,
5);
memset(buf,0,sizeof(buf));
inet_ntop(PF_INET6, &sin6.sin6_addr, buf, sizeof(buf));
if (fd < 0) {
printf("Failed to call back %s\n", buf);
return -1;
}
break;
default:
printf("Family = %d\n", req->family);
return -1;
}
/* Noops if auth == AUTH_NONE */
if (tcp_response(fd, auth, key, key_len, 10) <= 0) {
printf("Failed to respond to challenge\n");
close(fd);
return -1;
}
if (tcp_challenge(fd, auth, key, key_len, 10) <= 0) {
printf("Remote failed challenge\n");
close(fd);
return -1;
}
return fd;
}
static int
do_fence_request_tcp(fence_req_t *req, mcast_info *info)
{
int fd = -1;
char response = 1;
fd = connect_tcp(req, info->args.auth, info->key, info->key_len);
if (fd < 0) {
dbg_printf(2, "Could call back for fence request: %s\n",
strerror(errno));
goto out;
}
switch(req->request) {
case FENCE_NULL:
response = info->cb->null((char *)req->domain, info->priv);
break;
case FENCE_ON:
response = info->cb->on((char *)req->domain, info->priv);
break;
case FENCE_OFF:
response = info->cb->off((char *)req->domain, info->priv);
break;
case FENCE_REBOOT:
response = info->cb->reboot((char *)req->domain, info->priv);
break;
case FENCE_STATUS:
response = info->cb->status((char *)req->domain, info->priv);
break;
case FENCE_DEVSTATUS:
response = info->cb->devstatus(info->priv);
break;
}
dbg_printf(3, "Sending response to caller...\n");
if (write(fd, &response, 1) < 0) {
perror("write");
}
/* XVM shotguns multicast packets, so we want to avoid
* acting on the same request multiple times if the first
* attempt was successful.
*/
record_history(&info->history, req);
out:
if (fd != -1)
close(fd);
return 1;
}
int
mcast_dispatch(listener_context_t c, struct timeval *timeout)
{
mcast_info *info;
fence_req_t data;
fd_set rfds;
struct sockaddr_in sin;
int len;
int n;
socklen_t slen;
info = (mcast_info *)c;
VALIDATE(info);
FD_ZERO(&rfds);
FD_SET(info->mc_sock, &rfds);
n = select((info->mc_sock)+1, &rfds, NULL, NULL, timeout);
if (n < 0)
return n;
/*
* If no requests, we're done
*/
if (n == 0)
return 0;
slen = sizeof(sin);
len = recvfrom(info->mc_sock, &data, sizeof(data), 0,
(struct sockaddr *)&sin, &slen);
if (len <= 0) {
perror("recvfrom");
return len;
}
if (!verify_request(&data, info->args.hash, info->key,
info->key_len)) {
printf("Key mismatch; dropping packet\n");
return 0;
}
if ((info->args.flags & F_USE_UUID) &&
!(data.flags & RF_UUID)) {
printf("Dropping packet: Request to fence by "
"name while using UUIDs\n");
return 0;
}
if (!(info->args.flags & F_USE_UUID) &&
(data.flags & RF_UUID)) {
printf("Dropping packet: Request to fence by "
"UUID while using names\n");
return 0;
}
printf("Request %d domain %s\n", data.request, data.domain);
if (check_history(&info->history, &data) == 1) {
printf("We just did this request; dropping packet\n");
return 0;
}
switch(info->args.auth) {
case AUTH_NONE:
case AUTH_SHA1:
case AUTH_SHA256:
case AUTH_SHA512:
printf("Plain TCP request\n");
do_fence_request_tcp(&data, info);
break;
default:
printf("XXX Unhandled authentication\n");
}
return 0;
}
static int
mcast_config(config_object_t *config, mcast_options *args)
{
char value[1024];
int errors = 0;
if (sc_get(config, "listeners/multicast/@key_file",
value, sizeof(value)-1) == 0) {
dbg_printf(1, "Got %s for key_file\n", value);
args->key_file = strdup(value);
} else {
args->key_file = strdup(DEFAULT_KEY_FILE);
if (!args->key_file) {
dbg_printf(1, "Failed to allocate memory\n");
return -1;
}
}
- if (sc_get(config, "@name_mode", value, sizeof(value)-1) == 0) {
+ if (sc_get(config, "fence_virtd/@name_mode",
+ value, sizeof(value)-1) == 0) {
/*
* This is just an optimization. If an administrator
* configured something at the top level, we can use it
* to explicitly ignore UUID vs. name
*/
dbg_printf(1, "Got %s for name_mode\n", value);
if (!strcasecmp(value, "uuid")) {
args->flags |= RF_UUID;
} else if (!strcasecmp(value, "name")) {
args->flags &= ~RF_UUID;
} else {
dbg_printf(1, "Unsupported name_mode: %s\n", value);
++errors;
}
}
args->hash = DEFAULT_HASH;
if (sc_get(config, "listeners/multicast/@hash",
value, sizeof(value)-1) == 0) {
dbg_printf(1, "Got %s for hash\n", value);
if (!strcasecmp(value, "none")) {
args->hash = HASH_NONE;
} else if (!strcasecmp(value, "sha1")) {
args->hash = HASH_SHA1;
} else if (!strcasecmp(value, "sha256")) {
args->hash = HASH_SHA256;
} else if (!strcasecmp(value, "sha512")) {
args->hash = HASH_SHA512;
} else {
dbg_printf(1, "Unsupported hash: %s\n", value);
++errors;
}
}
args->auth = DEFAULT_AUTH;
if (sc_get(config, "listeners/multicast/@auth",
value, sizeof(value)-1) == 0) {
dbg_printf(1, "Got %s for auth\n", value);
if (!strcasecmp(value, "none")) {
args->hash = AUTH_NONE;
} else if (!strcasecmp(value, "sha1")) {
args->hash = AUTH_SHA1;
} else if (!strcasecmp(value, "sha256")) {
args->hash = AUTH_SHA256;
} else if (!strcasecmp(value, "sha512")) {
args->hash = AUTH_SHA512;
} else {
dbg_printf(1, "Unsupported auth: %s\n", value);
++errors;
}
}
args->family = PF_INET;
if (sc_get(config, "listeners/multicast/@family",
value, sizeof(value)-1) == 0) {
dbg_printf(1, "Got %s for family\n", value);
if (!strcasecmp(value, "ipv4")) {
args->family = PF_INET;
} else if (!strcasecmp(value, "ipv6")) {
args->family = PF_INET6;
} else {
dbg_printf(1, "Unsupported family: %s\n", value);
++errors;
}
}
if (sc_get(config, "listeners/multicast/@address",
value, sizeof(value)-1) == 0) {
dbg_printf(1, "Got %s for address\n", value);
args->addr = strdup(value);
} else {
if (args->family == PF_INET) {
args->addr = strdup(IPV4_MCAST_DEFAULT);
} else {
args->addr = strdup(IPV6_MCAST_DEFAULT);
}
}
if (!args->addr) {
return -1;
}
args->port = DEFAULT_MCAST_PORT;
if (sc_get(config, "listeners/multicast/@port",
value, sizeof(value)-1) == 0) {
dbg_printf(1, "Got %s for port\n", value);
args->port = atoi(value);
if (args->port <= 0) {
dbg_printf(1, "Invalid port: %s\n", value);
++errors;
}
}
args->ifindex = 0;
if (sc_get(config, "listeners/multicast/@interface",
value, sizeof(value)-1) == 0) {
dbg_printf(1, "Got %s for interface\n", value);
args->ifindex = if_nametoindex(value);
if (args->ifindex < 0) {
dbg_printf(1, "Invalid interface: %s\n", value);
++errors;
}
}
return errors;
}
int
mcast_init(listener_context_t *c, const fence_callbacks_t *cb,
config_object_t *config, void *priv)
{
mcast_info *info;
int mc_sock, ret;
/* Initialize NSS; required to do hashing, as silly as that
sounds... */
if (NSS_NoDB_Init(NULL) != SECSuccess) {
printf("Could not initialize NSS\n");
return 1;
}
info = malloc(sizeof(*info));
if (!info)
return -1;
memset(info, 0, sizeof(*info));
info->priv = priv;
info->cb = cb;
ret = mcast_config(config, &info->args);
if (ret < 0) {
perror("mcast_config");
return -1;
} else if (ret > 0) {
printf("%d errors found during configuration\n",ret);
return -1;
}
if (info->args.auth != AUTH_NONE || info->args.hash != HASH_NONE) {
info->key_len = read_key_file(info->args.key_file,
info->key, sizeof(info->key));
if (info->key_len < 0) {
printf("Could not read %s; operating without "
"authentication\n", info->args.key_file);
info->args.auth = AUTH_NONE;
info->args.hash = HASH_NONE;
}
}
if (info->args.family == PF_INET)
mc_sock = ipv4_recv_sk(info->args.addr,
info->args.port,
info->args.ifindex);
else
mc_sock = ipv6_recv_sk(info->args.addr,
info->args.port,
info->args.ifindex);
if (mc_sock < 0) {
printf("Could not set up multicast listen socket\n");
free(info);
return 1;
}
info->magic = MCAST_MAGIC;
info->mc_sock = mc_sock;
*c = (listener_context_t)info;
return 0;
}
int
mcast_shutdown(listener_context_t c)
{
mcast_info *info = (mcast_info *)c;
VALIDATE(info);
info->magic = 0;
free(info->args.key_file);
free(info->args.addr);
close(info->mc_sock);
free(info);
return 0;
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Wed, Jun 25, 5:19 AM (1 d, 19 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1952256
Default Alt Text
(22 KB)
Attached To
Mode
rF Fence Agents
Attached
Detach File
Event Timeline
Log In to Comment