Пример #1
0
static	int	
routeQuery(ROUTER *instance, void *session, GWBUF *queue)
{
WEB_SESSION	*wsession = (WEB_SESSION *)session;
char		*ptr;
int		i, found = 0;
char		*url;

	if ((url = gwbuf_get_property(queue, "URL")) == NULL)
	{
		respond_error(wsession, 404, "No URL available");
	}

	ptr = strrchr(url, '/');
	if (ptr)
		ptr++;
	else
		ptr = url;
	for (i = 0; pages[i].page; i++)
	{
		if (!strcmp(ptr, pages[i].page))
		{
			(pages[i].fcn)(wsession);
			found = 1;
		}
	}
	if (!found)
		respond_error(wsession, 404, "Unrecognised URL received");
	gwbuf_free(queue);
	return 0;
}
Пример #2
0
int
test2()
{
GWBUF   *buffer;
char len = 128;
char query[129];

        buffer = gwbuf_alloc(132);
	ss_info_dassert((buffer != NULL),"Buffer should not be null");

	memset(query,';',128);
    memset(query+128,'\0',1);
	*((unsigned char*)buffer->start) = len;
	*((unsigned char*)buffer->start+1) = 0;
	*((unsigned char*)buffer->start+2) = 0;
	*((unsigned char*)buffer->start+3) = 1;
	*((unsigned char*)buffer->start+4) = 0x03;
	memcpy(buffer->start + 5,query,strlen(query));
	char* result = modutil_get_SQL(buffer);
	ss_dassert(strcmp(result,query) == 0);
	gwbuf_free(buffer);
	free(result);
        ss_dfprintf(stderr, "\t..done\n");
	return 0;

}
Пример #3
0
static int
test1()
{
GWBUF   *buffer;
char    *(sql[100]);
int     result, length, residual;

        /* Poll tests */  
        ss_dfprintf(stderr,
                    "testmodutil : Rudimentary tests."); 
        buffer = gwbuf_alloc(100);
        ss_info_dassert(0 == modutil_is_SQL(buffer), "Default buffer should be diagnosed as not SQL");
        /* There would ideally be some straightforward way to create a SQL buffer? */
        ss_dfprintf(stderr, "\t..done\nExtract SQL from buffer");
        ss_info_dassert(0 == modutil_extract_SQL(buffer, sql, &length), "Default buffer should fail");
        ss_dfprintf(stderr, "\t..done\nExtract SQL from buffer different way?");
        ss_info_dassert(0 == modutil_MySQL_Query(buffer, sql, &length, &residual), "Default buffer should fail");
        ss_dfprintf(stderr, "\t..done\nReplace SQL in buffer");
        ss_info_dassert(0 == modutil_replace_SQL(buffer, "select * from some_table;"), "Default buffer should fail");
        ss_dfprintf(stderr, "\t..done\nTidy up.");
        gwbuf_free(buffer);
        ss_dfprintf(stderr, "\t..done\n");
		
	return 0;
        
}
Пример #4
0
/**
 * The routeQuery entry point. This is passed the query buffer
 * to which the filter should be applied. Once applied the
 * query should normally be passed to the downstream component
 * (filter or router) in the filter chain.
 *
 * If my_session->residual is set then duplicate that many bytes
 * and send them to the branch.
 *
 * If my_session->residual is zero then this must be a new request
 * Extract the SQL text if possible, match against that text and forward
 * the request. If the requets is not contained witin the packet we have
 * then set my_session->residual to the number of outstanding bytes
 *
 * @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)
{
    TEE_INSTANCE	*my_instance = (TEE_INSTANCE *)instance;
    TEE_SESSION		*my_session = (TEE_SESSION *)session;
    char		*ptr;
    int			rval;
    GWBUF		*buffer = NULL, *clone = NULL;
    unsigned char	command = gwbuf_length(queue) >= 5 ?
	*((unsigned char*)queue->start + 4) : 1;

#ifdef SS_DEBUG
    skygw_log_write(LOGFILE_TRACE,"Tee routeQuery: %d : %s",
		    atomic_add(&debug_seq,1),
		    ((char*)queue->start + 5));
#endif


    spinlock_acquire(&my_session->tee_lock);

    if(!my_session->active)
    {
	skygw_log_write(LOGFILE_TRACE, "Tee: Received a reply when the session was closed.");
	gwbuf_free(queue);
	spinlock_release(&my_session->tee_lock);
	return 0;
    }

    if(my_session->queue)
    {
	my_session->queue = gwbuf_append(my_session->queue,queue);
	buffer = modutil_get_next_MySQL_packet(&my_session->queue);
    }
    else
    {
	buffer = modutil_get_next_MySQL_packet(&queue);
	my_session->queue = queue;
    }

    if(buffer == NULL)
    {
	spinlock_release(&my_session->tee_lock);
	return 1;
    }
    
    clone = clone_query(my_instance, my_session,buffer);
    spinlock_release(&my_session->tee_lock);

    /* Reset session state */
    if(!reset_session_state(my_session,buffer))
	return 0;

    /** Route query downstream */
    spinlock_acquire(&my_session->tee_lock);
    rval = route_single_query(my_instance,my_session,buffer,clone);
    spinlock_release(&my_session->tee_lock);

    return rval;
}
Пример #5
0
/**
 * Free the memory associated with the session
 *
 * @param instance	The filter instance
 * @param session	The filter session
 */
