223 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			223 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * This file is distributed as part of the MariaDB Corporation MaxScale. It is free
 | 
						|
 * software: you can redistribute it and/or modify it under the terms of the
 | 
						|
 * GNU General Public License as published by the Free Software Foundation,
 | 
						|
 * version 2.
 | 
						|
 * 
 | 
						|
 * This program is distributed in the hope that it will be useful, but WITHOUT
 | 
						|
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 | 
						|
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 | 
						|
 * details.
 | 
						|
 * 
 | 
						|
 * You should have received a copy of the GNU General Public License along with
 | 
						|
 * this program; if not, write to the Free Software Foundation, Inc., 51
 | 
						|
 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 | 
						|
 * 
 | 
						|
 * Copyright MariaDB Corporation Ab 2013-2014
 | 
						|
 * 
 | 
						|
 */
 | 
						|
 | 
						|
/**
 | 
						|
 * @file gw_utils.c - A set if utility functions useful within the context
 | 
						|
 * of the gateway.
 | 
						|
 *
 | 
						|
 * @verbatim
 | 
						|
 * Revision History
 | 
						|
 *
 | 
						|
 * Date		Who			Description
 | 
						|
 * 03-06-2013	Massimiliano Pinto	gateway utils
 | 
						|
 * 12-06-2013	Massimiliano Pinto	gw_read_gwbuff
 | 
						|
 *					with error detection
 | 
						|
 *					and its handling
 | 
						|
 * 01-07-2013	Massimiliano Pinto	Removed session->backends
 | 
						|
 *					from gw_read_gwbuff()
 | 
						|
 * 25-09-2013	Massimiliano Pinto	setipaddress uses getaddrinfo
 | 
						|
 * 06-02-2014	Mark Riddoch		Added parse_bindconfig
 | 
						|
 * 10-02-2014	Massimiliano Pinto	Added return code to setipaddress
 | 
						|
 * 02-09-2014   Martin Brampton         Replace C++ comment with C comment
 | 
						|
 *
 | 
						|
 *@endverbatim
 | 
						|
 */
 | 
						|
 | 
						|
#include <gw.h>
 | 
						|
#include <dcb.h>
 | 
						|
#include <session.h>
 | 
						|
 | 
						|
#include <skygw_utils.h>
 | 
						|
#include <log_manager.h>
 | 
						|
 | 
						|
SPINLOCK tmplock = SPINLOCK_INIT;
 | 
						|
 | 
						|
extern int lm_enabled_logfiles_bitmask;
 | 
						|
 | 
						|
/*
 | 
						|
 * Set IP address in socket structure in_addr
 | 
						|
 *
 | 
						|
 * @param a	Pointer to a struct in_addr into which the address is written
 | 
						|
 * @param p	The hostname to lookup
 | 
						|
 * @return	1 on success, 0 on failure
 | 
						|
 */
 | 
						|
int
 | 
						|
