Beispiel #1
0
/**
 * gw_do_connect_to_backend
 *
 * This routine creates socket and connects to a backend server.
 * Connect it non-blocking operation. If connect fails, socket is closed.
 *
 * @param host The host to connect to
 * @param port The host TCP/IP port 
 * @param *fd where connected fd is copied
 * @return 0/1 on success and -1 on failure
 * If succesful, fd has file descriptor to socket which is connected to
 * backend server. In failure, fd == -1 and socket is closed.
 *
 */
int gw_do_connect_to_backend(
        char          *host,
        int           port,
        int*          fd)
{
	struct sockaddr_in serv_addr;
	int rv;
	int so = 0;
        
	memset(&serv_addr, 0, sizeof serv_addr);
	serv_addr.sin_family = AF_INET;
	so = socket(AF_INET,SOCK_STREAM,0);
        
	if (so < 0) {
                int eno = errno;
                errno = 0;
                LOGIF(LE, (skygw_log_write_flush(
                        LOGFILE_ERROR,
                        "Error: Establishing connection to backend server "
                        "%s:%d failed. Socket creation failed due "
                        "%d, %s.",
                        host,
                        port,
                        eno,
                        strerror(eno))));
                rv = -1;
                goto return_rv;
	}
	/* prepare for connect */
	setipaddress(&serv_addr.sin_addr, host);
	serv_addr.sin_port = htons(port);
	/* set socket to as non-blocking here */
	setnonblocking(so);
        rv = connect(so, (struct sockaddr *)&serv_addr, sizeof(serv_addr));

        if (rv != 0) {
                int eno = errno;
                errno = 0;
                
                if (eno == EINPROGRESS) {
                        rv = 1;
                } else {
                        int rc;
                        int oldfd = so;
                        
                        LOGIF(LE, (skygw_log_write_flush(
                                LOGFILE_ERROR,
                                "Error:  Failed to connect backend server %s:%d, "
                                "due %d, %s.",
                                host,
                                port,
                                eno,
                                strerror(eno))));
                        /*< Close newly created socket. */
                        rc = close(so);

                        if (rc != 0) {
                                int eno = errno;
                                errno = 0;
                                LOGIF(LE, (skygw_log_write_flush(
                                        LOGFILE_ERROR,
                                        "Error: Failed to "
                                        "close socket %d due %d, %s.",
                                        oldfd,
                                        eno,
                                        strerror(eno))));
                        }
                        goto return_rv;
                }
	}
        *fd = so;
        LOGIF(LD, (skygw_log_write_flush(
                LOGFILE_DEBUG,
                "%lu [gw_do_connect_to_backend] Connected to backend server "
                "%s:%d, fd %d.",
                pthread_self(),
                host,
                port,
                so)));
#if defined(SS_DEBUG)
        conn_open[so] = true;
#endif
return_rv:
	return rv;
}
Beispiel #2
0
/**
 * Monitor an individual server
 *
 * @param database	The database to probe
 */
static void
monitorDatabase(MONITOR_SERVERS	*database, char *defaultUser, char *defaultPasswd, MYSQL_MONITOR *handle)
{
MYSQL_ROW	row;
MYSQL_RES	*result;
int		num_fields;
int		isjoined = 0;
char            *uname = defaultUser, *passwd = defaultPasswd;
unsigned long int	server_version = 0;
char 			*server_string;

	if (database->server->monuser != NULL)
	{
		uname = database->server->monuser;
		passwd = database->server->monpw;
	}
	if (uname == NULL)
		return;

	/* Don't even probe server flagged as in maintenance */
	if (SERVER_IN_MAINT(database->server))
		return;

	if (database->con == NULL || mysql_ping(database->con) != 0)
	{
		char *dpwd = decryptPassword(passwd);
		int rc;
                int connect_timeout = handle->connect_timeout;
                int read_timeout = handle->read_timeout;
                int write_timeout = handle->write_timeout;

                database->con = mysql_init(NULL);

                rc = mysql_options(database->con, MYSQL_OPT_CONNECT_TIMEOUT, (void *)&connect_timeout);
                rc = mysql_options(database->con, MYSQL_OPT_READ_TIMEOUT, (void *)&read_timeout);
                rc = mysql_options(database->con, MYSQL_OPT_WRITE_TIMEOUT, (void *)&write_timeout);

		if (mysql_real_connect(database->con, database->server->name,
			uname, dpwd, NULL, database->server->port, NULL, 0) == NULL)
		{
			LOGIF(LE, (skygw_log_write_flush(
				LOGFILE_ERROR,
				"Error : Monitor was unable to connect to "
				"server %s:%d : \"%s\"",
				database->server->name,
				database->server->port,
				mysql_error(database->con))));
			server_clear_status(database->server, SERVER_RUNNING);
			if (mysql_errno(database->con) == ER_ACCESS_DENIED_ERROR)
			{
				server_set_status(database->server, SERVER_AUTH_ERROR);
			}
			database->server->node_id = -1;
			free(dpwd);
			return;
		}
		else
		{
			server_clear_status(database->server, SERVER_AUTH_ERROR);
		}
		free(dpwd);
	}

	/* If we get this far then we have a working connection */
	server_set_status(database->server, SERVER_RUNNING);

	/* get server version from current server */
	server_version = mysql_get_server_version(database->con);

	/* get server version string */
	server_string = (char *)mysql_get_server_info(database->con);
	if (server_string) {
		database->server->server_string = realloc(database->server->server_string, strlen(server_string)+1);
		if (database->server->server_string)
			strcpy(database->server->server_string, server_string);
	}	

	/* Check if the the SQL node is able to contact one or more data nodes */
	if (mysql_query(database->con, "SHOW STATUS LIKE 'Ndb_number_of_ready_data_nodes'") == 0
		&& (result = mysql_store_result(database->con)) != NULL)
	{
		num_fields = mysql_num_fields(result);
		while ((row = mysql_fetch_row(result)))
		{
			if (atoi(row[1]) > 0)
				isjoined = 1;
		}
		mysql_free_result(result);
	}

	/* Check the the SQL node id in the MySQL cluster */
	if (mysql_query(database->con, "SHOW STATUS LIKE 'Ndb_cluster_node_id'") == 0
		&& (result = mysql_store_result(database->con)) != NULL)
	{
		long cluster_node_id = -1;
		num_fields = mysql_num_fields(result);
		while ((row = mysql_fetch_row(result)))
		{
			cluster_node_id = strtol(row[1], NULL, 10);
			if ((errno == ERANGE && (cluster_node_id == LONG_MAX
				|| cluster_node_id == LONG_MIN)) || (errno != 0 && cluster_node_id == 0))
			{
				cluster_node_id = -1;
			}
			database->server->node_id = cluster_node_id;
		}
		mysql_free_result(result);
	}

	if (isjoined) {
		server_set_status(database->server, SERVER_NDB);
		database->server->depth = 0;
	} else {
		server_clear_status(database->server, SERVER_NDB);
		database->server->depth = -1;
	}
}
Beispiel #3
0
/**
 * The routeQuery entry point. This is passed the query buffer
 * to which the filter should be applied. Once processed the
 * query is passed to the downstream component
 * (filter or router) in the filter chain.
 *
 * The function checks whether required logging trigger conditions are met and if so, 
 * tries to extract a SQL query out of the query buffer, canonize the query, add 
 * a timestamp to it and publish the resulting string on the exchange.
 * The message is tagged with an unique identifier and the clientReply will
 * use the same identifier for the reply from the backend to form a query-reply pair.
 * 
 * @param instance	The filter instance data
 * @param session	The filter session
 * @param queue		The query data
 */
static	int	
routeQuery(FILTER *instance, void *session, GWBUF *queue)
{
  MQ_SESSION	*my_session = (MQ_SESSION *)session;
  MQ_INSTANCE	*my_instance = (MQ_INSTANCE *)instance;
  char		*ptr, t_buf[128], *combined,*canon_q,*sesshost,*sessusr;
  bool		success = false, src_ok = false,schema_ok = false,obj_ok = false;
  int		length, i, j,dbcount = 0;
  char**	sesstbls;
  unsigned int	plen = 0;
  amqp_basic_properties_t *prop;  

  /**The user is changing databases*/
  if(*((char*)(queue->start + 4)) == 0x02){
    if(my_session->db){
      free(my_session->db);
    }
    plen = pktlen(queue->start);
    my_session->db = calloc(plen,sizeof(char));
    memcpy(my_session->db,queue->start + 5,plen - 1);
  }

  if(modutil_is_SQL(queue)){

    /**Parse the query*/
   
    if (!query_is_parsed(queue)){
      success = parse_query(queue);
    }

    if(!success){
      skygw_log_write(LOGFILE_ERROR,"Error: Parsing query failed.");      
      goto send_downstream;
    }

    if(!my_instance->log_all){
      if(!skygw_is_real_query(queue)){
	goto send_downstream;
      }
    } 

    if(my_instance->trgtype == TRG_ALL){
      skygw_log_write_flush(LOGFILE_TRACE,"Trigger is TRG_ALL");
      schema_ok = true;
      src_ok = true;
      obj_ok = true;
      goto validate_triggers;
    }
    
    if(my_instance->trgtype & TRG_SOURCE && my_instance->src_trg){
      
      if(session_isvalid(my_session->session)){
	
        sessusr = session_getUser(my_session->session);
	sesshost = session_get_remote(my_session->session);
	
	/**Username was configured*/
	if(my_instance->src_trg->usize > 0){
	  for(i = 0;i<my_instance->src_trg->usize;i++){

	    if(strcmp(my_instance->src_trg->user[i],sessusr) == 0)
	      {
		skygw_log_write_flush(LOGFILE_TRACE,"Trigger is TRG_SOURCE: user: %s = %s",my_instance->src_trg->user[i],sessusr);
		src_ok = true;
		break;
	      }
	    
	  }

	  
	}

	/**If username was not matched, try to match hostname*/

	if(!src_ok && my_instance->src_trg->hsize > 0){

	  for(i = 0;i<my_instance->src_trg->hsize;i++){
	    
	    if(strcmp(my_instance->src_trg->host[i],sesshost) == 0)
	      {
		skygw_log_write_flush(LOGFILE_TRACE,"Trigger is TRG_SOURCE: host: %s = %s",my_instance->src_trg->host[i],sesshost);
		src_ok = true;
		break;
	      }
	  
	  }

	}

      }

      if(src_ok && !my_instance->strict_logging){
	schema_ok = true;
	obj_ok = true;
	goto validate_triggers;
      }

    }else{
      src_ok = true;
    }



    if(my_instance->trgtype & TRG_SCHEMA && my_instance->shm_trg){
      int tbsz = 0,z;
      char** tblnames = skygw_get_table_names(queue,&tbsz,true);
      char* tmp;
      bool all_remotes = true;

      for(z = 0;z<tbsz;z++){
	if((tmp = strchr(tblnames[z],'.')) != NULL){
	  char *lasts;
	  tmp = strtok_r(tblnames[z],".",&lasts);
	  for(i = 0; i<my_instance->shm_trg->size; i++){
	    
	    if(strcmp(tmp,my_instance->shm_trg->objects[i]) == 0){
	      
	      skygw_log_write_flush(LOGFILE_TRACE,"Trigger is TRG_SCHEMA: %s = %s",tmp,my_instance->shm_trg->objects[i]);
	      
	      schema_ok = true;
	      break;
	    }
	  } 
	}else{
	  all_remotes = false;
	}
	free(tblnames[z]);
      }
      free(tblnames);

      if(!schema_ok && !all_remotes && my_session->db && strlen(my_session->db)>0){

	for(i = 0; i<my_instance->shm_trg->size; i++){
	  
	  if(strcmp(my_session->db,my_instance->shm_trg->objects[i]) == 0){
	    
	    skygw_log_write_flush(LOGFILE_TRACE,"Trigger is TRG_SCHEMA: %s = %s",my_session->db,my_instance->shm_trg->objects[i]);
	    
	    schema_ok = true;
	    break;
	  }
	}
      }

      if(schema_ok && !my_instance->strict_logging){
	src_ok = true;
	obj_ok = true;
	goto validate_triggers;
      }

    }else{
      schema_ok = true;
    }


    if(my_instance->trgtype & TRG_OBJECT && my_instance->obj_trg){

      sesstbls = skygw_get_table_names(queue,&dbcount,false);

      for(j = 0; j<dbcount; j++){      
	char* tbnm = NULL;

	if((strchr(sesstbls[j],'.')) != NULL){
	  char *lasts;
	  tbnm = strtok_r(sesstbls[j],".",&lasts);
	  tbnm = strtok_r(NULL,".",&lasts);
	}else{
	  tbnm = sesstbls[j];
	}
	

	for(i = 0; i<my_instance->obj_trg->size; i++){
	  

	  if(!strcmp(tbnm,my_instance->obj_trg->objects[i])){
	    obj_ok = true;
	    skygw_log_write_flush(LOGFILE_TRACE,"Trigger is TRG_OBJECT: %s = %s",my_instance->obj_trg->objects[i],sesstbls[j]);
	    break;
	  }

	}

      }
      if(dbcount > 0){
	for(j = 0; j<dbcount; j++){
	  free(sesstbls[j]);
	}
	free(sesstbls);
	dbcount = 0;
      }

      if(obj_ok && !my_instance->strict_logging){
	src_ok = true;
	schema_ok = true;
	goto validate_triggers;
      }

    }else{
      obj_ok = true;
    }


  validate_triggers:

    if(src_ok&&schema_ok&&obj_ok){

      /**
       * Something matched the trigger, log the query
       */

      skygw_log_write_flush(LOGFILE_TRACE,"Routing message to: %s:%d %s as %s/%s, exchange: %s<%s> key:%s queue:%s",
			    my_instance->hostname,my_instance->port,
			    my_instance->vhost,my_instance->username,
			    my_instance->password,my_instance->exchange,
			    my_instance->exchange_type,my_instance->key,
			    my_instance->queue);

      if(my_session->uid == NULL){

	my_session->uid = calloc(33,sizeof(char));

	if(!my_session->uid){
	  skygw_log_write(LOGFILE_ERROR,"Error : Out of memory.");
	}else{
	  genkey(my_session->uid,32);
	}

      }
    
      if (queue->next != NULL)
      {
        queue = gwbuf_make_contiguous(queue);
      }
      
      if(modutil_extract_SQL(queue, &ptr, &length)){

	my_session->was_query = true;
      
	if((prop = malloc(sizeof(amqp_basic_properties_t)))){
	  prop->_flags = AMQP_BASIC_CONTENT_TYPE_FLAG |
	    AMQP_BASIC_DELIVERY_MODE_FLAG |
	    AMQP_BASIC_MESSAGE_ID_FLAG | 
	    AMQP_BASIC_CORRELATION_ID_FLAG;
	  prop->content_type = amqp_cstring_bytes("text/plain");
	  prop->delivery_mode = AMQP_DELIVERY_PERSISTENT;
	  prop->correlation_id = amqp_cstring_bytes(my_session->uid);
	  prop->message_id = amqp_cstring_bytes("query");
	}

   

	if(success){
      
	  /**Try to convert to a canonical form and use the plain query if unsuccessful*/
	  if((canon_q = skygw_get_canonical(queue)) == NULL){
	    skygw_log_write_flush(LOGFILE_ERROR,
				  "Error: Cannot form canonical query.");	
	  }

	}
 
	memset(t_buf,0,128);      
	sprintf(t_buf, "%lu|",(unsigned long)time(NULL));

	int qlen = strnlen(canon_q,length) + strnlen(t_buf,128);
	if((combined = malloc((qlen+1)*sizeof(char))) == NULL){
	  skygw_log_write_flush(LOGFILE_ERROR,
				"Error: Out of memory");
	}
	strcpy(combined,t_buf);
	strncat(combined,canon_q,length);
      
	pushMessage(my_instance,prop,combined);
	free(canon_q);
      }

    } 

    /** Pass the query downstream */
  }
 send_downstream:
  return my_session->down.routeQuery(my_session->down.instance,
				     my_session->down.session, queue);
}
Beispiel #4
0
/**
 * Associate a new session with this instance of the router.
 *
 * @param instance	The router instance data
 * @param session	The session itself
 * @return Session specific data for this session
 */
