Exemple #1
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);
}
Exemple #2
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);
}
Exemple #3
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);
}