/*
** SellaNMS
** $Id: ip_util.cxx,v 1.4 2005/11/25 04:11:37 sella Exp $
** Copyright (c) 2001-2005 Digital Genesis Software, LLC. All Rights Reserved.
** Released under the GPL Version 2 License.
** http://www.digitalgenesis.com
*/

static const char rcsid[] = "$Id: ip_util.cxx,v 1.4 2005/11/25 04:11:37 sella Exp $";

#include "ip_util.h"
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <stl/string>

#define inaddrr(x) (*(struct in_addr *) &ifr->x[sizeof sa.sin_port])
#define IFRSIZE	((int)(size * sizeof (struct ifreq)))

/* From a newsgroup example by Floyd Davidson (floyd@ptialaska.net) on 2002-07-16 04:50:07 PST */
void source_ip(const char *interface, struct in_addr *ip) {
	int sockfd, size  = 1;
	struct ifreq *ifr;
	struct ifconf ifc;
	struct sockaddr_in sa;

	if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP))) {
		fprintf(stderr, "Cannot open socket.\n");
		exit(EXIT_FAILURE);
	}

	ifc.ifc_len = IFRSIZE;
	ifc.ifc_req = NULL;

	do {
		++size;
		/* realloc buffer size until no overflow occurs  */
		if ((ifc.ifc_req = (ifreq*) realloc(ifc.ifc_req, IFRSIZE)) == NULL) {
			fprintf(stderr, "Out of memory.\n");
			exit(EXIT_FAILURE);
		}
		ifc.ifc_len = IFRSIZE;
		if (ioctl(sockfd, SIOCGIFCONF, &ifc)) {
			perror("ioctl SIOCFIFCONF");
			exit(EXIT_FAILURE);
		}
	} while (IFRSIZE <= ifc.ifc_len);

	ifr = ifc.ifc_req;
	for (;(char *) ifr < (char *) ifc.ifc_req + ifc.ifc_len; ++ifr) {

		if (ifr->ifr_addr.sa_data == (ifr + 1)->ifr_addr.sa_data) {
			continue;  /* duplicate, skip it */
		}

		if (ioctl(sockfd, SIOCGIFFLAGS, ifr)) {
			continue;  /* failed to get flags, skip it */
		}

		if (strncmp(ifr->ifr_name, "lo", 2) && (strlen(interface) < 1 || !strcmp(ifr->ifr_name, interface))) {
			*ip = inaddrr(ifr_addr.sa_data);
			break;
		}
	}

	/* Free memory. */
	free(ifc.ifc_req);

	close(sockfd);
}

/*
** Local Variables:
** c-basic-offset: 3
** tab-width: 3
** End:
** vim600: fdm=marker
** vim: noet ts=3 sw=3
*/