static	void	*
newSession(ROUTER *instance, SESSION *session)
{
ROUTER_INSTANCE	        *inst = (ROUTER_INSTANCE *)instance;
ROUTER_CLIENT_SES       *client_rses;
BACKEND                 *candidate = NULL;
int                     i;
BACKEND *master_host = NULL;

        LOGIF(LD, (skygw_log_write_flush(
                LOGFILE_DEBUG,
                "%lu [newSession] new router session with session "
                "%p, and inst %p.",
                pthread_self(),
                session,
                inst)));


	client_rses = (ROUTER_CLIENT_SES *)calloc(1, sizeof(ROUTER_CLIENT_SES));

        if (client_rses == NULL) {
                return NULL;
	}

#if defined(SS_DEBUG)
        client_rses->rses_chk_top = CHK_NUM_ROUTER_SES;
        client_rses->rses_chk_tail = CHK_NUM_ROUTER_SES;
#endif

	/**
         * Find the Master host from available servers
	 */
        master_host = get_root_master(inst->servers);

	/**
	 * Find a backend server to connect to. This is the extent of the
	 * load balancing algorithm we need to implement for this simple
	 * connection router.
	 */

	/*
	 * Loop over all the servers and find any that have fewer connections
         * than the candidate server.
	 *
	 * If a server has less connections than the current candidate we mark this
	 * as the new candidate to connect to.
	 *
	 * If a server has the same number of connections currently as the candidate
	 * and has had less connections over time than the candidate it will also
	 * become the new candidate. This has the effect of spreading the
         * connections over different servers during periods of very low load.
	 */
	for (i = 0; inst->servers[i]; i++) {
		if(inst->servers[i]) {
			LOGIF(LD, (skygw_log_write(
				LOGFILE_DEBUG,
				"%lu [newSession] Examine server in port %d with "
                                "%d connections. Status is %s, "
				"inst->bitvalue is %d",
                                pthread_self(),
				inst->servers[i]->server->port,
				inst->servers[i]->current_connection_count,
				STRSRVSTATUS(inst->servers[i]->server),
				inst->bitmask)));
		}

		if (SERVER_IN_MAINT(inst->servers[i]->server))
			continue;

		if (inst->servers[i]->weight == 0)
			continue;

		/* Check server status bits against bitvalue from router_options */
		if (inst->servers[i] &&
			SERVER_IS_RUNNING(inst->servers[i]->server) &&
			(inst->servers[i]->server->status & inst->bitmask & inst->bitvalue))
                {
			if (master_host) {
				if (inst->servers[i] == master_host && (inst->bitvalue & SERVER_SLAVE)) {
					/* skip root Master here, as it could also be slave of an external server
					 * that is not in the configuration.
					 * Intermediate masters (Relay Servers) are also slave and will be selected
					 * as Slave(s)
			 		 */

					continue;
				}
				if (inst->servers[i] == master_host && (inst->bitvalue & SERVER_MASTER)) {
					/* If option is "master" return only the root Master as there
					 * could be intermediate masters (Relay Servers)
					 * and they must not be selected.
			 	 	 */

					candidate = master_host;
					break;
				}
			} else {
					/* master_host is NULL, no master server.
					 * If requested router_option is 'master'
					 * candidate wll be NULL.
					 */
					if (inst->bitvalue & SERVER_MASTER) {
                                                candidate = NULL;
                                                break;
					}
			}

			/* If no candidate set, set first running server as
			our initial candidate server */
			if (candidate == NULL)
                        {
				candidate = inst->servers[i];
			}
                        else if ((inst->servers[i]->current_connection_count 
					* 1000) / inst->servers[i]->weight <
                                   (candidate->current_connection_count *
					1000) / candidate->weight)
                        {
				/* This running server has fewer
				connections, set it as a new candidate */
				candidate = inst->servers[i];
			}
                        else if ((inst->servers[i]->current_connection_count 
					* 1000) / inst->servers[i]->weight ==
                                   (candidate->current_connection_count *
					1000) / candidate->weight &&
                                 inst->servers[i]->server->stats.n_connections <
                                 candidate->server->stats.n_connections)
                        {
				/* This running server has the same number
				of connections currently as the candidate
				but has had fewer connections over time
				than candidate, set this server to candidate*/
				candidate = inst->servers[i];
			}
		}
	}

	/* There is no candidate server here!
	 * With router_option=slave a master_host could be set, so route traffic there.
	 * Otherwise, just clean up and return NULL
	 */
	if (!candidate) {
		if (master_host) {
			candidate = master_host;
		} else {
                	LOGIF(LE, (skygw_log_write_flush(
                      	  LOGFILE_ERROR,
                      	  "Error : Failed to create new routing session. "
                      	  "Couldn't find eligible candidate server. Freeing "
                       	 "allocated resources.")));
			free(client_rses);
			return NULL;
		}
	}

	client_rses->rses_capabilities = RCAP_TYPE_PACKET_INPUT;
        
	/*
	 * We now have the server with the least connections.
	 * Bump the connection count for this server
	 */
	atomic_add(&candidate->current_connection_count, 1);
	client_rses->backend = candidate;
        LOGIF(LD, (skygw_log_write(
                LOGFILE_DEBUG,
                "%lu [newSession] Selected server in port %d. "
                "Connections : %d\n",
                pthread_self(),
                candidate->server->port,
                candidate->current_connection_count)));

        /*
	 * Open a backend connection, putting the DCB for this
	 * connection in the client_rses->backend_dcb
	 */
        client_rses->backend_dcb = dcb_connect(candidate->server,
                                      session,
                                      candidate->server->protocol);
        if (client_rses->backend_dcb == NULL)
	{
                atomic_add(&candidate->current_connection_count, -1);
		free(client_rses);
		return NULL;
	}
        dcb_add_callback(
                         client_rses->backend_dcb,
                         DCB_REASON_NOT_RESPONDING,
                         &handle_state_switch,
                         client_rses);
        inst->stats.n_sessions++;

	/**
         * Add this session to the list of active sessions.
         */
	spinlock_acquire(&inst->lock);
	client_rses->next = inst->connections;
	inst->connections = client_rses;
	spinlock_release(&inst->lock);

        CHK_CLIENT_RSES(client_rses);

	skygw_log_write(
                LOGFILE_TRACE,
		 "Readconnroute: New session for server %s. "
                "Connections : %d",
		 candidate->server->unique_name,
		 candidate->current_connection_count);
	return (void *)client_rses;
}
Beispiel #5
0
/**
 * The entry point for the monitoring module thread
 *
 * @param arg	The handle of the monitor
 */
static void
monitorMain(void *arg)
{
MYSQL_MONITOR		*handle = (MYSQL_MONITOR *)arg;
MONITOR_SERVERS		*ptr;
size_t			nrounds = 0;
MONITOR_SERVERS		*candidate_master = NULL;
int			master_stickiness = handle->disableMasterFailback;
int			is_cluster=0;
int			log_no_members = 1;

	if (mysql_thread_init())
	{
                LOGIF(LE, (skygw_log_write_flush(
                                   LOGFILE_ERROR,
                                   "Fatal : mysql_thread_init failed in monitor "
                                   "module. Exiting.\n")));
                return;
	}                         
	handle->status = MONITOR_RUNNING;
	
	while (1)
	{
		if (handle->shutdown)
		{
			handle->status = MONITOR_STOPPING;
			mysql_thread_end();
			handle->status = MONITOR_STOPPED;
			return;
		}
		/** Wait base interval */
		thread_millisleep(MON_BASE_INTERVAL_MS);
		/** 
		 * Calculate how far away the monitor interval is from its full 
		 * cycle and if monitor interval time further than the base 
		 * interval, then skip monitoring checks. Excluding the first
		 * round.
		 */ 

		if (nrounds != 0 && ((nrounds*MON_BASE_INTERVAL_MS)%handle->interval) >= MON_BASE_INTERVAL_MS) 
		{
			nrounds += 1;
			continue;
		}

		nrounds += 1;

		/* reset cluster members counter */
		is_cluster=0;

		ptr = handle->databases;

		while (ptr)
		{
			monitorDatabase(handle, ptr);

			/* clear bits for non member nodes */
			if ( ! SERVER_IN_MAINT(ptr->server) && (ptr->server->node_id < 0 || ! SERVER_IS_JOINED(ptr->server))) {
				ptr->server->depth = -1;

				/* clear M/S status */
				server_clear_status(ptr->server, SERVER_SLAVE);
                		server_clear_status(ptr->server, SERVER_MASTER);
				
				/* clear master sticky status */
				server_clear_status(ptr->server, SERVER_MASTER_STICKINESS);
			}

			/* Log server status change */
			if (mon_status_changed(ptr))
			{
				LOGIF(LD, (skygw_log_write_flush(
					LOGFILE_DEBUG,
					"Backend server %s:%d state : %s",
					ptr->server->name,
					ptr->server->port,
					STRSRVSTATUS(ptr->server))));
			}

			if (SERVER_IS_DOWN(ptr->server))
			{
				/** Increase this server'e error count */
				ptr->mon_err_count += 1;
			}
			else
			{
				/** Reset this server's error count */
				ptr->mon_err_count = 0;
			}

			ptr = ptr->next;
		}

		/*
		 * Let's select a master server:
		 * it could be the candidate master following MIN(node_id) rule or
		 * the server that was master in the previous monitor polling cycle
		 * Decision depends on master_stickiness value set in configuration
		 */

		/* get the candidate master, followinf MIN(node_id) rule */
		candidate_master = get_candidate_master(handle->databases);

		/* Select the master, based on master_stickiness */
		handle->master = set_cluster_master(handle->master, candidate_master, master_stickiness);

		ptr = handle->databases;

		while (ptr && handle->master) {
			if (!SERVER_IS_JOINED(ptr->server) || SERVER_IN_MAINT(ptr->server)) {
				ptr = ptr->next;
				continue;
			}

			if (ptr != handle->master) {
				/* set the Slave role */
				server_set_status(ptr->server, SERVER_SLAVE);
				server_clear_status(ptr->server, SERVER_MASTER);

				/* clear master stickyness */
				server_clear_status(ptr->server, SERVER_MASTER_STICKINESS);
			} else {
				/* set the Master role */
				server_set_status(handle->master->server, SERVER_MASTER);
				server_clear_status(handle->master->server, SERVER_SLAVE);

				if (candidate_master && handle->master->server->node_id != candidate_master->server->node_id) {
					/* set master stickyness */
					server_set_status(handle->master->server, SERVER_MASTER_STICKINESS);
				} else {
					/* clear master stickyness */
					server_clear_status(ptr->server, SERVER_MASTER_STICKINESS);
				}			
			}

			is_cluster++;

			ptr = ptr->next;
		}

		if (is_cluster == 0 && log_no_members) {
			LOGIF(LE, (skygw_log_write_flush(
					LOGFILE_ERROR,
					"Error: there are no cluster members")));
			log_no_members = 0;
		} else {
			if (is_cluster > 0 && log_no_members == 0) {
				LOGIF(LE, (skygw_log_write_flush(
					LOGFILE_ERROR,
					"Info: found cluster members")));
				log_no_members = 1;
			}
		}
	}
}
Beispiel #6
0
/**
 * The entry point for the monitoring module thread
 *
 * @param arg	The handle of the monitor
 */
static void
monitorMain(void *arg)
{
    MONITOR* mon = (MONITOR*)arg;
MM_MONITOR	*handle;
MONITOR_SERVERS	*ptr;
int detect_stale_master;
MONITOR_SERVERS *root_master;
size_t nrounds = 0;

spinlock_acquire(&mon->lock);
handle = (MM_MONITOR *)mon->handle;
spinlock_release(&mon->lock);
detect_stale_master = handle->detectStaleMaster;

	if (mysql_thread_init())
	{
		LOGIF(LE, (skygw_log_write_flush(
                                   LOGFILE_ERROR,
                                   "Fatal : mysql_thread_init failed in monitor "
                                   "module. Exiting.\n")));
		return;
	}                         

	handle->status = MONITOR_RUNNING;
	while (1)
	{
		if (handle->shutdown)
		{
			handle->status = MONITOR_STOPPING;
			mysql_thread_end();
			handle->status = MONITOR_STOPPED;
			return;
		}

		/** Wait base interval */
		thread_millisleep(MON_BASE_INTERVAL_MS);
		/**
		 * Calculate how far away the monitor interval is from its full
		 * cycle and if monitor interval time further than the base
		 * interval, then skip monitoring checks. Excluding the first
		 * round.
		 */
                if (nrounds != 0 &&
                        ((nrounds*MON_BASE_INTERVAL_MS)%mon->interval) >=
                        MON_BASE_INTERVAL_MS)
                {
                        nrounds += 1;
                        continue;
                }
                nrounds += 1;

		/* start from the first server in the list */
		ptr = mon->databases;

		while (ptr)
		{
			/* copy server status into monitor pending_status */
			ptr->pending_status = ptr->server->status;

			/* monitor current node */
			monitorDatabase(mon, ptr);

                        if (mon_status_changed(ptr))
                        {
                                dcb_call_foreach(ptr->server,DCB_REASON_NOT_RESPONDING);
                        }
                        
                        if (mon_status_changed(ptr) || 
                                mon_print_fail_status(ptr))
                        {
                                LOGIF(LD, (skygw_log_write_flush(
                                        LOGFILE_DEBUG,
                                        "Backend server %s:%d state : %s",
                                        ptr->server->name,
                                        ptr->server->port,
                                        STRSRVSTATUS(ptr->server))));                                
                        }
                        if (SERVER_IS_DOWN(ptr->server))
                        {
                                /** Increase this server'e error count */
                                ptr->mon_err_count += 1;                                
                        }
                        else
                        {
                                /** Reset this server's error count */
                                ptr->mon_err_count = 0;
                        }

			ptr = ptr->next;
		}
	
		/* Get Master server pointer */
		root_master = get_current_master(mon);

		/* Update server status from monitor pending status on that server*/

                ptr = mon->databases;
		while (ptr)
		{
			if (! SERVER_IN_MAINT(ptr->server)) {
				/* If "detect_stale_master" option is On, let's use the previus master */
				if (detect_stale_master && root_master && (!strcmp(ptr->server->name, root_master->server->name) && ptr->server->port == root_master->server->port) && (ptr->server->status & SERVER_MASTER) && !(ptr->pending_status & SERVER_MASTER)) {
					/* in this case server->status will not be updated from pending_status */
					LOGIF(LM, (skygw_log_write_flush(
						LOGFILE_MESSAGE, "[mysql_mon]: root server [%s:%i] is no longer Master, let's use it again even if it could be a stale master, you have been warned!", ptr->server->name, ptr->server->port)));
					/* Set the STALE bit for this server in server struct */
					server_set_status(ptr->server, SERVER_STALE_STATUS);
				} else {
					ptr->server->status = ptr->pending_status;
				}
			}
			ptr = ptr->next;
		}
		
		ptr = mon->databases;
		monitor_event_t evtype;
		while(ptr)
		{
		    if(mon_status_changed(ptr))
		    {
			evtype = mon_get_event_type(ptr);
			if(isMySQLEvent(evtype))
			{
			    skygw_log_write(LOGFILE_TRACE,"Server changed state: %s[%s:%u]: %s",
				     ptr->server->unique_name,
				     ptr->server->name,ptr->server->port,
				     mon_get_event_name(ptr));
			    if(handle->script && handle->events[evtype])
			    {
				monitor_launch_script(mon,ptr,handle->script);
			    }
			}
		    }
		    ptr = ptr->next;
		}
	}
}
Beispiel #7
0
/**
 * Create an instance of the filter for a particular service
 * within MaxScale.
 * 
 * @param options	The options for this filter
 * @param params	The array of name/value pair parameters for the filter
 *
 * @return The instance data for this new instance
 */
static	FILTER	*
createInstance(char **options, FILTER_PARAMETER **params)
{
LAG_INSTANCE	*my_instance;
int		i,cflags = 0;

	if ((my_instance = calloc(1, sizeof(LAG_INSTANCE))) != NULL)
	{
	    my_instance->count = 0;
	    my_instance->time = 0;
	    my_instance->stats.n_add_count = 0;
	    my_instance->stats.n_add_time = 0;
	    my_instance->stats.n_modified = 0;
	    my_instance->match = NULL;
	    my_instance->nomatch = NULL;

	    for (i = 0; params && params[i]; i++)
	    {
		if (!strcmp(params[i]->name, "count"))
		    my_instance->count = atoi(params[i]->value);
		else if (!strcmp(params[i]->name, "time"))
		    my_instance->time = atoi(params[i]->value);
		else if (!strcmp(params[i]->name, "match"))
		    my_instance->match = strdup(params[i]->value);
		else if (!strcmp(params[i]->name, "ignore"))
		    my_instance->nomatch = strdup(params[i]->value);
		else
		{
		    LOGIF(LE, (skygw_log_write_flush(
			    LOGFILE_ERROR,
						     "lagfilter: Unexpected parameter '%s'.\n",
						     params[i]->name)));
		}
	    }

		if (options)
		{
		    for (i = 0; options[i]; i++)
		    {
			if (!strcasecmp(options[i], "ignorecase"))
			{
			    cflags |= REG_ICASE;
			}
			else if (!strcasecmp(options[i], "case"))
			{
			    cflags &= ~REG_ICASE;
			}
			else
			{
			    LOGIF(LE, (skygw_log_write_flush(
				    LOGFILE_ERROR,
				    "lagfilter: unsupported option '%s'.",
				    options[i])));
			}
		    }
		}

	    if(my_instance->match)
	    {
		if(regcomp(&my_instance->re,my_instance->match,cflags))
		{
		    LOGIF(LE, (skygw_log_write_flush(
				    LOGFILE_ERROR,
				    "lagfilter: Failed to compile regex '%s'.",
				    my_instance->match)));
		}
	    }
	    if(my_instance->nomatch)
	    {
		if(regcomp(&my_instance->nore,my_instance->nomatch,cflags))
		{
		    LOGIF(LE, (skygw_log_write_flush(
				    LOGFILE_ERROR,
				    "lagfilter: Failed to compile regex '%s'.",
				    my_instance->nomatch)));
		}
	    }
	}
	return (FILTER *)my_instance;
}
Beispiel #8
0
/**
 * Add a DCB to the set of descriptors within the polling
 * environment.
 *
 * @param dcb	The descriptor to add to the poll
 * @return	-1 on error or 0 on success
 */