static void
freeSession(FILTER *instance, void *session)
{
TEE_SESSION	*my_session = (TEE_SESSION *)session;
SESSION*	ses = my_session->branch_session;
session_state_t state;
#ifdef SS_DEBUG
skygw_log_write(LOGFILE_TRACE,"Tee free: %d", atomic_add(&debug_seq,1));
#endif
	if (ses != NULL)
	{
            state = ses->state;
            
		if (state == SESSION_STATE_ROUTER_READY)
		{
			session_free(ses);
		}
                else if (state == SESSION_STATE_TO_BE_FREED)
		{
			/** Free branch router session */
			ses->service->router->freeSession(
				ses->service->router_instance,
				ses->router_session);
			/** Free memory of branch client session */
			ses->state = SESSION_STATE_FREE;
			free(ses);
			/** This indicates that branch session is not available anymore */
			my_session->branch_session = NULL;
		}
                else if(state == SESSION_STATE_STOPPING)
                {
                    orphan_session_t* orphan;
                    if((orphan = malloc(sizeof(orphan_session_t))) == NULL)
                    {
                        skygw_log_write(LOGFILE_ERROR,"Error : Failed to "
                                "allocate memory for orphan session struct, "
                                "child session might leak memory.");
                    }else{
                        orphan->session = ses;
                        spinlock_acquire(&orphanLock);
                        orphan->next = allOrphans;
                        allOrphans = orphan;
                        spinlock_release(&orphanLock);
                    }
                }
	}
	if (my_session->dummy_filterdef)
	{
		filter_free(my_session->dummy_filterdef);
	}
        if(my_session->tee_replybuf)
            gwbuf_free(my_session->tee_replybuf);
	free(session);
        
	orphan_free(NULL);

        return;
}
Пример #6
0
/**
 * Trim bytes from the end of a GWBUF structure that may be the first
 * in a list. If the buffer has n_bytes or less then it will be freed and
 * the next buffer in the list will be returned, or if none, NULL.
 *
 * @param head		The buffer to trim
 * @param n_bytes	The number of bytes to trim off
 * @return 		The buffer chain or NULL if buffer chain now empty
 */
GWBUF *
gwbuf_rtrim(GWBUF *head, unsigned int n_bytes)
{
    GWBUF *rval = head;
    CHK_GWBUF(head);
    GWBUF_RTRIM(head, n_bytes);
    CHK_GWBUF(head);

    if (GWBUF_EMPTY(head))
    {
        rval = head->next;
        gwbuf_free(head);
    }
    return rval;
}
Пример #7
0
/**
 * Consume data from a buffer in the linked list. The assumption is to consume
 * n bytes from the buffer chain.
 *
 * If after consuming the bytes from the first buffer that buffer becomes
 * empty it will be freed and the linked list updated.
 *
 * The return value is the new head of the linked list.
 *
 * This call should be made with the caller holding the lock for the linked
 * list.
 *
 * @param head		The head of the linked list
 * @param length	The amount of data to consume
 * @return The head of the linked list
 */
GWBUF *
gwbuf_consume(GWBUF *head, unsigned int length)
{
GWBUF *rval = head;
        CHK_GWBUF(head);
	GWBUF_CONSUME(head, length);
        CHK_GWBUF(head);
        
	if (GWBUF_EMPTY(head))
	{
		rval = head->next;
		gwbuf_free(head);
	}
	return rval;
}
Пример #8
0
/**
 * Free the memory associated with the session
 *
 * @param instance	The filter instance
 * @param session	The filter session
 */
