]> git.saurik.com Git - apple/mdnsresponder.git/blobdiff - mDNSMacOSX/CFSocketPuma.c
mDNSResponder-58.tar.gz
[apple/mdnsresponder.git] / mDNSMacOSX / CFSocketPuma.c
diff --git a/mDNSMacOSX/CFSocketPuma.c b/mDNSMacOSX/CFSocketPuma.c
new file mode 100644 (file)
index 0000000..e0cf87c
--- /dev/null
@@ -0,0 +1,238 @@
+/*
+ * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ *
+ * This file is not normally used.
+ * It can be conditionally compiled in by defining RUN_ON_PUMA_WITHOUT_IFADDRS
+ * in CFSocket.c. It is included mainly as sample code for people building
+ * for other platforms that (like Puma) lack the getifaddrs() call.
+ * NOTE: YOU CANNOT use this code to build an mDNSResponder daemon for Puma
+ * that works just like the Jaguar one, because Puma lacks other necessary
+ * functionality (like the LibInfo support to receive MIG messages from clients).
+
+    Change History (most recent first):
+
+$Log: CFSocketPuma.c,v $
+Revision 1.4  2003/08/12 19:56:25  cheshire
+Update to APSL 2.0
+
+Revision 1.3  2003/07/02 21:19:51  cheshire
+<rdar://problem/3313413> Update copyright notices, etc., in source code comments
+
+Revision 1.2  2002/09/21 20:44:51  zarzycki
+Added APSL info
+
+Revision 1.1  2002/09/17 01:36:23  cheshire
+Move Puma support to CFSocketPuma.c
+
+ */
+
+#include <sys/ioctl.h>
+#include <sys/sockio.h>
+#define ifaddrs ifa_info
+#ifndef        ifa_broadaddr
+#define        ifa_broadaddr   ifa_dstaddr     /* broadcast address interface */
+#endif
+#include <sys/cdefs.h>
+
+/* Our own header for the programs that need interface configuration info.
+   Include this file, instead of "unp.h". */
+
+#define        IFA_NAME        16                      /* same as IFNAMSIZ in <net/if.h> */
+#define        IFA_HADDR        8                      /* allow for 64-bit EUI-64 in future */
+
+struct ifa_info {
+  char    ifa_name[IFA_NAME];  /* interface name, null terminated */
+  u_char  ifa_haddr[IFA_HADDR];        /* hardware address */
+  u_short ifa_hlen;                            /* #bytes in hardware address: 0, 6, 8 */
+  short   ifa_flags;                   /* IFF_xxx constants from <net/if.h> */
+  short   ifa_myflags;                 /* our own IFI_xxx flags */
+  struct sockaddr  *ifa_addr;  /* primary address */
+  struct sockaddr  *ifa_brdaddr;/* broadcast address */
+  struct sockaddr  *ifa_dstaddr;/* destination address */
+  struct ifa_info  *ifa_next;  /* next of these structures */
+};
+
+#define        IFI_ALIAS       1                       /* ifa_addr is an alias */
+
+                                       /* function prototypes */
+struct ifa_info        *get_ifa_info(int, int);
+struct ifa_info        *Get_ifa_info(int, int);
+void                    free_ifa_info(struct ifa_info *);
+
+#define HAVE_SOCKADDR_SA_LEN   1
+
+struct ifa_info *
+get_ifa_info(int family, int doaliases)
+{
+       struct ifa_info         *ifi, *ifihead, **ifipnext;
+       int                                     sockfd, len, lastlen, flags, myflags;
+       char                            *ptr, *buf, lastname[IFNAMSIZ], *cptr;
+       struct ifconf           ifc;
+       struct ifreq            *ifr, ifrcopy;
+       struct sockaddr_in      *sinptr;
+
+       sockfd = socket(AF_INET, SOCK_DGRAM, 0);
+
+       lastlen = 0;
+       len = 100 * sizeof(struct ifreq);       /* initial buffer size guess */
+       for ( ; ; ) {
+               buf = (char *) malloc(len);
+               ifc.ifc_len = len;
+               ifc.ifc_buf = buf;
+               if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
+                       if (errno != EINVAL || lastlen != 0)
+                               debugf("ioctl error");
+               } else {
+                       if (ifc.ifc_len == lastlen)
+                               break;          /* success, len has not changed */
+                       lastlen = ifc.ifc_len;
+               }
+               len += 10 * sizeof(struct ifreq);       /* increment */
+               free(buf);
+       }
+       ifihead = NULL;
+       ifipnext = &ifihead;
+       lastname[0] = 0;
+/* end get_ifa_info1 */
+
+/* include get_ifa_info2 */
+       for (ptr = buf; ptr < buf + ifc.ifc_len; ) {
+               ifr = (struct ifreq *) ptr;
+
+#ifdef HAVE_SOCKADDR_SA_LEN
+               len = MAX(sizeof(struct sockaddr), ifr->ifr_addr.sa_len);
+#else
+               switch (ifr->ifr_addr.sa_family) {
+#ifdef IPV6
+               case AF_INET6:  
+                       len = sizeof(struct sockaddr_in6);
+                       break;
+#endif
+               case AF_INET:   
+               default:        
+                       len = sizeof(struct sockaddr);
+                       break;
+               }
+#endif /* HAVE_SOCKADDR_SA_LEN */
+               ptr += sizeof(ifr->ifr_name) + len;     /* for next one in buffer */
+
+               if (ifr->ifr_addr.sa_family != family)
+                       continue;       /* ignore if not desired address family */
+
+               myflags = 0;
+               if ( (cptr = strchr(ifr->ifr_name, ':')) != NULL)
+                       *cptr = 0;              /* replace colon will null */
+               if (strncmp(lastname, ifr->ifr_name, IFNAMSIZ) == 0) {
+                       if (doaliases == 0)
+                               continue;       /* already processed this interface */
+                       myflags = IFI_ALIAS;
+               }
+               memcpy(lastname, ifr->ifr_name, IFNAMSIZ);
+
+               ifrcopy = *ifr;
+               ioctl(sockfd, SIOCGIFFLAGS, &ifrcopy);
+               flags = ifrcopy.ifr_flags;
+               if ((flags & IFF_UP) == 0)
+                       continue;       /* ignore if interface not up */
+
+               ifi = (struct ifa_info *) calloc(1, sizeof(struct ifa_info));
+               *ifipnext = ifi;                        /* prev points to this new one */
+               ifipnext = &ifi->ifa_next;      /* pointer to next one goes here */
+
+               ifi->ifa_flags = flags;         /* IFF_xxx values */
+               ifi->ifa_myflags = myflags;     /* IFI_xxx values */
+               memcpy(ifi->ifa_name, ifr->ifr_name, IFA_NAME);
+               ifi->ifa_name[IFA_NAME-1] = '\0';
+/* end get_ifa_info2 */
+/* include get_ifa_info3 */
+               switch (ifr->ifr_addr.sa_family) {
+               case AF_INET:
+                       sinptr = (struct sockaddr_in *) &ifr->ifr_addr;
+                       if (ifi->ifa_addr == NULL) {
+                               ifi->ifa_addr = (struct sockaddr *) calloc(1, sizeof(struct sockaddr_in));
+                               memcpy(ifi->ifa_addr, sinptr, sizeof(struct sockaddr_in));
+
+#ifdef SIOCGIFBRDADDR
+                               if (flags & IFF_BROADCAST) {
+                                       ioctl(sockfd, SIOCGIFBRDADDR, &ifrcopy);
+                                       sinptr = (struct sockaddr_in *) &ifrcopy.ifr_broadaddr;
+                                       ifi->ifa_brdaddr = (struct sockaddr *) calloc(1, sizeof(struct sockaddr_in));
+                                       memcpy(ifi->ifa_brdaddr, sinptr, sizeof(struct sockaddr_in));
+                               }
+#endif
+
+#ifdef SIOCGIFDSTADDR
+                               if (flags & IFF_POINTOPOINT) {
+                                       ioctl(sockfd, SIOCGIFDSTADDR, &ifrcopy);
+                                       sinptr = (struct sockaddr_in *) &ifrcopy.ifr_dstaddr;
+                                       ifi->ifa_dstaddr = (struct sockaddr *) calloc(1, sizeof(struct sockaddr_in));
+                                       memcpy(ifi->ifa_dstaddr, sinptr, sizeof(struct sockaddr_in));
+                               }
+#endif
+                       }
+                       break;
+
+               default:
+                       break;
+               }
+       }
+       free(buf);
+       return(ifihead);        /* pointer to first structure in linked list */
+}
+/* end get_ifa_info3 */
+
+/* include free_ifa_info */
+mDNSlocal void freeifaddrs(struct ifa_info *ifihead)
+{
+       struct ifa_info *ifi, *ifinext;
+
+       for (ifi = ifihead; ifi != NULL; ifi = ifinext) {
+               if (ifi->ifa_addr != NULL)
+                       free(ifi->ifa_addr);
+               if (ifi->ifa_brdaddr != NULL)
+                       free(ifi->ifa_brdaddr);
+               if (ifi->ifa_dstaddr != NULL)
+                       free(ifi->ifa_dstaddr);
+               ifinext = ifi->ifa_next;        /* can't fetch ifa_next after free() */
+               free(ifi);                                      /* the ifa_info{} itself */
+       }
+}
+/* end free_ifa_info */
+
+struct ifa_info *
+Get_ifa_info(int family, int doaliases)
+{
+       struct ifa_info *ifi;
+
+       if ( (ifi = get_ifa_info(family, doaliases)) == NULL)
+               debugf("get_ifa_info error");
+       return(ifi);
+}
+
+mDNSlocal int getifaddrs(struct ifa_info **ifalist)
+       {
+       *ifalist = get_ifa_info(PF_INET, false);
+       if( ifalist == nil )
+               return -1;
+       else
+               return(0);
+       }