int
poll_add_dcb(DCB *dcb)
{
        int         rc = -1;
        dcb_state_t old_state = DCB_STATE_UNDEFINED;
        dcb_state_t new_state;
        struct	epoll_event	ev;

        CHK_DCB(dcb);

#ifdef EPOLLRDHUP
	ev.events = EPOLLIN | EPOLLOUT | EPOLLRDHUP | EPOLLHUP | EPOLLET;
#else
	ev.events = EPOLLIN | EPOLLOUT | EPOLLHUP | EPOLLET;
#endif
	ev.data.ptr = dcb;

        /*<
         * Choose new state according to the role of dcb.
         */
        if (dcb->dcb_role == DCB_ROLE_REQUEST_HANDLER) {
                new_state = DCB_STATE_POLLING;
        } else {
                ss_dassert(dcb->dcb_role == DCB_ROLE_SERVICE_LISTENER);
                new_state = DCB_STATE_LISTENING;
        }
        /*<
         * If dcb is in unexpected state, state change fails indicating that dcb
         * is not polling anymore.
         */
        if (dcb_set_state(dcb, new_state, &old_state)) {
                rc = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, dcb->fd, &ev);

                if (rc != 0) {
                        int eno = errno;
                        errno = 0;
                        LOGIF(LE, (skygw_log_write_flush(
                                LOGFILE_ERROR,
                                "Error : Adding dcb %p in state %s "
                                "to poll set failed. epoll_ctl failed due "
                                "%d, %s.",
                                dcb,
                                STRDCBSTATE(dcb->state),
                                eno,
                                strerror(eno))));
                } else {
                        LOGIF(LD, (skygw_log_write(
                                LOGFILE_DEBUG,
                                "%lu [poll_add_dcb] Added dcb %p in state %s to "
                                "poll set.",
                                pthread_self(),
                                dcb,
                                STRDCBSTATE(dcb->state))));
                }
                ss_info_dassert(rc == 0, "Unable to add poll"); /*< trap in debug */
        } else {
                LOGIF(LE, (skygw_log_write_flush(
                        LOGFILE_ERROR,
                        "Error : Unable to set new state for dcb %p "
                        "in state %s. Adding to poll set failed.",
                        dcb,
                        STRDCBSTATE(dcb->state))));
        }
        
	return rc; 
}
Beispiel #9
0
/**
 * Process a configuration context and turn it into the set of object
 * we need.
 *
 * @param context	The configuration data
 * @return A zero result indicates a fatal error
 */
static	int
process_config_context(CONFIG_CONTEXT *context)
{
CONFIG_CONTEXT		*obj;
int			error_count = 0;

	/**
	 * Process the data and create the services and servers defined
	 * in the data.
	 */
	obj = context;
	while (obj)
	{
		char *type = config_get_value(obj->parameters, "type");
		if (type == NULL)
		{
			LOGIF(LE, (skygw_log_write_flush(
                                LOGFILE_ERROR,
                                "Error : Configuration object '%s' has no type.",
                                obj->object)));
			error_count++;
		}
		else if (!strcmp(type, "service"))
		{
                        char *router = config_get_value(obj->parameters,
                                                        "router");
                        if (router)
                        {
				obj->element = service_alloc(obj->object, router);
				char *user =
                                        config_get_value(obj->parameters, "user");
				char *auth =
                                        config_get_value(obj->parameters, "passwd");
				char *enable_root_user =
					config_get_value(obj->parameters, "enable_root_user");

				if (enable_root_user)
					serviceEnableRootUser(obj->element, atoi(enable_root_user));

				if (!auth)
					auth = config_get_value(obj->parameters, "auth");

				if (obj->element && user && auth)
				{
					serviceSetUser(obj->element, user, auth);
				}
				else if (user && auth == NULL)
				{
					LOGIF(LE, (skygw_log_write_flush(
		                                LOGFILE_ERROR,
               			                "Error : Service '%s' has a "
						"user defined but no "
						"corresponding password.",
		                                obj->object)));
				}
			}
			else
			{
				obj->element = NULL;
				LOGIF(LE, (skygw_log_write_flush(
                                        LOGFILE_ERROR,
                                        "Error : No router defined for service "
                                        "'%s'\n",
                                        obj->object)));
				error_count++;
			}
		}
		else if (!strcmp(type, "server"))
		{
                        char *address;
			char *port;
			char *protocol;
			char *monuser;
			char *monpw;

                        address = config_get_value(obj->parameters, "address");
			port = config_get_value(obj->parameters, "port");
			protocol = config_get_value(obj->parameters, "protocol");
			monuser = config_get_value(obj->parameters,
                                                   "monitoruser");
			monpw = config_get_value(obj->parameters, "monitorpw");

			if (address && port && protocol)
			{
				obj->element = server_alloc(address,
                                                            protocol,
                                                            atoi(port));
			}
			else
			{
				obj->element = NULL;
				LOGIF(LE, (skygw_log_write_flush(
                                        LOGFILE_ERROR,
                                        "Error : Server '%s' is missing a "
                                        "required configuration parameter. A "
                                        "server must "
                                        "have address, port and protocol "
                                        "defined.",
                                        obj->object)));
				error_count++;
			}
			if (obj->element && monuser && monpw)
				serverAddMonUser(obj->element, monuser, monpw);
			else if (monuser && monpw == NULL)
			{
				LOGIF(LE, (skygw_log_write_flush(
	                                LOGFILE_ERROR,
					"Error : Server '%s' has a monitoruser"
					"defined but no corresponding password.",
                                        obj->object)));
			}
		}
		obj = obj->next;
	}

	/*
	 * Now we have the services we can add the servers to the services
	 * add the protocols to the services
	 */
	obj = context;
	while (obj)
	{
		char *type = config_get_value(obj->parameters, "type");
		if (type == NULL)
			;
		else if (!strcmp(type, "service"))
		{
                        char *servers;
			char *roptions;
                        
			servers = config_get_value(obj->parameters, "servers");
			roptions = config_get_value(obj->parameters,
                                                    "router_options");
			if (servers && obj->element)
			{
				char *s = strtok(servers, ",");
				while (s)
				{
					CONFIG_CONTEXT *obj1 = context;
					while (obj1)
					{
						if (strcmp(s, obj1->object) == 0 &&
                                                    obj->element && obj1->element)
                                                {
							serviceAddBackend(
                                                                obj->element,
                                                                obj1->element);
                                                }
						obj1 = obj1->next;
					}
					s = strtok(NULL, ",");
				}
			}
			else if (servers == NULL)
			{
				LOGIF(LE, (skygw_log_write_flush(
                                        LOGFILE_ERROR,
                                        "Error : The service '%s' is missing a "
                                        "definition of the servers that provide "
                                        "the service.",
                                        obj->object)));
			}
			if (roptions && obj->element)
			{
				char *s = strtok(roptions, ",");
				while (s)
				{
					serviceAddRouterOption(obj->element, s);
					s = strtok(NULL, ",");
				}
			}
		}
		else if (!strcmp(type, "listener"))
		{
                        char *service;
			char *address;
			char *port;
			char *protocol;

                        service = config_get_value(obj->parameters, "service");
			port = config_get_value(obj->parameters, "port");
			address = config_get_value(obj->parameters, "address");
			protocol = config_get_value(obj->parameters, "protocol");
                        
			if (service && port && protocol)
			{
				CONFIG_CONTEXT *ptr = context;
				while (ptr && strcmp(ptr->object, service) != 0)
					ptr = ptr->next;
				if (ptr && ptr->element)
				{
					serviceAddProtocol(ptr->element,
                                                           protocol,
							   address,
                                                           atoi(port));
				}
				else
				{
					LOGIF(LE, (skygw_log_write_flush(
						LOGFILE_ERROR,
                                        	"Error : Listener '%s', "
                                        	"service '%s' not found. "
						"Listener will not execute.",
	                                        obj->object, service)));
					error_count++;
				}
			}
			else
			{
				LOGIF(LE, (skygw_log_write_flush(
                                        LOGFILE_ERROR,
                                        "Error : Listener '%s' is misisng a "
                                        "required "
                                        "parameter. A Listener must have a "
                                        "service, port and protocol defined.",
                                        obj->object)));
				error_count++;
			}
		}
		else if (!strcmp(type, "monitor"))
		{
                        char *module;
			char *servers;
			char *user;
			char *passwd;

                        module = config_get_value(obj->parameters, "module");
			servers = config_get_value(obj->parameters, "servers");
			user = config_get_value(obj->parameters, "user");
			passwd = config_get_value(obj->parameters, "passwd");

                        if (module)
			{
				obj->element = monitor_alloc(obj->object, module);
				if (servers && obj->element)
				{
					char *s = strtok(servers, ",");
					while (s)
					{
						CONFIG_CONTEXT *obj1 = context;
						while (obj1)
						{
							if (strcmp(s, obj1->object) == 0 &&
                                                            obj->element && obj1->element)
                                                        {
								monitorAddServer(
                                                                        obj->element,
                                                                        obj1->element);
                                                        }
							obj1 = obj1->next;
						}
						s = strtok(NULL, ",");
					}
				}
				if (obj->element && user && passwd)
				{
					monitorAddUser(obj->element,
                                                       user,
                                                       passwd);
				}
				else if (obj->element && user)
				{
					LOGIF(LE, (skygw_log_write_flush(
						LOGFILE_ERROR, "Error: "
						"Monitor '%s' defines a "
						"username with no password.",
						obj->object)));
					error_count++;
				}
			}
			else
			{
				obj->element = NULL;
				LOGIF(LE, (skygw_log_write_flush(
                                        LOGFILE_ERROR,
                                        "Error : Monitor '%s' is missing a "
                                        "require module parameter.",
                                        obj->object)));
				error_count++;
			}
		}
		else if (strcmp(type, "server") != 0)
		{
			LOGIF(LE, (skygw_log_write_flush(
                                LOGFILE_ERROR,
                                "Error : Configuration object '%s' has an "
                                "invalid type specified.",
                                obj->object)));
			error_count++;
		}

		obj = obj->next;
	}

	if (error_count)
	{
		LOGIF(LE, (skygw_log_write_flush(
                        LOGFILE_ERROR,
                        "Error : %d errors where encountered processing the "
                        "configuration file '%s'.",
                        error_count,
                        config_file)));
		return 0;
	}
	return 1;
}
Beispiel #10
0
/**
 * Start an individual port/protocol pair
 *
 * @param service	The service
 * @param port		The port to start
 * @return		The number of listeners started
 */
static int
serviceStartPort(SERVICE *service, SERV_PROTOCOL *port)
{
int		listeners = 0;
char		config_bind[40];
GWPROTOCOL	*funcs;

        port->listener = dcb_alloc(DCB_ROLE_SERVICE_LISTENER);

        if (port->listener == NULL)
	{
		LOGIF(LE, (skygw_log_write_flush(
			LOGFILE_ERROR,
			"Error : Failed to create listener for service %s.",
			service->name)));
		goto retblock;
	}
	
	if (strcmp(port->protocol, "MySQLClient") == 0) {
		int loaded;

		if (service->users == NULL) {
			/*
			 * Allocate specific data for MySQL users
			 * including hosts and db names
			 */
			service->users = mysql_users_alloc();
	
			if ((loaded = load_mysql_users(service)) < 0)
			{
				LOGIF(LE, (skygw_log_write_flush(
					LOGFILE_ERROR,
					"Error : Unable to load users from %s:%d for "
					"service %s.",
					(port->address == NULL ? "0.0.0.0" : port->address),
					port->port,
					service->name)));
				
				{
					/* Try loading authentication data from file cache */
					char	*ptr, path[4097];
					strcpy(path, "/usr/local/mariadb-maxscale");
					if ((ptr = getenv("MAXSCALE_HOME")) != NULL)
					{
						strncpy(path, ptr, 4096);
					}
					strncat(path, "/", 4096);
					strncat(path, service->name, 4096);
					strncat(path, "/.cache/dbusers", 4096);
					loaded = dbusers_load(service->users, path);
					if (loaded != -1)
					{
						LOGIF(LE, (skygw_log_write_flush(
							LOGFILE_ERROR,
							"Using cached credential information.")));
					}
				}
				if (loaded == -1)
				{
					hashtable_free(service->users->data);
					free(service->users);
					dcb_free(port->listener);
					port->listener = NULL;
					goto retblock;
				}
			}
			else
			{
				/* Save authentication data to file cache */
				char	*ptr, path[4097];
                                int mkdir_rval = 0;
				strcpy(path, "/usr/local/mariadb-maxscale");
				if ((ptr = getenv("MAXSCALE_HOME")) != NULL)
				{
					strncpy(path, ptr, 4096);
				}
				strncat(path, "/", 4096);
				strncat(path, service->name, 4096);
				if (access(path, R_OK) == -1)
                                {
					mkdir_rval = mkdir(path, 0777);
                                }

                                if(mkdir_rval)
                                {
                                    skygw_log_write(LOGFILE_ERROR,"Error : Failed to create directory '%s': [%d] %s",
                                                    path,
                                                    errno,
                                                    strerror(errno));
                                    mkdir_rval = 0;
                                }

				strncat(path, "/.cache", 4096);
				if (access(path, R_OK) == -1)
                                {
					mkdir_rval = mkdir(path, 0777);
                                }

                                if(mkdir_rval)
                                {
                                    skygw_log_write(LOGFILE_ERROR,"Error : Failed to create directory '%s': [%d] %s",
                                                    path,
                                                    errno,
                                                    strerror(errno));
                                    mkdir_rval = 0;
                                }
				strncat(path, "/dbusers", 4096);
				dbusers_save(service->users, path);
			}
			if (loaded == 0)
			{
				LOGIF(LE, (skygw_log_write_flush(
					LOGFILE_ERROR,
					"Service %s: failed to load any user "
					"information. Authentication will "
					"probably fail as a result.",
					service->name)));
			}

			/* At service start last update is set to USERS_REFRESH_TIME seconds earlier.
 			 * This way MaxScale could try reloading users' just after startup
 			 */
			service->rate_limit.last=time(NULL) - USERS_REFRESH_TIME;
			service->rate_limit.nloads=1;

			LOGIF(LM, (skygw_log_write(
				LOGFILE_MESSAGE,
				"Loaded %d MySQL Users for service [%s].",
				loaded, service->name)));
		}
	} 
	else 
	{
		if (service->users == NULL) {
			/* Generic users table */
			service->users = users_alloc();
		}
	}

	if ((funcs=(GWPROTOCOL *)load_module(port->protocol, MODULE_PROTOCOL)) 
		== NULL)
	{
		if (service->users->data)
		{
			hashtable_free(service->users->data);
		}
		free(service->users);
		dcb_free(port->listener);
		port->listener = NULL;
		LOGIF(LE, (skygw_log_write_flush(
                        LOGFILE_ERROR,
			"Error : Unable to load protocol module %s. Listener "
                        "for service %s not started.",
			port->protocol,
                        service->name)));
		goto retblock;
	}
	memcpy(&(port->listener->func), funcs, sizeof(GWPROTOCOL));
	port->listener->session = NULL;
	
	if (port->address)
		sprintf(config_bind, "%s:%d", port->address, port->port);
	else
		sprintf(config_bind, "0.0.0.0:%d", port->port);

	if (port->listener->func.listen(port->listener, config_bind)) 
	{
                port->listener->session = session_alloc(service, port->listener);

                if (port->listener->session != NULL) 
		{
                        port->listener->session->state = SESSION_STATE_LISTENER;
                        listeners += 1;
                } 
                else 
		{
			LOGIF(LE, (skygw_log_write_flush(
				LOGFILE_ERROR,
				"Error : Failed to create session to service %s.",
				service->name)));
			
			if (service->users->data)
			{
				hashtable_free(service->users->data);
			}
			free(service->users);
                        dcb_close(port->listener);
			port->listener = NULL;
			goto retblock;
                }
        } 
        else 
	{       
                LOGIF(LE, (skygw_log_write_flush(
                        LOGFILE_ERROR,
			"Error : Unable to start to listen port %d for %s %s.",
			port->port,
                        port->protocol,
                        service->name)));
		if (service->users->data)
		{
			hashtable_free(service->users->data);
		}
		free(service->users);
		dcb_close(port->listener);
		port->listener = NULL;
        }
        
retblock:
	return listeners;
}
Beispiel #11
0
/**
 * Start an individual port/protocol pair
 *
 * @param service	The service
 * @param port		The port to start
 * @return		The number of listeners started
 */
static int
serviceStartPort(SERVICE *service, SERV_PROTOCOL *port)
{
int		listeners = 0;
char		config_bind[40];
GWPROTOCOL	*funcs;

        port->listener = dcb_alloc(DCB_ROLE_SERVICE_LISTENER);

        if (port->listener == NULL)
	{
		return 0;
	}
	if (strcmp(port->protocol, "MySQLClient") == 0) {
		int loaded = load_mysql_users(service);
		LOGIF(LM, (skygw_log_write(
                        LOGFILE_MESSAGE,
                        "Loaded %d MySQL Users.",
                        loaded)));
	}

	if ((funcs =
             (GWPROTOCOL *)load_module(port->protocol, MODULE_PROTOCOL)) == NULL)
	{
		dcb_free(port->listener);
		port->listener = NULL;
		LOGIF(LE, (skygw_log_write_flush(
                        LOGFILE_ERROR,
			"Error : Unable to load protocol module %s. Listener "
                        "for service %s not started.",
			port->protocol,
                        service->name)));
		return 0;
	}
	memcpy(&(port->listener->func), funcs, sizeof(GWPROTOCOL));
	port->listener->session = NULL;
	if (port->address)
		sprintf(config_bind, "%s:%d", port->address, port->port);
	else
		sprintf(config_bind, "0.0.0.0:%d", port->port);

	if (port->listener->func.listen(port->listener, config_bind)) {
                port->listener->session = session_alloc(service, port->listener);
                
                if (port->listener->session != NULL) {
                        port->listener->session->state = SESSION_STATE_LISTENER;
                        listeners += 1;
                } else {
                        dcb_close(port->listener);
                }
        } else {
                dcb_close(port->listener);
                
                LOGIF(LE, (skygw_log_write_flush(
                        LOGFILE_ERROR,
			"Error : Unable to start to listen port %d for %s %s.",
			port->port,
                        port->protocol,
                        service->name)));
        }
	return listeners;
}
Beispiel #12
0
/**
 * The clientReply entry point. This is passed the response buffer
 * to which the filter should be applied. Once processed the
 * query is passed to the upstream component
 * (filter or router) in the filter chain.
 *
 * The function tries to extract a SQL query response out of the response buffer,
 * adds a timestamp to it and publishes the resulting string on the exchange.
 * The message is tagged with the same identifier that the query was.
 * 
 * @param instance	The filter instance data
 * @param session	The filter session
 * @param reply		The response data
 */
