Example #1
0
/**
 * Convert a chain of GWBUF structures into a single GWBUF structure
 *
 * @param orig		The chain to convert
 * @return		The contiguous buffer
 */
GWBUF *
gwbuf_make_contiguous(GWBUF *orig)
{
    GWBUF	*newbuf;
    char	*ptr;
    int	len;

    if (orig->next == NULL)
        return orig;

    if ((newbuf = gwbuf_alloc(gwbuf_length(orig))) != NULL)
    {
        newbuf->gwbuf_type = orig->gwbuf_type;
        newbuf->hint = hint_dup(orig->hint);
        ptr = GWBUF_DATA(newbuf);

        while (orig)
        {
            len = GWBUF_LENGTH(orig);
            memcpy(ptr, GWBUF_DATA(orig), len);
            ptr += len;
            orig = gwbuf_consume(orig, len);
        }
    }
    return newbuf;
}
Example #2
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;
}
Example #3
0
/**
 * We have data from the client, we must route it to the backend.
 * This is simply a case of sending it to the connection that was
 * chosen when we started the client session.
 *
 * @param instance		The router instance
 * @param router_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	
execute(ROUTER *instance, void *router_session, GWBUF *queue)
{
CLI_SESSION	*session = (CLI_SESSION *)router_session;

	/* Extract the characters */
	while (queue)
	{
		strncat(session->cmdbuf, GWBUF_DATA(queue), MIN(GWBUF_LENGTH(queue),cmdbuflen-1));
		queue = gwbuf_consume(queue, GWBUF_LENGTH(queue));
	}

	execute_cmd(session);
	return 1;
}
Example #4
0
/**
 * Process a request packet from the slave server.
 *
 * The router can handle a limited subset of requests from the slave, these
 * include a subset of general SQL queries, a slave registeration command and
 * the binlog dump command.
 *
 * The strategy for responding to these commands is to use caches responses
 * for the the same commands that have previously been made to the real master
 * if this is possible, if it is not then the router itself will synthesize a
 * response.
 *
 * @param router	The router instance this defines the master for this replication chain
 * @param slave		The slave specific data
 * @param queue		The incoming request packet
 */
int
blr_slave_request(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, GWBUF *queue)
{
	if (slave->state < 0 || slave->state > BLRS_MAXSTATE)
	{
        	LOGIF(LE, (skygw_log_write(
                           LOGFILE_ERROR, "Invalid slave state machine state (%d) for binlog router.",
					slave->state)));
		gwbuf_consume(queue, gwbuf_length(queue));
		return 0;
	}

	slave->stats.n_requests++;
	switch (MYSQL_COMMAND(queue))
	{
	case COM_QUERY:
		return blr_slave_query(router, slave, queue);
		break;
	case COM_REGISTER_SLAVE:
		return blr_slave_register(router, slave, queue);
		break;
	case COM_BINLOG_DUMP:
		return blr_slave_binlog_dump(router, slave, queue);
		break;
	case COM_STATISTICS:
		return blr_statistics(router, slave, queue);
		break;
	case COM_PING:
		return blr_ping(router, slave, queue);
		break;
	case COM_QUIT:
		LOGIF(LD, (skygw_log_write(LOGFILE_DEBUG,
			"COM_QUIT received from slave with server_id %d",
				slave->serverid)));
		break;
	default:
		blr_send_custom_error(slave->dcb, 1, 0,
			"MySQL command not supported by the binlog router.");
        	LOGIF(LE, (skygw_log_write(
                           LOGFILE_ERROR,
			"Unexpected MySQL Command (%d) received from slave",
			MYSQL_COMMAND(queue))));	
		break;
	}
	return 0;
}
Example #5
0
/**
 * Remove the first mysql statement from buffer. Return pointer to the removed
 * statement or NULL if buffer is empty.
 * 
 * Clone buf, calculate the length of included mysql stmt, and point the 
 * statement with cloned buffer. Move the start pointer of buf accordingly
 * so that it only cover the remaining buffer.
 * 
 */
GWBUF* gw_MySQL_get_next_stmt(
        GWBUF** p_readbuf)
{
        GWBUF*         stmtbuf;
        size_t         buflen;
        size_t         strlen;
        uint8_t*       packet;
        
        if (*p_readbuf == NULL)
        {
                stmtbuf = NULL;
                goto return_stmtbuf;
        }                
        CHK_GWBUF(*p_readbuf);
        
        if (GWBUF_EMPTY(*p_readbuf))
        {
                stmtbuf = NULL;
                goto return_stmtbuf;
        }
        buflen = GWBUF_LENGTH((*p_readbuf));
        packet = GWBUF_DATA((*p_readbuf));
        strlen = MYSQL_GET_PACKET_LEN(packet);

        if (strlen+4 == buflen)
        {
                stmtbuf = *p_readbuf;
                *p_readbuf = NULL;
                goto return_stmtbuf;
        }
        /** vraa :Multi-packet stmt is not supported as of 7.3.14 */
        if (strlen-1 > buflen-5)
        {
                stmtbuf = NULL;
                goto return_stmtbuf;
        }
        stmtbuf = gwbuf_clone_portion(*p_readbuf, 0, strlen+4);
        *p_readbuf = gwbuf_consume(*p_readbuf, strlen+4);
        
return_stmtbuf:
        return stmtbuf;
}
Example #6
0
/**
 * We have data from the client, we must route it to the backend.
 * This is simply a case of sending it to the connection that was
 * chosen when we started the client session.
 *
 * @param instance		The router instance
 * @param router_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	
execute(ROUTER *instance, void *router_session, GWBUF *queue)
{
CLI_SESSION	*session = (CLI_SESSION *)router_session;

	/* Extract the characters */
	while (queue)
	{
		strncat(session->cmdbuf, GWBUF_DATA(queue), GWBUF_LENGTH(queue));
		queue = gwbuf_consume(queue, GWBUF_LENGTH(queue));
	}

	if (strrchr(session->cmdbuf, '\n'))
	{
		if (execute_cmd(session))
			dcb_printf(session->session->client, "MaxScale> ");
		else
			session->session->client->func.close(session->session->client);
	}
	return 1;
}
Example #7
0
/**
 * Read event for EPOLLIN on the telnetd protocol module.
 *
 * @param dcb	The descriptor control block
 * @return
 */
