/*
 *
 * @APPLE_LICENSE_HEADER_START@
 *
 * Copyright (c) 1999-2001 Apple Computer, Inc.  All Rights Reserved. The
 * contents of this file constitute Original Code as defined in and are
 * subject to the Apple Public Source License Version 1.2 (the 'License').
 * You may not use this file except in compliance with the License.  Please
 * obtain a copy of the License at http://www.apple.com/publicsource and
 * read it before using this file.
 *
 * This 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@
 *
 */
#include "GetLocalIPAddressString.h"


#ifdef __MACOS__
	#include "BogusDefs.h"
#else
	#include <string.h>
	#include <fcntl.h>
	#include <sys/types.h>
	#include <sys/socket.h>
	#include <netinet/in.h>
	#include <arpa/inet.h>
	#include <sys/ioctl.h>
	#include <netinet/in.h>
	#include <net/if.h>
	

#endif

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#if __solaris__
	#include <sys/sockio.h>
	#include <stropts.h>
#endif


short GetLocalIPAddressString(char *returnStr, short maxSize)
{
	short result = 0;
	int err = -1;
		
	char defaultAddress[] = "255.255.255.255";
	char* addr = defaultAddress;
	do 
	{
	
		//Most of this code is similar to the SIOCGIFCONF code presented in Stevens,
		//Unix Network Programming, section 16.6
		
		//Use the SIOCGIFCONF ioctl call to iterate through the network interfaces
		static const unsigned long kMaxAddrBufferSize = 2048;
		
		char* ifReqIter = NULL;
		struct ifconf ifc;
		struct ifreq* ifr;
		char buffer[kMaxAddrBufferSize];
		
		int tempSocket = socket(AF_INET, SOCK_DGRAM, 0);
		if (tempSocket == -1) break;
			
		ifc.ifc_len = kMaxAddrBufferSize;
		ifc.ifc_buf = buffer;
		
#if (__linux__ || __MacOSX__ || __MACOS__ || __linuxppc__ || __solaris__)
	 	err = ioctl(tempSocket, SIOCGIFCONF, (char*)&ifc);
#elif __FreeBSD__
	 	err = ioctl(tempSocket, OSIOCGIFCONF, (char*)&ifc);
#else
		#error
#endif
		if (err == -1) break;
		

#if __FreeBSD__
		{
			int netdev1, netdev2;
			struct ifreq *netdevifr;
			netdevifr = ifc.ifc_req;
			netdev1 = ifc.ifc_len / sizeof(struct ifreq);
			for (netdev2=netdev1-1; netdev2>=0; netdev2--)
				{
				if (ioctl(tempSocket, SIOCGIFADDR, &netdevifr[netdev2]) != 0)
					continue;
				}
		}
#endif

		
		close(tempSocket);
		tempSocket = -1;

//		int numIPAddrs = 0;
		
		for (ifReqIter = buffer; ifReqIter < (buffer + ifc.ifc_len);)
		{
			ifr = (struct ifreq*)ifReqIter;
#if __MacOSX__ 
			ifReqIter += sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len;
			if (ifr->ifr_addr.sa_len == 0)
			{
				switch (ifr->ifr_addr.sa_family)
				{
					case AF_INET:
						ifReqIter += sizeof(struct sockaddr_in);
						break;
					default:
						ifReqIter += sizeof(struct sockaddr);
				}
			}
#else
			ifReqIter += sizeof(ifr->ifr_name) + 0;
			switch (ifr->ifr_addr.sa_family)
			{
				case AF_INET:
					ifReqIter += sizeof(struct sockaddr_in);
					break;
				default:
					ifReqIter += sizeof(struct sockaddr);
			}
#endif
				
			//Only count interfaces in the AF_INET family.
			//And don't count localhost, loopback interfaces
			if ((ifr->ifr_addr.sa_family == AF_INET) && (strncmp(ifr->ifr_name, "lo", 2) != 0))
			{
				struct sockaddr_in* addrPtr = (struct sockaddr_in*)&ifr->ifr_addr;	
				addr = inet_ntoa(addrPtr->sin_addr);
				//printf("found local address: %s\n", addr);
				err = 0;
				break;
			}
		}
	
	} while (0);
		

	result = strlen(addr);
	
	if (maxSize < result)
	{	err = -1;
	}
	else
		strcpy(returnStr, addr);

	return err;
}