static int clientReply(FILTER* instance, void *session, GWBUF *reply)
{
  MQ_SESSION		*my_session = (MQ_SESSION *)session;
  MQ_INSTANCE		*my_instance = (MQ_INSTANCE *)instance;
  char			t_buf[128],*combined;
  unsigned int		err_code = AMQP_STATUS_OK,
    pkt_len = pktlen(reply->sbuf->data), offset = 0;
  amqp_basic_properties_t prop;

  spinlock_acquire(my_instance->rconn_lock);

  if(my_instance->conn_stat != AMQP_STATUS_OK){

    if(difftime(time(NULL),my_instance->last_rconn) > my_instance->rconn_intv){

      my_instance->last_rconn = time(NULL);

      if(init_conn(my_instance,my_session)){
	my_instance->rconn_intv = 1.0;
	my_instance->conn_stat = AMQP_STATUS_OK;	

      }else{
	my_instance->rconn_intv += 5.0;
	skygw_log_write(LOGFILE_ERROR,
			"Error : Failed to reconnect to the MQRabbit server ");
      }
      err_code = my_instance->conn_stat;
    }
  }

  spinlock_release(my_instance->rconn_lock);

  if (err_code == AMQP_STATUS_OK && my_session->was_query){

    int packet_ok = 0, was_last = 0;

    my_session->was_query = 0;

    if(pkt_len > 0){
      prop._flags = AMQP_BASIC_CONTENT_TYPE_FLAG |
	AMQP_BASIC_DELIVERY_MODE_FLAG |
	AMQP_BASIC_MESSAGE_ID_FLAG | 
	AMQP_BASIC_CORRELATION_ID_FLAG;
      prop.content_type = amqp_cstring_bytes("text/plain");
      prop.delivery_mode = AMQP_DELIVERY_PERSISTENT;
      prop.correlation_id = amqp_cstring_bytes(my_session->uid);
      prop.message_id = amqp_cstring_bytes("reply");
      if(!(combined = calloc(GWBUF_LENGTH(reply) + 256,sizeof(char)))){
	skygw_log_write_flush(LOGFILE_ERROR,
			      "Error : Out of memory");
      }

      memset(t_buf,0,128);
      sprintf(t_buf,"%lu|",(unsigned long)time(NULL));
      
      
      memcpy(combined + offset,t_buf,strnlen(t_buf,40));
      offset += strnlen(t_buf,40);

      if(*(reply->sbuf->data + 4) == 0x00){ /**OK packet*/
	unsigned int aff_rows = 0, l_id = 0, s_flg = 0, wrn = 0;
	unsigned char *ptr = (unsigned char*)(reply->sbuf->data + 5);
	pkt_len = pktlen(reply->sbuf->data);
	aff_rows = consume_leitoi(&ptr);
	l_id = consume_leitoi(&ptr);
	s_flg |= *ptr++;
	s_flg |= (*ptr++ << 8);
	wrn |= *ptr++;
	wrn |= (*ptr++ << 8);
	sprintf(combined + offset,"OK - affected_rows: %d "
		" last_insert_id: %d "
		" status_flags: %#0x "
		" warnings: %d ",		
		aff_rows,l_id,s_flg,wrn);
	offset += strnlen(combined,GWBUF_LENGTH(reply) + 256) - offset;

	if(pkt_len > 7){
	  int plen = consume_leitoi(&ptr);
	  if(plen > 0){
	    sprintf(combined + offset," message: %.*s\n",plen,ptr);
	  }
	}

	packet_ok = 1;
	was_last = 1;

      }else if(*(reply->sbuf->data + 4) == 0xff){ /**ERR packet*/

	sprintf(combined + offset,"ERROR - message: %.*s",
		(int)(reply->end - ((void*)(reply->sbuf->data + 13))),
		(char *)reply->sbuf->data + 13);
	packet_ok = 1;
	was_last = 1;
    
      }else if(*(reply->sbuf->data + 4) == 0xfb){ /**LOCAL_INFILE request packet*/
      
	unsigned char	*rset = (unsigned char*)reply->sbuf->data;
	strcpy(combined + offset,"LOCAL_INFILE: ");
	strncat(combined + offset,(const char*)rset+5,pktlen(rset));
	packet_ok = 1;
	was_last = 1;
      
      }else{ /**Result set*/
      
	unsigned char	*rset = (unsigned char*)(reply->sbuf->data + 4);
	char		*tmp;
	unsigned int	col_cnt = consume_leitoi(&rset);

	tmp = calloc(256,sizeof(char));
	sprintf(tmp,"Columns: %d",col_cnt);
	memcpy(combined + offset,tmp,strnlen(tmp,256));
	offset += strnlen(tmp,256);
	memcpy(combined + offset,"\n",1);
	offset++;
	free(tmp);
       
	packet_ok = 1;
	was_last = 1;
	
      }
      if(packet_ok){
	if((err_code = amqp_basic_publish(my_session->conn,my_session->channel,
					  amqp_cstring_bytes(my_instance->exchange),
					  amqp_cstring_bytes(my_instance->key),
					  0,0,&prop,amqp_cstring_bytes(combined))
	    ) != AMQP_STATUS_OK){
	  spinlock_acquire(my_instance->rconn_lock);  
	  my_instance->conn_stat = err_code;
	  spinlock_release(my_instance->rconn_lock);

	  skygw_log_write_flush(LOGFILE_ERROR,
				"Error : Failed to publish message to MQRabbit server: "
				"%s",amqp_error_string2(err_code));
	
	}else if(was_last){

	  /**Successful reply received and sent, releasing uid*/
	  
	  free(my_session->uid);
	  my_session->uid = NULL;

	} 
      }
      free(combined);
    }

  }  

  return my_session->up.clientReply(my_session->up.instance,
				    my_session->up.session, reply);
}
Beispiel #13
0
/**
 * The routeQuery entry point. This is passed the query buffer
 * to which the filter should be applied. Once processed the
 * query is passed to the downstream component
 * (filter or router) in the filter chain.
 *
 * The function tries to extract a SQL query out of the query buffer,
 * adds a timestamp to it and publishes the resulting string on the exchange.
 * The message is tagged with an unique identifier and the clientReply will
 * use the same identifier for the reply from the backend.
 * 
 * @param instance	The filter instance data
 * @param session	The filter session
 * @param queue		The query data
 */
static	int	
routeQuery(FILTER *instance, void *session, GWBUF *queue)
{
  MQ_SESSION	*my_session = (MQ_SESSION *)session;
  MQ_INSTANCE	*my_instance = (MQ_INSTANCE *)instance;
  char		*ptr, t_buf[128], *combined;
  int		length, err_code = AMQP_STATUS_OK;
  amqp_basic_properties_t prop;
  spinlock_acquire(my_instance->rconn_lock);
  if(my_instance->conn_stat != AMQP_STATUS_OK){

    if(difftime(time(NULL),my_instance->last_rconn) > my_instance->rconn_intv){

      my_instance->last_rconn = time(NULL);

      if(init_conn(my_instance,my_session)){
	my_instance->rconn_intv = 1.0;
	my_instance->conn_stat = AMQP_STATUS_OK;	

      }else{
	my_instance->rconn_intv += 5.0;
	skygw_log_write(LOGFILE_ERROR,
			"Error : Failed to reconnect to the MQRabbit server ");
      }
      err_code = my_instance->conn_stat;
    }
  }
  spinlock_release(my_instance->rconn_lock);

  if(modutil_is_SQL(queue)){

    if(my_session->uid == NULL){

      my_session->uid = calloc(33,sizeof(char));

      if(!my_session->uid){
	skygw_log_write(LOGFILE_ERROR,"Error : Out of memory.");
      }else{
	genkey(my_session->uid,32);
      }

    }
    
  }

  if (err_code == AMQP_STATUS_OK){

    if(modutil_extract_SQL(queue, &ptr, &length)){

      my_session->was_query = 1;

      prop._flags = AMQP_BASIC_CONTENT_TYPE_FLAG |
	AMQP_BASIC_DELIVERY_MODE_FLAG |
	AMQP_BASIC_MESSAGE_ID_FLAG | 
	AMQP_BASIC_CORRELATION_ID_FLAG;
      prop.content_type = amqp_cstring_bytes("text/plain");
      prop.delivery_mode = AMQP_DELIVERY_PERSISTENT;
      prop.correlation_id = amqp_cstring_bytes(my_session->uid);
      prop.message_id = amqp_cstring_bytes("query");

      memset(t_buf,0,128);      
      sprintf(t_buf, "%lu|",(unsigned long)time(NULL));

      int qlen = length + strnlen(t_buf,128);
      if((combined = malloc((qlen+1)*sizeof(char))) == NULL){
	skygw_log_write_flush(LOGFILE_ERROR,
			      "Error : Out of memory");
      }
      strcpy(combined,t_buf);
      strncat(combined,ptr,length);
      
      if((err_code = amqp_basic_publish(my_session->conn,my_session->channel,
					amqp_cstring_bytes(my_instance->exchange),
					amqp_cstring_bytes(my_instance->key),
					0,0,&prop,amqp_cstring_bytes(combined))
	  ) != AMQP_STATUS_OK){
	spinlock_acquire(my_instance->rconn_lock);  
	my_instance->conn_stat = err_code;
	spinlock_release(my_instance->rconn_lock);

	skygw_log_write_flush(LOGFILE_ERROR,
			      "Error : Failed to publish message to MQRabbit server: "
			      "%s",amqp_error_string2(err_code));
	
      } 

    }

  }
  /** Pass the query downstream */
  return my_session->down.routeQuery(my_session->down.instance,
				     my_session->down.session, queue);
}
Beispiel #14
0
/**
 * Load the user/passwd form mysql.user table into the service users' hashtable
 * environment.
 *
 * @param service	The current service
 * @param users		The users table into which to load the users
 * @return      -1 on any error or the number of users inserted (0 means no users at all)
 */
static int
getUsers(SERVICE *service, struct users *users)
{
	MYSQL			*con = NULL;
	MYSQL_ROW		row;
	MYSQL_RES		*result = NULL;
	int			num_fields = 0;
	char			*service_user = NULL;
	char			*service_passwd = NULL;
	char			*dpwd;
	int			total_users = 0;
	SERVER			*server;
	char			*users_query;
	unsigned char		hash[SHA_DIGEST_LENGTH]="";
	char			*users_data = NULL;
	int 			nusers = 0;
	int			users_data_row_len = MYSQL_USER_MAXLEN + MYSQL_HOST_MAXLEN + MYSQL_PASSWORD_LEN;
	struct sockaddr_in	serv_addr;
	MYSQL_USER_HOST		key;

	/* enable_root for MySQL protocol module means load the root user credentials from backend databases */
	if(service->enable_root) {
		users_query = LOAD_MYSQL_USERS_QUERY " ORDER BY HOST DESC";
	} else {
		users_query = LOAD_MYSQL_USERS_QUERY USERS_QUERY_NO_ROOT " ORDER BY HOST DESC";
	}

	serviceGetUser(service, &service_user, &service_passwd);

	/** multi-thread environment requires that thread init succeeds. */
	if (mysql_thread_init()) {
		LOGIF(LE, (skygw_log_write_flush(
                        LOGFILE_ERROR,
                        "Error : mysql_thread_init failed.")));
		return -1;
	}
    
	con = mysql_init(NULL);

 	if (con == NULL) {
		LOGIF(LE, (skygw_log_write_flush(
                        LOGFILE_ERROR,
                        "Error : mysql_init: %s",
                        mysql_error(con))));
		return -1;
	}

	if (mysql_options(con, MYSQL_OPT_USE_REMOTE_CONNECTION, NULL)) {
		LOGIF(LE, (skygw_log_write_flush(
                        LOGFILE_ERROR,
                        "Error : failed to set external connection. "
                        "It is needed for backend server connections. "
                        "Exiting.")));
		return -1;
	}
	/*
	 * Attempt to connect to each database in the service in turn until
	 * we find one that we can connect to or until we run out of databases
	 * to try
	 */
	server = service->databases;
	dpwd = decryptPassword(service_passwd);
	while (server != NULL && mysql_real_connect(con,
                                                    server->name,
                                                    service_user,
                                                    dpwd,
                                                    NULL,
                                                    server->port,
                                                    NULL,
                                                    0) == NULL)
	{
                server = server->nextdb;
	}
	free(dpwd);

	if (server == NULL)
	{
		LOGIF(LE, (skygw_log_write_flush(
                        LOGFILE_ERROR,
                        "Error : Unable to get user data from backend database "
                        "for service %s. Missing server information.",
                        service->name)));
		mysql_close(con);
		return -1;
	}

	if (mysql_query(con, MYSQL_USERS_COUNT)) {
		LOGIF(LE, (skygw_log_write_flush(
                        LOGFILE_ERROR,
                        "Error : Loading users for service %s encountered "
                        "error: %s.",
                        service->name,
                        mysql_error(con))));
		mysql_close(con);
		return -1;
	}
	result = mysql_store_result(con);

	if (result == NULL) {
		LOGIF(LE, (skygw_log_write_flush(
                        LOGFILE_ERROR,
                        "Error : Loading users for service %s encountered "
                        "error: %s.",
                        service->name,
                        mysql_error(con))));
		mysql_close(con);
		return -1;
	}
	num_fields = mysql_num_fields(result);
	row = mysql_fetch_row(result);

	nusers = atoi(row[0]);

	mysql_free_result(result);

	if (!nusers) {
		LOGIF(LE, (skygw_log_write_flush(
                        LOGFILE_ERROR,
                        "Error : Counting users for service %s returned 0",
                        service->name)));
		mysql_close(con);
		return -1;
	}

	if (mysql_query(con, users_query)) {
		LOGIF(LE, (skygw_log_write_flush(
                        LOGFILE_ERROR,
                        "Error : Loading users for service %s encountered "
                        "error: %s.",
                        service->name,
                        mysql_error(con))));
		mysql_close(con);
		return -1;
	}

	result = mysql_store_result(con);
  
	if (result == NULL) {
		LOGIF(LE, (skygw_log_write_flush(
                        LOGFILE_ERROR,
                        "Error : Loading users for service %s encountered "
                        "error: %s.",
                        service->name,
                        mysql_error(con))));
		mysql_close(con);
		return -1;
	}
	num_fields = mysql_num_fields(result);
	
	users_data = (char *)malloc(nusers * (users_data_row_len * sizeof(char)) + 1);

	if(users_data == NULL)
		return -1;

	while ((row = mysql_fetch_row(result))) { 
		/**
                 * Four fields should be returned.
                 * user and passwd+1 (escaping the first byte that is '*') are
                 * added to hashtable.
                 */
		
		char ret_ip[INET_ADDRSTRLEN + 1]="";
		const char *rc;

		/* prepare the user@host data struct */
		memset(&serv_addr, 0, sizeof(serv_addr));
		memset(&key, 0, sizeof(key));

		/* if host == '%', 0 is passed */
		if (setipaddress(&serv_addr.sin_addr, strcmp(row[1], "%") ? row[1] : "0.0.0.0")) {

			key.user = strdup(row[0]);

			if(key.user == NULL) {
				LOGIF(LE, (skygw_log_write_flush(
					LOGFILE_ERROR,
					"%lu [getUsers()] strdup() failed for user %s",
					pthread_self(),
					row[0])));

				continue;
			}

			memcpy(&key.ipv4, &serv_addr, sizeof(serv_addr));
			
			rc = inet_ntop(AF_INET, &(serv_addr).sin_addr, ret_ip, INET_ADDRSTRLEN);

			/* add user@host as key and passwd as value in the MySQL users hash table */
			if (mysql_users_add(users, &key, strlen(row[2]) ? row[2]+1 : row[2])) {
				LOGIF(LD, (skygw_log_write_flush(
					LOGFILE_DEBUG,
					"%lu [mysql_users_add()] Added user %s@%s(%s)",
					pthread_self(),
					row[0],
					row[1],
					rc == NULL ? "NULL" : ret_ip)));
		
				/* Append data in the memory area for SHA1 digest */	
				strncat(users_data, row[3], users_data_row_len);

				total_users++;
			} else {
				LOGIF(LE, (skygw_log_write_flush(
					LOGFILE_ERROR,
					"%lu [mysql_users_add()] Failed adding user %s@%s(%s)",
					pthread_self(),
					row[0],
					row[1],
					rc == NULL ? "NULL" : ret_ip)));

				continue;
			}

		} else {
			/* setipaddress() failed, skip user add and log this*/
			LOGIF(LE, (skygw_log_write_flush(
				LOGFILE_ERROR,
				"%lu [getUsers()] setipaddress failed: user %s@%s not added",
				pthread_self(),
				row[0],
				row[1])));
		}
	}

	/* compute SHA1 digest for users' data */
        SHA1((const unsigned char *) users_data, strlen(users_data), hash);

	memcpy(users->cksum, hash, SHA_DIGEST_LENGTH);

	free(users_data);

	mysql_free_result(result);
	mysql_close(con);
	mysql_thread_end();

	return total_users;
}
Beispiel #15
0
/**
 * This routine reads data from a binary file named ".secrets" and extracts the AES encryption key
 * and the AES Init Vector.
 * If the path parameter is not null the custom path is interpreted as a folder
 * containing the .secrets file. Otherwise the default location is used.
 * @return	The keys structure or NULL on error
 */
