Beispiel #1
0
GWBUF *gwbuf_clone_portion(
    GWBUF *buf,
    size_t start_offset,
    size_t length)
{
    GWBUF* clonebuf;

    CHK_GWBUF(buf);
    ss_dassert(start_offset+length <= GWBUF_LENGTH(buf));

    if ((clonebuf = (GWBUF *)malloc(sizeof(GWBUF))) == NULL)
    {
        ss_dassert(clonebuf != NULL);
        LOGIF(LE, (skygw_log_write_flush(
                       LOGFILE_ERROR,
                       "Error : Memory allocation failed due to %s.",
                       strerror(errno))));
        return NULL;
    }
    atomic_add(&buf->sbuf->refcount, 1);
    clonebuf->sbuf = buf->sbuf;
    clonebuf->gwbuf_type = buf->gwbuf_type; /*< clone info bits too */
    clonebuf->start = (void *)((char*)buf->start+start_offset);
    clonebuf->end = (void *)((char *)clonebuf->start+length);
    clonebuf->gwbuf_type = buf->gwbuf_type; /*< clone the type for now */
    clonebuf->properties = NULL;
    clonebuf->hint = NULL;
    clonebuf->gwbuf_info = buf->gwbuf_info;
    clonebuf->gwbuf_bufobj = buf->gwbuf_bufobj;
    clonebuf->next = NULL;
    clonebuf->tail = clonebuf;
    CHK_GWBUF(clonebuf);
    return clonebuf;

}
Beispiel #2
0
/** 
 * Creates MySQL protocol structure 
 *
 * @param dcb *          Must be non-NULL.
 * @param fd	
 *
 * @return 
 *
 * 
 * @details Protocol structure does not have fd because dcb is not
 * connected yet. 
 *
 */
MySQLProtocol* mysql_protocol_init(
        DCB* dcb,
        int  fd)
{
        MySQLProtocol* p;
        
	p = (MySQLProtocol *) calloc(1, sizeof(MySQLProtocol));
        ss_dassert(p != NULL);
        
        if (p == NULL) {
            int eno = errno;
            errno = 0;
            LOGIF(LE, (skygw_log_write_flush(
                    LOGFILE_ERROR,
                    "%lu [mysql_init_protocol] MySQL protocol init failed : "
                    "memory allocation due error  %d, %s.",
                    pthread_self(),
                    eno,
                    strerror(eno))));
            goto return_p;
        }
	p->state = MYSQL_ALLOC;
#if defined(SS_DEBUG)
        p->protocol_chk_top = CHK_NUM_PROTOCOL;
        p->protocol_chk_tail = CHK_NUM_PROTOCOL;
#endif
        /*< Assign fd with protocol */
        p->fd = fd;
	p->owner_dcb = dcb;
        CHK_PROTOCOL(p);
return_p:
        return p;
}
Beispiel #3
0
/**
 * Increment the usage count of a gateway buffer. This gets a new
 * GWBUF structure that shares the actual data with the existing
 * GWBUF structure but allows for the data copy to be avoided and
 * also for each GWBUF to point to different portions of the same
 * SHARED_BUF.
 *
 * @param buf The buffer to use
 * @return A new GWBUF structure
 */
GWBUF *
gwbuf_clone(GWBUF *buf)
{
    GWBUF	*rval;

    if ((rval = (GWBUF *)calloc(1,sizeof(GWBUF))) == NULL)
    {
        ss_dassert(rval != NULL);
        LOGIF(LE, (skygw_log_write_flush(
                       LOGFILE_ERROR,
                       "Error : Memory allocation failed due to %s.",
                       strerror(errno))));
        return NULL;
    }

    atomic_add(&buf->sbuf->refcount, 1);
    rval->sbuf = buf->sbuf;
    rval->start = buf->start;
    rval->end = buf->end;
    rval->gwbuf_type = buf->gwbuf_type;
    rval->gwbuf_info = buf->gwbuf_info;
    rval->gwbuf_bufobj = buf->gwbuf_bufobj;
    rval->tail = rval;
    CHK_GWBUF(rval);
    return rval;
}
Beispiel #4
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;

}
Beispiel #5
0
/**
 * List the defined services in a tabular format.
 *
 * @param dcb		DCB to print the service list to.
 */
void
dListServices(DCB *dcb)
{
SERVICE	*ptr;

	spinlock_acquire(&service_spin);
	ptr = allServices;
	if (ptr)
	{
		dcb_printf(dcb, "Services.\n");
		dcb_printf(dcb, "--------------------------+----------------------+--------+---------------\n");
		dcb_printf(dcb, "%-25s | %-20s | #Users | Total Sessions\n",
			"Service Name", "Router Module");
		dcb_printf(dcb, "--------------------------+----------------------+--------+---------------\n");
	}
	while (ptr)
	{
		ss_dassert(ptr->stats.n_current >= 0);
		dcb_printf(dcb, "%-25s | %-20s | %6d | %5d\n",
			ptr->name, ptr->routerModule,
			ptr->stats.n_current, ptr->stats.n_sessions);
		ptr = ptr->next;
	}
	if (allServices)
		dcb_printf(dcb, "--------------------------+----------------------+--------+---------------\n\n");
	spinlock_release(&service_spin);
}
Beispiel #6
0
int session_unlink_dcb(SESSION* session,
                       DCB*     dcb)
{
    int nlink;

    CHK_SESSION(session);

    spinlock_acquire(&session->ses_lock);
    ss_dassert(session->refcount > 0);
    /*<
     * Remove dcb from session's router_client_session.
     */
    nlink = atomic_add(&session->refcount, -1);
    nlink -= 1;

    if (nlink == 0)
    {
        session->state = SESSION_STATE_TO_BE_FREED;
    }

    if (dcb != NULL)
    {
        if (session->client_dcb == dcb)
        {
            session->client_dcb = NULL;
        }
        dcb->session = NULL;
    }
    spinlock_release(&session->ses_lock);

    return nlink;
}
Beispiel #7
0
/**
 * Remove a descriptor from the set of descriptors within the
 * polling environment.
 * The state change command may fail because concurrent threads may call
 * dcb_set_state simultaneously and the conflict is prevented in dcb_set_state.
 *
 * @param dcb	The descriptor to remove
 * @return	-1 on error or 0 on success
 */