static int
telnetd_read_event(DCB* dcb)
{
int		n;
GWBUF		*head = NULL;
SESSION		*session = dcb->session;
ROUTER_OBJECT	*router = session->service->router;
ROUTER		*router_instance = session->service->router_instance;
void		*rsession = session->router_session;
TELNETD		*telnetd = (TELNETD *)dcb->protocol;
char		*password, *t;

	if ((n = dcb_read(dcb, &head)) != -1)
	{
		if (head)
		{
			unsigned char *ptr = GWBUF_DATA(head);
			ptr = GWBUF_DATA(head);
			while (GWBUF_LENGTH(head) && *ptr == TELNET_IAC)
			{
				telnetd_command(dcb, ptr + 1);
				GWBUF_CONSUME(head, 3);
				ptr = GWBUF_DATA(head);
			}
			if (GWBUF_LENGTH(head))
			{
				switch (telnetd->state)
				{
				case TELNETD_STATE_LOGIN:
					telnetd->username = strndup(GWBUF_DATA(head), GWBUF_LENGTH(head));
					/* Strip the cr/lf from the username */
				        t = strstr(telnetd->username, "\r\n");
				        if (t)
                				*t = 0;
					telnetd->state = TELNETD_STATE_PASSWD;
					dcb_printf(dcb, "Password: "******"\r\n");
				        if (t)
                				*t = 0;
					if (admin_verify(telnetd->username, password))
					{
						telnetd_echo(dcb, 1);
						telnetd->state = TELNETD_STATE_DATA;
						dcb_printf(dcb, "\n\nMaxScale> ");
					}
					else
					{
						dcb_printf(dcb, "\n\rLogin incorrect\n\rLogin: ");
						telnetd_echo(dcb, 1);
						telnetd->state = TELNETD_STATE_LOGIN;
						free(telnetd->username);
					}
					gwbuf_consume(head, GWBUF_LENGTH(head));
					free(password);
					break;
				case TELNETD_STATE_DATA:
					router->routeQuery(router_instance, rsession, head);
					break;
				}
			}
			else
			{
				// Force the free of the buffer header
				gwbuf_consume(head, 0);
			}
		}
	}
	return n;
}
Example #8
0
/**
 * Receive the MySQL authentication packet from backend, packet # is 2
 *
 * @param protocol The MySQL protocol structure
 * @return -1 in case of failure, 0 if there was nothing to read, 1 if read
 * was successful.
 */
int gw_receive_backend_auth(
        MySQLProtocol *protocol)
{
	int n = -1;
	GWBUF   *head = NULL;
	DCB     *dcb = protocol->owner_dcb;
	uint8_t *ptr = NULL;
        int      rc = 0;

        n = dcb_read(dcb, &head);

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

	if ((n = dcb_read(dcb, &head)) != -1) {
		if (head) {
			payload = GWBUF_DATA(head);
			h_len = gwbuf_length(head);

			/*
			 * The mysql packets content starts at byte fifth
			 * just return with less bytes
			 */

			if (h_len <= 4) {
				/* log error this exit point */
				conn->state = MYSQL_AUTH_FAILED;
				return 1;
			}

			//get mysql packet size, 3 bytes
			packet_len = gw_mysql_get_byte3(payload);

			if (h_len < (packet_len + 4)) {
				/*
				 * data in buffer less than expected in the
                                 * packet. Log error this exit point
				 */
				conn->state = MYSQL_AUTH_FAILED;
				return 1;
			}

			// skip the 4 bytes header
			payload += 4;

			//Now decode mysql handshake
			success = gw_decode_mysql_server_handshake(conn,
                                                                   payload);

			if (success < 0) {
				/* MySQL handshake has not been properly decoded
				 * we cannot continue
				 * log error this exit point
				 */
				conn->state = MYSQL_AUTH_FAILED;
				return 1;
			}

			conn->state = MYSQL_AUTH_SENT;

			// consume all the data here
			head = gwbuf_consume(head, GWBUF_LENGTH(head));

			return 0;
		}
	}
	
	// Nothing done here, log error this
	return 1;
}