static MAXKEYS *
secrets_readKeys(char* path)
{
char		secret_file[PATH_MAX+1];
char		*home;
MAXKEYS		*keys;
struct stat 	secret_stats;
int		fd;
int             len;
static int	reported = 0;
	if(path != NULL)
	    snprintf(secret_file, PATH_MAX, "%s/.secrets", path);
	else
	    snprintf(secret_file, PATH_MAX, "%s/.secrets", get_datadir());
	/* Try to access secrets file */
	if (access(secret_file, R_OK) == -1) 
	{
                int eno = errno;
                errno = 0;
		if (eno == ENOENT)
		{
			if (!reported)
			{
				LOGIF(LM, (skygw_log_write(
				LOGFILE_MESSAGE,
				"Encrypted password file %s can't be accessed "
				"(%s). Password encryption is not used.",
				secret_file,
				strerror(eno))));
				reported = 1;
			}
		}
		else
		{
			LOGIF(LE, (skygw_log_write_flush(
				LOGFILE_ERROR,
				"Error : access for secrets file "
				"[%s] failed. Error %d, %s.",
				secret_file,
				eno,
				strerror(eno))));
		}
		return NULL;
        }

	/* open secret file */
	if ((fd = open(secret_file, O_RDONLY)) < 0)
	{
                int eno = errno;
                errno = 0;
		LOGIF(LE, (skygw_log_write_flush(
                        LOGFILE_ERROR,
                        "Error : Failed opening secret "
                        "file [%s]. Error %d, %s.",
                        secret_file,
                        eno,
                        strerror(eno))));
		return NULL;

	}

	/* accessing file details */
	if (fstat(fd, &secret_stats) < 0) {
                int eno = errno;
                errno = 0;
		close(fd);
                LOGIF(LE, (skygw_log_write_flush(
                        LOGFILE_ERROR,
                        "Error : fstat for secret file %s "
                        "failed. Error %d, %s.",
                        secret_file,
                        eno,
                        strerror(eno))));
		return NULL;	
	}	

	if (secret_stats.st_size != sizeof(MAXKEYS))
	{
                int eno = errno;
                errno = 0;
		close(fd);
                LOGIF(LE, (skygw_log_write_flush(
                        LOGFILE_ERROR,
                        "Error : Secrets file %s has "
                        "incorrect size. Error %d, %s.",
                        secret_file,
                        eno,
                        strerror(eno))));
		return NULL;
	}
	if (secret_stats.st_mode != (S_IRUSR|S_IFREG))
	{
		close(fd);
                LOGIF(LE, (skygw_log_write_flush(
                        LOGFILE_ERROR,
                        "Error : Ignoring secrets file "
                        "%s, invalid permissions.",
                        secret_file)));
		return NULL;
	}

	if ((keys = (MAXKEYS *)malloc(sizeof(MAXKEYS))) == NULL)
	{
		close(fd);
                LOGIF(LE, (skygw_log_write_flush(
                        LOGFILE_ERROR,
                        "Error : Memory allocation failed "
                        "for key structure.")));
		return NULL;
	}
        
	/**
         * Read all data from file.
         * MAXKEYS (secrets.h) is struct for key, _not_ length-related macro.
         */
        len = read(fd, keys, sizeof(MAXKEYS));
        
	if (len != sizeof(MAXKEYS))
	{
                int eno = errno;
                errno = 0;
		close(fd);
		free(keys);
                LOGIF(LE, (skygw_log_write_flush(
                        LOGFILE_ERROR,
                        "Error : Read from secrets file "
                        "%s failed. Read %d, expected %d bytes. Error %d, %s.",
                        secret_file,
                        len,
                        sizeof(MAXKEYS),
                        eno,
                        strerror(eno))));
		return NULL;
	}

	/* Close the file */
	if (close(fd) < 0) {
                int eno = errno;
                errno = 0;
		free(keys);
                LOGIF(LE, (skygw_log_write_flush(
                        LOGFILE_ERROR,
                        "Error : Failed closing the "
                        "secrets file %s. Error %d, %s.",
                        secret_file,
                        eno,
                        strerror(eno))));
		return NULL;
	}
        ss_dassert(keys != NULL);
	return keys;
}
Beispiel #16
0
/**
 * Process a configuration context update and turn it into the set of object
 * we need.
 *
 * @param context	The configuration data
 */
static	int
process_config_update(CONFIG_CONTEXT *context)
{
CONFIG_CONTEXT		*obj;
SERVICE			*service;
SERVER			*server;

	/**
	 * Process the data and create the services and servers defined
	 * in the data.
	 */
	obj = context;
	while (obj)
	{
		char *type = config_get_value(obj->parameters, "type");
		if (type == NULL)
                {
                    LOGIF(LE,
                          (skygw_log_write_flush(
                                  LOGFILE_ERROR,
                                  "Error : Configuration object %s has no type.",
                                  obj->object)));
                }
		else if (!strcmp(type, "service"))
		{
			char *router = config_get_value(obj->parameters,
                                                        "router");
			if (router)
			{
				if ((service = service_find(obj->object)) != NULL)
				{
                                        char *user;
					char *auth;
					char *enable_root_user;

					enable_root_user = config_get_value(obj->parameters, "enable_root_user");

                                        user = config_get_value(obj->parameters,
                                                                "user");
					auth = config_get_value(obj->parameters,
                                                                "passwd");
					if (user && auth) {
						service_update(service, router,
                                                               user,
                                                               auth);
						if (enable_root_user)
							serviceEnableRootUser(service, atoi(enable_root_user));
					}

					obj->element = service;
				}
				else
				{
                                        char *user;
					char *auth;
					char *enable_root_user;

					enable_root_user = config_get_value(obj->parameters, "enable_root_user");

                                        user = config_get_value(obj->parameters,
                                                                "user");
					auth = config_get_value(obj->parameters,
                                                                "passwd");
					obj->element = service_alloc(obj->object,
                                                                     router);

					if (obj->element && user && auth)
                                        {
						serviceSetUser(obj->element,
                                                               user,
                                                               auth);
						if (enable_root_user)
							serviceEnableRootUser(service, atoi(enable_root_user));
                                        }
				}
			}
			else
			{
				obj->element = NULL;
				LOGIF(LE, (skygw_log_write_flush(
                                        LOGFILE_ERROR,
                                        "Error : No router defined for service "
                                        "'%s'.",
                                        obj->object)));
			}
		}
		else if (!strcmp(type, "server"))
		{
                        char *address;
			char *port;
			char *protocol;
			char *monuser;
			char *monpw;
                        
			address = config_get_value(obj->parameters, "address");
			port = config_get_value(obj->parameters, "port");
			protocol = config_get_value(obj->parameters, "protocol");
			monuser = config_get_value(obj->parameters,
                                                   "monitoruser");
			monpw = config_get_value(obj->parameters, "monitorpw");

                        if (address && port && protocol)
			{
				if ((server =
                                     server_find(address, atoi(port))) != NULL)
				{
					server_update(server,
                                                      protocol,
                                                      monuser,
                                                      monpw);
					obj->element = server;
				}
				else
				{
					obj->element = server_alloc(address,
                                                                    protocol,
                                                                    atoi(port));
					if (obj->element && monuser && monpw)
                                        {
						serverAddMonUser(obj->element,
                                                                 monuser,
                                                                 monpw);
                                        }
				}
			}
			else
                        {
				LOGIF(LE, (skygw_log_write_flush(
                                        LOGFILE_ERROR,
                                        "Error : Server '%s' is missing a "
                                        "required "
                                        "configuration parameter. A server must "
                                        "have address, port and protocol "
                                        "defined.",
                                        obj->object)));
                        }
		}
		obj = obj->next;
	}

	/*
	 * Now we have the services we can add the servers to the services
	 * add the protocols to the services
	 */
	obj = context;
	while (obj)
	{
		char *type = config_get_value(obj->parameters, "type");
		if (type == NULL)
			;
		else if (!strcmp(type, "service"))
		{
                        char *servers;
			char *roptions;
                        
			servers = config_get_value(obj->parameters, "servers");
			roptions = config_get_value(obj->parameters,
                                                    "router_options");
			if (servers && obj->element)
			{
				char *s = strtok(servers, ",");
				while (s)
				{
					CONFIG_CONTEXT *obj1 = context;
					while (obj1)
					{
						if (strcmp(s, obj1->object) == 0 &&
                                                    obj->element && obj1->element)
                                                {
							if (!serviceHasBackend(obj->element, obj1->element))
                                                        {
								serviceAddBackend(
                                                                        obj->element,
                                                                        obj1->element);
                                                        }
                                                }
						obj1 = obj1->next;
					}
					s = strtok(NULL, ",");
				}
			}
			if (roptions && obj->element)
			{
				char *s = strtok(roptions, ",");
				serviceClearRouterOptions(obj->element);
				while (s)
				{
					serviceAddRouterOption(obj->element, s);
					s = strtok(NULL, ",");
				}
			}
		}
		else if (!strcmp(type, "listener"))
		{
                        char *service;
			char *port;
			char *protocol;
			char *address;

                        service = config_get_value(obj->parameters, "service");
			address = config_get_value(obj->parameters, "address");
			port = config_get_value(obj->parameters, "port");
			protocol = config_get_value(obj->parameters, "protocol");

                        if (service && port && protocol)
			{
				CONFIG_CONTEXT *ptr = context;
				while (ptr && strcmp(ptr->object, service) != 0)
					ptr = ptr->next;
                                
				if (ptr &&
                                    ptr->element &&
                                    serviceHasProtocol(ptr->element,
                                                       protocol,
                                                       atoi(port)) == 0)
				{
					serviceAddProtocol(ptr->element,
                                                           protocol,
							   address,
                                                           atoi(port));
					serviceStartProtocol(ptr->element,
                                                             protocol,
                                                             atoi(port));
				}
			}
		}
		else if (strcmp(type, "server") != 0 &&
                         strcmp(type, "monitor") != 0)
		{
			LOGIF(LE, (skygw_log_write_flush(
                                LOGFILE_ERROR,
                                "Error : Configuration object %s has an invalid "
                                "type specified.",
                                obj->object)));
		}
		obj = obj->next;
	}
	return 1;
}
Beispiel #17
0
/**
 * Monitor an individual server
 *
 * @param handle        The MySQL Monitor object
 * @param database	The database to probe
 */
static void
monitorDatabase(MONITOR* mon, MONITOR_SERVERS *database)
{
    MM_MONITOR *handle = mon->handle;
MYSQL_ROW	  row;
MYSQL_RES	  *result;
int               isslave = 0;
int               ismaster = 0;
char		  *uname  = mon->user;
char              *passwd = mon->password;
unsigned long int server_version = 0;
char 		  *server_string;

        if (database->server->monuser != NULL)
	{
		uname = database->server->monuser;
		passwd = database->server->monpw;
	}
	
	if (uname == NULL)
		return;
        
	/* Don't probe servers in maintenance mode */
	if (SERVER_IN_MAINT(database->server))
		return;

        /** Store previous status */
        database->mon_prev_status = database->server->status;
        
	if (database->con == NULL || mysql_ping(database->con) != 0)
	{
		char *dpwd = decryptPassword(passwd);
                int  read_timeout = 1;
		if(database->con)
		    mysql_close(database->con);
                database->con = mysql_init(NULL);

                mysql_options(database->con, MYSQL_OPT_READ_TIMEOUT, (void *)&read_timeout);
                
		if (mysql_real_connect(database->con,
                                       database->server->name,
                                       uname,
                                       dpwd,
                                       NULL,
                                       database->server->port,
                                       NULL,
                                       0) == NULL)
		{
                        free(dpwd);
                        
                        if (mon_print_fail_status(database))
                        {
                                LOGIF(LE, (skygw_log_write_flush(
                                        LOGFILE_ERROR,
                                        "Error : Monitor was unable to connect to "
                                        "server %s:%d : \"%s\"",
                                        database->server->name,
                                        database->server->port,
                                        mysql_error(database->con))));
                        }

			/* The current server is not running
			 *
			 * Store server NOT running in server and monitor server pending struct
			 *
			 */
			if (mysql_errno(database->con) == ER_ACCESS_DENIED_ERROR)
			{
				server_set_status(database->server, SERVER_AUTH_ERROR);
				monitor_set_pending_status(database, SERVER_AUTH_ERROR);
			}
			server_clear_status(database->server, SERVER_RUNNING);
			monitor_clear_pending_status(database, SERVER_RUNNING);

			/* Also clear M/S state in both server and monitor server pending struct */
			server_clear_status(database->server, SERVER_SLAVE);
			server_clear_status(database->server, SERVER_MASTER);
			monitor_clear_pending_status(database, SERVER_SLAVE);
			monitor_clear_pending_status(database, SERVER_MASTER);

			/* Clean addition status too */
			server_clear_status(database->server, SERVER_STALE_STATUS);
			monitor_clear_pending_status(database, SERVER_STALE_STATUS);

			return;
		}  else {
                        server_clear_status(database->server, SERVER_AUTH_ERROR);
                        monitor_clear_pending_status(database, SERVER_AUTH_ERROR);
                }
		free(dpwd);
	}
        /* Store current status in both server and monitor server pending struct */
	server_set_status(database->server, SERVER_RUNNING);
	monitor_set_pending_status(database, SERVER_RUNNING);

	/* get server version from current server */
	server_version = mysql_get_server_version(database->con);

	/* get server version string */
	server_string = (char *)mysql_get_server_info(database->con);
	if (server_string) {
		database->server->server_string = realloc(database->server->server_string, strlen(server_string)+1);
		if (database->server->server_string)
			strcpy(database->server->server_string, server_string);
	}

        /* get server_id form current node */
        if (mysql_query(database->con, "SELECT @@server_id") == 0
                && (result = mysql_store_result(database->con)) != NULL)
        {
                long server_id = -1;

		if(mysql_field_count(database->con) != 1)
		{
		    mysql_free_result(result);
		    skygw_log_write(LE,"Error: Unexpected result for 'SELECT @@server_id'. Expected 1 column."
				    " MySQL Version: %s",version_str);
		    return;
		}

                while ((row = mysql_fetch_row(result)))
                {
                        server_id = strtol(row[0], NULL, 10);
                        if ((errno == ERANGE && (server_id == LONG_MAX
                                || server_id == LONG_MIN)) || (errno != 0 && server_id == 0))
                        {
                                server_id = -1;
                        }
                        database->server->node_id = server_id;
                }
                mysql_free_result(result);
        }

	/* Check if the Slave_SQL_Running and Slave_IO_Running status is
	 * set to Yes
	 */

	/* Check first for MariaDB 10.x.x and get status for multimaster replication */
	if (server_version >= 100000) {

		if (mysql_query(database->con, "SHOW ALL SLAVES STATUS") == 0
			&& (result = mysql_store_result(database->con)) != NULL)
		{
			int i = 0;
			long master_id = -1;

			if(mysql_field_count(database->con) < 42)
			{
			    mysql_free_result(result);
			    skygw_log_write(LE,"Error: \"SHOW ALL SLAVES STATUS\" "
				    "returned less than the expected amount of columns. Expected 42 columns"
				    " MySQL Version: %s",version_str);
			    return;
			}

			while ((row = mysql_fetch_row(result)))
			{
				/* get Slave_IO_Running and Slave_SQL_Running values*/
				if (strncmp(row[12], "Yes", 3) == 0
						&& strncmp(row[13], "Yes", 3) == 0) {
					isslave += 1;
				}

				/* If Slave_IO_Running = Yes, assign the master_id to current server: this allows building 
				 * the replication tree, slaves ids will be added to master(s) and we will have at least the 
				 * root master server.
				 * Please note, there could be no slaves at all if Slave_SQL_Running == 'No'
				 */
				if (strncmp(row[12], "Yes", 3) == 0) {
					/* get Master_Server_Id values */
                                        master_id = atol(row[41]);
                                        if (master_id == 0)
                                                master_id = -1;
				}

				i++;
			}
			/* store master_id of current node */
			memcpy(&database->server->master_id, &master_id, sizeof(long));

			mysql_free_result(result);

			/* If all configured slaves are running set this node as slave */
			if (isslave > 0 && isslave == i)
				isslave = 1;
			else
				isslave = 0;
		}
	} else {	
		if (mysql_query(database->con, "SHOW SLAVE STATUS") == 0
			&& (result = mysql_store_result(database->con)) != NULL)
		{
			long master_id = -1;

			if(mysql_field_count(database->con) < 40)
			{
			    mysql_free_result(result);

			    if(server_version < 5*10000 + 5*100)
			    {
				if(database->log_version_err)
				{
				    skygw_log_write(LE,"Error: \"SHOW SLAVE STATUS\" "
					    " for versions less than 5.5 does not have master_server_id, "
					    "replication tree cannot be resolved for server %s."
					    " MySQL Version: %s",database->server->unique_name,version_str);
				    database->log_version_err = false;
				}
			    }
			    else
			    {
				skygw_log_write(LE,"Error: \"SHOW SLAVE STATUS\" "
					"returned less than the expected amount of columns. Expected 40 columns."
					" MySQL Version: %s",version_str);
			    }
			    return;
			}

			while ((row = mysql_fetch_row(result)))
			{
				/* get Slave_IO_Running and Slave_SQL_Running values*/
				if (strncmp(row[10], "Yes", 3) == 0
						&& strncmp(row[11], "Yes", 3) == 0) {
					isslave = 1;
				}

				/* If Slave_IO_Running = Yes, assign the master_id to current server: this allows building 
				 * the replication tree, slaves ids will be added to master(s) and we will have at least the 
				 * root master server.
				 * Please note, there could be no slaves at all if Slave_SQL_Running == 'No'
				 */
				if (strncmp(row[10], "Yes", 3) == 0) {
					/* get Master_Server_Id values */
					master_id = atol(row[39]);
					if (master_id == 0)
						master_id = -1;
				}
			}
			/* store master_id of current node */
			memcpy(&database->server->master_id, &master_id, sizeof(long));

			mysql_free_result(result);
		}
	}

	/* get variable 'read_only' set by an external component */
	if (mysql_query(database->con, "SHOW GLOBAL VARIABLES LIKE 'read_only'") == 0
		&& (result = mysql_store_result(database->con)) != NULL)
	{
		if(mysql_field_count(database->con) < 2)
		{
		    mysql_free_result(result);
		    skygw_log_write(LE,"Error: Unexpected result for \"SHOW GLOBAL VARIABLES LIKE 'read_only'\". Expected 2 columns."
				    " MySQL Version: %s",version_str);
		    return;
		}

		while ((row = mysql_fetch_row(result)))
		{
			if (strncasecmp(row[1], "OFF", 3) == 0) {
				ismaster = 1;
			} else {
				isslave = 1;
			}
		}
		mysql_free_result(result);
	}

	/* Remove addition info */
	monitor_clear_pending_status(database, SERVER_STALE_STATUS);

	/* Set the Slave Role */
	if (isslave)
	{
		monitor_set_pending_status(database, SERVER_SLAVE);
		/* Avoid any possible stale Master state */
		monitor_clear_pending_status(database, SERVER_MASTER);

		/* Set replication depth to 1 */
		database->server->depth = 1;
	} else {
		/* Avoid any possible Master/Slave stale state */
		monitor_clear_pending_status(database, SERVER_SLAVE);
		monitor_clear_pending_status(database, SERVER_MASTER);
	}

	/* Set the Master role */
        if (ismaster)
        {
		monitor_clear_pending_status(database, SERVER_SLAVE);
                monitor_set_pending_status(database, SERVER_MASTER);

		/* Set replication depth to 0 */
		database->server->depth = 0;
        }

}
Beispiel #18
0
/**
 * Create an instance of the filter for a particular service
 * within MaxScale.
 * 
 * @param options	The options for this filter
 * @param params	The array of name/value pair parameters for the filter
 *
 * @return The instance data for this new instance
 */