int
poll_remove_dcb(DCB *dcb)
{
        struct	epoll_event ev;
        int                 rc = -1;
        dcb_state_t         old_state = DCB_STATE_UNDEFINED;
        dcb_state_t         new_state = DCB_STATE_NOPOLLING;

        CHK_DCB(dcb);

        /*< It is possible that dcb has already been removed from the set */
        if (dcb->state != DCB_STATE_POLLING) 
	{
                if (dcb->state == DCB_STATE_NOPOLLING ||
                    dcb->state == DCB_STATE_ZOMBIE)
                {
                        rc = 0;
                }
                goto return_rc;
        }
        /*<
         * Set state to NOPOLLING and remove dcb from poll set.
         */
        if (dcb_set_state(dcb, new_state, &old_state)) 
	{
		/**
		 * Only positive fds can be removed from epoll set.
		 */		 
		if (dcb->fd > 0) 
		{
			rc = epoll_ctl(epoll_fd, EPOLL_CTL_DEL, dcb->fd, &ev);

			if (rc != 0) {
				int eno = errno;
				errno = 0;
				LOGIF(LE, (skygw_log_write_flush(
					LOGFILE_ERROR,
					"Error : epoll_ctl failed due %d, %s.",
					eno,
					strerror(eno))));
			}
			ss_dassert(rc == 0); /*< trap in debug */
		}
        }
        /*<
         * This call was redundant, but the end result is correct.
         */
        else if (old_state == new_state)
        {
                rc = 0;
                goto return_rc;
        }
        
        /*< Set bit for each maxscale thread */
        bitmask_copy(&dcb->memdata.bitmask, poll_bitmask()); 
        rc = 0;
return_rc:
        return rc;
}
Beispiel #8
0
/**
 * Allocate a new gateway buffer structure of size bytes.
 *
 * For now we allocate memory directly from malloc for buffer the management
 * structure and the actual data buffer itself. We may swap at a future date
 * to a more effecient mechanism.
 *
 * @param	size The size in bytes of the data area required
 * @return	Pointer to the buffer structure or NULL if memory could not
 *		be allocated.
 */
GWBUF	*
gwbuf_alloc(unsigned int size)
{
    GWBUF		*rval;
    SHARED_BUF	*sbuf;

    /* Allocate the buffer header */
    if ((rval = (GWBUF *)malloc(sizeof(GWBUF))) == NULL)
    {
        goto retblock;;
    }

    /* Allocate the shared data buffer */
    if ((sbuf = (SHARED_BUF *)malloc(sizeof(SHARED_BUF))) == NULL)
    {
        free(rval);
        rval = NULL;
        goto retblock;
    }

    /* Allocate the space for the actual data */
    if ((sbuf->data = (unsigned char *)malloc(size)) == NULL)
    {
        ss_dassert(sbuf->data != NULL);
        free(rval);
        free(sbuf);
        rval = NULL;
        goto retblock;
    }
    spinlock_init(&rval->gwbuf_lock);
    rval->start = sbuf->data;
    rval->end = (void *)((char *)rval->start+size);
    sbuf->refcount = 1;
    rval->sbuf = sbuf;
    rval->next = NULL;
    rval->tail = rval;
    rval->hint = NULL;
    rval->properties = NULL;
    rval->gwbuf_type = GWBUF_TYPE_UNDEFINED;
    rval->gwbuf_info = GWBUF_INFO_NONE;
    rval->gwbuf_bufobj = NULL;
    CHK_GWBUF(rval);
retblock:
    if (rval == NULL)
    {
        LOGIF(LE, (skygw_log_write_flush(
                       LOGFILE_ERROR,
                       "Error : Memory allocation failed due to %s.",
                       strerror(errno))));
    }
    return rval;
}
Beispiel #9
0
/**
 * Error Reply routine
 *
 * The routine will reply to client errors and/or closing the session
 * or try to open a new backend connection.
 *
 * @param       instance        The router instance
 * @param       router_session  The router session
 * @param       message         The error message to reply
 * @param       backend_dcb     The backend DCB
 * @param       action     	The action: REPLY, REPLY_AND_CLOSE, NEW_CONNECTION
 *
 */
static  void
errorReply(
    ROUTER *instance,
    void   *router_session,
    char   *message,
    DCB    *backend_dcb,
    int     action)
{
    DCB		*client = NULL;
    SESSION         *session = backend_dcb->session;
    client = session->client;

    ss_dassert(client != NULL);
}
Beispiel #10
0
/**
 * Trim bytes form the end of a GWBUF structure. If the
 * buffer has n_bytes or less then it will be freed and
 * NULL will be returned.
 *
 * This routine assumes the buffer is not part of a chain
 *
 * @param buf		The buffer to trim
 * @param n_bytes	The number of bytes to trim off
 * @return 		The buffer chain or NULL if buffer has <= n_bytes
 */