static void
freeSession(FILTER *instance, void *session)
{
    TEE_SESSION *my_session = (TEE_SESSION *) session;
    SESSION* ses = my_session->branch_session;
    session_state_t state;
#ifdef SS_DEBUG
    MXS_INFO("Tee free: %d", atomic_add(&debug_seq, 1));
#endif
    if (ses != NULL)
    {
        state = ses->state;

        if (state == SESSION_STATE_ROUTER_READY)
        {
            session_free(ses);
        }
        else if (state == SESSION_STATE_TO_BE_FREED)
        {
            /** Free branch router session */
            ses->service->router->freeSession(
                                              ses->service->router_instance,
                                              ses->router_session);
            /** Free memory of branch client session */
            ses->state = SESSION_STATE_FREE;
            free(ses);
            /** This indicates that branch session is not available anymore */
            my_session->branch_session = NULL;
        }
        else if (state == SESSION_STATE_STOPPING)
        {
            create_orphan(ses);
        }
    }
    if (my_session->dummy_filterdef)
    {
        filter_free(my_session->dummy_filterdef);
    }
    if (my_session->tee_replybuf)
    {
        gwbuf_free(my_session->tee_replybuf);
    }
    free(session);

    orphan_free(NULL);

    return;
}
Пример #9
0
/**
 * Route the main query downstream along the main filter chain and possibly route
 * a clone of the buffer to the branch session. If the clone buffer is NULL, nothing
 * is routed to the branch session.
 * @param my_instance Tee instance
 * @param my_session Tee session
 * @param buffer Main buffer
 * @param clone Cloned buffer
 * @return 1 on success, 0 on failure.
 */