static	FILTER	*
createInstance(char **options, FILTER_PARAMETER **params)
{
int		i;
TOPN_INSTANCE	*my_instance;

	if ((my_instance = calloc(1, sizeof(TOPN_INSTANCE))) != NULL)
	{
		my_instance->topN = 10;
		my_instance->match = NULL;
		my_instance->exclude = NULL;
		my_instance->source = NULL;
		my_instance->user = NULL;
		my_instance->filebase = strdup("top");
		for (i = 0; params && params[i]; i++)
		{
			if (!strcmp(params[i]->name, "count"))
				my_instance->topN = atoi(params[i]->value);
			else if (!strcmp(params[i]->name, "filebase"))
			{
				free(my_instance->filebase);
				my_instance->filebase = strdup(params[i]->value);
			}
			else if (!strcmp(params[i]->name, "match"))
			{
				my_instance->match = strdup(params[i]->value);
			}
			else if (!strcmp(params[i]->name, "exclude"))
			{
				my_instance->exclude = strdup(params[i]->value);
			}
			else if (!strcmp(params[i]->name, "source"))
				my_instance->source = strdup(params[i]->value);
			else if (!strcmp(params[i]->name, "user"))
				my_instance->user = strdup(params[i]->value);
			else if (!filter_standard_parameter(params[i]->name))
			{
				LOGIF(LE, (skygw_log_write_flush(
					LOGFILE_ERROR,
					"topfilter: Unexpected parameter '%s'.\n",
					params[i]->name)));
			}
		}
		if (options)
		{
			LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR,
				"topfilter: Options are not supported by this "
				" filter. They will be ignored\n")));
		}
		my_instance->sessions = 0;
		if (my_instance->match &&
			regcomp(&my_instance->re, my_instance->match, REG_ICASE))
		{
			LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR,
				"topfilter: Invalid regular expression '%s'"
				" for the match parameter.\n",
					my_instance->match)));
			free(my_instance->match);
			free(my_instance->source);
			free(my_instance->user);
			free(my_instance->filebase);
			free(my_instance);
			return NULL;
		}
		if (my_instance->exclude &&
			regcomp(&my_instance->exre, my_instance->exclude,
								REG_ICASE))
		{
			LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR,
				"qlafilter: Invalid regular expression '%s'"
				" for the nomatch paramter.\n",
					my_instance->match)));
			regfree(&my_instance->re);
			free(my_instance->match);
			free(my_instance->source);
			free(my_instance->user);
			free(my_instance->filebase);
			free(my_instance);
			return NULL;
		}
	}
	return (FILTER *)my_instance;
}
Beispiel #19
0
/**
 * Start an individual port/protocol pair
 *
 * @param service	The service
 * @param port		The port to start
 * @return		The number of listeners started
 */
static int
serviceStartPort(SERVICE *service, SERV_PROTOCOL *port)
{
int		listeners = 0;
char		config_bind[40];
GWPROTOCOL	*funcs;

        port->listener = dcb_alloc(DCB_ROLE_SERVICE_LISTENER);

        if (port->listener == NULL)
	{
		return 0;
	}
	if (strcmp(port->protocol, "MySQLClient") == 0) {
		int loaded;
		/* Allocate specific data for MySQL users */
		service->users = mysql_users_alloc();
		loaded = load_mysql_users(service);
		/* At service start last update is set to USERS_REFRESH_TIME seconds earlier.
 		 * This way MaxScale could try reloading users' just after startup
 		 */

		service->rate_limit.last=time(NULL) - USERS_REFRESH_TIME;
		service->rate_limit.nloads=1;

		LOGIF(LM, (skygw_log_write(
                        LOGFILE_MESSAGE,
                        "Loaded %d MySQL Users.",
                        loaded)));
	} else {
		/* Generic users table */
		service->users = users_alloc();
	}

	if ((funcs =
             (GWPROTOCOL *)load_module(port->protocol, MODULE_PROTOCOL)) == NULL)
	{
		dcb_free(port->listener);
		port->listener = NULL;
		LOGIF(LE, (skygw_log_write_flush(
                        LOGFILE_ERROR,
			"Error : Unable to load protocol module %s. Listener "
                        "for service %s not started.",
			port->protocol,
                        service->name)));
		return 0;
	}
	memcpy(&(port->listener->func), funcs, sizeof(GWPROTOCOL));
	port->listener->session = NULL;
	if (port->address)
		sprintf(config_bind, "%s:%d", port->address, port->port);
	else
		sprintf(config_bind, "0.0.0.0:%d", port->port);

	if (port->listener->func.listen(port->listener, config_bind)) {
                port->listener->session = session_alloc(service, port->listener);

                if (port->listener->session != NULL) {
                        port->listener->session->state = SESSION_STATE_LISTENER;
                        listeners += 1;
                } else {
                        dcb_close(port->listener);
                }
        } else {
                dcb_close(port->listener);
                
                LOGIF(LE, (skygw_log_write_flush(
                        LOGFILE_ERROR,
			"Error : Unable to start to listen port %d for %s %s.",
			port->port,
                        port->protocol,
                        service->name)));
        }
	return listeners;
}
Beispiel #20
0
/**
 * Monitor an individual server
 *
 * @param handle        The MySQL Monitor object
 * @param database      The database to probe
 */
static void
monitorDatabase(MONITOR *mon, MONITOR_SERVERS *database)
{
    GALERA_MONITOR* handle = (GALERA_MONITOR*)mon->handle;
MYSQL_ROW	row;
MYSQL_RES	*result,*result2;
int		isjoined = 0;
char		*uname  = mon->user;
char		*passwd = mon->password;
unsigned long int	server_version = 0;
char 			*server_string;

	if (database->server->monuser != NULL)
	{
		uname = database->server->monuser;
		passwd = database->server->monpw;
	}
	if (uname == NULL)
		return;

	/* Don't even probe server flagged as in maintenance */
	if (SERVER_IN_MAINT(database->server))
		return;

	/** Store previous status */
	database->mon_prev_status = database->server->status;

	if (database->con == NULL || mysql_ping(database->con) != 0)
	{
		char *dpwd = decryptPassword(passwd);
		int connect_timeout = mon->connect_timeout;
		int read_timeout = mon->read_timeout;
		int write_timeout = mon->write_timeout;

		if(database->con)
		    mysql_close(database->con);
		database->con = mysql_init(NULL);

		mysql_options(database->con, MYSQL_OPT_CONNECT_TIMEOUT, (void *)&connect_timeout);
		mysql_options(database->con, MYSQL_OPT_READ_TIMEOUT, (void *)&read_timeout);
		mysql_options(database->con, MYSQL_OPT_WRITE_TIMEOUT, (void *)&write_timeout);

		if (mysql_real_connect(database->con, database->server->name,
			uname, dpwd, NULL, database->server->port, NULL, 0) == NULL)
		{
			free(dpwd);

			server_clear_status(database->server, SERVER_RUNNING);

			/* Also clear Joined, M/S and Stickiness bits */
			server_clear_status(database->server, SERVER_JOINED);
			server_clear_status(database->server, SERVER_SLAVE);
			server_clear_status(database->server, SERVER_MASTER);
			server_clear_status(database->server, SERVER_MASTER_STICKINESS);

			if (mysql_errno(database->con) == ER_ACCESS_DENIED_ERROR)
			{
				server_set_status(database->server, SERVER_AUTH_ERROR);
			}

			database->server->node_id = -1;

			if (mon_status_changed(database) && mon_print_fail_status(database))
			{
				LOGIF(LE, (skygw_log_write_flush(
					LOGFILE_ERROR,
					"Error : Monitor was unable to connect to "
					"server %s:%d : \"%s\"",
					database->server->name,
					database->server->port,
					mysql_error(database->con))));
			}

			return;
		}
		else
		{
			server_clear_status(database->server, SERVER_AUTH_ERROR);
		}
		free(dpwd);
	}

	/* If we get this far then we have a working connection */
	server_set_status(database->server, SERVER_RUNNING);

	/* get server version string */
	server_string = (char *)mysql_get_server_info(database->con);
	if (server_string) {
		database->server->server_string = realloc(database->server->server_string, strlen(server_string)+1);
		if (database->server->server_string)
			strcpy(database->server->server_string, server_string);
	}	

	/* Check if the the Galera FSM shows this node is joined to the cluster */
	if (mysql_query(database->con, "SHOW STATUS LIKE 'wsrep_local_state'") == 0
		&& (result = mysql_store_result(database->con)) != NULL)
	{
		if(mysql_field_count(database->con) < 2)
		{
		    mysql_free_result(result);
		    skygw_log_write(LE,"Error: Unexpected result for \"SHOW STATUS LIKE 'wsrep_local_state'\". Expected 2 columns."
				    " MySQL Version: %s",version_str);
		    return;
		}

		while ((row = mysql_fetch_row(result)))
		{
			if (strcmp(row[1], "4") == 0) 
				isjoined = 1;
	
			/* Check if the node is a donor and is using xtrabackup, in this case it can stay alive */
			else if (strcmp(row[1], "2") == 0 && handle->availableWhenDonor == 1) {
				if (mysql_query(database->con, "SHOW VARIABLES LIKE 'wsrep_sst_method'") == 0
					&& (result2 = mysql_store_result(database->con)) != NULL)
				{
				    		if(mysql_field_count(database->con) < 2)
						{
						    mysql_free_result(result);
						    mysql_free_result(result2);
						    skygw_log_write(LE,"Error: Unexpected result for \"SHOW VARIABLES LIKE 'wsrep_sst_method'\". Expected 2 columns."
							    " MySQL Version: %s",version_str);
						    return;
						}
					while ((row = mysql_fetch_row(result)))
					{
						if (strncmp(row[1], "xtrabackup", 10) == 0)
							isjoined = 1;
					}
					mysql_free_result(result2);
				}
			}
		}
		mysql_free_result(result);
	}

	/* Check the the Galera node index in the cluster */
	if (mysql_query(database->con, "SHOW STATUS LIKE 'wsrep_local_index'") == 0
		&& (result = mysql_store_result(database->con)) != NULL)
	{
		long local_index = -1;

		if(mysql_field_count(database->con) < 2)
		{
		    mysql_free_result(result);
		    skygw_log_write(LE,"Error: Unexpected result for \"SHOW STATUS LIKE 'wsrep_local_index'\". Expected 2 columns."
							    " MySQL Version: %s",version_str);
		    return;
		}

		while ((row = mysql_fetch_row(result)))
		{
			local_index = strtol(row[1], NULL, 10);
			if ((errno == ERANGE && (local_index == LONG_MAX
				|| local_index == LONG_MIN)) || (errno != 0 && local_index == 0))
			{
				local_index = -1;
			}
			database->server->node_id = local_index;
		}
		mysql_free_result(result);
	}

	if (isjoined)
		server_set_status(database->server, SERVER_JOINED);
	else
		server_clear_status(database->server, SERVER_JOINED);
}
Beispiel #21
0
/**
 * Load the dynamic library related to a gateway module. The routine
 * will look for library files in the current directory, 
 * $MAXSCALE_HOME/modules and /usr/local/skysql/MaxScale/modules.
 *
 * @param module	Name of the module to load
 * @param type		Type of module, used purely for registration
 * @return		The module specific entry point structure or NULL
 */
void *
load_module(const char *module, const char *type)
{
char		*home, *version;
char		fname[MAXPATHLEN];
void		*dlhandle, *sym;
char		*(*ver)();
void		*(*ep)(), *modobj;
MODULES		*mod;
MODULE_INFO	*mod_info = NULL;

        if ((mod = find_module(module)) == NULL)
	{
                /*<
		 * The module is not already loaded
		 *
		 * Search of the shared object.
		 */
		sprintf(fname, "./lib%s.so", module);
		if (access(fname, F_OK) == -1)
		{
			home = get_maxscale_home ();
			sprintf(fname, "%s/modules/lib%s.so", home, module);

                        if (access(fname, F_OK) == -1)
			{
				LOGIF(LE, (skygw_log_write_flush(
                                        LOGFILE_ERROR,
					"Error : Unable to find library for "
                                        "module: %s.",
                                        module)));
				return NULL;
			}
		}

		if ((dlhandle = dlopen(fname, RTLD_NOW|RTLD_LOCAL)) == NULL)
		{
			LOGIF(LE, (skygw_log_write_flush(
                                LOGFILE_ERROR,
				"Error : Unable to load library for module: "
                                "%s\n\n\t\t      %s."
                                "\n\n",
                                module,
                                dlerror())));
			return NULL;
		}

		if ((sym = dlsym(dlhandle, "version")) == NULL)
		{
                        LOGIF(LE, (skygw_log_write_flush(
                                LOGFILE_ERROR,
                                "Error : Version interface not supported by "
                                "module: %s\n\t\t\t      %s.",
                                module,
                                dlerror())));
			dlclose(dlhandle);
			return NULL;
		}
		ver = sym;
		version = ver();

		/*
		 * If the module has a ModuleInit function cal it now.
		 */
		if ((sym = dlsym(dlhandle, "ModuleInit")) != NULL)
		{
			void (*ModuleInit)() = sym;
			ModuleInit();
		}

		if ((sym = dlsym(dlhandle, "info")) != NULL)
		{
			int fatal = 0;
			mod_info = sym;
			if (strcmp(type, MODULE_PROTOCOL) == 0
				&& mod_info->modapi != MODULE_API_PROTOCOL)
			{
                        	LOGIF(LE, (skygw_log_write_flush(
					LOGFILE_ERROR,
					"Module '%s' does not implement "
					"the protocol API.\n",
					module)));
				fatal = 1;
			}
			if (strcmp(type, MODULE_ROUTER) == 0
				&& mod_info->modapi != MODULE_API_ROUTER)
			{
                        	LOGIF(LE, (skygw_log_write_flush(
					LOGFILE_ERROR,
					"Module '%s' does not implement "
					"the router API.\n",
					module)));
				fatal = 1;
			}
			if (strcmp(type, MODULE_MONITOR) == 0
				&& mod_info->modapi != MODULE_API_MONITOR)
			{
                        	LOGIF(LE, (skygw_log_write_flush(
					LOGFILE_ERROR,
					"Module '%s' does not implement "
					"the monitor API.\n",
					module)));
				fatal = 1;
			}
			if (strcmp(type, MODULE_FILTER) == 0
				&& mod_info->modapi != MODULE_API_FILTER)
			{
                        	LOGIF(LE, (skygw_log_write_flush(
					LOGFILE_ERROR,
					"Module '%s' does not implement "
					"the filter API.\n",
					module)));
				fatal = 1;
			}
			if (fatal)
			{
				dlclose(dlhandle);
				return NULL;
			}
		}

		if ((sym = dlsym(dlhandle, "GetModuleObject")) == NULL)
		{
			LOGIF(LE, (skygw_log_write_flush(
                                LOGFILE_ERROR,
                                "Error : Expected entry point interface missing "
                                "from module: %s\n\t\t\t      %s.",
                                module,
                                dlerror())));
			dlclose(dlhandle);
			return NULL;
		}
		ep = sym;
		modobj = ep();

		LOGIF(LM, (skygw_log_write_flush(
                        LOGFILE_MESSAGE,
                        "Loaded module %s: %s from %s",
                        module,
                        version,
                        fname)));
		register_module(module, type, dlhandle, version, modobj, mod_info);
	}
	else
	{
		/*
		 * The module is already loaded, get the entry points again and
		 * return a reference to the already loaded module.
		 */
		modobj = mod->modobj;
	}

	return modobj;
}
Beispiel #22
0
/**
 * The entry point for the monitoring module thread
 *
 * @param arg	The handle of the monitor
 */