GWBUF *
gwbuf_trim(GWBUF *buf, unsigned int n_bytes)
{
    ss_dassert(buf->next == NULL);

    if (GWBUF_LENGTH(buf) <= n_bytes)
    {
        gwbuf_consume(buf, GWBUF_LENGTH(buf));
        return NULL;
    }
    buf->end = (void *)((char *)buf->end - n_bytes);

    return buf;
}
Beispiel #11
0
/**
 * Error Handler routine
 *
 * The routine will handle errors that occurred in backend writes.
 *
 * @param       instance        The router instance
 * @param       router_session  The router session
 * @param       message         The error message to reply
 * @param       backend_dcb     The backend DCB
 * @param       action     	The action: REPLY, REPLY_AND_CLOSE, NEW_CONNECTION
 *
 */
static  void
handleError(
        ROUTER           *instance,
        void             *router_session,
        GWBUF            *errbuf,
        DCB              *backend_dcb,
        error_action_t   action,
        bool             *succp)
{
	DCB		*client = NULL;
	SESSION         *session = backend_dcb->session;
	client = session->client;

	ss_dassert(client != NULL);
}
Beispiel #12
0
/**
 * Client Reply routine
 *
 * The routine will reply to client data from backend server
 *
 * @param       instance        The router instance
 * @param       router_session  The router session
 * @param       backend_dcb     The backend DCB
 * @param       queue           The GWBUF with reply data
 */
static  void
clientReply(
        ROUTER *instance,
        void   *router_session,
        GWBUF  *queue,
        DCB    *backend_dcb)
{
	DCB *client ;

	client = backend_dcb->session->client;

	ss_dassert(client != NULL);

	SESSION_ROUTE_REPLY(backend_dcb->session, queue);
}
Beispiel #13
0
/**
 * Client Reply routine
 *
 * The routine will reply to client data from backend server
 *
 * @param       instance        The router instance
 * @param       router_session  The router session
 * @param       backend_dcb     The backend DCB
 * @param       queue           The GWBUF with reply data
 */
static  void
clientReply(
    ROUTER *instance,
    void   *router_session,
    GWBUF  *queue,
    DCB    *backend_dcb)
{
    DCB *client = NULL;

    client = backend_dcb->session->client;

    ss_dassert(client != NULL);

    client->func.write(client, queue);
}
Beispiel #14
0
/**
 * Returns pointer to GWBUF of a requested type.
 * As of 10.3.14 only MySQL to plain text conversion is supported.
 * Return NULL if conversion between types is not supported or due lacking
 * type information.
 */
GWBUF *gwbuf_clone_transform(
        GWBUF *      head, 
        gwbuf_type_t targettype)
{
        gwbuf_type_t src_type;
        GWBUF*       clonebuf;
        
        CHK_GWBUF(head);
        src_type = head->gwbuf_type;
        
        if (targettype == GWBUF_TYPE_UNDEFINED ||
                src_type == GWBUF_TYPE_UNDEFINED ||
                src_type == GWBUF_TYPE_PLAINSQL ||
                targettype == src_type)
        {
                clonebuf = NULL;
                goto return_clonebuf;
        }

        switch (src_type)
        {
                case GWBUF_TYPE_MYSQL:
                        if (targettype == GWBUF_TYPE_PLAINSQL)
                        {
                                /** Crete reference to string part of buffer */
                                clonebuf = gwbuf_clone_portion(
                                                head, 
                                                5, 
                                                GWBUF_LENGTH(head)-5);                                
                                ss_dassert(clonebuf != NULL);
                                /** Overwrite the type with new format */
                                clonebuf->gwbuf_type = targettype;
                        }
                        else
                        {
                                clonebuf = NULL;
                        }
                        break;
                        
                default:
                        clonebuf = NULL;
                        break;                        
        } /*< switch (src_type) */
        
return_clonebuf:
        return clonebuf;
}
Beispiel #15
0
/**
 * Returns pointer to GWBUF of a requested type.
 * As of 10.3.14 only MySQL to plain text conversion is supported.
 * Return NULL if conversion between types is not supported or due lacking
 * type information.
 */
GWBUF *gwbuf_clone_transform(
    GWBUF *      head,
    gwbuf_type_t targettype)
{
    gwbuf_type_t src_type;
    GWBUF*       clonebuf;

    CHK_GWBUF(head);
    src_type = head->gwbuf_type;

    if (targettype == GWBUF_TYPE_UNDEFINED ||
            src_type == GWBUF_TYPE_UNDEFINED ||
            src_type == GWBUF_TYPE_PLAINSQL ||
            targettype == src_type)
    {
        clonebuf = NULL;
        goto return_clonebuf;
    }

    if (GWBUF_IS_TYPE_MYSQL(head))
    {
        if (GWBUF_TYPE_PLAINSQL == targettype)
        {
            /** Crete reference to string part of buffer */
            clonebuf = gwbuf_clone_portion(
                           head,
                           5,
                           GWBUF_LENGTH(head)-5);
            ss_dassert(clonebuf != NULL);
            /** Overwrite the type with new format */
            gwbuf_set_type(clonebuf, targettype);
        }
        else
        {
            clonebuf = NULL;
        }
    }
    else
    {
        clonebuf = NULL;
    }

return_clonebuf:
    return clonebuf;
}
Beispiel #16
0
static query_test_t* query_test_init(
        const char*        query_str,
        skygw_query_type_t query_type,
        bool               case_should_fail,
        bool               exec_also_in_server)
{
        query_test_t* qtest;

        qtest = (query_test_t *)calloc(1, sizeof(query_test_t));
        ss_dassert(qtest != NULL);
        qtest->qt_chk_top = CHK_NUM_QUERY_TEST;
        qtest->qt_chk_tail = CHK_NUM_QUERY_TEST;
        qtest->qt_query_str = query_str;
        qtest->qt_query_type = query_type;
        qtest->qt_should_fail = case_should_fail;
        qtest->qt_exec_also_in_server = exec_also_in_server;
        return qtest;
}
Beispiel #17
0
/**
 * gw_mysql_close
 *
 * close a connection if opened
 * free data scructure for MySQLProtocol
 *
 * @param ptr The MySQLProtocol ** to close/free
 *
 */