int route_single_query(TEE_INSTANCE* my_instance, TEE_SESSION* my_session, GWBUF* buffer, GWBUF* clone)
{
    int rval = 0;
    if(!my_session->active ||
       my_session->branch_session == NULL ||
       my_session->branch_session->state != SESSION_STATE_ROUTER_READY)
    {
	rval = 0;
	my_session->active = 0;
	return rval;
    }
    rval = my_session->down.routeQuery(my_session->down.instance,
				       my_session->down.session,
				       buffer);
    if (clone)
    {
	my_session->n_duped++;

	if (my_session->branch_session->state == SESSION_STATE_ROUTER_READY)
	{
	    SESSION_ROUTE_QUERY(my_session->branch_session, clone);
	}
	else
	{
	    /** Close tee session */
	    my_session->active = 0;
	    rval = 0;
	    LOGIF(LT, (skygw_log_write(
		    LOGFILE_TRACE,
				     "Closed tee filter session: Child session in invalid state.")));
	    gwbuf_free(clone);
	}
    }
    else
    {
	if (my_session->active)
	{
	    LOGIF(LT, (skygw_log_write(
		    LOGFILE_TRACE,
				     "Closed tee filter session: Child session is NULL.")));
	    my_session->active = 0;
	    rval = 0;
	}
	my_session->n_rejected++;
    }
    return rval;
}
Пример #10
0
int main(int argc, char** argv)
{

	unsigned int psize;
	GWBUF* qbuff;
	char *tok;
	char readbuff[4092];
	FILE* infile;
	FILE* outfile;
	
	if(argc != 3){
		printf("Usage: canonizer <input file> <output file>\n");
		return 1;
	} 

	if(mysql_library_init(num_elements, server_options, server_groups)){
		printf("Embedded server init failed.\n");
		return 1;
	}
	
	infile = fopen(argv[1],"rb");
	outfile = fopen(argv[2],"wb");
	
	if(infile == NULL || outfile == NULL){
		printf("Opening files failed.\n");
		return 1;
	}

	while(!feof(infile))
		{
			fgets(readbuff,4092,infile);
			psize = strlen(readbuff);
			if(psize < 4092){
				qbuff = gwbuf_alloc(psize + 7);
				*(qbuff->sbuf->data + 0) = (unsigned char)psize;
				*(qbuff->sbuf->data + 1) = (unsigned char)(psize>>8);
				*(qbuff->sbuf->data + 2) = (unsigned char)(psize>>16);
				*(qbuff->sbuf->data + 4) = 0x03;
				memcpy(qbuff->start + 5,readbuff,psize + 1);
				parse_query(qbuff);
				tok = skygw_get_canonical(qbuff);
				fprintf(outfile,"%s\n",tok);
				free(tok);
				gwbuf_free(qbuff);
			}			
		}
Пример #11
0
/**
 * Route the main query downstream along the main filter chain and possibly route
 * a clone of the buffer to the branch session. If the clone buffer is NULL, nothing
 * is routed to the branch session.
 * @param my_instance Tee instance
 * @param my_session Tee session
 * @param buffer Main buffer
 * @param clone Cloned buffer
 * @return 1 on success, 0 on failure.
 */
int route_single_query(TEE_INSTANCE* my_instance, TEE_SESSION* my_session, GWBUF* buffer, GWBUF* clone)
{
    int rval = 0;
    if (!my_session->active ||
        my_session->branch_session == NULL ||
        my_session->branch_session->state != SESSION_STATE_ROUTER_READY)
    {
        rval = 0;
        my_session->active = 0;
        return rval;
    }

    if (clone == NULL)
    {
        /** We won't be expecting any response from the child branch */
        my_session->waiting[CHILD] = false;
        my_session->multipacket[CHILD] = false;
        my_session->eof[CHILD] = 2;
        my_session->n_rejected++;
    }

    rval = my_session->down.routeQuery(my_session->down.instance,
                                       my_session->down.session,
                                       buffer);
    if (clone)
    {
        my_session->n_duped++;

        if (my_session->branch_session->state == SESSION_STATE_ROUTER_READY)
        {
            SESSION_ROUTE_QUERY(my_session->branch_session, clone);
        }
        else
        {
            /** Close tee session */
            my_session->active = 0;
            rval = 0;
            MXS_INFO("Closed tee filter session: Child session in invalid state.");
            gwbuf_free(clone);
        }
    }

    return rval;
}
Пример #12
0
void free_buffers()
{
	if(instance.buffer){
		int i;
		for(i = 0;i<instance.buffer_count;i++){
			gwbuf_free(instance.buffer[i]);	  
		}
		free(instance.buffer);
		instance.buffer = NULL;
		instance.buffer_count = 0;

	}
  
	if(instance.infile >= 0){
		close(instance.infile);
		free(instance.infile_name);
		instance.infile = -1;
	}
}
Пример #13
0
/**
 * We have data from the client, this is a HTTP URL
 *
 * @param instance	The router instance
 * @param session	The router session returned from the newSession call
 * @param queue		The queue of data buffers to route
 * @return The number of bytes sent
 */
static	int
handle_url(INFO_INSTANCE *instance, INFO_SESSION *session, GWBUF *queue)
{
char		*uri;
int		i;
RESULTSET	*set;

	uri = (char *)GWBUF_DATA(queue);
	for (i = 0; supported_uri[i].uri; i++)
	{
		if (strcmp(uri, supported_uri[i].uri) == 0)
		{
			set = (*supported_uri[i].func)();
			resultset_stream_json(set, session->dcb);
			resultset_free(set);
		}
	}
	gwbuf_free(queue);
	return 1;
}
Пример #14
0
/**
 * Consume data from a buffer in the linked list. The assumption is to consume
 * n bytes from the buffer chain.
 *
 * If after consuming the bytes from the first buffer that buffer becomes
 * empty it will be freed and the linked list updated.
 *
 * The return value is the new head of the linked list.
 *
 * This call should be made with the caller holding the lock for the linked
 * list.
 *
 * @param head		The head of the linked list
 * @param length	The amount of data to consume
 * @return The head of the linked list
 */
GWBUF *
gwbuf_consume(GWBUF *head, unsigned int length)
{
    GWBUF *rval = head;

    CHK_GWBUF(head);
    GWBUF_CONSUME(head, length);
    CHK_GWBUF(head);

    if (GWBUF_EMPTY(head))
    {
        rval = head->next;
        if (head->next)
            head->next->tail = head->tail;

        gwbuf_free(head);
    }

    ss_dassert(rval == NULL || (rval->end > rval->start));
    return rval;
}
Пример #15
0
void work_buffer(void* thr_num)
{
	unsigned int index = instance.session_count;
	GWBUF* fake_ok = gen_packet(PACKET_OK);
	while(instance.running){

		pthread_mutex_lock(&instance.work_mtx);
		pthread_mutex_unlock(&instance.work_mtx);

		index = atomic_add(&instance.sess_ind,1);

		if(instance.running &&
		   index < instance.session_count &&
		   instance.buff_ind < instance.buffer_count)
			{
				struct timespec ts1;
				ts1.tv_sec = 0;				

				if(instance.head->instance->routeQuery(instance.head->filter,

													instance.head->session[index],
													   instance.buffer[instance.buff_ind]) == 0){
					if(instance.outfile > 0){
						const char* msg = "Query returned 0.\n";
						write(instance.outfile,msg,strlen(msg));
					}
				}
				if(instance.tail->instance->clientReply){
					instance.tail->instance->clientReply(instance.tail->filter,
														 instance.tail->session[index],
														 fake_ok);
				}
				atomic_add(&instance.last_ind,1);
				ts1.tv_nsec = 1000*instance.rt_delay*1000000;
				nanosleep(&ts1, NULL);
			}

	}
	gwbuf_free(fake_ok);
}
Пример #16
0
int main(int argc, char** argv)
{
	if(argc < 3){
		fprintf(stderr,"Usage: classify <input> <expected output>");
		return 1;
	}
	int rd = 0,buffsz = getpagesize(),strsz = 0,ex_val = 0;
	char buffer[1024], *strbuff = (char*)calloc(buffsz,sizeof(char));
	FILE *input,*expected;

	if(mysql_library_init(num_elements, server_options, server_groups))
		{
			printf("Error: Cannot initialize Embedded Library.");
		    return 1;
		}

	input = fopen(argv[1],"rb");

    if(input == NULL)
    {
        printf("Error: Failed to open input file %s", argv[1]);
        return 1;
    }
    
	expected = fopen(argv[2],"rb");

    if(expected == NULL)
    {
        fclose(input);
        printf("Error: Failed to open expected output file %s", argv[2]);
        return 1;
    }

	while((rd = fread(buffer,sizeof(char),1023,input))){
		
		/**Fill the read buffer*/

		if(strsz + rd >= buffsz){

			char* tmp = realloc(strbuff,(buffsz*2)*sizeof(char));
			
			if(tmp == NULL){
				free(strbuff);
				fclose(input);
				fclose(expected);
				mysql_library_end();
				fprintf(stderr,"Error: Memory allocation failed.");
				return 1;
			}
			strbuff = tmp;
			buffsz *= 2;
		}
		
		memcpy(strbuff+strsz,buffer,rd);
		strsz += rd;
		*(strbuff+strsz) = '\0';

		char *tok,*nlptr;

		/**Remove newlines*/
		while((nlptr = strpbrk(strbuff,"\n")) != NULL && (nlptr - strbuff) < strsz){
			memmove(nlptr,nlptr+1,strsz - (nlptr + 1 - strbuff));
			strsz -= 1;
		}


		/**Parse read buffer for full queries*/

		while(strpbrk(strbuff,";") != NULL){
			tok = strpbrk(strbuff,";");
			unsigned int qlen = tok - strbuff + 1;
			GWBUF* buff = gwbuf_alloc(qlen+6);
			*((unsigned char*)(buff->start)) = qlen;
			*((unsigned char*)(buff->start + 1)) = (qlen >> 8);
			*((unsigned char*)(buff->start + 2)) = (qlen >> 16);
			*((unsigned char*)(buff->start + 3)) = 0x00;
			*((unsigned char*)(buff->start + 4)) = 0x03;
			memcpy(buff->start+5, strbuff, qlen);
			memmove(strbuff,tok + 1, strsz - qlen);
			strsz -= qlen;
			memset(strbuff + strsz,0,buffsz - strsz);
			skygw_query_type_t type = query_classifier_get_type(buff);
			char qtypestr[64];
			char expbuff[256];
			int expos = 0;
			
			while((rd = fgetc(expected)) != '\n' && !feof(expected)){
				expbuff[expos++] = rd;
			}
			expbuff[expos] = '\0';

			if(type == QUERY_TYPE_UNKNOWN){
				sprintf(qtypestr,"QUERY_TYPE_UNKNOWN");
			}
			if(type & QUERY_TYPE_LOCAL_READ){
				sprintf(qtypestr,"QUERY_TYPE_LOCAL_READ");
			}
			if(type & QUERY_TYPE_READ){
				sprintf(qtypestr,"QUERY_TYPE_READ");
			}
			if(type & QUERY_TYPE_WRITE){
				sprintf(qtypestr,"QUERY_TYPE_WRITE");
			}
			if(type & QUERY_TYPE_MASTER_READ){
				sprintf(qtypestr,"QUERY_TYPE_MASTER_READ");
			}
			if(type & QUERY_TYPE_SESSION_WRITE){
				sprintf(qtypestr,"QUERY_TYPE_SESSION_WRITE");
			}
			if(type & QUERY_TYPE_USERVAR_READ){
				sprintf(qtypestr,"QUERY_TYPE_USERVAR_READ");
			}
			if(type & QUERY_TYPE_SYSVAR_READ){
				sprintf(qtypestr,"QUERY_TYPE_SYSVAR_READ");
			}
			if(type & QUERY_TYPE_GSYSVAR_READ){
				sprintf(qtypestr,"QUERY_TYPE_GSYSVAR_READ");
			}
			if(type & QUERY_TYPE_GSYSVAR_WRITE){
				sprintf(qtypestr,"QUERY_TYPE_GSYSVAR_WRITE");
			}
			if(type & QUERY_TYPE_BEGIN_TRX){
				sprintf(qtypestr,"QUERY_TYPE_BEGIN_TRX");
			}
			if(type & QUERY_TYPE_ENABLE_AUTOCOMMIT){
				sprintf(qtypestr,"QUERY_TYPE_ENABLE_AUTOCOMMIT");
			}
			if(type & QUERY_TYPE_DISABLE_AUTOCOMMIT){
				sprintf(qtypestr,"QUERY_TYPE_DISABLE_AUTOCOMMIT");
			}
			if(type & QUERY_TYPE_ROLLBACK){
				sprintf(qtypestr,"QUERY_TYPE_ROLLBACK");
			}
			if(type & QUERY_TYPE_COMMIT){
				sprintf(qtypestr,"QUERY_TYPE_COMMIT");
			}
			if(type & QUERY_TYPE_PREPARE_NAMED_STMT){
				sprintf(qtypestr,"QUERY_TYPE_PREPARE_NAMED_STMT");
			}
			if(type & QUERY_TYPE_PREPARE_STMT){
				sprintf(qtypestr,"QUERY_TYPE_PREPARE_STMT");
			}
			if(type & QUERY_TYPE_EXEC_STMT){
				sprintf(qtypestr,"QUERY_TYPE_EXEC_STMT");
			}
			if(type & QUERY_TYPE_CREATE_TMP_TABLE){
				sprintf(qtypestr,"QUERY_TYPE_CREATE_TMP_TABLE");
			}
			if(type & QUERY_TYPE_READ_TMP_TABLE){
				sprintf(qtypestr,"QUERY_TYPE_READ_TMP_TABLE");
			}
			
			if(strcmp(qtypestr,expbuff) != 0){
				printf("Error in output: '%s' was expected but got '%s'",expbuff,qtypestr);
				ex_val = 1;
			}
			
			gwbuf_free(buff);			
		}
	}
	fclose(input);
	fclose(expected);
	mysql_library_end();
	free(strbuff);
	return ex_val;
}
Пример #17
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 Luafilter calls the routeQuery functions of both the session and the global script.
 * The query is passed as a string parameter to the routeQuery Lua function and
 * the return values of the session specific function, if any were returned,
 * are interpreted. If the first value is bool, it is interpreted as a decision
 * whether to route the query or to send an error packet to the client.
 * If it is a string, the current query is replaced with the return value and
 * the query will be routed. If nil is returned, the query is routed normally.
 *
 * @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)
{
    LUA_SESSION *my_session = (LUA_SESSION *) session;
    LUA_INSTANCE *my_instance = (LUA_INSTANCE *) instance;
    DCB* dcb = my_session->session->client_dcb;
    char *fullquery = NULL, *ptr;
    bool route = true;
    GWBUF* forward = queue;
    int rc = 0;

    if (modutil_is_SQL(queue) || modutil_is_SQL_prepare(queue))
    {
        fullquery = modutil_get_SQL(queue);

        if (fullquery && my_session->lua_state)
        {
            spinlock_acquire(&my_session->lock);
            lua_getglobal(my_session->lua_state, "routeQuery");
            lua_pushlstring(my_session->lua_state, fullquery, strlen(fullquery));
            if (lua_pcall(my_session->lua_state, 1, 1, 0))
            {
                MXS_ERROR("luafilter: Session scope call to 'routeQuery' failed: '%s'.",
                          lua_tostring(my_session->lua_state, -1));
            }
            else if (lua_gettop(my_session->lua_state))
            {
                if (lua_isstring(my_session->lua_state, -1))
                {
                    if (forward)
                    {
                        gwbuf_free(forward);
                    }
                    forward = modutil_create_query((char*) lua_tostring(my_session->lua_state, -1));
                }
                else if (lua_isboolean(my_session->lua_state, -1))
                {
                    route = lua_toboolean(my_session->lua_state, -1);
                }
            }
            spinlock_release(&my_session->lock);
        }

        if (my_instance->global_lua_state)
        {
            spinlock_acquire(&my_instance->lock);
            lua_getglobal(my_instance->global_lua_state, "routeQuery");
            lua_pushlstring(my_instance->global_lua_state, fullquery, strlen(fullquery));
            if (lua_pcall(my_instance->global_lua_state, 1, 0, 0))
            {
                MXS_ERROR("luafilter: Global scope call to 'routeQuery' failed: '%s'.",
                          lua_tostring(my_session->lua_state, -1));
            }
            else if (lua_gettop(my_instance->global_lua_state))
            {
                if (lua_isstring(my_instance->global_lua_state, -1))
                {
                    if (forward)
                    {
                        gwbuf_free(forward);
                    }
                    forward = modutil_create_query((char*)
                                                   lua_tostring(my_instance->global_lua_state, -1));
                }
                else if (lua_isboolean(my_instance->global_lua_state, -1))
                {
                    route = lua_toboolean(my_instance->global_lua_state, -1);
                }
            }
            spinlock_release(&my_instance->lock);
        }

        free(fullquery);
    }

    if (!route)
    {
        gwbuf_free(queue);
        GWBUF* err = modutil_create_mysql_err_msg(1, 0, 1045, "28000", "Access denied.");
        rc = dcb->func.write(dcb, err);
    }
    else
    {
        rc = my_session->down.routeQuery(my_session->down.instance,
                                         my_session->down.session, forward);
    }

    return rc;
}
Пример #18
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.
 *
 * @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)
{
    int rc, branch, eof;
    TEE_SESSION *my_session = (TEE_SESSION *) session;
    bool route = false, mpkt;
    GWBUF *complete = NULL;
    unsigned char *ptr;
    uint16_t flags = 0;
    int min_eof = my_session->command != 0x04 ? 2 : 1;
    int more_results = 0;
#ifdef SS_DEBUG
    int prev_debug_seq = atomic_add(&debug_seq, 1);
    ptr = (unsigned char*) reply->start;
    MXS_INFO("Tee clientReply [%s] [%s] [%s]: %d",
             instance ? "parent" : "child",
             my_session->active ? "open" : "closed",
             PTR_IS_ERR(ptr) ? "ERR" : PTR_IS_OK(ptr) ? "OK" : "RSET",
             prev_debug_seq);
#endif

    spinlock_acquire(&my_session->tee_lock);

    if (!my_session->active)
    {
        MXS_INFO("Tee: Failed to return reply, session is closed");
        gwbuf_free(reply);
        rc = 0;
        if (my_session->waiting[PARENT])
        {
            GWBUF* errbuf = modutil_create_mysql_err_msg(1, 0, 1, "0000", "Session closed.");
            my_session->waiting[PARENT] = false;
            my_session->up.clientReply(my_session->up.instance,
                                       my_session->up.session,
                                       errbuf);
        }
        goto retblock;
    }

    branch = instance == NULL ? CHILD : PARENT;

    my_session->tee_partials[branch] = gwbuf_append(my_session->tee_partials[branch], reply);
    my_session->tee_partials[branch] = gwbuf_make_contiguous(my_session->tee_partials[branch]);
    complete = modutil_get_complete_packets(&my_session->tee_partials[branch]);

    if (complete == NULL)
    {
        /** Incomplete packet */
        MXS_DEBUG("tee.c: Incomplete packet, "
                  "waiting for a complete packet before forwarding.");
        rc = 1;
        goto retblock;
    }

    complete = gwbuf_make_contiguous(complete);

    if (my_session->tee_partials[branch] &&
        GWBUF_EMPTY(my_session->tee_partials[branch]))
    {
        gwbuf_free(my_session->tee_partials[branch]);
        my_session->tee_partials[branch] = NULL;
    }

    ptr = (unsigned char*) complete->start;

    if (my_session->replies[branch] == 0)
    {
        MXS_INFO("Tee: First reply to a query for [%s].", branch == PARENT ? "PARENT" : "CHILD");
        /* Reply is in a single packet if it is an OK, ERR or LOCAL_INFILE packet.
         * Otherwise the reply is a result set and the amount of packets is unknown.
         */
        if (PTR_IS_ERR(ptr) || PTR_IS_LOCAL_INFILE(ptr) ||
            PTR_IS_OK(ptr) || !my_session->multipacket[branch])
        {
            my_session->waiting[branch] = false;
            my_session->multipacket[branch] = false;
            if (PTR_IS_OK(ptr))
            {
                flags = get_response_flags(ptr, true);
                more_results = (flags & 0x08) && my_session->client_multistatement;
                if (more_results)
                {
                    MXS_INFO("Tee: [%s] waiting for more results.", branch == PARENT ? "PARENT" : "CHILD");
                }
            }
        }
#ifdef SS_DEBUG
        else
        {
            MXS_DEBUG("tee.c: [%ld] Waiting for a result set from %s session.",
                      my_session->d_id,
                      branch == PARENT ? "parent" : "child");
        }
#endif
    }

    if (my_session->waiting[branch])
    {
        eof = modutil_count_signal_packets(complete, my_session->use_ok, my_session->eof[branch] > 0, &more_results);
        more_results &= my_session->client_multistatement;
        my_session->eof[branch] += eof;

        if (my_session->eof[branch] >= min_eof)
        {
#ifdef SS_DEBUG
            MXS_DEBUG("tee.c [%ld] %s received last EOF packet",
                      my_session->d_id,
                      branch == PARENT ? "parent" : "child");
#endif
            my_session->waiting[branch] = more_results;
            if (more_results)
            {
                my_session->eof[branch] = 0;
            }
        }
    }

    if (branch == PARENT)
    {
        my_session->tee_replybuf = gwbuf_append(my_session->tee_replybuf, complete);
    }
    else
    {
        gwbuf_free(complete);
    }

    my_session->replies[branch]++;
    rc = 1;
    mpkt = my_session->multipacket[PARENT] || my_session->multipacket[CHILD];

    if (my_session->tee_replybuf != NULL)
    {

        if (my_session->branch_session == NULL)
        {
            rc = 0;
            gwbuf_free(my_session->tee_replybuf);
            my_session->tee_replybuf = NULL;
            MXS_ERROR("Tee child session was closed.");
        }

        if (mpkt)
        {

            if (my_session->waiting[PARENT])
            {
                route = true;

            }
            else if (my_session->eof[PARENT] >= min_eof &&
                     my_session->eof[CHILD] >= min_eof)
            {
                route = true;
#ifdef SS_DEBUG
                MXS_DEBUG("tee.c:[%ld] Routing final packet of response set.", my_session->d_id);
#endif
            }
        }
        else if (!my_session->waiting[PARENT] &&
                 !my_session->waiting[CHILD])
        {
#ifdef SS_DEBUG
            MXS_DEBUG("tee.c:[%ld] Routing single packet response.", my_session->d_id);
#endif
            route = true;
        }
    }

    if (route)
    {
#ifdef SS_DEBUG
        MXS_DEBUG("tee.c:[%ld] Routing buffer '%p' parent(waiting [%s] replies [%d] eof[%d])"
                  " child(waiting [%s] replies[%d] eof [%d])",
                  my_session->d_id,
                  my_session->tee_replybuf,
                  my_session->waiting[PARENT] ? "true" : "false",
                  my_session->replies[PARENT],
                  my_session->eof[PARENT],
                  my_session->waiting[CHILD] ? "true" : "false",
                  my_session->replies[CHILD],
                  my_session->eof[CHILD]);
#endif

        rc = my_session->up.clientReply(my_session->up.instance,
                                        my_session->up.session,
                                        my_session->tee_replybuf);
        my_session->tee_replybuf = NULL;
    }

    if (my_session->queue &&
        !my_session->waiting[PARENT] &&
        !my_session->waiting[CHILD])
    {
        GWBUF* buffer = modutil_get_next_MySQL_packet(&my_session->queue);
        GWBUF* clone = clone_query(my_session->instance, my_session, buffer);
        reset_session_state(my_session, buffer);
        route_single_query(my_session->instance, my_session, buffer, clone);
        MXS_INFO("tee: routing queued query");

    }

retblock:

    spinlock_release(&my_session->tee_lock);

    return rc;
}
Пример #19
0
/**
 * Loads a query from a file
 *@return 0 if successful, 1 if an error occurred
 */