static void
monitorMain(void *arg)
{
    MONITOR* mon = (MONITOR*)arg;
GALERA_MONITOR		*handle;
MONITOR_SERVERS		*ptr;
size_t			nrounds = 0;
MONITOR_SERVERS		*candidate_master = NULL;
int			master_stickiness;
int			is_cluster=0;
int			log_no_members = 1;
monitor_event_t evtype;

    spinlock_acquire(&mon->lock);
    handle = (GALERA_MONITOR *)mon->handle;
    spinlock_release(&mon->lock);
    master_stickiness = handle->disableMasterFailback;
	if (mysql_thread_init())
	{
                LOGIF(LE, (skygw_log_write_flush(
                                   LOGFILE_ERROR,
                                   "Fatal : mysql_thread_init failed in monitor "
                                   "module. Exiting.\n")));
                return;
	}                         
	handle->status = MONITOR_RUNNING;
	
	while (1)
	{
		if (handle->shutdown)
		{
			handle->status = MONITOR_STOPPING;
			mysql_thread_end();
			handle->status = MONITOR_STOPPED;
			return;
		}
		/** Wait base interval */
		thread_millisleep(MON_BASE_INTERVAL_MS);
		/** 
		 * Calculate how far away the monitor interval is from its full 
		 * cycle and if monitor interval time further than the base 
		 * interval, then skip monitoring checks. Excluding the first
		 * round.
		 */ 

		if (nrounds != 0 && ((nrounds*MON_BASE_INTERVAL_MS)%mon->interval) >= MON_BASE_INTERVAL_MS)
		{
			nrounds += 1;
			continue;
		}

		nrounds += 1;

		/* reset cluster members counter */
		is_cluster=0;

		ptr = mon->databases;

		while (ptr)
		{
			ptr->mon_prev_status = ptr->server->status;

			monitorDatabase(mon, ptr);

			/* clear bits for non member nodes */
			if ( ! SERVER_IN_MAINT(ptr->server) && (ptr->server->node_id < 0 || ! SERVER_IS_JOINED(ptr->server))) {
				ptr->server->depth = -1;

				/* clear M/S status */
				server_clear_status(ptr->server, SERVER_SLAVE);
                		server_clear_status(ptr->server, SERVER_MASTER);
				
				/* clear master sticky status */
				server_clear_status(ptr->server, SERVER_MASTER_STICKINESS);
			}

			/* Log server status change */
			if (mon_status_changed(ptr))
			{
				LOGIF(LD, (skygw_log_write_flush(
					LOGFILE_DEBUG,
					"Backend server %s:%d state : %s",
					ptr->server->name,
					ptr->server->port,
					STRSRVSTATUS(ptr->server))));
			}
                        
                        if (!(SERVER_IS_RUNNING(ptr->server)) || 
                            !(SERVER_IS_IN_CLUSTER(ptr->server)))
                        {
					dcb_call_foreach(ptr->server,DCB_REASON_NOT_RESPONDING);
                        }

			if (SERVER_IS_DOWN(ptr->server))
			{
				/** Increase this server'e error count */
				dcb_call_foreach(ptr->server,DCB_REASON_NOT_RESPONDING);
				ptr->mon_err_count += 1;

			}
			else
			{
				/** Reset this server's error count */
				ptr->mon_err_count = 0;
			}

			ptr = ptr->next;
		}

		/*
		 * Let's select a master server:
		 * it could be the candidate master following MIN(node_id) rule or
		 * the server that was master in the previous monitor polling cycle
		 * Decision depends on master_stickiness value set in configuration
		 */

		/* get the candidate master, following MIN(node_id) rule */
		candidate_master = get_candidate_master(mon->databases);

		/* Select the master, based on master_stickiness */
                if (1 == handle->disableMasterRoleSetting) {
                    handle->master = NULL;
                }
                else {
                    handle->master = set_cluster_master(handle->master, candidate_master, master_stickiness);
                }

		ptr = mon->databases;

		while (ptr) {
			if (!SERVER_IS_JOINED(ptr->server) || SERVER_IN_MAINT(ptr->server)) {
				ptr = ptr->next;
				continue;
			}

                        if (handle->master) {
                            if (ptr != handle->master) {
				/* set the Slave role */
				server_set_status(ptr->server, SERVER_SLAVE);
				server_clear_status(ptr->server, SERVER_MASTER);

				/* clear master stickiness */
				server_clear_status(ptr->server, SERVER_MASTER_STICKINESS);
                            } else {
				/* set the Master role */
				server_set_status(handle->master->server, SERVER_MASTER);
				server_clear_status(handle->master->server, SERVER_SLAVE);

				if (candidate_master && handle->master->server->node_id != candidate_master->server->node_id) {
					/* set master stickiness */
					server_set_status(handle->master->server, SERVER_MASTER_STICKINESS);
				} else {
					/* clear master stickiness */
					server_clear_status(ptr->server, SERVER_MASTER_STICKINESS);
				}			
                            }
                        }

			is_cluster++;

			ptr = ptr->next;
		}

		if (is_cluster == 0 && log_no_members) {
			LOGIF(LE, (skygw_log_write_flush(
					LOGFILE_ERROR,
					"Error: there are no cluster members")));
			log_no_members = 0;
		} else {
			if (is_cluster > 0 && log_no_members == 0) {
				LOGIF(LE, (skygw_log_write_flush(
					LOGFILE_ERROR,
					"Info: found cluster members")));
				log_no_members = 1;
			}
		}


		ptr = mon->databases;

		while(ptr)
		{

		    /** Execute monitor script if a server state has changed */
		    if(mon_status_changed(ptr))
		    {
			evtype = mon_get_event_type(ptr);
			if(isGaleraEvent(evtype))
			{
			    skygw_log_write(LOGFILE_TRACE,"Server changed state: %s[%s:%u]: %s",
				     ptr->server->unique_name,
				     ptr->server->name,ptr->server->port,
				     mon_get_event_name(ptr));
			    if(handle->script && handle->events[evtype])
			    {
				monitor_launch_script(mon,ptr,handle->script);
			    }
			}
		    }
		    ptr = ptr->next;
		}
	}
}
Beispiel #23
0
/**
 * Monitor an individual server
 *
 * @param handle        The MySQL Monitor object
 * @param database      The database to probe
 */
static void
monitorDatabase(MYSQL_MONITOR *handle, MONITOR_SERVERS *database)
{
MYSQL_ROW	row;
MYSQL_RES	*result;
int		num_fields;
int		isjoined = 0;
char		*uname  = handle->defaultUser;
char		*passwd = handle->defaultPasswd;
unsigned long int	server_version = 0;
char 			*server_string;

	if (database->server->monuser != NULL)
	{
		uname = database->server->monuser;
		passwd = database->server->monpw;
	}
	if (uname == NULL)
		return;

	/* Don't even probe server flagged as in maintenance */
	if (SERVER_IN_MAINT(database->server))
		return;

	/** Store previous status */
	database->mon_prev_status = database->server->status;

	if (database->con == NULL || mysql_ping(database->con) != 0)
	{
		char *dpwd = decryptPassword(passwd);
		int rc;
		int connect_timeout = handle->connect_timeout;
		int read_timeout = handle->read_timeout;
		int write_timeout = handle->write_timeout;;

		database->con = mysql_init(NULL);

		rc = mysql_options(database->con, MYSQL_OPT_CONNECT_TIMEOUT, (void *)&connect_timeout);
		rc = mysql_options(database->con, MYSQL_OPT_READ_TIMEOUT, (void *)&read_timeout);
		rc = mysql_options(database->con, MYSQL_OPT_WRITE_TIMEOUT, (void *)&write_timeout);

		if (mysql_real_connect(database->con, database->server->name,
			uname, dpwd, NULL, database->server->port, NULL, 0) == NULL)
		{
			free(dpwd);

			server_clear_status(database->server, SERVER_RUNNING);

			/* Also clear Joined, M/S and Stickiness bits */
			server_clear_status(database->server, SERVER_JOINED);
			server_clear_status(database->server, SERVER_SLAVE);
			server_clear_status(database->server, SERVER_MASTER);
			server_clear_status(database->server, SERVER_MASTER_STICKINESS);

			if (mysql_errno(database->con) == ER_ACCESS_DENIED_ERROR)
			{
				server_set_status(database->server, SERVER_AUTH_ERROR);
			}

			database->server->node_id = -1;

			if (mon_status_changed(database) && mon_print_fail_status(database))
			{
				LOGIF(LE, (skygw_log_write_flush(
					LOGFILE_ERROR,
					"Error : Monitor was unable to connect to "
					"server %s:%d : \"%s\"",
					database->server->name,
					database->server->port,
					mysql_error(database->con))));
			}

			return;
		}
		else
		{
			server_clear_status(database->server, SERVER_AUTH_ERROR);
		}
		free(dpwd);
	}

	/* If we get this far then we have a working connection */
	server_set_status(database->server, SERVER_RUNNING);

	/* get server version from current server */
	server_version = mysql_get_server_version(database->con);

	/* get server version string */
	server_string = (char *)mysql_get_server_info(database->con);
	if (server_string) {
		database->server->server_string = realloc(database->server->server_string, strlen(server_string)+1);
		if (database->server->server_string)
			strcpy(database->server->server_string, server_string);
	}	

	/* Check if the the Galera FSM shows this node is joined to the cluster */
	if (mysql_query(database->con, "SHOW STATUS LIKE 'wsrep_local_state_comment'") == 0
		&& (result = mysql_store_result(database->con)) != NULL)
	{
		num_fields = mysql_num_fields(result);
		while ((row = mysql_fetch_row(result)))
		{
			if (strncasecmp(row[1], "SYNCED", 3) == 0)
				isjoined = 1;
		}
		mysql_free_result(result);
	}

	/* Check the the Galera node index in the cluster */
	if (mysql_query(database->con, "SHOW STATUS LIKE 'wsrep_local_index'") == 0
		&& (result = mysql_store_result(database->con)) != NULL)
	{
		long local_index = -1;
		num_fields = mysql_num_fields(result);
		while ((row = mysql_fetch_row(result)))
		{
			local_index = strtol(row[1], NULL, 10);
			if ((errno == ERANGE && (local_index == LONG_MAX
				|| local_index == LONG_MIN)) || (errno != 0 && local_index == 0))
			{
				local_index = -1;
			}
			database->server->node_id = local_index;
		}
		mysql_free_result(result);
	}

	if (isjoined)
		server_set_status(database->server, SERVER_JOINED);
	else
		server_clear_status(database->server, SERVER_JOINED);
}
Beispiel #24
0
/**
 * Create an instance of the filter for a particular service
 * within MaxScale.
 * 
 * @param options	The options for this filter
 * @param params	The array of name/value pair parameters for the filter
 *
 * @return The instance data for this new instance
 */
static	FILTER	*
createInstance(char **options, FILTER_PARAMETER **params)
{
QLA_INSTANCE	*my_instance;
int		i;

	if ((my_instance = calloc(1, sizeof(QLA_INSTANCE))) != NULL)
	{
		if (options){
			my_instance->filebase = strdup(options[0]);
		}else{
			my_instance->filebase = strdup("qla");
		}
		my_instance->source = NULL;
		my_instance->userName = NULL;
		my_instance->match = NULL;
		my_instance->nomatch = NULL;
		if (params)
		{
			for (i = 0; params[i]; i++)
			{
				if (!strcmp(params[i]->name, "match"))
				{
					my_instance->match = strdup(params[i]->value);
				}
				else if (!strcmp(params[i]->name, "exclude"))
				{
					my_instance->nomatch = strdup(params[i]->value);
				}
				else if (!strcmp(params[i]->name, "source"))
					my_instance->source = strdup(params[i]->value);
				else if (!strcmp(params[i]->name, "user"))
					my_instance->userName = strdup(params[i]->value);
				else if (!strcmp(params[i]->name, "filebase"))
				{
					if (my_instance->filebase){
						free(my_instance->filebase);
						my_instance->filebase = NULL;
					}
					my_instance->filebase = strdup(params[i]->value);
				}
				else if (!filter_standard_parameter(params[i]->name))
				{
					LOGIF(LE, (skygw_log_write_flush(
						LOGFILE_ERROR,
						"qlafilter: Unexpected parameter '%s'.\n",
						params[i]->name)));
				}
			}
		}
		my_instance->sessions = 0;
		if (my_instance->match &&
			regcomp(&my_instance->re, my_instance->match, REG_ICASE))
		{
			LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR,
				"qlafilter: Invalid regular expression '%s'"
				" for the match parameter.\n",
					my_instance->match)));
			free(my_instance->match);
			free(my_instance->source);
			if(my_instance->filebase){
				free(my_instance->filebase);
			}
			free(my_instance);
			return NULL;
		}
		if (my_instance->nomatch &&
			regcomp(&my_instance->nore, my_instance->nomatch,
								REG_ICASE))
		{
			LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR,
				"qlafilter: Invalid regular expression '%s'"
				" for the nomatch paramter.\n",
					my_instance->match)));
			if (my_instance->match)
				regfree(&my_instance->re);
			free(my_instance->match);
			free(my_instance->source);
			if(my_instance->filebase){
				free(my_instance->filebase);
			}
			free(my_instance);
			return NULL;
		}
	}
	return (FILTER *)my_instance;
}
Beispiel #25
0
/**
 * secrets_readKeys
 *
 * This routine reads data from a binary file and extracts the AES encryption key
 * and the AES Init Vector
 *
 * @return	The keys structure or NULL on error
 */
static MAXKEYS *
secrets_readKeys()
{
char		secret_file[255];
char		*home;
MAXKEYS		*keys;
struct stat 	secret_stats;
int		fd;
int             len;

        home = getenv("MAXSCALE_HOME");

        if (home == NULL) {
                home = "/usr/local/skysql/MaxScale";
        }
	snprintf(secret_file, 255, "%s/etc/.secrets", home);

	/* Try to access secrets file */
	if (access(secret_file, R_OK) == -1) {
                int eno = errno;
                errno = 0;
                LOGIF(LE, (skygw_log_write_flush(
                        LOGFILE_ERROR,
                        "Error : access for secrets file "
                        "[%s] failed. Error %d, %s.",
                        secret_file,
                        eno,
                        strerror(eno))));
		return NULL;
        }

	/* open secret file */
	if ((fd = open(secret_file, O_RDONLY)) < 0)
	{
                int eno = errno;
                errno = 0;
		LOGIF(LE, (skygw_log_write_flush(
                        LOGFILE_ERROR,
                        "Error : Failed opening secret "
                        "file [%s]. Error %d, %s.",
                        secret_file,
                        eno,
                        strerror(eno))));
		return NULL;

	}

	/* accessing file details */
	if (fstat(fd, &secret_stats) < 0) {
                int eno = errno;
                errno = 0;
                LOGIF(LE, (skygw_log_write_flush(
                        LOGFILE_ERROR,
                        "Error : fstat for secret file %s "
                        "failed. Error %d, %s.",
                        secret_file,
                        eno,
                        strerror(eno))));
		return NULL;	
	}	

	if (secret_stats.st_size != sizeof(MAXKEYS))
	{
                int eno = errno;
                errno = 0;
                LOGIF(LE, (skygw_log_write_flush(
                        LOGFILE_ERROR,
                        "Error : Secrets file %s has "
                        "incorrect size. Error %d, %s.",
                        secret_file,
                        eno,
                        strerror(eno))));
		return NULL;
	}
	if (secret_stats.st_mode != (S_IRUSR|S_IFREG))
	{
                LOGIF(LE, (skygw_log_write_flush(
                        LOGFILE_ERROR,
                        "Error : Ignoring secrets file "
                        "%s, invalid permissions.",
                        secret_file)));
		return NULL;
	}

	if ((keys = (MAXKEYS *)malloc(sizeof(MAXKEYS))) == NULL)
	{
                LOGIF(LE, (skygw_log_write_flush(
                        LOGFILE_ERROR,
                        "Error : Memory allocation failed "
                        "for key structure.")));
		return NULL;
	}
        
	/**
         * Read all data from file.
         * MAXKEYS (secrets.h) is struct for key, _not_ length-related macro.
         */
        len = read(fd, keys, sizeof(MAXKEYS));
        
	if (len != sizeof(MAXKEYS))
	{
                int eno = errno;
                errno = 0;
		free(keys);
                LOGIF(LE, (skygw_log_write_flush(
                        LOGFILE_ERROR,
                        "Error : Read from secrets file "
                        "%s failed. Read %d, expected %d bytes. Error %d, %s.",
                        secret_file,
                        len,
                        sizeof(MAXKEYS),
                        eno,
                        strerror(eno))));
		return NULL;
	}

	/* Close the file */
	if (close(fd) < 0) {
                int eno = errno;
                errno = 0;
		free(keys);
                LOGIF(LE, (skygw_log_write_flush(
                        LOGFILE_ERROR,
                        "Error : Failed closing the "
                        "secrets file %s. Error %d, %s.",
                        secret_file,
                        eno,
                        strerror(eno))));
		return NULL;
	}
        ss_dassert(keys != NULL);
	return keys;
}
Beispiel #26
0
/**
 * Allocate a new session for a new client of the specified service.
 *
 * Create the link to the router session by calling the newSession
 * entry point of the router using the router instance of the
 * service this session is part of.
 *
 * @param service	The service this connection was established by
 * @param client_dcb	The client side DCB
 * @return		The newly created session or NULL if an error occured
 */