void gw_mysql_close(MySQLProtocol **ptr) {
	MySQLProtocol *conn = *ptr;

        ss_dassert(*ptr != NULL);
        
	if (*ptr == NULL)
		return;


	if (conn->fd > 0) {
		/* COM_QUIT will not be sent here, but from the caller of this routine! */
		close(conn->fd);
	} else {
		// no socket here
	}

	free(*ptr);

	*ptr = NULL;
}
Beispiel #18
0
/**
 * @node Unlink from backend server, unlink from router's connection list,
 * and free memory of a router client session.  
 *
 * Parameters:
 * @param router - <usage>
 *          <description>
 *
 * @param router_cli_ses - <usage>
 *          <description>
 *
 * @return void
 *
 * 
 * @details (write detailed description here)
 *
 */
static void freeSession(
        ROUTER* router_instance,
        void*   router_client_ses)
{
        ROUTER_INSTANCE*   router = (ROUTER_INSTANCE *)router_instance;
        ROUTER_CLIENT_SES* router_cli_ses =
                (ROUTER_CLIENT_SES *)router_client_ses;
        int prev_val;
        
        prev_val = atomic_add(&router_cli_ses->backend->current_connection_count, -1);
        ss_dassert(prev_val > 0);
        
	spinlock_acquire(&router->lock);
        
	if (router->connections == router_cli_ses) {
		router->connections = router_cli_ses->next;
        } else {
		ROUTER_CLIENT_SES *ptr = router->connections;
                
		while (ptr != NULL && ptr->next != router_cli_ses) {
			ptr = ptr->next;
                }
                
		if (ptr != NULL) {
			ptr->next = router_cli_ses->next;
                }
	}
	spinlock_release(&router->lock);

        LOGIF(LD, (skygw_log_write_flush(
                LOGFILE_DEBUG,
                "%lu [freeSession] Unlinked router_client_session %p from "
                "router %p and from server on port %d. Connections : %d. ",
                pthread_self(),
                router_cli_ses,
                router,
                router_cli_ses->backend->server->port,
                prev_val-1)));

        free(router_cli_ses);
}
Beispiel #19
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;
}
Beispiel #20
0
bool gwbuf_set_type(
        GWBUF*       buf,
        gwbuf_type_t type)
{
        bool succp;
        CHK_GWBUF(buf);
        
        switch (type) {
                case GWBUF_TYPE_MYSQL:
                case GWBUF_TYPE_PLAINSQL:
                case GWBUF_TYPE_UNDEFINED:
                        buf->gwbuf_type = type;
                        succp = true;
                        break;
                default:
                        succp = false;
                        break;
        }
        ss_dassert(succp);
        return succp;
}
Beispiel #21
0
/**
 * Add a buffer object to GWBUF buffer.
 *
 * @param buf           GWBUF where object is added
 * @param id            Type identifier for object
 * @param data          Object data
 * @param donefun_dp    Clean-up function to be executed before buffer is freed.
 */
void gwbuf_add_buffer_object(
    GWBUF* buf,
    bufobj_id_t id,
    void*  data,
    void (*donefun_fp)(void *))
{
    buffer_object_t** p_b;
    buffer_object_t*  newb;

    CHK_GWBUF(buf);
    newb = (buffer_object_t *)malloc(sizeof(buffer_object_t));
    ss_dassert(newb != NULL);

    if (newb == NULL)
    {
        LOGIF(LE, (skygw_log_write_flush(
                       LOGFILE_ERROR,
                       "Error : Memory allocation failed due to %s.",
                       strerror(errno))));
        return;
    }
    newb->bo_id = id;
    newb->bo_data = data;
    newb->bo_donefun_fp = donefun_fp;
    newb->bo_next = NULL;
    /** Lock */
    spinlock_acquire(&buf->gwbuf_lock);
    p_b = &buf->gwbuf_bufobj;
    /** Search the end of the list and add there */
    while (*p_b != NULL)
    {
        p_b = &(*p_b)->bo_next;
    }
    *p_b = newb;
    /** Set flag */
    buf->gwbuf_info |= GWBUF_INFO_PARSED;
    /** Unlock */
    spinlock_release(&buf->gwbuf_lock);
}
Beispiel #22
0
/**
 * Add a property to a buffer.
 *
 * @param buf	The buffer to add the property to
 * @param name	The property name
 * @param value	The property value
 * @return	Non-zero on success
 */