setipaddress(struct in_addr *a, char *p) {
 | 
						|
#ifdef __USE_POSIX
 | 
						|
	struct addrinfo *ai = NULL, hint;
 | 
						|
	int    rc;
 | 
						|
	struct sockaddr_in * res_addr;
 | 
						|
	memset(&hint, 0, sizeof (hint));
 | 
						|
 | 
						|
	hint.ai_socktype = SOCK_STREAM;
 | 
						|
 | 
						|
	/*
 | 
						|
	* This is for the listening socket, matching INADDR_ANY only for now.
 | 
						|
	* For future specific addresses bind, a dedicated routine woulbd be better
 | 
						|
	*/
 | 
						|
 | 
						|
	if (strcmp(p, "0.0.0.0") == 0) {
 | 
						|
		hint.ai_flags = AI_PASSIVE;
 | 
						|
		hint.ai_family = AF_UNSPEC;
 | 
						|
		if ((rc = getaddrinfo(p, NULL, &hint, &ai)) != 0) {
 | 
						|
			LOGIF(LE, (skygw_log_write_flush(
 | 
						|
				LOGFILE_ERROR,
 | 
						|
					"Error : getaddrinfo failed for [%s] due [%s]",
 | 
						|
					p,
 | 
						|
					gai_strerror(rc))));
 | 
						|
 | 
						|
			return 0;
 | 
						|
		}
 | 
						|
	} else {
 | 
						|
		hint.ai_flags = AI_CANONNAME;
 | 
						|
		hint.ai_family = AF_INET;
 | 
						|
 | 
						|
		if ((rc = getaddrinfo(p, NULL, &hint, &ai)) != 0) {
 | 
						|
			LOGIF(LE, (skygw_log_write_flush(
 | 
						|
				LOGFILE_ERROR,
 | 
						|
					"Error : getaddrinfo failed for [%s] due [%s]",
 | 
						|
					p,
 | 
						|
					gai_strerror(rc))));
 | 
						|
 | 
						|
			return 0;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
        /* take the first one */
 | 
						|
	if (ai != NULL) {
 | 
						|
		res_addr = (struct sockaddr_in *)(ai->ai_addr);
 | 
						|
		memcpy(a, &res_addr->sin_addr, sizeof(struct in_addr));
 | 
						|
 | 
						|
		freeaddrinfo(ai);
 | 
						|
 | 
						|
		return 1;
 | 
						|
	}
 | 
						|
#else
 | 
						|
	struct hostent *h;
 | 
						|
 | 
						|
        spinlock_acquire(&tmplock);
 | 
						|
        h = gethostbyname(p);
 | 
						|
        spinlock_release(&tmplock);
 | 
						|
        
 | 
						|
	if (h == NULL) {
 | 
						|
		if ((a->s_addr = inet_addr(p)) == -1) {
 | 
						|
			LOGIF(LE, (skygw_log_write_flush(
 | 
						|
				LOGFILE_ERROR,
 | 
						|
					"Error : gethostbyname failed for [%s]",
 | 
						|
					p)));
 | 
						|
 | 
						|
			return 0;
 | 
						|
		}
 | 
						|
	} else {
 | 
						|
        	/* take the first one */
 | 
						|
		memcpy(a, h->h_addr, h->h_length);
 | 
						|
 | 
						|
		return 1;
 | 
						|
	}
 | 
						|
#endif
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Daemonize the process by forking and putting the process into the
 | 
						|
 * background.
 | 
						|
 */
 | 
						|
void gw_daemonize(void) {
 | 
						|
	pid_t pid;
 | 
						|
 | 
						|
	pid = fork();
 | 
						|
 | 
						|
	if (pid < 0) {
 | 
						|
		fprintf(stderr, "fork() error %s\n", strerror(errno));
 | 
						|
		exit(1);
 | 
						|
	}
 | 
						|
 | 
						|
	if (pid != 0) {
 | 
						|
		/* exit from main */
 | 
						|
		exit(0);
 | 
						|
	}
 | 
						|
 | 
						|
	if (setsid() < 0) {
 | 
						|
		fprintf(stderr, "setsid() error %s\n", strerror(errno));
 | 
						|
		exit(1);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Parse the bind config data. This is passed in a string as address:port.
 | 
						|
 *
 | 
						|
 * The address may be either a . seperated IP address or a hostname to
 | 
						|
 * lookup. The address 0.0.0.0 is the wildcard address for SOCKADR_ANY.
 | 
						|
 * The ':' and port may be omitted, in which case the default port is
 | 
						|
 * used.
 | 
						|
 *
 | 
						|
 * @param config	The bind address and port seperated by a ':'
 | 
						|
 * @param def_port	The default port to use
 | 
						|
 * @param addr		The sockaddr_in in which the data is written
 | 
						|
 * @return		0 on failure
 | 
						|
 */
 | 
						|
int
 | 
						|
parse_bindconfig(char *config, unsigned short def_port, struct sockaddr_in *addr)
 | 
						|
{
 | 
						|
char			*port, buf[1024];
 | 
						|
short			pnum;
 | 
						|
struct hostent		*hp;
 | 
						|
 | 
						|
 | 
						|
	strncpy(buf, config, 1024);
 | 
						|
	port = strrchr(buf, ':');
 | 
						|
	if (port)
 | 
						|
	{
 | 
						|
		*port = 0;
 | 
						|
		port++;
 | 
						|
		pnum = atoi(port);
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		pnum = def_port;
 | 
						|
	}
 | 
						|
 | 
						|
	if (!strcmp(buf, "0.0.0.0"))
 | 
						|
	{
 | 
						|
		addr->sin_addr.s_addr = htonl(INADDR_ANY);
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		if (!inet_aton(buf, &addr->sin_addr))
 | 
						|
		{
 | 
						|
			if ((hp = gethostbyname(buf)) != NULL)
 | 
						|
			{
 | 
						|
				bcopy(hp->h_addr, &(addr->sin_addr.s_addr), hp->h_length);
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
                		LOGIF(LE, (skygw_log_write_flush(
 | 
						|
		                        LOGFILE_ERROR,
 | 
						|
                       			 "Error : Failed to lookup host '%s'. ",
 | 
						|
		                        buf)));
 | 
						|
				return 0;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	addr->sin_family = AF_INET;
 | 
						|
	addr->sin_port = htons(pnum);
 | 
						|
	return 1;
 | 
						|
}
 |