SESSION *
session_alloc(SERVICE *service, DCB *client_dcb)
{
        SESSION 	*session;

        session = (SESSION *)calloc(1, sizeof(SESSION));
        ss_info_dassert(session != NULL,
                        "Allocating memory for session failed.");
        
        if (session == NULL) {
                int eno = errno;
                errno = 0;
                LOGIF(LE, (skygw_log_write_flush(
                        LOGFILE_ERROR,
                        "Error : Failed to allocate memory for "
                        "session object due error %d, %s.",
                        eno,
                        strerror(eno))));
		goto return_session;
        }
#if defined(SS_DEBUG)
        session->ses_chk_top = CHK_NUM_SESSION;
        session->ses_chk_tail = CHK_NUM_SESSION;
#endif
        spinlock_init(&session->ses_lock);
        /*<
         * Prevent backend threads from accessing before session is completely
         * initialized.
         */
        spinlock_acquire(&session->ses_lock);
        session->service = service;
	session->client = client_dcb;
	session->n_filters = 0;
	memset(&session->stats, 0, sizeof(SESSION_STATS));
	session->stats.connect = time(0);
	session->state = SESSION_STATE_ALLOC;
        /*<
	 * Associate the session to the client DCB and set the reference count on
	 * the session to indicate that there is a single reference to the
         * session. There is no need to protect this or use atomic add as the
         * session has not been made available to the other threads at this
         * point.
         */
        session->data = client_dcb->data;
	client_dcb->session = session;
	session->refcount = 1;
        /*<
         * This indicates that session is ready to be shared with backend
         * DCBs. Note that this doesn't mean that router is initialized yet!
         */
        session->state = SESSION_STATE_READY;
        
        /*< Release session lock */
        spinlock_release(&session->ses_lock);

	/*
	 * Only create a router session if we are not the listening 
	 * DCB or an internal DCB. Creating a router session may create a connection to a
	 * backend server, depending upon the router module implementation
	 * and should be avoided for the listener session
	 *
	 * Router session creation may create other DCBs that link to the
	 * session, therefore it is important that the session lock is
         * relinquished beforethe router call.
	 */
	if (client_dcb->state != DCB_STATE_LISTENING && 
                client_dcb->dcb_role != DCB_ROLE_INTERNAL)
	{
		session->router_session =
                    service->router->newSession(service->router_instance,
                                                session);
	
                if (session->router_session == NULL) {
                        /**
                         * Inform other threads that session is closing.
                         */
                        session->state = SESSION_STATE_STOPPING;
                        /*<
                         * Decrease refcount, set dcb's session pointer NULL
                         * and set session pointer to NULL.
                         */
                        session_free(session);
                        client_dcb->session = NULL;
                        session = NULL;
                        LOGIF(LE, (skygw_log_write_flush(
                                LOGFILE_ERROR,
                                "Error : Failed to create %s session.",
                                service->name)));
                        
                        goto return_session;
                }

		/*
		 * Pending filter chain being setup set the head of the chain to
		 * be the router. As filters are inserted the current head will
		 * be pushed to the filter and the head updated.
		 *
		 * NB This dictates that filters are created starting at the end
		 * of the chain nearest the router working back to the client
		 * protocol end of the chain.
		 */
		session->head.instance = service->router_instance;
		session->head.session = session->router_session;

		session->head.routeQuery = (void *)(service->router->routeQuery);

		session->tail.instance = session;
		session->tail.session = session;
		session->tail.clientReply = session_reply;

		if (service->n_filters > 0)
		{
			if (!session_setup_filters(session))
			{
				/**
				 * Inform other threads that session is closing.
				 */
				session->state = SESSION_STATE_STOPPING;
				/*<
				 * Decrease refcount, set dcb's session pointer NULL
				 * and set session pointer to NULL.
				 */
				session_free(session);
				client_dcb->session = NULL;
				session = NULL;
				LOGIF(LE, (skygw_log_write_flush(
					LOGFILE_ERROR,
					"Error : Failed to create %s session.",
					service->name)));
				goto return_session;
			}
		}
        }

	spinlock_acquire(&session_spin);
        
        if (session->state != SESSION_STATE_READY)
        {
                session_free(session);
                client_dcb->session = NULL;
                session = NULL;
                LOGIF(LE, (skygw_log_write_flush(
                        LOGFILE_ERROR,
                        "Error : Failed to create %s session.",
                        service->name)));
                spinlock_release(&session_spin);
        }
        else
        {
                session->state = SESSION_STATE_ROUTER_READY;
                session->next = allSessions;
                allSessions = session;
                spinlock_release(&session_spin);
                atomic_add(&service->stats.n_sessions, 1);
                atomic_add(&service->stats.n_current, 1);
                CHK_SESSION(session);
        }        
return_session:
	return session;
}
Beispiel #27
0
/**
 * The entry point for the monitoring module thread
 *
 * @param arg	The handle of the monitor
 */
static void
monitorMain(void *arg)
{
MYSQL_MONITOR	*handle = (MYSQL_MONITOR *)arg;
MONITOR_SERVERS	*ptr;
long master_id;
size_t nrounds = 0;

	if (mysql_thread_init())
	{
                LOGIF(LE, (skygw_log_write_flush(
                                   LOGFILE_ERROR,
                                   "Fatal : mysql_thread_init failed in monitor "
                                   "module. Exiting.\n")));
                return;
	}                         
	handle->status = MONITOR_RUNNING;
	
	while (1)
	{
		if (handle->shutdown)
		{
			handle->status = MONITOR_STOPPING;
			mysql_thread_end();
			handle->status = MONITOR_STOPPED;
			return;
		}

		/** Wait base interval */
		thread_millisleep(MON_BASE_INTERVAL_MS);
		/** 
		 * Calculate how far away the monitor interval is from its full 
		 * cycle and if monitor interval time further than the base 
		 * interval, then skip monitoring checks. Excluding the first
		 * round.
		 */ 
		if (nrounds != 0 && 
			((nrounds*MON_BASE_INTERVAL_MS)%handle->interval) >= 
			MON_BASE_INTERVAL_MS) 
		{
			nrounds += 1;
			continue;
		}
		nrounds += 1;
		master_id = -1;
		ptr = handle->databases;

		while (ptr)
		{
			unsigned int prev_status = ptr->server->status;
			monitorDatabase(ptr, handle->defaultUser, handle->defaultPasswd,handle);

			if (ptr->server->status != prev_status ||
				SERVER_IS_DOWN(ptr->server))
			{
				LOGIF(LD, (skygw_log_write_flush(
					LOGFILE_DEBUG,
					"Backend server %s:%d state : %s",
					ptr->server->name,
					ptr->server->port,
					STRSRVSTATUS(ptr->server))));
			}

			ptr = ptr->next;
		}
	}
}
Beispiel #28
0
/**
 * secrets_writeKeys
 *
 * This routine writes into a binary file the AES encryption key
 * and the AES Init Vector
 *
 * @param secret_file   The file with secret keys
 * @return 0 on success and 1 on failure
 */
int secrets_writeKeys(char *path)
{
int				fd,randfd;
unsigned int	randval;
MAXKEYS			key;
char secret_file[PATH_MAX + 10];

if(strlen(path) > PATH_MAX)
{
    skygw_log_write(LOGFILE_ERROR,"Error: Pathname too long.");
    return 1;
}

	sprintf(secret_file,"%s/.secrets",path);

	/* Open for writing | Create | Truncate the file for writing */
        if ((fd = open(secret_file, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR)) < 0)
	{
		LOGIF(LE, (skygw_log_write_flush(
                        LOGFILE_ERROR,
                        "Error : failed opening secret "
                        "file [%s]. Error %d, %s.",
                        secret_file,
                        errno,
                        strerror(errno))));
		return 1;
	}

	/* Open for writing | Create | Truncate the file for writing */
        if ((randfd = open("/dev/random", O_RDONLY)) < 0)
	{
		LOGIF(LE, (skygw_log_write_flush(
                        LOGFILE_ERROR,
                        "Error : failed opening /dev/random. Error %d, %s.",
                        errno,
                        strerror(errno))));
		close(fd);
		return 1;
	}

		if(read(randfd,(void*)&randval,sizeof(unsigned int)) < 1)
    {
		LOGIF(LE, (skygw_log_write_flush(
                        LOGFILE_ERROR,
						"Error : failed to read /dev/random.")));
		close(fd);
		close(randfd);
		return 1;
    }

    close(randfd);
	srand(randval);
	secrets_random_str(key.enckey, MAXSCALE_KEYLEN);
	secrets_random_str(key.initvector, MAXSCALE_IV_LEN);

	/* Write data */
	if (write(fd, &key, sizeof(key)) < 0)
	{
		LOGIF(LE, (skygw_log_write_flush(
                        LOGFILE_ERROR,
                        "Error : failed writing into "
                        "secret file [%s]. Error %d, %s.",
                        secret_file,
                        errno,
                        strerror(errno))));
		close(fd);
		return 1;
	}

	/* close file */
	if (close(fd) < 0)
	{
		LOGIF(LE, (skygw_log_write_flush(
                        LOGFILE_ERROR,
                        "Error : failed closing the "
                        "secret file [%s]. Error %d, %s.",
                        secret_file,
                        errno,
                        strerror(errno))));
	}

	if( chmod(secret_file, S_IRUSR) < 0)
	{
		LOGIF(LE, (skygw_log_write_flush(
                        LOGFILE_ERROR,
                        "Error : failed to change the permissions of the"
                        "secret file [%s]. Error %d, %s.",
                        secret_file,
                        errno,
                        strerror(errno))));
	}

	return 0;
}
Beispiel #29
0
/**
 * The clientReply entry point. This is passed the response buffer
 * to which the filter should be applied. Once processed the
 * query is passed to the upstream component
 * (filter or router) in the filter chain.
 *
 * The function tries to extract a SQL query response out of the response buffer,
 * adds a timestamp to it and publishes the resulting string on the exchange.
 * The message is tagged with the same identifier that the query was.
 * 
 * @param instance	The filter instance data
 * @param session	The filter session
 * @param reply		The response data
 */
static int clientReply(FILTER* instance, void *session, GWBUF *reply)
{
  MQ_SESSION		*my_session = (MQ_SESSION *)session;
  MQ_INSTANCE		*my_instance = (MQ_INSTANCE *)instance;
  char			t_buf[128],*combined;
  unsigned int		pkt_len = pktlen(reply->sbuf->data), offset = 0;
  amqp_basic_properties_t *prop;

  if (my_session->was_query){

    int packet_ok = 0, was_last = 0;

    my_session->was_query = false;

    if(pkt_len > 0){
      if((prop = malloc(sizeof(amqp_basic_properties_t)))){
	prop->_flags = AMQP_BASIC_CONTENT_TYPE_FLAG |
	  AMQP_BASIC_DELIVERY_MODE_FLAG |
	  AMQP_BASIC_MESSAGE_ID_FLAG | 
	  AMQP_BASIC_CORRELATION_ID_FLAG;
	prop->content_type = amqp_cstring_bytes("text/plain");
	prop->delivery_mode = AMQP_DELIVERY_PERSISTENT;
	prop->correlation_id = amqp_cstring_bytes(my_session->uid);
	prop->message_id = amqp_cstring_bytes("reply");
      }
      if(!(combined = calloc(GWBUF_LENGTH(reply) + 256,sizeof(char)))){
	skygw_log_write_flush(LOGFILE_ERROR,
			      "Error : Out of memory");
      }

      memset(t_buf,0,128);
      sprintf(t_buf,"%lu|",(unsigned long)time(NULL));
      
      
      memcpy(combined + offset,t_buf,strnlen(t_buf,40));
      offset += strnlen(t_buf,40);

      if(*(reply->sbuf->data + 4) == 0x00){ /**OK packet*/
	unsigned int aff_rows = 0, l_id = 0, s_flg = 0, wrn = 0;
	unsigned char *ptr = (unsigned char*)(reply->sbuf->data + 5);
	pkt_len = pktlen(reply->sbuf->data);
	aff_rows = consume_leitoi(&ptr);
	l_id = consume_leitoi(&ptr);
	s_flg |= *ptr++;
	s_flg |= (*ptr++ << 8);
	wrn |= *ptr++;
	wrn |= (*ptr++ << 8);
	sprintf(combined + offset,"OK - affected_rows: %d "
		" last_insert_id: %d "
		" status_flags: %#0x "
		" warnings: %d ",		
		aff_rows,l_id,s_flg,wrn);
	offset += strnlen(combined,GWBUF_LENGTH(reply) + 256) - offset;

	if(pkt_len > 7){
	  int plen = consume_leitoi(&ptr);
	  if(plen > 0){
	    sprintf(combined + offset," message: %.*s\n",plen,ptr);
	  }
	}

	packet_ok = 1;
	was_last = 1;

      }else if(*(reply->sbuf->data + 4) == 0xff){ /**ERR packet*/

	sprintf(combined + offset,"ERROR - message: %.*s",
		(int)(reply->end - ((void*)(reply->sbuf->data + 13))),
		(char *)reply->sbuf->data + 13);
	packet_ok = 1;
	was_last = 1;
    
      }else if(*(reply->sbuf->data + 4) == 0xfb){ /**LOCAL_INFILE request packet*/
      
	unsigned char	*rset = (unsigned char*)reply->sbuf->data;
	strcpy(combined + offset,"LOCAL_INFILE: ");
	strncat(combined + offset,(const char*)rset+5,pktlen(rset));
	packet_ok = 1;
	was_last = 1;
      
      }else{ /**Result set*/
      
	unsigned char	*rset = (unsigned char*)(reply->sbuf->data + 4);
	char		*tmp;
	unsigned int	col_cnt = consume_leitoi(&rset);

	tmp = calloc(256,sizeof(char));
	sprintf(tmp,"Columns: %d",col_cnt);
	memcpy(combined + offset,tmp,strnlen(tmp,256));
	offset += strnlen(tmp,256);
	memcpy(combined + offset,"\n",1);
	offset++;
	free(tmp);
       
	packet_ok = 1;
	was_last = 1;
	
      }
      if(packet_ok){

	pushMessage(my_instance,prop,combined);

	if(was_last){

	  /**Successful reply received and sent, releasing uid*/
	  
	  free(my_session->uid);
	  my_session->uid = NULL;

	} 
      }
    }

  }

  return my_session->up.clientReply(my_session->up.instance,
				    my_session->up.session, reply);
}
Beispiel #30
0
/**
 * Receive the MySQL authentication packet from backend, packet # is 2
 *
 * @param protocol The MySQL protocol structure
 * @return -1 in case of failure, 0 if there was nothing to read, 1 if read
 * was successful.
 */
int gw_receive_backend_auth(
        MySQLProtocol *protocol)
{
	int n = -1;
	GWBUF   *head = NULL;
	DCB     *dcb = protocol->owner_dcb;
	uint8_t *ptr = NULL;
        int      rc = 0;

        n = dcb_read(dcb, &head);

        /*<
         * Read didn't fail and there is enough data for mysql packet.
         */
        if (n != -1 &&
            head != NULL &&
            GWBUF_LENGTH(head) >= 5)
        {
                ptr = GWBUF_DATA(head);
                /*<
                 * 5th byte is 0x0 if successful.
                 */
                if (ptr[4] == '\x00') {
                        rc = 1;
                } else {
                        uint8_t* tmpbuf =
                                (uint8_t *)calloc(1, GWBUF_LENGTH(head)+1);
                        memcpy(tmpbuf, ptr, GWBUF_LENGTH(head));
                        LOGIF(LD, (skygw_log_write(
                                LOGFILE_DEBUG,
                                "%lu [gw_receive_backend_auth] Invalid "
                                "authentication message from backend dcb %p "
                                "fd %d, ptr[4] = %p, msg %s.",
                                pthread_self(),
                                dcb,
                                dcb->fd,
                                tmpbuf[4],
                                tmpbuf)));
                        
                                free(tmpbuf);
                                rc = -1;
                }
                /*<
                 * Remove data from buffer.
                 */
                head = gwbuf_consume(head, GWBUF_LENGTH(head));
        }
        else if (n == 0)
        {
                /*<
                 * This is considered as success because call didn't fail,
                 * although no bytes was read.
                 */
                rc = 0;
                LOGIF(LD, (skygw_log_write(
                        LOGFILE_DEBUG,
                        "%lu [gw_receive_backend_auth] Read zero bytes from "
                        "backend dcb %p fd %d in state %s. n %d, head %p, len %d",
                        pthread_self(),
                        dcb,
                        dcb->fd,
                        STRDCBSTATE(dcb->state),
                        n,
                        head,
                        (head == NULL) ? 0 : GWBUF_LENGTH(head))));
        }
        else
        {
                ss_dassert(n < 0 && head == NULL);
                rc = -1;
                LOGIF(LD, (skygw_log_write_flush(
                        LOGFILE_DEBUG,
                        "%lu [gw_receive_backend_auth] Reading from backend dcb %p "
                        "fd %d in state %s failed. n %d, head %p, len %d",
                        pthread_self(),
                        dcb,
                        dcb->fd,
                        STRDCBSTATE(dcb->state),
                        n,
                        head,
                        (head == NULL) ? 0 : GWBUF_LENGTH(head))));
        }
        
        return rc;
}