Patch to remove segfault on the exiting of a service.
[openais.git] / exec / totemip.c
blob0f6b9d9de5506e4cde002a1c43b4a4e810c4b4f8
1 /*
2 * Copyright (c) 2005 Red Hat Inc
3 * Copyright (c) 2006 Sun Microsystems, Inc.
5 * All rights reserved.
7 * Author: Patrick Caulfield (pcaulfie@redhat.com)
9 * This software licensed under BSD license, the text of which follows:
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions are met:
14 * - Redistributions of source code must retain the above copyright notice,
15 * this list of conditions and the following disclaimer.
16 * - Redistributions in binary form must reproduce the above copyright notice,
17 * this list of conditions and the following disclaimer in the documentation
18 * and/or other materials provided with the distribution.
19 * - Neither the name of the MontaVista Software, Inc. nor the names of its
20 * contributors may be used to endorse or promote products derived from this
21 * software without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
27 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
33 * THE POSSIBILITY OF SUCH DAMAGE.
36 /* IPv4/6 abstraction */
38 #include <sys/ioctl.h>
39 #include <sys/types.h>
40 #include <sys/socket.h>
41 #include <arpa/inet.h>
42 #include <netinet/in.h>
43 #include <arpa/inet.h>
44 #include <netdb.h>
45 #if defined(OPENAIS_BSD) || defined(OPENAIS_DARWIN) || defined(OPENAIS_SOLARIS)
46 #include <sys/sockio.h>
47 #include <net/if.h>
48 #ifndef OPENAIS_SOLARIS
49 #include <net/if_var.h>
50 #endif
51 #include <netinet/in_var.h>
52 #endif
53 #include <string.h>
54 #include <stdio.h>
55 #include <errno.h>
56 #include <assert.h>
57 #include <stdlib.h>
58 #include <unistd.h>
60 #if defined(OPENAIS_LINUX)
61 #include <net/if.h>
63 /* ARGH!! I hate netlink */
64 #include <asm/types.h>
65 #include <linux/rtnetlink.h>
67 /* this should catch 2.6.19 headers */
68 #ifndef IFA_MAX
69 #include <linux/if_addr.h>
70 #endif
71 /* redefine macro that disappeared in 2.6.19 */
72 #ifndef IFA_RTA
73 #define IFA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrmsg))))
74 #endif
76 #endif
78 #if ! defined(OPENAIS_SOLARIS) && ! defined(s6_addr16)
79 #define s6_addr16 __u6_addr.__u6_addr16
80 #endif
82 #include "swab.h"
83 #include "totemip.h"
85 #define LOCALHOST_IPV4 "127.0.0.1"
86 #define LOCALHOST_IPV6 "::1"
88 #define NETLINK_BUFSIZE 16384
90 #ifdef SO_NOSIGPIPE
91 void totemip_nosigpipe(int s)
93 int on = 1;
94 setsockopt(s, SOL_SOCKET, SO_NOSIGPIPE, (void *)&on, sizeof(on));
96 #endif
98 /* Compare two addresses */
99 int totemip_equal(struct totem_ip_address *addr1, struct totem_ip_address *addr2)
101 int addrlen = 0;
103 if (addr1->family != addr2->family)
104 return 0;
106 if (addr1->family == AF_INET) {
107 addrlen = sizeof(struct in_addr);
109 if (addr1->family == AF_INET6) {
110 addrlen = sizeof(struct in6_addr);
112 assert(addrlen);
114 if (memcmp(addr1->addr, addr2->addr, addrlen) == 0)
115 return 1;
116 else
117 return 0;
121 /* Copy a totem_ip_address */
122 void totemip_copy(struct totem_ip_address *addr1, struct totem_ip_address *addr2)
124 memcpy(addr1, addr2, sizeof(struct totem_ip_address));
127 void totemip_copy_endian_convert(struct totem_ip_address *addr1, struct totem_ip_address *addr2)
129 addr1->nodeid = swab32(addr2->nodeid);
130 addr1->family = swab16(addr2->family);
131 if (addr1 != addr2) {
132 memcpy(addr1->addr, addr2->addr, TOTEMIP_ADDRLEN);
136 /* For sorting etc. params are void * for qsort's benefit */
137 int totemip_compare(const void *a, const void *b)
139 int i;
140 struct totem_ip_address *totemip_a = (struct totem_ip_address *)a;
141 struct totem_ip_address *totemip_b = (struct totem_ip_address *)b;
142 struct in_addr ipv4_a1;
143 struct in_addr ipv4_a2;
144 struct in6_addr ipv6_a1;
145 struct in6_addr ipv6_a2;
146 unsigned short family;
149 * Use memcpy to align since totem_ip_address is unaligned on various archs
151 memcpy (&family, &totemip_a->family, sizeof (unsigned short));
153 if (family == AF_INET) {
154 memcpy (&ipv4_a1, totemip_a->addr, sizeof (struct in_addr));
155 memcpy (&ipv4_a2, totemip_b->addr, sizeof (struct in_addr));
156 if (ipv4_a1.s_addr == ipv4_a2.s_addr) {
157 return (0);
159 if (htonl(ipv4_a1.s_addr) < htonl(ipv4_a2.s_addr)) {
160 return -1;
161 } else {
162 return +1;
164 } else
165 if (family == AF_INET6) {
167 * Compare 16 bits at a time the ipv6 address
169 memcpy (&ipv6_a1, totemip_a->addr, sizeof (struct in6_addr));
170 memcpy (&ipv6_a2, totemip_b->addr, sizeof (struct in6_addr));
171 for (i = 0; i < 8; i++) {
172 #ifndef OPENAIS_SOLARIS
173 int res = htons(ipv6_a1.s6_addr16[i]) -
174 htons(ipv6_a2.s6_addr16[i]);
175 #else
176 int res = htons(((uint16_t *)ipv6_a1.s6_addr)[i]) -
177 htons(((uint16_t *)ipv6_a2.s6_addr)[i]);
178 #endif
179 if (res) {
180 return res;
183 return 0;
184 } else {
186 * Family not set, should be!
188 assert (0);
189 exit (1);
193 /* Build a localhost totem_ip_address */
194 int totemip_localhost(int family, struct totem_ip_address *localhost)
196 char *addr_text;
197 uint32_t nodeid;
199 memset (localhost, 0, sizeof (struct totem_ip_address));
201 if (family == AF_INET) {
202 addr_text = LOCALHOST_IPV4;
203 if (inet_pton(family, addr_text, (char *)&nodeid) <= 0) {
204 return -1;
206 localhost->nodeid = ntohl(nodeid);
207 } else {
208 addr_text = LOCALHOST_IPV6;
211 if (inet_pton(family, addr_text, (char *)localhost->addr) <= 0)
212 return -1;
214 localhost->family = family;
216 return 0;
219 int totemip_localhost_check(struct totem_ip_address *addr)
221 struct totem_ip_address localhost;
223 if (totemip_localhost(addr->family, &localhost))
224 return 0;
225 return totemip_equal(addr, &localhost);
228 const char *totemip_print(struct totem_ip_address *addr)
230 static char buf[INET6_ADDRSTRLEN];
232 return inet_ntop(addr->family, addr->addr, buf, sizeof(buf));
235 /* Make a totem_ip_address into a usable sockaddr_storage */
236 int totemip_totemip_to_sockaddr_convert(struct totem_ip_address *ip_addr,
237 uint16_t port, struct sockaddr_storage *saddr, int *addrlen)
239 int ret = -1;
241 if (ip_addr->family == AF_INET) {
242 struct sockaddr_in *sin = (struct sockaddr_in *)saddr;
244 memset(sin, 0, sizeof(struct sockaddr_in));
245 #if defined(OPENAIS_BSD) || defined(OPENAIS_DARWIN)
246 sin->sin_len = sizeof(struct sockaddr_in);
247 #endif
248 sin->sin_family = ip_addr->family;
249 sin->sin_port = htons (port);
250 memcpy(&sin->sin_addr, ip_addr->addr, sizeof(struct in_addr));
251 *addrlen = sizeof(struct sockaddr_in);
252 ret = 0;
255 if (ip_addr->family == AF_INET6) {
256 struct sockaddr_in6 *sin = (struct sockaddr_in6 *)saddr;
258 memset(sin, 0, sizeof(struct sockaddr_in6));
259 #if defined(OPENAIS_BSD) || defined(OPENAIS_DARWIN)
260 sin->sin6_len = sizeof(struct sockaddr_in6);
261 #endif
262 sin->sin6_family = ip_addr->family;
263 sin->sin6_port = htons (port);
264 sin->sin6_scope_id = 2;
265 memcpy(&sin->sin6_addr, ip_addr->addr, sizeof(struct in6_addr));
267 *addrlen = sizeof(struct sockaddr_in6);
268 ret = 0;
271 return ret;
274 /* Converts an address string string into a totem_ip_address.
275 * family can be AF_INET, AF_INET6 or 0 (for "don't care")
277 int totemip_parse(struct totem_ip_address *totemip, char *addr, int family)
279 struct addrinfo *ainfo;
280 struct addrinfo ahints;
281 struct sockaddr_in *sa;
282 struct sockaddr_in6 *sa6;
283 int ret;
285 memset(&ahints, 0, sizeof(ahints));
286 ahints.ai_socktype = SOCK_DGRAM;
287 ahints.ai_protocol = IPPROTO_UDP;
288 ahints.ai_family = family;
290 /* Lookup the nodename address */
291 ret = getaddrinfo(addr, NULL, &ahints, &ainfo);
292 if (ret)
293 return -1;
295 sa = (struct sockaddr_in *)ainfo->ai_addr;
296 sa6 = (struct sockaddr_in6 *)ainfo->ai_addr;
297 totemip->family = ainfo->ai_family;
299 if (ainfo->ai_family == AF_INET)
300 memcpy(totemip->addr, &sa->sin_addr, sizeof(struct in_addr));
301 else
302 memcpy(totemip->addr, &sa6->sin6_addr, sizeof(struct in6_addr));
304 freeaddrinfo(ainfo);
306 return 0;
309 /* Make a sockaddr_* into a totem_ip_address */
310 int totemip_sockaddr_to_totemip_convert(struct sockaddr_storage *saddr, struct totem_ip_address *ip_addr)
312 int ret = -1;
314 ip_addr->family = saddr->ss_family;
315 ip_addr->nodeid = 0;
317 if (saddr->ss_family == AF_INET) {
318 struct sockaddr_in *sin = (struct sockaddr_in *)saddr;
320 memcpy(ip_addr->addr, &sin->sin_addr, sizeof(struct in_addr));
321 ret = 0;
324 if (saddr->ss_family == AF_INET6) {
325 struct sockaddr_in6 *sin = (struct sockaddr_in6 *)saddr;
327 memcpy(ip_addr->addr, &sin->sin6_addr, sizeof(struct in6_addr));
329 ret = 0;
331 return ret;
334 #if defined(OPENAIS_BSD) || defined(OPENAIS_DARWIN) || defined(OPENAIS_SOLARIS)
335 int totemip_iface_check(struct totem_ip_address *bindnet,
336 struct totem_ip_address *boundto,
337 int *interface_up,
338 int *interface_num)
340 #ifndef OPENAIS_SOLARIS
341 #define NEXT_IFR(a) ((struct ifreq *)((u_char *)&(a)->ifr_addr +\
342 ((a)->ifr_addr.sa_len ? (a)->ifr_addr.sa_len : sizeof((a)->ifr_addr))))
343 #else
344 #define NEXT_IFR(a) ((struct ifreq *)((u_char *)&(a)->ifr_addr +\
345 sizeof((a)->ifr_addr)))
346 #endif
348 struct sockaddr_in *intf_addr_mask;
349 struct sockaddr_storage bindnet_ss, intf_addr_ss;
350 struct sockaddr_in *intf_addr_sin = (struct sockaddr_in *)&intf_addr_ss;
351 struct sockaddr_in *bindnet_sin = (struct sockaddr_in *)&bindnet_ss;
352 struct ifreq *ifr, *lifr;
353 int id_fd;
354 struct ifconf ifc;
355 struct ifreq ifrb;
356 int numreqs = 0;
357 int res;
358 int addrlen;
360 *interface_up = 0;
361 *interface_num = 0;
363 totemip_totemip_to_sockaddr_convert(bindnet,
364 0, &bindnet_ss, &addrlen);
367 * Generate list of local interfaces in ifc.ifc_req structure
369 id_fd = socket (AF_INET, SOCK_DGRAM, 0);
370 ifc.ifc_buf = NULL;
371 do {
372 void *ifc_buf_tmp;
373 numreqs += 32;
374 ifc.ifc_len = sizeof (struct ifreq) * numreqs;
375 ifc_buf_tmp = realloc (ifc.ifc_buf, ifc.ifc_len);
376 if (ifc_buf_tmp == NULL) {
377 close (id_fd);
378 if (ifc.ifc_buf != NULL) {
379 free (ifc.ifc_buf);
381 return -1;
383 ifc.ifc_buf = ifc_buf_tmp;
384 res = ioctl (id_fd, SIOCGIFCONF, &ifc);
385 if (res < 0) {
386 close (id_fd);
387 free (ifc.ifc_buf);
388 return -1;
390 } while (ifc.ifc_len == sizeof (struct ifreq) * numreqs);
391 res = -1;
394 * Find interface address to bind to
396 lifr = (struct ifreq *)ifc.ifc_buf + (ifc.ifc_len / sizeof(*lifr));
398 for (ifr = ifc.ifc_req; ifr < lifr; ifr = NEXT_IFR(ifr)) {
399 strcpy(ifrb.ifr_name, ifr->ifr_name);
401 /* Skip if no address set
403 if (ioctl(id_fd, SIOCGIFADDR, &ifrb) < 0)
404 continue;
406 memcpy(&intf_addr_ss, &ifrb.ifr_addr, sizeof(intf_addr_ss));
407 if (intf_addr_sin->sin_family == AF_INET) {
408 /* Retrieve mask
410 if (ioctl(id_fd, SIOCGIFNETMASK, &ifrb) < 0) {
411 break;
413 intf_addr_mask = (struct sockaddr_in *)&ifrb.ifr_addr;
415 if ( bindnet_sin->sin_family == AF_INET &&
416 (intf_addr_sin->sin_addr.s_addr & intf_addr_mask->sin_addr.s_addr) ==
417 (bindnet_sin->sin_addr.s_addr & intf_addr_mask->sin_addr.s_addr)) {
419 totemip_copy(boundto, bindnet);
420 memcpy(boundto->addr, &intf_addr_sin->sin_addr, sizeof(intf_addr_sin->sin_addr));
422 /* Get inteface state
424 if (ioctl(id_fd, SIOCGIFFLAGS, &ifrb) < 0) {
425 break;
427 *interface_up = ifrb.ifr_flags & IFF_UP;
429 /* Get interface index
431 #ifdef SIOCGIFINDEX
432 if (ioctl(id_fd, SIOCGIFINDEX, &ifrb) < 0) {
433 break;
435 *interface_num = ifrb.ifr_index;
436 #else
437 *interface_num = if_nametoindex(ifrb.ifr_name);
438 #endif
439 res = 0;
440 break; /* for */
444 if (ifc.ifc_buf != NULL) {
445 free (ifc.ifc_buf);
447 close (id_fd);
449 return (res);
451 #elif defined(OPENAIS_LINUX)
453 static void parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
455 while (RTA_OK(rta, len)) {
456 if (rta->rta_type <= max)
457 tb[rta->rta_type] = rta;
458 rta = RTA_NEXT(rta,len);
462 int totemip_iface_check(struct totem_ip_address *bindnet,
463 struct totem_ip_address *boundto,
464 int *interface_up,
465 int *interface_num)
467 int fd;
468 struct {
469 struct nlmsghdr nlh;
470 struct rtgenmsg g;
471 } req;
472 struct sockaddr_nl nladdr;
473 struct totem_ip_address ipaddr;
474 static char rcvbuf[NETLINK_BUFSIZE];
476 *interface_up = 0;
477 *interface_num = 0;
478 memset(&ipaddr, 0, sizeof(ipaddr));
480 /* Make sure we preserve these */
481 ipaddr.family = bindnet->family;
482 ipaddr.nodeid = bindnet->nodeid;
484 /* Ask netlink for a list of interface addresses */
485 fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
486 if (fd <0)
487 return -1;
489 setsockopt(fd,SOL_SOCKET,SO_RCVBUF,&rcvbuf,sizeof(rcvbuf));
491 memset(&nladdr, 0, sizeof(nladdr));
492 nladdr.nl_family = AF_NETLINK;
494 req.nlh.nlmsg_len = sizeof(req);
495 req.nlh.nlmsg_type = RTM_GETADDR;
496 req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
497 req.nlh.nlmsg_pid = 0;
498 req.nlh.nlmsg_seq = 1;
499 req.g.rtgen_family = bindnet->family;
501 if (sendto(fd, (void *)&req, sizeof(req), 0,
502 (struct sockaddr*)&nladdr, sizeof(nladdr)) < 0) {
503 close(fd);
504 return -1;
507 /* Look through the return buffer for our address */
508 while (1)
510 int status;
511 struct nlmsghdr *h;
512 struct iovec iov = { rcvbuf, sizeof(rcvbuf) };
513 struct msghdr msg = {
514 (void*)&nladdr, sizeof(nladdr),
515 &iov, 1,
516 NULL, 0,
520 status = recvmsg(fd, &msg, 0);
521 if (!status) {
522 close(fd);
523 return -1;
526 h = (struct nlmsghdr *)rcvbuf;
527 if (h->nlmsg_type == NLMSG_DONE)
528 break;
530 if (h->nlmsg_type == NLMSG_ERROR) {
531 close(fd);
532 return -1;
535 while (NLMSG_OK(h, status)) {
536 if (h->nlmsg_type == RTM_NEWADDR) {
537 struct ifaddrmsg *ifa = NLMSG_DATA(h);
538 struct rtattr *tb[IFA_MAX+1];
539 int len = h->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa));
540 int found_if = 0;
542 memset(tb, 0, sizeof(tb));
544 parse_rtattr(tb, IFA_MAX, IFA_RTA(ifa), len);
546 memcpy(ipaddr.addr, RTA_DATA(tb[IFA_ADDRESS]), TOTEMIP_ADDRLEN);
547 if (totemip_equal(&ipaddr, bindnet))
548 found_if = 1;
550 /* If the address we have is an IPv4 network address, then
551 substitute the actual IP address of this interface */
552 if (!found_if && tb[IFA_BROADCAST] && ifa->ifa_family == AF_INET) {
553 uint32_t network;
554 uint32_t addr;
555 uint32_t netmask = htonl(~((1<<(32-ifa->ifa_prefixlen))-1));
557 memcpy(&network, RTA_DATA(tb[IFA_BROADCAST]), sizeof(uint32_t));
558 memcpy(&addr, bindnet->addr, sizeof(uint32_t));
560 if (addr == (network & netmask)) {
561 memcpy(ipaddr.addr, RTA_DATA(tb[IFA_ADDRESS]), TOTEMIP_ADDRLEN);
562 found_if = 1;
566 if (found_if) {
568 /* Found it - check I/F is UP */
569 struct ifreq ifr;
570 int ioctl_fd; /* Can't do ioctls on netlink FDs */
572 ioctl_fd = socket(AF_INET, SOCK_STREAM, 0);
573 if (ioctl_fd < 0) {
574 close(fd);
575 return -1;
577 memset(&ifr, 0, sizeof(ifr));
578 ifr.ifr_ifindex = ifa->ifa_index;
580 /* SIOCGIFFLAGS needs an interface name */
581 status = ioctl(ioctl_fd, SIOCGIFNAME, &ifr);
582 status = ioctl(ioctl_fd, SIOCGIFFLAGS, &ifr);
583 if (status) {
584 close(ioctl_fd);
585 close(fd);
586 return -1;
589 if (ifr.ifr_flags & IFF_UP)
590 *interface_up = 1;
592 *interface_num = ifa->ifa_index;
593 close(ioctl_fd);
594 goto finished;
598 h = NLMSG_NEXT(h, status);
601 finished:
602 totemip_copy (boundto, &ipaddr);
603 close(fd);
604 return 0;
606 #endif /* OPENAIS_LINUX */