int
gwbuf_add_property(GWBUF *buf, char *name, char *value)
{
    BUF_PROPERTY	*prop;

    if ((prop = malloc(sizeof(BUF_PROPERTY))) == NULL)
    {
        ss_dassert(prop != NULL);

        LOGIF(LE, (skygw_log_write_flush(
                       LOGFILE_ERROR,
                       "Error : Memory allocation failed due to %s.",
                       strerror(errno))));
        return 0;
    }
    prop->name = strdup(name);
    prop->value = strdup(value);
    spinlock_acquire(&buf->gwbuf_lock);
    prop->next = buf->properties;
    buf->properties = prop;
    spinlock_release(&buf->gwbuf_lock);
    return 1;
}
Beispiel #23
0
static int handle_state_switch(DCB* dcb,DCB_REASON reason, void * routersession)
{
    ss_dassert(dcb != NULL);
    SESSION* session = dcb->session;
    ROUTER_CLIENT_SES* rses = (ROUTER_CLIENT_SES*)routersession;
    SERVICE* service = session->service;
    ROUTER* router = (ROUTER *)service->router;

    switch(reason)
    {
	case DCB_REASON_CLOSE:
        dcb->func.close(dcb);
        break;
    case DCB_REASON_DRAINED:
        /** Do we need to do anything? */
        break;
    case DCB_REASON_HIGH_WATER:
        /** Do we need to do anything? */
        break;
    case DCB_REASON_LOW_WATER:
        /** Do we need to do anything? */
        break;
    case DCB_REASON_ERROR:
        dcb->func.error(dcb);
        break;
    case DCB_REASON_HUP:
        dcb->func.hangup(dcb);
        break;
    case DCB_REASON_NOT_RESPONDING:
        dcb->func.hangup(dcb);
        break;
    default:
        break;
    }

    return 0;
}
Beispiel #24
0
GWBUF *gwbuf_clone_portion(
        GWBUF *buf,
        size_t start_offset,
        size_t length)
{
        GWBUF* clonebuf;
        
        CHK_GWBUF(buf);
        ss_dassert(start_offset+length <= GWBUF_LENGTH(buf));
        
        if ((clonebuf = (GWBUF *)malloc(sizeof(GWBUF))) == NULL)
        {
                return NULL;
        }
        atomic_add(&buf->sbuf->refcount, 1);
        clonebuf->sbuf = buf->sbuf;
        clonebuf->start = (void *)((char*)buf->start)+start_offset;
        clonebuf->end = (void *)((char *)clonebuf->start)+length;
        clonebuf->gwbuf_type = buf->gwbuf_type; /*< clone the type for now */ 
        clonebuf->next = NULL;
        CHK_GWBUF(clonebuf);
        return clonebuf;
        
}
Beispiel #25
0
/**
 * Deallocate the specified session
 *
 * @param session	The session to deallocate
 */
bool session_free(
        SESSION *session)
{
        bool    succp = false;
        SESSION *ptr;
        int     nlink;
	int	i;

        CHK_SESSION(session);

        /*<
         * Remove one reference. If there are no references left,
         * free session.
         */
        nlink = session_unlink_dcb(session, NULL);

        if (nlink != 0) {
                ss_dassert(nlink > 0);
                goto return_succp;
        }
        
	/* First of all remove from the linked list */
	spinlock_acquire(&session_spin);
	if (allSessions == session)
	{
		allSessions = session->next;
	}
	else
	{
		ptr = allSessions;
		while (ptr && ptr->next != session)
		{
			ptr = ptr->next;
		}
		if (ptr)
			ptr->next = session->next;
	}
	spinlock_release(&session_spin);
	atomic_add(&session->service->stats.n_current, -1);

	/* Free router_session and session */
        if (session->router_session) {
                session->service->router->freeSession(
                        session->service->router_instance,
                        session->router_session);
        }
	if (session->n_filters)
	{
		for (i = 0; i < session->n_filters; i++)
		{
			session->filters[i].filter->obj->closeSession(
					session->filters[i].instance,
					session->filters[i].session);
		}
		for (i = 0; i < session->n_filters; i++)
		{
			session->filters[i].filter->obj->freeSession(
					session->filters[i].instance,
					session->filters[i].session);
		}
		free(session->filters);
	}
	free(session);
        succp = true;
        
return_succp :
        return succp;
}
Beispiel #26
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 #27
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 #28
0
/**
 * Associate a new session with this instance of the filter.
 *
 * Create the file to log to and open it.
 *
 * @param instance	The filter instance data
 * @param session	The session itself
 * @return Session specific data for this session
 */
