mirror of https://github.com/sipwise/heartbeat.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
699 lines
16 KiB
699 lines
16 KiB
/*
|
|
* Adapted from alanr's UDP broadcast heartbeat bcast.c by Stéphane Billiart
|
|
* <stephane@reefedge.com>
|
|
*
|
|
* (c) 2002 Stéphane Billiart <stephane@reefedge.com>
|
|
* (c) 2002 Alan Robertson <alanr@unix.sh>
|
|
*
|
|
* Brian Tinsley <btinsley@emageon.com>
|
|
* - allow use of hostname in ha.cf
|
|
* - set IP type of service of write socket
|
|
* - many MALLOC calls were not checked for failure
|
|
* - code janitor
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library 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
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#include <lha_internal.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#ifdef HAVE_STRINGS_H
|
|
#include <strings.h>
|
|
#endif
|
|
#include <ctype.h>
|
|
#include <fcntl.h>
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <netinet/in.h>
|
|
|
|
#ifndef HAVE_INET_ATON
|
|
extern int inet_aton(const char *, struct in_addr *);
|
|
#endif
|
|
#include <netinet/in_systm.h>
|
|
#include <netinet/ip.h>
|
|
#include <arpa/inet.h>
|
|
#if defined(SO_BINDTODEVICE)
|
|
#include <net/if.h>
|
|
#endif
|
|
|
|
#include <heartbeat.h>
|
|
#include <HBcomm.h>
|
|
|
|
|
|
/*
|
|
* Plugin information
|
|
*/
|
|
#define PIL_PLUGINTYPE HB_COMM_TYPE
|
|
#define PIL_PLUGINTYPE_S HB_COMM_TYPE_S
|
|
#define PIL_PLUGIN ucast
|
|
#define PIL_PLUGIN_S "ucast"
|
|
#define PIL_PLUGINLICENSE LICENSE_LGPL
|
|
#define PIL_PLUGINLICENSEURL URL_LGPL
|
|
#include <pils/plugin.h>
|
|
|
|
|
|
/*
|
|
* Macros/Defines
|
|
*/
|
|
#define ISUCASTOBJECT(mp) ((mp) && ((mp)->vf == (void*)&ucastOps))
|
|
#define UCASTASSERT(mp) g_assert(ISUCASTOBJECT(mp))
|
|
|
|
#define LOG PluginImports->log
|
|
#define MALLOC PluginImports->alloc
|
|
#define STRDUP PluginImports->mstrdup
|
|
#define FREE PluginImports->mfree
|
|
|
|
#define MAXBINDTRIES 10
|
|
|
|
|
|
/*
|
|
* Structure Declarations
|
|
*/
|
|
|
|
struct ip_private {
|
|
char* interface; /* Interface name */
|
|
struct in_addr heartaddr; /* Peer node address */
|
|
struct sockaddr_in addr; /* Local address */
|
|
int port; /* UDP port */
|
|
int rsocket; /* Read-socket */
|
|
int wsocket; /* Write-socket */
|
|
};
|
|
|
|
|
|
/*
|
|
* Function Prototypes
|
|
*/
|
|
|
|
PIL_rc PIL_PLUGIN_INIT(PILPlugin *us, const PILPluginImports *imports);
|
|
|
|
static int ucast_parse(const char *line);
|
|
static struct hb_media* ucast_new(const char *intf, const char *addr);
|
|
static int ucast_open(struct hb_media *mp);
|
|
static int ucast_close(struct hb_media *mp);
|
|
static void* ucast_read(struct hb_media *mp, int* lenp);
|
|
static int ucast_write(struct hb_media *mp, void *msg, int len);
|
|
|
|
static int HB_make_receive_sock(struct hb_media *ei);
|
|
static int HB_make_send_sock(struct hb_media *mp);
|
|
|
|
static struct ip_private* new_ip_interface(const char *ifn,
|
|
const char *hbaddr, int port);
|
|
|
|
static int ucast_descr(char **buffer);
|
|
static int ucast_mtype(char **buffer);
|
|
static int ucast_isping(void);
|
|
|
|
|
|
/*
|
|
* External Data
|
|
*/
|
|
|
|
extern struct hb_media *sysmedia[];
|
|
extern int nummedia;
|
|
|
|
/*
|
|
* Module Public Data
|
|
*/
|
|
|
|
const char hb_media_name[] = "UDP/IP unicast";
|
|
|
|
static struct hb_media_fns ucastOps = {
|
|
NULL,
|
|
ucast_parse,
|
|
ucast_open,
|
|
ucast_close,
|
|
ucast_read,
|
|
ucast_write,
|
|
ucast_mtype,
|
|
ucast_descr,
|
|
ucast_isping
|
|
};
|
|
|
|
PIL_PLUGIN_BOILERPLATE2("1.0", Debug)
|
|
static const PILPluginImports* PluginImports;
|
|
static PILPlugin* OurPlugin;
|
|
static PILInterface* OurInterface;
|
|
static struct hb_media_imports* OurImports;
|
|
static void* interfprivate;
|
|
static int localudpport;
|
|
|
|
|
|
/*
|
|
* Implmentation
|
|
*/
|
|
|
|
PIL_rc PIL_PLUGIN_INIT(PILPlugin *us, const PILPluginImports *imports)
|
|
{
|
|
/* Force the compiler to do a little type checking */
|
|
(void)(PILPluginInitFun)PIL_PLUGIN_INIT;
|
|
|
|
PluginImports = imports;
|
|
OurPlugin = us;
|
|
|
|
/* Register ourself as a plugin */
|
|
imports->register_plugin(us, &OurPIExports);
|
|
|
|
/* Register our interface implementation */
|
|
return imports->register_interface(us, PIL_PLUGINTYPE_S,
|
|
PIL_PLUGIN_S, &ucastOps, NULL,
|
|
&OurInterface, (void*)&OurImports, interfprivate);
|
|
}
|
|
|
|
static int ucast_parse(const char *line)
|
|
{
|
|
const char *bp = line;
|
|
int toklen;
|
|
struct hb_media *mp;
|
|
char dev[MAXLINE];
|
|
char ucast[MAXLINE];
|
|
|
|
/* Skip over white space, then grab the device */
|
|
bp += strspn(bp, WHITESPACE);
|
|
toklen = strcspn(bp, WHITESPACE);
|
|
strncpy(dev, bp, toklen);
|
|
bp += toklen;
|
|
dev[toklen] = EOS;
|
|
|
|
if (*dev != EOS) {
|
|
#ifdef NOTYET
|
|
if (!is_valid_dev(dev)) {
|
|
PILCallLog(LOG, PIL_CRIT, "ucast: bad device [%s]", dev);
|
|
return HA_FAIL;
|
|
}
|
|
#endif
|
|
bp += strspn(bp, WHITESPACE);
|
|
toklen = strcspn(bp, WHITESPACE);
|
|
strncpy(ucast, bp, toklen);
|
|
bp += toklen;
|
|
ucast[toklen] = EOS;
|
|
|
|
if (*ucast == EOS) {
|
|
PILCallLog(LOG, PIL_CRIT,
|
|
"ucast: [%s] missing target IP address/hostname",
|
|
dev);
|
|
return HA_FAIL;
|
|
}
|
|
if (!(mp = ucast_new(dev, ucast))) {
|
|
return HA_FAIL;
|
|
}
|
|
|
|
sysmedia[nummedia++] = mp;
|
|
}
|
|
|
|
return HA_OK;
|
|
}
|
|
|
|
static int ucast_mtype(char **buffer)
|
|
{
|
|
*buffer = STRDUP(PIL_PLUGIN_S);
|
|
if (!*buffer) {
|
|
PILCallLog(LOG, PIL_CRIT, "ucast: memory allocation error (line %d)",
|
|
(__LINE__ - 2) );
|
|
return 0;
|
|
}
|
|
|
|
return strlen(*buffer);
|
|
}
|
|
|
|
static int ucast_descr(char **buffer)
|
|
{
|
|
*buffer = strdup(hb_media_name);
|
|
if (!*buffer) {
|
|
PILCallLog(LOG, PIL_CRIT, "ucast: memory allocation error (line %d)",
|
|
(__LINE__ - 2) );
|
|
return 0;
|
|
}
|
|
|
|
return strlen(*buffer);
|
|
}
|
|
|
|
static int ucast_isping(void)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int ucast_init(void)
|
|
{
|
|
struct servent *service;
|
|
|
|
g_assert(OurImports != NULL);
|
|
|
|
if (localudpport <= 0) {
|
|
const char *chport;
|
|
if ((chport = OurImports->ParamValue("udpport")) != NULL) {
|
|
if (sscanf(chport, "%d", &localudpport) <= 0
|
|
|| localudpport <= 0) {
|
|
PILCallLog(LOG, PIL_CRIT,
|
|
"ucast: bad port number %s", chport);
|
|
return HA_FAIL;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* No port specified in the configuration... */
|
|
|
|
if (localudpport <= 0) {
|
|
/* If our service name is in /etc/services, then use it */
|
|
if ((service=getservbyname(HA_SERVICENAME, "udp")) != NULL)
|
|
localudpport = ntohs(service->s_port);
|
|
else
|
|
localudpport = UDPPORT;
|
|
}
|
|
return HA_OK;
|
|
}
|
|
|
|
/*
|
|
* Create new UDP/IP unicast heartbeat object
|
|
* Name of interface and address are passed as parameters
|
|
*/
|
|
static struct hb_media*
|
|
ucast_new(const char *intf, const char *addr)
|
|
{
|
|
struct ip_private *ipi;
|
|
struct hb_media *ret;
|
|
char *name;
|
|
|
|
ucast_init();
|
|
|
|
if (!(ipi = new_ip_interface(intf, addr, localudpport))) {
|
|
PILCallLog(LOG, PIL_CRIT, "ucast: interface [%s] does not exist", intf);
|
|
return NULL;
|
|
}
|
|
if (!(ret = (struct hb_media*)MALLOC(sizeof(struct hb_media)))) {
|
|
PILCallLog(LOG, PIL_CRIT, "ucast: memory allocation error (line %d)",
|
|
(__LINE__ - 2) );
|
|
FREE(ipi->interface);
|
|
FREE(ipi);
|
|
} else {
|
|
memset(ret, 0, sizeof(*ret));
|
|
ret->pd = (void*)ipi;
|
|
if (!(name = STRDUP(intf))) {
|
|
PILCallLog(LOG, PIL_CRIT,
|
|
"ucast: memory allocation error (line %d)",
|
|
(__LINE__ - 3) );
|
|
FREE(ipi->interface);
|
|
FREE(ipi);
|
|
FREE(ret);
|
|
ret = NULL;
|
|
}
|
|
else {
|
|
ret->name = name;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* Open UDP/IP unicast heartbeat interface
|
|
*/
|
|
static int ucast_open(struct hb_media* mp)
|
|
{
|
|
struct ip_private * ei;
|
|
|
|
UCASTASSERT(mp);
|
|
ei = (struct ip_private*)mp->pd;
|
|
|
|
if ((ei->wsocket = HB_make_send_sock(mp)) < 0)
|
|
return HA_FAIL;
|
|
if ((ei->rsocket = HB_make_receive_sock(mp)) < 0) {
|
|
ucast_close(mp);
|
|
return HA_FAIL;
|
|
}
|
|
|
|
PILCallLog(LOG, PIL_INFO, "ucast: started on port %d interface %s to %s",
|
|
localudpport, ei->interface, inet_ntoa(ei->addr.sin_addr));
|
|
|
|
return HA_OK;
|
|
}
|
|
|
|
/*
|
|
* Close UDP/IP unicast heartbeat interface
|
|
*/
|
|
static int ucast_close(struct hb_media* mp)
|
|
{
|
|
struct ip_private *ei;
|
|
int rc = HA_OK;
|
|
|
|
UCASTASSERT(mp);
|
|
ei = (struct ip_private*)mp->pd;
|
|
|
|
if (ei->rsocket >= 0) {
|
|
if (close(ei->rsocket) < 0) {
|
|
rc = HA_FAIL;
|
|
}
|
|
ei->rsocket = -1;
|
|
}
|
|
if (ei->wsocket >= 0) {
|
|
if (close(ei->wsocket) < 0) {
|
|
rc = HA_FAIL;
|
|
}
|
|
ei->wsocket = -1;
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
|
|
/*
|
|
* Receive a heartbeat unicast packet from UDP interface
|
|
*/
|
|
|
|
char ucast_pkt[MAXMSG];
|
|
|
|
static void *
|
|
ucast_read(struct hb_media* mp, int *lenp)
|
|
{
|
|
struct ip_private *ei;
|
|
socklen_t addr_len;
|
|
struct sockaddr_in their_addr;
|
|
int numbytes;
|
|
|
|
UCASTASSERT(mp);
|
|
ei = (struct ip_private*)mp->pd;
|
|
|
|
addr_len = sizeof(struct sockaddr);
|
|
if ((numbytes = recvfrom(ei->rsocket, ucast_pkt, MAXMSG-1, 0,
|
|
(struct sockaddr *)&their_addr, &addr_len)) == -1) {
|
|
if (errno != EINTR) {
|
|
PILCallLog(LOG, PIL_CRIT, "ucast: error receiving from socket: %s",
|
|
strerror(errno));
|
|
}
|
|
return NULL;
|
|
}
|
|
if (numbytes == 0) {
|
|
PILCallLog(LOG, PIL_CRIT, "ucast: received zero bytes");
|
|
return NULL;
|
|
}
|
|
|
|
ucast_pkt[numbytes] = EOS;
|
|
|
|
if (DEBUGPKT) {
|
|
PILCallLog(LOG, PIL_DEBUG, "ucast: received %d byte packet from %s",
|
|
numbytes, inet_ntoa(their_addr.sin_addr));
|
|
}
|
|
if (DEBUGPKTCONT) {
|
|
PILCallLog(LOG, PIL_DEBUG, "%s", ucast_pkt);
|
|
}
|
|
|
|
*lenp = numbytes +1;
|
|
|
|
return ucast_pkt;
|
|
|
|
|
|
}
|
|
|
|
/*
|
|
* Send a heartbeat packet over unicast UDP/IP interface
|
|
*/
|
|
|
|
static int
|
|
ucast_write(struct hb_media* mp, void *pkt, int len)
|
|
{
|
|
struct ip_private *ei;
|
|
int rc;
|
|
|
|
UCASTASSERT(mp);
|
|
ei = (struct ip_private*)mp->pd;
|
|
|
|
if ((rc = sendto(ei->wsocket, pkt, len, 0
|
|
, (struct sockaddr *)&ei->addr
|
|
, sizeof(struct sockaddr))) != len) {
|
|
if (!mp->suppresserrs) {
|
|
PILCallLog(LOG, PIL_CRIT, "Unable to send [%d] ucast packet: %s"
|
|
, rc, strerror(errno));
|
|
}
|
|
return HA_FAIL;
|
|
}
|
|
|
|
if (DEBUGPKT) {
|
|
PILCallLog(LOG, PIL_DEBUG, "ucast: sent %d bytes to %s", rc,
|
|
inet_ntoa(ei->addr.sin_addr));
|
|
}
|
|
if (DEBUGPKTCONT) {
|
|
PILCallLog(LOG, PIL_DEBUG, "%s", (const char*)pkt);
|
|
}
|
|
return HA_OK;
|
|
}
|
|
|
|
/*
|
|
* Set up socket for sending unicast UDP heartbeats
|
|
*/
|
|
|
|
static int HB_make_send_sock(struct hb_media *mp)
|
|
{
|
|
int sockfd;
|
|
struct ip_private *ei;
|
|
int tos;
|
|
#if defined(SO_BINDTODEVICE)
|
|
struct ifreq i;
|
|
#endif
|
|
#if defined(SO_REUSEPORT)
|
|
int i = 1;
|
|
#endif
|
|
|
|
UCASTASSERT(mp);
|
|
ei = (struct ip_private*)mp->pd;
|
|
|
|
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
|
PILCallLog(LOG, PIL_CRIT, "ucast: Error creating write socket: %s",
|
|
strerror(errno));
|
|
}
|
|
|
|
/*
|
|
* 21 December 2002
|
|
* Added by Brian TInsley <btinsley@emageon.com>
|
|
*/
|
|
tos = IPTOS_LOWDELAY;
|
|
if (setsockopt(sockfd, IPPROTO_IP, IP_TOS,
|
|
&tos, sizeof(tos)) < 0) {
|
|
PILCallLog(LOG, PIL_CRIT, "ucast: error setting socket option IP_TOS: %s",
|
|
strerror(errno));
|
|
}
|
|
else {
|
|
PILCallLog(LOG, PIL_INFO,
|
|
"ucast: write socket priority set to IPTOS_LOWDELAY on %s",
|
|
ei->interface);
|
|
}
|
|
|
|
#if defined(SO_BINDTODEVICE)
|
|
{
|
|
/*
|
|
* We want to send out this particular interface
|
|
*
|
|
* This is so we can have redundant NICs, and heartbeat on both
|
|
*/
|
|
strcpy(i.ifr_name, ei->interface);
|
|
|
|
if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
|
|
&i, sizeof(i)) == -1) {
|
|
PILCallLog(LOG, PIL_CRIT,
|
|
"ucast: error setting option SO_BINDTODEVICE(w) on %s: %s",
|
|
i.ifr_name, strerror(errno));
|
|
close(sockfd);
|
|
return -1;
|
|
}
|
|
PILCallLog(LOG, PIL_INFO, "ucast: bound send socket to device: %s",
|
|
i.ifr_name);
|
|
}
|
|
#endif
|
|
#if defined(SO_REUSEPORT)
|
|
{
|
|
/* this is for OpenBSD to allow multiple *
|
|
* ucast connections, e.g. a more than *
|
|
* two node cluster */
|
|
|
|
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT,
|
|
&i, sizeof(i)) == -1) {
|
|
PILCallLog(LOG, PIL_CRIT,
|
|
"ucast: error setting option SO_REUSEPORT(w): %s", strerror(errno));
|
|
close(sockfd);
|
|
return -1;
|
|
}
|
|
PILCallLog(LOG, PIL_INFO, "ucast: set SO_REUSEPORT(w)");
|
|
}
|
|
#endif
|
|
if (fcntl(sockfd,F_SETFD, FD_CLOEXEC) < 0) {
|
|
PILCallLog(LOG, PIL_CRIT, "ucast: error setting close-on-exec flag: %s",
|
|
strerror(errno));
|
|
}
|
|
|
|
return sockfd;
|
|
}
|
|
|
|
/*
|
|
* Set up socket for listening to heartbeats (UDP unicast)
|
|
*/
|
|
|
|
static int HB_make_receive_sock(struct hb_media *mp) {
|
|
|
|
struct ip_private *ei;
|
|
struct sockaddr_in my_addr;
|
|
int sockfd;
|
|
int bindtries;
|
|
int boundyet = 0;
|
|
int j;
|
|
|
|
UCASTASSERT(mp);
|
|
ei = (struct ip_private*)mp->pd;
|
|
|
|
memset(&(my_addr), 0, sizeof(my_addr)); /* zero my address struct */
|
|
my_addr.sin_family = AF_INET; /* host byte order */
|
|
my_addr.sin_port = htons(ei->port); /* short, network byte order */
|
|
my_addr.sin_addr.s_addr = INADDR_ANY; /* auto-fill with my IP */
|
|
|
|
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
|
|
PILCallLog(LOG, PIL_CRIT, "ucast: error creating read socket: %s",
|
|
strerror(errno));
|
|
return -1;
|
|
}
|
|
/*
|
|
* Set SO_REUSEADDR on the server socket s. Variable j is used
|
|
* as a scratch varable.
|
|
*
|
|
* 16th February 2000
|
|
* Added by Horms <horms@vergenet.net>
|
|
* with thanks to Clinton Work <work@scripty.com>
|
|
*/
|
|
j = 1;
|
|
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
|
|
(void *)&j, sizeof j) < 0) {
|
|
/* Ignore it. It will almost always be OK anyway. */
|
|
PILCallLog(LOG, PIL_CRIT,
|
|
"ucast: error setting socket option SO_REUSEADDR: %s",
|
|
strerror(errno));
|
|
}
|
|
#if defined(SO_BINDTODEVICE)
|
|
{
|
|
/*
|
|
* We want to receive packets only from this interface...
|
|
*/
|
|
struct ifreq i;
|
|
strcpy(i.ifr_name, ei->interface);
|
|
|
|
if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
|
|
&i, sizeof(i)) == -1) {
|
|
PILCallLog(LOG, PIL_CRIT,
|
|
"ucast: error setting option SO_BINDTODEVICE(r) on %s: %s",
|
|
i.ifr_name, strerror(errno));
|
|
close(sockfd);
|
|
return -1;
|
|
}
|
|
PILCallLog(LOG, PIL_INFO, "ucast: bound receive socket to device: %s",
|
|
i.ifr_name);
|
|
}
|
|
#endif
|
|
#if defined(SO_REUSEPORT)
|
|
{
|
|
/*
|
|
* Needed for OpenBSD for more than two nodes in a ucast cluster
|
|
*/
|
|
int i = 1;
|
|
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT,
|
|
&i, sizeof(i)) == -1) {
|
|
PILCallLog(LOG, PIL_CRIT,
|
|
"ucast: error setting option SO_REUSEPORT(r) %s", strerror(errno));
|
|
close(sockfd);
|
|
return -1;
|
|
}
|
|
PILCallLog(LOG, PIL_INFO, "ucast: set SO_REUSEPORT(w)");
|
|
}
|
|
#endif
|
|
|
|
/* Try binding a few times before giving up */
|
|
/* Sometimes a process with it open is exiting right now */
|
|
|
|
for (bindtries=0; !boundyet && bindtries < MAXBINDTRIES; ++bindtries) {
|
|
if (bind(sockfd, (struct sockaddr *)&my_addr,
|
|
sizeof(struct sockaddr)) < 0) {
|
|
PILCallLog(LOG, PIL_CRIT, "ucast: error binding socket. Retrying: %s",
|
|
strerror(errno));
|
|
sleep(1);
|
|
}
|
|
else{
|
|
boundyet = 1;
|
|
}
|
|
}
|
|
if (!boundyet) {
|
|
#if !defined(SO_BINDTODEVICE)
|
|
if (errno == EADDRINUSE) {
|
|
/* This happens with multiple udp or ppp interfaces */
|
|
PILCallLog(LOG, PIL_INFO,
|
|
"ucast: someone already listening on port %d [%s]",
|
|
ei->port, ei->interface);
|
|
PILCallLog(LOG, PIL_INFO, "ucast: UDP read process exiting");
|
|
close(sockfd);
|
|
cleanexit(0);
|
|
}
|
|
#else
|
|
PILCallLog(LOG, PIL_CRIT, "ucast: unable to bind socket. Giving up: %s",
|
|
strerror(errno));
|
|
close(sockfd);
|
|
return -1;
|
|
#endif
|
|
}
|
|
if (fcntl(sockfd,F_SETFD, FD_CLOEXEC) < 0) {
|
|
PILCallLog(LOG, PIL_CRIT, "ucast: error setting close-on-exec flag: %s",
|
|
strerror(errno));
|
|
}
|
|
return sockfd;
|
|
}
|
|
|
|
static struct ip_private* new_ip_interface(const char *ifn,
|
|
const char *hbaddr, int port)
|
|
{
|
|
struct ip_private *ep;
|
|
struct hostent *h;
|
|
|
|
/*
|
|
* 21 December 2002
|
|
* Added by Brian TInsley <btinsley@emageon.com>
|
|
*/
|
|
if (!(h = gethostbyname(hbaddr))) {
|
|
PILCallLog(LOG, PIL_CRIT, "ucast: cannot resolve hostname");
|
|
return NULL;
|
|
}
|
|
|
|
if (!(ep = (struct ip_private*) MALLOC(sizeof(struct ip_private)))) {
|
|
PILCallLog(LOG, PIL_CRIT, "ucast: memory allocation error (line %d)",
|
|
(__LINE__ - 2) );
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* use address from gethostbyname
|
|
*/
|
|
memcpy(&ep->heartaddr, h->h_addr_list[0], sizeof(ep->heartaddr));
|
|
|
|
if (!(ep->interface = STRDUP(ifn))) {
|
|
PILCallLog(LOG, PIL_CRIT, "ucast: memory allocation error (line %d)",
|
|
(__LINE__ - 2) );
|
|
FREE(ep);
|
|
return NULL;
|
|
}
|
|
|
|
memset(&ep->addr, 0, sizeof(ep->addr)); /* zero the struct */
|
|
ep->addr.sin_family = AF_INET; /* host byte order */
|
|
ep->addr.sin_port = htons(port); /* short, network byte order */
|
|
ep->port = port;
|
|
ep->wsocket = -1;
|
|
ep->rsocket = -1;
|
|
ep->addr.sin_addr = ep->heartaddr;
|
|
|
|
return ep;
|
|
}
|