int load_query()
{
	char** query_list = NULL;
	char* buffer = NULL;
	int i, qcount = 0, qbuff_sz = 10, rval = 0;
	int offset = 0;
	unsigned int qlen = 0;
	buffer = (char*)calloc(4092,sizeof(char));
	if(buffer == NULL){
		printf("Error: cannot allocate enough memory.\n");
		MXS_ERROR("cannot allocate enough memory.\n");
		return 1;
	}

	query_list = calloc(qbuff_sz,sizeof(char*));
	if(query_list == NULL){
		printf("Error: cannot allocate enough memory.\n");
		MXS_ERROR("cannot allocate enough memory.\n");
		free(buffer);
		return 1;
	}


	while((offset = fdgets(instance.infile,buffer,4092))){

		if(qbuff_sz <= qcount){
			char** tmpbuff = realloc(query_list,sizeof(char*)*qbuff_sz*2);
			if(tmpbuff == NULL){
				printf("Error: cannot allocate enough memory.\n");
				MXS_ERROR("cannot allocate enough memory.\n");
				rval = 1;
				goto retblock;
			}
			
			query_list = tmpbuff;
			qbuff_sz *= 2;
			
		}
		
		query_list[qcount] = calloc((offset + 1),sizeof(char));
		strcpy(query_list[qcount],buffer);
		offset = 0;
		qcount++;
		
	}

	/**TODO check what messes up the first querystring*/
	GWBUF** tmpbff = malloc(sizeof(GWBUF*)*(qcount + 1));
	if(tmpbff){
		for(i = 0;i<qcount;i++){
    
			tmpbff[i] = gwbuf_alloc(strlen(query_list[i]) + 6);

			if(tmpbff[i] == NULL)
				{
					printf("Error: cannot allocate a new buffer.\n");
					MXS_ERROR("cannot allocate a new buffer.\n");
					int x;
					for(x = 0;x<i;x++)
						{
							gwbuf_free(tmpbff[x]);
						}
					free(tmpbff);
					rval = 1;
					goto retblock;
				}

			gwbuf_set_type(tmpbff[i],GWBUF_TYPE_MYSQL);
			strcpy((char*)(tmpbff[i]->start + 5),query_list[i]);
			qlen = strlen(query_list[i]) + 1;
			tmpbff[i]->sbuf->data[0] = qlen;
			tmpbff[i]->sbuf->data[1] = (qlen << 8);
			tmpbff[i]->sbuf->data[2] = (qlen << 16);
			tmpbff[i]->sbuf->data[3] = 0x00;
			tmpbff[i]->sbuf->data[4] = 0x03;

		}
		tmpbff[qcount] = NULL;
		instance.buffer = tmpbff;
	}else{
		printf("Error: cannot allocate enough memory for buffers.\n");
		MXS_ERROR("cannot allocate enough memory for buffers.\n");    
		free_buffers();
	    rval = 1;
		goto retblock;
	}

	if(qcount < 1){
		rval = 1;
		goto retblock;
	}
  
	instance.buffer_count = qcount;

	retblock:

	for(i = 0;i<qcount;i++)
		{
			free(query_list[i]);
		}
	free(query_list);
	free(buffer);
	return rval;
}