static void *
newSession(FILTER *instance, SESSION *session)
{
    TEE_INSTANCE *my_instance = (TEE_INSTANCE *) instance;
    TEE_SESSION *my_session;
    char *remote, *userName;

    if (strcmp(my_instance->service->name, session->service->name) == 0)
    {
        MXS_ERROR("%s: Recursive use of tee filter in service.",
                  session->service->name);
        my_session = NULL;
        goto retblock;
    }

    HASHTABLE* ht = hashtable_alloc(100, simple_str_hash, strcmp);
    bool is_loop = detect_loops(my_instance, ht, session->service);
    hashtable_free(ht);

    if (is_loop)
    {
        MXS_ERROR("%s: Recursive use of tee filter in service.",
                  session->service->name);
        my_session = NULL;
        goto retblock;
    }

    if ((my_session = calloc(1, sizeof(TEE_SESSION))) != NULL)
    {
        my_session->active = 1;
        my_session->residual = 0;
        my_session->tee_replybuf = NULL;
        my_session->client_dcb = session->client;
        my_session->instance = my_instance;
        my_session->client_multistatement = false;
        my_session->queue = NULL;
        spinlock_init(&my_session->tee_lock);
        if (my_instance->source &&
            (remote = session_get_remote(session)) != NULL)
        {
            if (strcmp(remote, my_instance->source))
            {
                my_session->active = 0;

                MXS_WARNING("Tee filter is not active.");
            }
        }
        userName = session_getUser(session);

        if (my_instance->userName &&
            userName &&
            strcmp(userName, my_instance->userName))
        {
            my_session->active = 0;

            MXS_WARNING("Tee filter is not active.");
        }

        if (my_session->active)
        {
            DCB* dcb;
            SESSION* ses;
            FILTER_DEF* dummy;
            UPSTREAM* dummy_upstream;

            if ((dcb = dcb_clone(session->client)) == NULL)
            {
                freeSession(instance, (void *) my_session);
                my_session = NULL;

                MXS_ERROR("Creating client DCB for Tee "
                          "filter failed. Terminating session.");

                goto retblock;
            }

            if ((dummy = filter_alloc("tee_dummy", "tee_dummy")) == NULL)
            {
                dcb_close(dcb);
                freeSession(instance, (void *) my_session);
                my_session = NULL;
                MXS_ERROR("tee: Allocating memory for "
                          "dummy filter definition failed."
                          " Terminating session.");

                goto retblock;
            }



            if ((ses = session_alloc(my_instance->service, dcb)) == NULL)
            {
                filter_free(dummy);
                dcb_close(dcb);
                freeSession(instance, (void *) my_session);
                my_session = NULL;
                MXS_ERROR("Creating client session for Tee "
                          "filter failed. Terminating session.");

                goto retblock;
            }

            ss_dassert(ses->ses_is_child);

            dummy->obj = GetModuleObject();
            dummy->filter = NULL;
            my_session->branch_session = ses;
            my_session->branch_dcb = dcb;
            my_session->dummy_filterdef = dummy;

            if ((dummy_upstream = filterUpstream(
                                                 dummy, my_session, &ses->tail)) == NULL)
            {
                filter_free(dummy);
                closeSession(instance, (void*) my_session);
                dcb_close(dcb);
                free(my_session);
                MXS_ERROR("tee: Allocating memory for"
                          "dummy upstream failed."
                          " Terminating session.");

                return NULL;
            }

            ses->tail = *dummy_upstream;
            MySQLProtocol* protocol = (MySQLProtocol*) session->client->protocol;
            my_session->use_ok = protocol->client_capabilities & (1 << 6);
            free(dummy_upstream);
        }
    }
retblock:
    return my_session;
}
Beispiel #29
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 #30
0
int main(int argc, char** argv)
{
        slist_cursor_t*    c;
        const char*        q;
        query_test_t*      qtest;
        bool               succp;
        bool               failp = true;
        unsigned int       f = 0;
        int                nsucc = 0;
        int                nfail = 0;
        int                rc = 0;
        MYSQL*             mysql;
        char*              workingdir;
        char               ddoption[1024];

        ss_dfprintf(stderr, ">> testmain\n");
        c = slist_init();

        /** Test some functions */
        q = "SELECT MY_UDF('Hello')";
        slcursor_add_case(
                c,
                query_test_init(q, QUERY_TYPE_WRITE, false, true));

        /** This could be QUERY_TYPE_LOCAL_READ */
        q = "SELECT repeat('a', 1024)";
        slcursor_add_case(
                c,
                query_test_init(q, QUERY_TYPE_READ, false, true));

        /** This could be QUERY_TYPE_LOCAL_READ */
        q = "SELECT soundex('Hello')";
        slcursor_add_case(
                c,
                query_test_init(q, QUERY_TYPE_READ, false, true));

        q = "SELECT ssoundexx('Hello')";
        slcursor_add_case(
                c,
                query_test_init(q, QUERY_TYPE_WRITE, false, true));

        /** This could be QUERY_TYPE_LOCAL_READ */
        q = "SELECT now()";
        slcursor_add_case(
                c,
                query_test_init(q, QUERY_TYPE_READ, false, true));

        /** This could be QUERY_TYPE_LOCAL_READ */
        q = "SELECT rand()";
        slcursor_add_case(
                c,
                query_test_init(q, QUERY_TYPE_READ, false, true));

        q = "SELECT rand(234), MY_UDF('Hello'), soundex('Hello')";
        slcursor_add_case(
                c,
                query_test_init(q, QUERY_TYPE_WRITE, false, true));

        
        /** Read-only SELECTs */
        q = "SELECT user from mysql.user";
        slcursor_add_case(
                c,
                query_test_init(q, QUERY_TYPE_READ, false, true));

        q = "select tt1.id, tt2.id from t1 tt1, t2 tt2 where tt1.name is "
                "not null and tt2.name is not null";
        slcursor_add_case(
                c,
                query_test_init(q, QUERY_TYPE_READ, false, false));

        /** SELECT ..INTO clauses > session updates */
        q = "SELECT user from mysql.user INTO DUMPFILE '/tmp/dump1'";
        slcursor_add_case(
                c,
                query_test_init(q, QUERY_TYPE_SESSION_WRITE, false, false));

        q = "SELECT user INTO DUMPFILE '/tmp/dump2 ' from mysql.user";
        slcursor_add_case(
                c,
                query_test_init(q, QUERY_TYPE_SESSION_WRITE, false, false));

        q = "SELECT user from mysql.user INTO OUTFILE '/tmp/out1'";
        slcursor_add_case(
                c,
                query_test_init(q, QUERY_TYPE_SESSION_WRITE, false, false));

        /** Database and table name must be separated by a dot */
        q = "SELECT user INTO OUTFILE '/tmp/out2 ' from mysql-user";
        slcursor_add_case(
                c,
                query_test_init(q, QUERY_TYPE_SESSION_WRITE, true, false));

        /** Database and table name must be separated by a dot */
        q = "SELECT user INTO OUTFILE '/tmp/out2 ' from mysql_foo_user";
        slcursor_add_case(
                c,
                query_test_init(q, QUERY_TYPE_SESSION_WRITE, false, false));
        
        q = "SELECT user FROM mysql.user limit 1 INTO @local_variable";
        slcursor_add_case(
                c,
                query_test_init(q, QUERY_TYPE_SESSION_WRITE, false, false));

        q = "SELECT user INTO @local_variable FROM mysql.user limit 1";
        slcursor_add_case(
                c,
                query_test_init(q, QUERY_TYPE_SESSION_WRITE, false, false));
        
        q = "SELECT non_existent_attr INTO @d FROM non_existent_table";
        slcursor_add_case(
                c,
                query_test_init(q, QUERY_TYPE_SESSION_WRITE, false, false));

        q = "select * from table1 "
                "where table1.field IN "
                "(select * from table1a union select * from table1b) union "
                "select * from table2 where table2.field = "
                "(select (select f1 from table2a where table2a.f2 = table2b.f3) "
                "from table2b where table2b.f1 = table2.f2) union "
                "select * from table3";
        slcursor_add_case(
                c,
                query_test_init(q, QUERY_TYPE_READ, false, true));
                
        /** RENAME TABLEs */
        q = "RENAME TABLE T1 to T2";
        slcursor_add_case(
                c,
                query_test_init(q, QUERY_TYPE_WRITE, false, false));

        
        /** INSERTs */
        q = "INSERT INTO T1 (SELECT * FROM T2)";
        slcursor_add_case(
                c,
                query_test_init(q, QUERY_TYPE_WRITE, false, true));

        q = "INSERT INTO T1 VALUES(2, 'foo', 'toomanyattributes')";
        slcursor_add_case(
                c,
                query_test_init(q, QUERY_TYPE_WRITE, false, true));

        q = "INSERT INTO T2 VALUES(1, 'sthrgey')";
        slcursor_add_case(
                c,
                query_test_init(q, QUERY_TYPE_WRITE, false, false));

        q = "INSERT INTO T2 VALUES(8, 'ergstrhe')";
        slcursor_add_case(
                c,
                query_test_init(q, QUERY_TYPE_WRITE, false, false));

        q = "INSERT INTO T2 VALUES(9, NULL)";
        slcursor_add_case(
                c,
                query_test_init(q, QUERY_TYPE_WRITE, false, false));


        /** Ok, delimeter is client-side parameter which shouldn't be handled
         * on server side.
         */
        q = "delimiter //";
        slcursor_add_case(
                c,
                query_test_init(q, QUERY_TYPE_SESSION_WRITE, true, true));

        /** SETs, USEs > Session updates */
        q = "SET @a=1";
        slcursor_add_case(
                c,
                query_test_init(q, QUERY_TYPE_SESSION_WRITE, false, true));
        
        q = "USE TEST";
        slcursor_add_case(
                c,
                query_test_init(q, QUERY_TYPE_SESSION_WRITE, false, false));

        
        /** Object creation statements */
        q = "create procedure si (out param1 int) \nbegin select count(*) "
                "into param1 from t1; \nend";
        slcursor_add_case(
                c,
                query_test_init(q, QUERY_TYPE_WRITE, false, true));
        
        q = "CREATE TABLE T1 (id integer primary key, name varchar(10))";
        slcursor_add_case(
                c,
                query_test_init(q, QUERY_TYPE_WRITE, false, true));

        q = "DROP TABLE T1";
        slcursor_add_case(
                c,
                query_test_init(q, QUERY_TYPE_WRITE, false, false));

        q = "ALTER TABLE T1 ADD COLUMN WHYME INTEGER NOT NULL";
        slcursor_add_case(
                c,
                query_test_init(q, QUERY_TYPE_WRITE, false, false));

        q = "TRUNCATE TABLE T1";
        slcursor_add_case(
                c,
                query_test_init(q, QUERY_TYPE_WRITE, false, false));

        q = "DROP SERVER IF EXISTS VICTIMSRV";
        slcursor_add_case(
                c,
                query_test_init(q, QUERY_TYPE_SESSION_WRITE, false, true));

        q = "CREATE USER FOO IDENTIFIED BY 'BAR'";
        slcursor_add_case(
                c,
                query_test_init(q, QUERY_TYPE_WRITE, false, true));

        q = "OPTIMIZE NO_WRITE_TO_BINLOG TABLE T1";
        slcursor_add_case(
                c,
                query_test_init(q, QUERY_TYPE_WRITE, false, true));

        q = "SELECT NOW();CREATE TABLE T1 (ID INTEGER);"
                "SET sql_log_bin=0;CREATE TABLE T2 (ID INTEGER)";
        slcursor_add_case(
                c,
                query_test_init(q, QUERY_TYPE_WRITE, false, true));
        
        
        /** Setting database makes this SESSION_WRITE */
        q = "USE TEST;CREATE TABLE T1 (ID INTEGER);"
                "SET sql_log_bin=0;CREATE TABLE T2 (ID INTEGER)";
        slcursor_add_case(
                c,
                query_test_init(q, QUERY_TYPE_SESSION_WRITE, false, true));
        
        /**
         * Init libmysqld.
         */
        workingdir = getenv("PWD");
        
        if (workingdir == NULL) {
                fprintf(stderr,
                        "Failed to resolve the working directory, $PWD is not "
                        "set.\n");
                ss_dassert(workingdir != NULL);
        } else if (access(workingdir, R_OK) != 0) {
                char errbuf[STRERROR_BUFLEN];
                fprintf(stderr,
                        "Failed to access the working directory due %d, %s\n",
                        errno,
                        strerror_r(errno, errbuf, sizeof(errbuf)));
                ss_dassert(false);
        } else {
                char** so = server_options;
                snprintf(datadir, 1023, "%s/data", workingdir);
                mkdir(datadir, 0777);
                snprintf(ddoption, 1023, "--datadir=%s", datadir);

                while (strncmp(*so++, "--datadir=", 10) != 0) ;

                if (*so == NULL) {
                        fprintf(stderr, "Failed to find datadir option.\n");
                        ss_dassert(*so != NULL);
                }
                *so = ddoption;
                
                snprintf(mysqldir, 1023, "%s/mysql", workingdir);
                setenv("MYSQL_HOME", mysqldir, 1);
        }
        failp = mysql_library_init(num_elements, server_options, server_groups);

        if (failp) {
                MYSQL* mysql = mysql_init(NULL);
                ss_dassert(mysql != NULL);
                fprintf(stderr,
                        "mysql_init failed, %d : %s\n",
                        mysql_errno(mysql),
                        mysql_error(mysql));
                ss_dassert(!failp);
        }

        fprintf(stderr,
                "\nExecuting selected cases in "
                "skygw_query_classifier_get_type :\n\n");
        /**
         * Set cursor to the beginning, scan through the list and execute
         * test cases.
         */
        succp = slcursor_move_to_begin(c);
        
        while(succp) {
                qtest = slcursor_get_case(c);
                qtest->qt_result_type =
                        skygw_query_classifier_get_type(qtest->qt_query_str, f,
						&mysql);
                succp = slcursor_step_ahead(c);
        }
        /**
         * Scan through test results and compare them against expected
         * results.
         */
        succp = slcursor_move_to_begin(c);
        fprintf(stderr, "\nScanning through the results :\n\n");
        
        while(succp) {
                qtest = slcursor_get_case(c);
            
                if (!query_test_types_match(qtest)) {
                        nfail += 1;
                        ss_dfprintf(stderr,
                                    "* Failed: \"%s\" -> %s (Expected %s)\n",
                                    query_test_get_querystr(qtest),
                                    STRQTYPE(query_test_get_result_type(qtest)),
                                    STRQTYPE(query_test_get_query_type(qtest)));
                } else {
                        nsucc += 1;
                        ss_dfprintf(stderr,
                                    "Succeed\t: \"%s\" -> %s\n",
                                    query_test_get_querystr(qtest),
                                    STRQTYPE(query_test_get_query_type(qtest)));
                }
                succp = slcursor_step_ahead(c);
        }
        fprintf(stderr,
                "------------------------------------------\n"
                "Tests in total %d, SUCCEED %d, FAILED %d\n",
                nsucc+nfail,
                nsucc,
                nfail);

        /**
         * Scan test results and re-execute those which are marked to be
         * executed also in the server. This serves mostly debugging purposes.
         */
        succp = slcursor_move_to_begin(c);
        mysql = mysql_init(NULL);

        if (mysql == NULL) {
                fprintf(stderr, "mysql_init failed\n");
                ss_dassert(mysql != NULL);
        }

        mysql_options(mysql,
                      MYSQL_READ_DEFAULT_GROUP,
                      "libmysqld_client");
        mysql_options(mysql, MYSQL_OPT_USE_EMBEDDED_CONNECTION, NULL);
        mysql_options(mysql, MYSQL_OPT_USE_EMBEDDED_CONNECTION, NULL);

        mysql = mysql_real_connect(mysql,
                                   NULL,
                                   "skygw",
                                   "skygw",
                                   NULL,
                                   0,
                                   NULL,
                                   CLIENT_MULTI_STATEMENTS);
        
        if (mysql == NULL) {
                fprintf(stderr, "mysql_real_connect failed\n");
                ss_dassert(mysql != NULL);
        }

        fprintf(stderr,
                "\nRe-execution of selected cases in Embedded server :\n\n");
        
        while(succp) {
                qtest = slcursor_get_case(c);

                if (query_test_exec_also_in_server(qtest)) {
                        MYSQL_RES*  results;
                        MYSQL_ROW   record;
                        const char* query_str;
                
                        query_str = query_test_get_querystr(qtest);
                        failp = mysql_query(mysql, query_str);

                        if (failp) {
                                ss_dfprintf(stderr,
                                            "* Failed: \"%s\" -> %d : %s\n",
                                            query_str,
                                            mysql_errno(mysql),
                                            mysql_error(mysql));
                        } else {
                                ss_dfprintf(stderr,
                                            "Succeed\t: \"%s\"\n",
                                            query_str);
                                results = mysql_store_result(mysql);
                    
                                if (results != NULL) {
                        
                                        while((record = mysql_fetch_row(results))) {
                                                while(record != NULL && *record != NULL) {
                                                        ss_dfprintf(stderr, "%s ", *record);
                                                        record++;
                                                }
                                                ss_dfprintf(stderr, "\n");
                                        }
                                        mysql_free_result(results);
                                }
                        }
                }
                succp = slcursor_step_ahead(c);
            
        }
        slist_done(c);
        fprintf(stderr, "------------------------------------------\n");
        
return_with_handle:
        mysql_close(mysql);
        mysql_thread_end();
        mysql_library_end();
        
return_without_server:
        ss_dfprintf(stderr, "\n<< testmain\n");
        fflush(stderr);
        return rc;
}