/* $Id: mcast.c,v 1.15.2.4 2005/01/12 02:25:47 horms Exp $ */ /* * mcast.c: implements hearbeat API for UDP multicast communication * * Copyright (C) 2000 Alan Robertson * Copyright (C) 2000 Chris Wright * * Thanks to WireX for providing hardware to test on. * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_SYS_SOCKIO_H # include #endif #include #define PIL_PLUGINTYPE HB_COMM_TYPE #define PIL_PLUGINTYPE_S HB_COMM_TYPE_S #define PIL_PLUGIN mcast #define PIL_PLUGIN_S "mcast" #define PIL_PLUGINLICENSE LICENSE_LGPL #define PIL_PLUGINLICENSEURL URL_LGPL #include #include struct mcast_private { char * interface; /* Interface name */ struct in_addr mcast; /* multicast address */ struct sockaddr_in addr; /* multicast addr */ u_short port; int rsocket; /* Read-socket */ int wsocket; /* Write-socket */ u_char ttl; /* TTL value for outbound packets */ u_char loop; /* boolean, loop back outbound packets */ }; static int mcast_parse(const char* configline); static struct hb_media * mcast_new(const char * intf, const char *mcast , u_short port, u_char ttl, u_char loop); static int mcast_open(struct hb_media* mp); static int mcast_close(struct hb_media* mp); static void* mcast_read(struct hb_media* mp, int* lenp); static int mcast_write(struct hb_media* mp, void* p, int len); static int mcast_descr(char** buffer); static int mcast_mtype(char** buffer); static int mcast_isping(void); /* * mcastclose is called as part of unloading the mcast HBcomm plugin. * If there was any global data allocated, or file descriptors opened, etc. * which is associated with the plugin, and not a single interface * in particular, here's our chance to clean it up. */ static void mcastclosepi(PILPlugin*pi) { } /* * mcastcloseintf called as part of shutting down the mcast HBcomm interface. * If there was any global data allocated, or file descriptors opened, etc. * which is associated with the mcast implementation, here's our chance * to clean it up. */ static PIL_rc mcastcloseintf(PILInterface* pi, void* pd) { return PIL_OK; } static struct hb_media_fns mcastOps ={ NULL, /* Create single object function */ mcast_parse, /* whole-line parse function */ mcast_open, mcast_close, mcast_read, mcast_write, mcast_mtype, mcast_descr, mcast_isping, }; PIL_PLUGIN_BOILERPLATE("1.0", Debug, mcastclosepi); static const PILPluginImports* PluginImports; static PILPlugin* OurPlugin; static PILInterface* OurInterface; static struct hb_media_imports* OurImports; static void* interfprivate; #define LOG PluginImports->log #define MALLOC PluginImports->alloc #define STRDUP PluginImports->mstrdup #define FREE PluginImports->mfree PIL_rc PIL_PLUGIN_INIT(PILPlugin*us, const PILPluginImports* imports); 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 , &mcastOps , mcastcloseintf /*close */ , &OurInterface , (void*)&OurImports , interfprivate); } /* helper functions */ static int mcast_make_receive_sock(struct hb_media* hbm); static int mcast_make_send_sock(struct hb_media * hbm); static struct mcast_private * new_mcast_private(const char *ifn, const char *mcast, u_short port, u_char ttl, u_char loop); static int set_mcast_if(int sockfd, char *ifname); static int set_mcast_loop(int sockfd, u_char loop); static int set_mcast_ttl(int sockfd, u_char ttl); static int join_mcast_group(int sockfd, struct in_addr *addr, char *ifname); static int if_getaddr(const char *ifname, struct in_addr *addr); static int is_valid_dev(const char *dev); static int is_valid_mcast_addr(const char *addr); static int get_port(const char *port, u_short *p); static int get_ttl(const char *ttl, u_char *t); static int get_loop(const char *loop, u_char *l); #define ISMCASTOBJECT(mp) ((mp) && ((mp)->vf == (void*)&mcastOps)) #define MCASTASSERT(mp) g_assert(ISMCASTOBJECT(mp)) static int mcast_mtype(char** buffer) { *buffer = STRDUP(PIL_PLUGIN_S); if (!*buffer) { return 0; } return STRLEN(*buffer); } static int mcast_descr(char **buffer) { *buffer = STRDUP("UDP/IP multicast"); if (!*buffer) { return 0; } return STRLEN(*buffer); } static int mcast_isping(void) { /* nope, this is not a ping device */ return 0; } /* mcast_parse will parse the line in the config file that is * associated with the media's type (hb_dev_mtype). It should * receive the rest of the line after the mtype. And it needs * to call hb_dev_new, add the media to the list of available media. * * So in this case, the config file line should look like * mcast [device] [mcast group] [port] [mcast ttl] [mcast loop] * for example: * mcast eth0 225.0.0.1 694 1 0 */ static int mcast_parse(const char *line) { const char * bp = line; char dev[MAXLINE]; char mcast[MAXLINE]; char token[MAXLINE]; u_short port; u_char ttl; u_char loop; int toklen; struct hb_media * mp; /* 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) { if (!is_valid_dev(dev)) { PILCallLog(LOG, PIL_CRIT, "mcast bad device [%s]", dev); return HA_FAIL; } /* Skip over white space, then grab the multicast group */ bp += strspn(bp, WHITESPACE); toklen = strcspn(bp, WHITESPACE); strncpy(mcast, bp, toklen); bp += toklen; mcast[toklen] = EOS; if (*mcast == EOS) { PILCallLog(LOG, PIL_CRIT, "mcast [%s] missing mcast address", dev); return(HA_FAIL); } if (!is_valid_mcast_addr(mcast)) { PILCallLog(LOG, PIL_CRIT, "mcast [%s] bad addr [%s]", dev, mcast); return(HA_FAIL); } /* Skip over white space, then grab the port */ bp += strspn(bp, WHITESPACE); toklen = strcspn(bp, WHITESPACE); strncpy(token, bp, toklen); bp += toklen; token[toklen] = EOS; if (*token == EOS) { PILCallLog(LOG, PIL_CRIT, "mcast [%s] missing port", dev); return(HA_FAIL); } if (get_port(token, &port) == -1) { PILCallLog(LOG, PIL_CRIT, " mcast [%s] bad port [%d]", dev, port); return HA_FAIL; } /* Skip over white space, then grab the ttl */ bp += strspn(bp, WHITESPACE); toklen = strcspn(bp, WHITESPACE); strncpy(token, bp, toklen); bp += toklen; token[toklen] = EOS; if (*token == EOS) { PILCallLog(LOG, PIL_CRIT, "mcast [%s] missing ttl", dev); return(HA_FAIL); } if (get_ttl(token, &ttl) == -1) { PILCallLog(LOG, PIL_CRIT, " mcast [%s] bad ttl [%d]", dev, ttl); return HA_FAIL; } /* Skip over white space, then grab the loop */ bp += strspn(bp, WHITESPACE); toklen = strcspn(bp, WHITESPACE); strncpy(token, bp, toklen); bp += toklen; token[toklen] = EOS; if (*token == EOS) { PILCallLog(LOG, PIL_CRIT, "mcast [%s] missing loop", dev); return(HA_FAIL); } if (get_loop(token, &loop) == -1) { PILCallLog(LOG, PIL_CRIT, " mcast [%s] bad loop [%d]", dev, loop); return HA_FAIL; } if ((mp = mcast_new(dev, mcast, port, ttl, loop)) == NULL) { return(HA_FAIL); } OurImports->RegisterNewMedium(mp); } return(HA_OK); } /* * Create new UDP/IP multicast heartbeat object * pass in name of interface, multicast address, port, multicast * ttl, and multicast loopback value as parameters. * This should get called from hb_dev_parse(). */ static struct hb_media * mcast_new(const char * intf, const char *mcast, u_short port, u_char ttl, u_char loop) { struct mcast_private* mcp; struct hb_media * ret; /* create new mcast_private struct...hmmm...who frees it? */ mcp = new_mcast_private(intf, mcast, port, ttl, loop); if (mcp == NULL) { PILCallLog(LOG, PIL_WARN, "Error creating mcast_private(%s, %s, %d, %d, %d)", intf, mcast, port, ttl, loop); return(NULL); } ret = (struct hb_media*) MALLOC(sizeof(struct hb_media)); if (ret != NULL) { char * name; ret->pd = (void*)mcp; name = STRDUP(intf); if (name != NULL) { ret->name = name; } else { FREE(ret); ret = NULL; } } if(ret == NULL) { FREE(mcp->interface); FREE(mcp); } return(ret); } /* * Open UDP/IP multicast heartbeat interface */ static int mcast_open(struct hb_media* hbm) { struct mcast_private * mcp; MCASTASSERT(hbm); mcp = (struct mcast_private *) hbm->pd; if ((mcp->wsocket = mcast_make_send_sock(hbm)) < 0) { return(HA_FAIL); } if ((mcp->rsocket = mcast_make_receive_sock(hbm)) < 0) { mcast_close(hbm); return(HA_FAIL); } PILCallLog(LOG, PIL_INFO, "UDP multicast heartbeat started for group %s " "port %d interface %s (ttl=%d loop=%d)" , inet_ntoa(mcp->mcast), mcp->port, mcp->interface, mcp->ttl, mcp->loop); return(HA_OK); } /* * Close UDP/IP multicast heartbeat interface */ static int mcast_close(struct hb_media* hbm) { struct mcast_private * mcp; int rc = HA_OK; MCASTASSERT(hbm); mcp = (struct mcast_private *) hbm->pd; if (mcp->rsocket >= 0) { if (close(mcp->rsocket) < 0) { rc = HA_FAIL; } } if (mcp->wsocket >= 0) { if (close(mcp->wsocket) < 0) { rc = HA_FAIL; } } return(rc); } /* * Receive a heartbeat multicast packet from UDP interface */ static void * mcast_read(struct hb_media* hbm, int *lenp) { struct mcast_private * mcp; char buf[MAXLINE]; socklen_t addr_len = sizeof(struct sockaddr); struct sockaddr_in their_addr; /* connector's addr information */ int numbytes; void *pkt; MCASTASSERT(hbm); mcp = (struct mcast_private *) hbm->pd; if ((numbytes=recvfrom(mcp->rsocket, buf, MAXLINE-1, 0 ,(struct sockaddr *)&their_addr, &addr_len)) < 0) { if (errno != EINTR) { PILCallLog(LOG, PIL_CRIT, "Error receiving from socket: %s" , strerror(errno)); } return NULL; } /* Avoid possible buffer overruns */ buf[numbytes] = EOS; if (Debug >= PKTTRACE) { PILCallLog(LOG, PIL_DEBUG, "got %d byte packet from %s" , numbytes, inet_ntoa(their_addr.sin_addr)); } if (Debug >= PKTCONTTRACE && numbytes > 0) { PILCallLog(LOG, PIL_DEBUG, "%s", buf); } pkt = ha_malloc(numbytes + 1); if(!pkt){ PILCallLog(LOG, PIL_CRIT , "Error in allocating memory"); return(NULL); } memcpy(pkt, buf, numbytes + 1); *lenp = numbytes + 1 ; return(pkt); } /* * Send a heartbeat packet over multicast UDP/IP interface */ static int mcast_write(struct hb_media* hbm, void *pkt, int len) { struct mcast_private * mcp; int rc; MCASTASSERT(hbm); mcp = (struct mcast_private *) hbm->pd; if ((rc=sendto(mcp->wsocket, pkt, len, 0 , (struct sockaddr *)&mcp->addr , sizeof(struct sockaddr))) != len) { PILCallLog(LOG, PIL_CRIT, "Unable to send mcast packet [%d]: %s" , rc, strerror(errno)); return(HA_FAIL); } if (Debug >= PKTTRACE) { PILCallLog(LOG, PIL_DEBUG, "sent %d bytes to %s" , rc, inet_ntoa(mcp->addr.sin_addr)); } if (Debug >= PKTCONTTRACE) { PILCallLog(LOG, PIL_DEBUG, "%s", (const char *)pkt); } return(HA_OK); return(HA_OK); } /* * Set up socket for sending multicast UDP heartbeats */ static int mcast_make_send_sock(struct hb_media * hbm) { int sockfd; struct mcast_private * mcp; MCASTASSERT(hbm); mcp = (struct mcast_private *) hbm->pd; if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { PILCallLog(LOG, PIL_WARN, "Error getting socket: %s", strerror(errno)); return(sockfd); } if (set_mcast_if(sockfd, mcp->interface) < 0) { PILCallLog(LOG, PIL_WARN, "Error setting outbound mcast interface: %s", strerror(errno)); } if (set_mcast_loop(sockfd, mcp->loop) < 0) { PILCallLog(LOG, PIL_WARN, "Error setting outbound mcast loopback value: %s", strerror(errno)); } if (set_mcast_ttl(sockfd, mcp->ttl) < 0) { PILCallLog(LOG, PIL_WARN, "Error setting outbound mcast TTL: %s", strerror(errno)); } if (fcntl(sockfd,F_SETFD, FD_CLOEXEC)) { PILCallLog(LOG, PIL_WARN, "Error setting the close-on-exec flag: %s", strerror(errno)); } return(sockfd); } /* * Set up socket for listening to heartbeats (UDP multicasts) */ #define MAXBINDTRIES 10 static int mcast_make_receive_sock(struct hb_media * hbm) { struct mcast_private * mcp; int sockfd; int bindtries; int boundyet=0; int one=1; int rc; int binderr=0; MCASTASSERT(hbm); mcp = (struct mcast_private *) hbm->pd; if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { PILCallLog(LOG, PIL_CRIT, "Error getting socket"); return -1; } /* set REUSEADDR option on socket so you can bind a multicast */ /* reader to multiple interfaces */ if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(one)) < 0){ PILCallLog(LOG, PIL_CRIT, "Error setsockopt(SO_REUSEADDR)"); } /* ripped off from udp.c, if we all use SO_REUSEADDR */ /* this shouldn't be necessary */ /* 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) { rc=bind(sockfd, (struct sockaddr *)&mcp->addr, sizeof(mcp->addr)); binderr=errno; if (rc==0) { boundyet=1; } else if (rc == -1) { if (binderr == EADDRINUSE) { PILCallLog(LOG, PIL_CRIT, "Can't bind (EADDRINUSE), " "retrying"); sleep(1); } else { /* don't keep trying if the error isn't caused by */ /* the address being in use already...real error */ break; } } } if (!boundyet) { if (binderr == EADDRINUSE) { /* This happens with multiple udp or ppp interfaces */ PILCallLog(LOG, PIL_INFO , "Someone already listening on port %d [%s]" , mcp->port , mcp->interface); PILCallLog(LOG, PIL_INFO, "multicast read process exiting"); close(sockfd); cleanexit(0); } else { PILCallLog(LOG, PIL_WARN, "Unable to bind socket. Giving up: %s", strerror(errno)); close(sockfd); return(-1); } } /* join the multicast group...this is what really makes this a */ /* multicast reader */ if (join_mcast_group(sockfd, &mcp->mcast, mcp->interface) == -1) { PILCallLog(LOG, PIL_CRIT, "Can't join multicast group %s on interface %s", inet_ntoa(mcp->mcast), mcp->interface); PILCallLog(LOG, PIL_INFO, "multicast read process exiting"); close(sockfd); cleanexit(0); } if (ANYDEBUG) PILCallLog(LOG, PIL_DEBUG, "Successfully joined multicast group %s on" "interface %s", inet_ntoa(mcp->mcast), mcp->interface); if (fcntl(sockfd,F_SETFD, FD_CLOEXEC)) { PILCallLog(LOG, PIL_WARN, "Error setting the close-on-exec flag: %s", strerror(errno)); } return(sockfd); } static struct mcast_private * new_mcast_private(const char *ifn, const char *mcast, u_short port, u_char ttl, u_char loop) { struct mcast_private *mcp; mcp = MALLOCT(struct mcast_private); if (mcp == NULL) { return NULL; } mcp->interface = (char *)STRDUP(ifn); if(mcp->interface == NULL) { FREE(mcp); return NULL; } /* Set up multicast address */ if (inet_pton(AF_INET, mcast, (void *)&mcp->mcast) <= 0) { FREE(mcp->interface); FREE(mcp); return NULL; } memset(&mcp->addr, 0, sizeof(mcp->addr)); /* zero the struct */ mcp->addr.sin_family = AF_INET; /* host byte order */ mcp->addr.sin_port = htons(port); /* short, network byte order */ mcp->addr.sin_addr = mcp->mcast; mcp->port = port; mcp->wsocket = -1; mcp->rsocket = -1; mcp->ttl=ttl; mcp->loop=loop; return(mcp); } /* set_mcast_loop takes a boolean flag, loop, which is useful on * a writing socket. with loop enabled (the default on a multicast socket) * the outbound packet will get looped back and received by the sending * interface, if it is listening for the multicast group and port that the * packet was sent to. Returns 0 on success -1 on failure. */ static int set_mcast_loop(int sockfd, u_char loop) { return setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)); } /* set_mcast_ttl will set the time-to-live value for the writing socket. * the socket default is TTL=1. The TTL is used to limit the scope of the * packet and can range from 0-255. * TTL Scope * ---------------------------------------------------------------------- * 0 Restricted to the same host. Won't be output by any interface. * 1 Restricted to the same subnet. Won't be forwarded by a router. * <32 Restricted to the same site, organization or department. * <64 Restricted to the same region. * <128 Restricted to the same continent. * <255 Unrestricted in scope. Global. * * Returns 0 on success -1 on failure. */ static int set_mcast_ttl(int sockfd, u_char ttl) { return setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)); } /* * set_mcast_if takes the name of an interface (i.e. eth0) and then * sets that as the interface to use for outbound multicast traffic. * If ifname is NULL, then it the OS will assign the interface. * Returns 0 on success -1 on faliure. */ static int set_mcast_if(int sockfd, char *ifname) { int rc; struct in_addr addr; /* Zero out the struct... we only care about the address... */ memset(&addr, 0, sizeof(addr)); rc = if_getaddr(ifname, &addr); if (rc == -1) return -1; return setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_IF , (void*)&addr, sizeof(addr)); } /* join_mcast_group is used to join a multicast group. the group is * specified by a class D multicast address 224.0.0.0/8 in the in_addr * structure passed in as a parameter. The interface name can be used * to "bind" the multicast group to a specific interface (or any * interface if ifname is NULL); * returns 0 on success, -1 on failure. */ static int join_mcast_group(int sockfd, struct in_addr *addr, char *ifname) { struct ip_mreq mreq_add; memset(&mreq_add, 0, sizeof(mreq_add)); memcpy(&mreq_add.imr_multiaddr, addr, sizeof(struct in_addr)); if (ifname) { if_getaddr(ifname, &mreq_add.imr_interface); } return setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void*)&mreq_add, sizeof(mreq_add)); } /* if_getaddr gets the ip address from an interface * specified by name and places it in addr. * returns 0 on success and -1 on failure. */ static int if_getaddr(const char *ifname, struct in_addr *addr) { int fd; struct ifreq if_info; if (!addr) return -1; addr->s_addr = INADDR_ANY; memset(&if_info, 0, sizeof(if_info)); if (ifname) { strncpy(if_info.ifr_name, ifname, IFNAMSIZ-1); } else { /* ifname is NULL, so use any address */ return 0; } if ((fd=socket(AF_INET, SOCK_DGRAM, 0)) == -1) { PILCallLog(LOG, PIL_CRIT, "Error getting socket"); return -1; } if (Debug > 0) { PILCallLog(LOG, PIL_DEBUG, "looking up address for %s" , if_info.ifr_name); } if (ioctl(fd, SIOCGIFADDR, &if_info) == -1) { PILCallLog(LOG, PIL_CRIT, "Error ioctl(SIOCGIFADDR)"); close(fd); return -1; } /* * This #define w/void cast is to quiet alignment errors on some * platforms (notably Solaris) */ #define SOCKADDR_IN(a) ((struct sockaddr_in *)((void*)(a))) memcpy(addr, &(SOCKADDR_IN(&if_info.ifr_addr)->sin_addr) , sizeof(struct in_addr)); close(fd); return 0; } /* returns true or false */ static int is_valid_dev(const char *dev) { int rc=0; if (dev) { struct in_addr addr; if (if_getaddr(dev, &addr) != -1) rc = 1; } return rc; } /* returns true or false */ #define MCAST_NET 0xf0000000 #define MCAST_BASE 0xe0000000 static int is_valid_mcast_addr(const char *addr) { unsigned long mc_addr; /* make sure address is in host byte order */ mc_addr = ntohl(inet_addr(addr)); if ((mc_addr & MCAST_NET) == MCAST_BASE) return 1; return 0; } /* return port number on success, 0 on failure */ static int get_port(const char *port, u_short *p) { /* not complete yet */ *p=(u_short)atoi(port); return 0; } /* returns ttl on succes, -1 on failure */ static int get_ttl(const char *ttl, u_char *t) { /* not complete yet */ *t=(u_char)atoi(ttl); return 0; } /* returns loop on success, -1 on failure */ static int get_loop(const char *loop, u_char *l) { /* not complete yet */ *l=(u_char)atoi(loop); return 0; } /* * $Log: mcast.c,v $ * Revision 1.15.2.4 2005/01/12 02:25:47 horms * Fix gcc-4.0 compile problems (Andreas Jochens) * * Revision 1.15.2.3 2004/05/12 00:10:14 alan * Changed all the HBcomm plugins to use PILCallLog() for logging * instead of calling the function pointer directly. * Also, in the process fixed several mismatches between arguments * and format strings, and a couple of format string vulnerabilities. * * Revision 1.19 2004/05/11 22:04:35 alan * Changed all the HBcomm plugins to use PILCallLog() for logging instead of calling * the function pointer directly. * Also, in the process fixed several mismatches between arguments and format strings, and * a couple of format string vulnerabilities. * * Revision 1.18 2004/04/28 22:30:29 alan * Put in some fixes for extra freeing of memory in the communications plugins. * * Revision 1.17 2004/03/03 05:31:50 alan * Put in Gochun Shi's new netstrings on-the-wire data format code. * this allows sending binary data, among many other things! * * Revision 1.16 2004/02/17 22:11:59 lars * Pet peeve removal: _Id et al now gone, replaced with consistent Id header. * * Revision 1.15 2004/01/21 11:34:15 horms * - Replaced numerous malloc + strcpy/strncpy invocations with strdup * * This usually makes the code a bit cleaner * * Also is easier not to make code with potential buffer over-runs * - Added STRDUP to pils modules * - Removed some spurious MALLOC and FREE redefinitions * _that could never be used_ * - Make sure the return value of strdup is honoured in error conditions * * Revision 1.14 2003/02/07 08:37:17 horms * Removed inclusion of portability.h from .h files * so that it does not need to be installed. * * Revision 1.13 2003/02/05 09:06:34 horms * Lars put a lot of work into making sure that portability.h * is included first, everywhere. However this broke a few * things when building against heartbeat headers that * have been installed (usually somewhere under /usr/include or * /usr/local/include). * * This patch should resolve this problem without undoing all of * Lars's hard work. * * As an asside: I think that portability.h is a virus that has * infected all of heartbeat's code and now must also infect all * code that builds against heartbeat. I wish that it didn't need * to be included all over the place. Especially in headers to * be installed on the system. However, I respect Lars's opinion * that this is the best way to resolve some weird build problems * in the current tree. * * Revision 1.12 2003/01/31 10:02:09 lars * Various small code cleanups: * - Lots of "signed vs unsigned" comparison fixes * - time_t globally replaced with TIME_T * - All seqnos moved to "seqno_t", which defaults to unsigned long * - DIMOF() definition centralized to portability.h and typecast to int * - EOS define moved to portability.h * - dropped inclusion of signal.h from stonith.h, so that sigignore is * properly defined * * Revision 1.11 2002/10/21 10:17:19 horms * hb api clients may now be built outside of the heartbeat tree * * Revision 1.10 2002/09/19 22:40:18 alan * Changed a few error return checks to not print anything and return * if an error was encountered. * Changed a few debug messages to only print if a strictly positive number * of chars was received. * * Revision 1.9 2002/09/12 03:52:07 alan * Fixed up a comment :-(. * * Revision 1.8 2002/09/12 03:39:45 alan * Fixed some logging level names in the code and also * fixed an error in the license chosen for a file. * * Revision 1.7 2002/06/16 06:11:26 alan * Put in a couple of changes to the PILS interfaces * - exported license information (name, URL) * - imported malloc/free * * Revision 1.6 2002/05/01 23:50:35 alan * Put in some comments about how the code avoids potential buffer overruns. * * Revision 1.5 2002/04/13 22:35:08 alan * Changed ha_msg_add_nv to take an end pointer to make it safer. * Added a length parameter to string2msg so it would be safer. * Changed the various networking plugins to use the new string2msg(). * * Revision 1.4 2002/04/09 12:45:36 alan * Put in changes to the bcast, mcast and serial code such that * interrupted system calls in reads are ignored. * * Revision 1.3 2002/01/17 15:21:23 alan * Put in Ram Pai's patch for the bug in the multicast code. * * Revision 1.2 2001/09/07 16:18:17 alan * Updated ping.c to conform to the new plugin loading system. * Changed log messages in bcast, mcast, ping and serial to use the * new logging function. * * Revision 1.1 2001/08/10 17:16:44 alan * New code for the new plugin loading system. * * Revision 1.11 2001/06/23 04:30:26 alan * Changed the code to use inet_pton() when it's available, and * emulate it when it's not... Patch was from Chris Wright. * * Revision 1.10 2001/06/08 04:57:48 alan * Changed "config.h" to * */