Home | History | Annotate | Download | only in cups
      1 /*
      2  * Network interface functions for CUPS.
      3  *
      4  * Copyright 2007-2010 by Apple Inc.
      5  * Copyright 1997-2006 by Easy Software Products, all rights reserved.
      6  *
      7  * These coded instructions, statements, and computer programs are the
      8  * property of Apple Inc. and are protected by Federal copyright
      9  * law.  Distribution and use rights are outlined in the file "LICENSE.txt"
     10  * "LICENSE" which should have been included with this file.  If this
     11  * file is missing or damaged, see the license at "http://www.cups.org/".
     12  */
     13 
     14 /*
     15  * Include necessary headers.
     16  */
     17 
     18 #include "http-private.h"
     19 
     20 
     21 #ifndef HAVE_GETIFADDRS
     22 /*
     23  * '_cups_getifaddrs()' - Get a list of network interfaces on the system.
     24  */
     25 
     26 int					/* O - 0 on success, -1 on error */
     27 _cups_getifaddrs(struct ifaddrs **addrs)/* O - List of interfaces */
     28 {
     29   int			sock;		/* Socket */
     30   char			buffer[65536],	/* Buffer for address info */
     31 			*bufptr,	/* Pointer into buffer */
     32 			*bufend;	/* End of buffer */
     33   struct ifconf		conf;		/* Interface configurations */
     34   struct sockaddr	addr;		/* Address data */
     35   struct ifreq		*ifp;		/* Interface data */
     36   int			ifpsize;	/* Size of interface data */
     37   struct ifaddrs	*temp;		/* Pointer to current interface */
     38   struct ifreq		request;	/* Interface request */
     39 
     40 
     41  /*
     42   * Start with an empty list...
     43   */
     44 
     45   if (addrs == NULL)
     46     return (-1);
     47 
     48   *addrs = NULL;
     49 
     50  /*
     51   * Create a UDP socket to get the interface data...
     52   */
     53 
     54   memset (&addr, 0, sizeof(addr));
     55   if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
     56     return (-1);
     57 
     58  /*
     59   * Try to get the list of interfaces...
     60   */
     61 
     62   conf.ifc_len = sizeof(buffer);
     63   conf.ifc_buf = buffer;
     64 
     65   if (ioctl(sock, SIOCGIFCONF, &conf) < 0)
     66   {
     67    /*
     68     * Couldn't get the list of interfaces...
     69     */
     70 
     71     close(sock);
     72     return (-1);
     73   }
     74 
     75  /*
     76   * OK, got the list of interfaces, now lets step through the
     77   * buffer to pull them out...
     78   */
     79 
     80 #  ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
     81 #    define sockaddr_len(a)	((a)->sa_len)
     82 #  else
     83 #    define sockaddr_len(a)	(sizeof(struct sockaddr))
     84 #  endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
     85 
     86   for (bufptr = buffer, bufend = buffer + conf.ifc_len;
     87        bufptr < bufend;
     88        bufptr += ifpsize)
     89   {
     90    /*
     91     * Get the current interface information...
     92     */
     93 
     94     ifp     = (struct ifreq *)bufptr;
     95     ifpsize = sizeof(ifp->ifr_name) + sockaddr_len(&(ifp->ifr_addr));
     96 
     97     if (ifpsize < sizeof(struct ifreq))
     98       ifpsize = sizeof(struct ifreq);
     99 
    100     memset(&request, 0, sizeof(request));
    101     memcpy(request.ifr_name, ifp->ifr_name, sizeof(ifp->ifr_name));
    102 
    103    /*
    104     * Check the status of the interface...
    105     */
    106 
    107     if (ioctl(sock, SIOCGIFFLAGS, &request) < 0)
    108       continue;
    109 
    110    /*
    111     * Allocate memory for a single interface record...
    112     */
    113 
    114     if ((temp = calloc(1, sizeof(struct ifaddrs))) == NULL)
    115     {
    116      /*
    117       * Unable to allocate memory...
    118       */
    119 
    120       close(sock);
    121       return (-1);
    122     }
    123 
    124    /*
    125     * Add this record to the front of the list and copy the name, flags,
    126     * and network address...
    127     */
    128 
    129     temp->ifa_next  = *addrs;
    130     *addrs          = temp;
    131     temp->ifa_name  = strdup(ifp->ifr_name);
    132     temp->ifa_flags = request.ifr_flags;
    133     if ((temp->ifa_addr = calloc(1, sockaddr_len(&(ifp->ifr_addr)))) != NULL)
    134       memcpy(temp->ifa_addr, &(ifp->ifr_addr), sockaddr_len(&(ifp->ifr_addr)));
    135 
    136    /*
    137     * Try to get the netmask for the interface...
    138     */
    139 
    140     if (!ioctl(sock, SIOCGIFNETMASK, &request))
    141     {
    142      /*
    143       * Got it, make a copy...
    144       */
    145 
    146       if ((temp->ifa_netmask = calloc(1, sizeof(request.ifr_netmask))) != NULL)
    147 	memcpy(temp->ifa_netmask, &(request.ifr_netmask),
    148 	       sizeof(request.ifr_netmask));
    149     }
    150 
    151    /*
    152     * Then get the broadcast or point-to-point (destination) address,
    153     * if applicable...
    154     */
    155 
    156     if (temp->ifa_flags & IFF_BROADCAST)
    157     {
    158      /*
    159       * Have a broadcast address, so get it!
    160       */
    161 
    162       if (!ioctl(sock, SIOCGIFBRDADDR, &request))
    163       {
    164        /*
    165 	* Got it, make a copy...
    166 	*/
    167 
    168 	if ((temp->ifa_broadaddr =
    169 	         calloc(1, sizeof(request.ifr_broadaddr))) != NULL)
    170 	  memcpy(temp->ifa_broadaddr, &(request.ifr_broadaddr),
    171 		 sizeof(request.ifr_broadaddr));
    172       }
    173     }
    174     else if (temp->ifa_flags & IFF_POINTOPOINT)
    175     {
    176      /*
    177       * Point-to-point interface; grab the remote address...
    178       */
    179 
    180       if (!ioctl(sock, SIOCGIFDSTADDR, &request))
    181       {
    182 	temp->ifa_dstaddr = malloc(sizeof(request.ifr_dstaddr));
    183 	memcpy(temp->ifa_dstaddr, &(request.ifr_dstaddr),
    184 	       sizeof(request.ifr_dstaddr));
    185       }
    186     }
    187   }
    188 
    189  /*
    190   * OK, we're done with the socket, close it and return 0...
    191   */
    192 
    193   close(sock);
    194 
    195   return (0);
    196 }
    197 
    198 
    199 /*
    200  * '_cups_freeifaddrs()' - Free an interface list...
    201  */
    202 
    203 void
    204 _cups_freeifaddrs(struct ifaddrs *addrs)/* I - Interface list to free */
    205 {
    206   struct ifaddrs	*next;		/* Next interface in list */
    207 
    208 
    209   while (addrs != NULL)
    210   {
    211    /*
    212     * Make a copy of the next interface pointer...
    213     */
    214 
    215     next = addrs->ifa_next;
    216 
    217    /*
    218     * Free data values as needed...
    219     */
    220 
    221     if (addrs->ifa_name)
    222     {
    223       free(addrs->ifa_name);
    224       addrs->ifa_name = NULL;
    225     }
    226 
    227     if (addrs->ifa_addr)
    228     {
    229       free(addrs->ifa_addr);
    230       addrs->ifa_addr = NULL;
    231     }
    232 
    233     if (addrs->ifa_netmask)
    234     {
    235       free(addrs->ifa_netmask);
    236       addrs->ifa_netmask = NULL;
    237     }
    238 
    239     if (addrs->ifa_dstaddr)
    240     {
    241       free(addrs->ifa_dstaddr);
    242       addrs->ifa_dstaddr = NULL;
    243     }
    244 
    245    /*
    246     * Free this node and continue to the next...
    247     */
    248 
    249     free(addrs);
    250 
    251     addrs = next;
    252   }
    253 }
    254 #endif /* !HAVE_GETIFADDRS */
    255