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

}
Exemple #5
0
/**
 *
 * @param my_instance
 * @param my_session
 * @param buffer
 * @return
 */
GWBUF* clone_query(TEE_INSTANCE* my_instance, TEE_SESSION* my_session, GWBUF* buffer)
{
    GWBUF* clone = NULL;
    int length, residual = 0;
    char* ptr;
    
	if (my_session->branch_session &&
		my_session->branch_session->state == SESSION_STATE_ROUTER_READY)
	{
		if (my_session->residual)
		{
			clone = gwbuf_clone_all(buffer);

			if (my_session->residual < GWBUF_LENGTH(clone))
			{
				GWBUF_RTRIM(clone, GWBUF_LENGTH(clone) - residual);
			}
			my_session->residual -= GWBUF_LENGTH(clone);

			if (my_session->residual < 0)
			{
				my_session->residual = 0;
			}
		}
		else if (my_session->active && (ptr = modutil_get_SQL(buffer)) != NULL)
		{
			if ((my_instance->match == NULL ||
					regexec(&my_instance->re, ptr, 0, NULL, 0) == 0) &&
				(my_instance->nomatch == NULL ||
					regexec(&my_instance->nore,ptr,0,NULL, 0) != 0))
			{
				length = modutil_MySQL_query_len(buffer, &residual);
				clone = gwbuf_clone_all(buffer);
				my_session->residual = residual;
			}
			free(ptr);
		}
		else if (packet_is_required(buffer))
		{
			clone = gwbuf_clone_all(buffer);
		}
	}
    return clone;
}
Exemple #6
0
/**
 * Check if a GWBUF structure is a MySQL COM_QUERY packet
 *
 * @param	buf	Buffer to check
 * @return	True if GWBUF is a COM_QUERY packet
 */
int
modutil_is_SQL(GWBUF *buf)
{
unsigned char	*ptr;

	if (GWBUF_LENGTH(buf) < 5)
		return 0;
	ptr = GWBUF_DATA(buf);
	return ptr[4] == 0x03;		// COM_QUERY
}
Exemple #7
0
/**
 * Check if a GWBUF structure is a MySQL COM_STMT_PREPARE packet
 *
 * @param	buf	Buffer to check
 * @return	True if GWBUF is a COM_STMT_PREPARE packet
 */
int
modutil_is_SQL_prepare(GWBUF *buf)
{
unsigned char	*ptr;

	if (GWBUF_LENGTH(buf) < 5)
		return 0;
	ptr = GWBUF_DATA(buf);
	return ptr[4] == 0x16 ;		// COM_STMT_PREPARE
}
Exemple #8
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;
}
Exemple #9
0
/**
 * Return the number of bytes of data in the linked list.
 *
 * @param head	The current head of the linked list
 * @return The number of bytes of data in the linked list
 */
unsigned int
gwbuf_length(GWBUF *head)
{
int	rval = 0;
        CHK_GWBUF(head);
	while (head)
	{
		rval += GWBUF_LENGTH(head);
		head = head->next;
	}
	return rval;
}
Exemple #10
0
/**
 * We have data from the client, this is a SQL command, or other MySQL
 * packet type.
 *
 * @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 *rinstance, void *router_session, GWBUF *queue)
{
INFO_INSTANCE	*instance = (INFO_INSTANCE *)rinstance;
INFO_SESSION	*session = (INFO_SESSION *)router_session;
uint8_t		*data;
int		length, len, residual;
char		*sql;

	if (GWBUF_TYPE(queue) == GWBUF_TYPE_HTTP)
	{
		return handle_url(instance, session, queue);
	}
	if (session->queue)
	{
		queue = gwbuf_append(session->queue, queue);
		session->queue = NULL;
		queue = gwbuf_make_contiguous(queue);
	}
	data = (uint8_t *)GWBUF_DATA(queue);
	length = data[0] + (data[1] << 8) + (data[2] << 16);
	if (length + 4 > GWBUF_LENGTH(queue))
	{
		// Incomplete packet, must be buffered
		session->queue = queue;
		return 1;
	}

	// We have a complete request in a signle buffer
	if (modutil_MySQL_Query(queue, &sql, &len, &residual))
	{
		sql = strndup(sql, len);
		int rc = maxinfo_execute_query(instance, session, sql);
		free(sql);
		return rc;
	}
	else
	{
		switch (MYSQL_COMMAND(queue))
		{
		case COM_PING:
			return maxinfo_ping(instance, session, queue);
		case COM_STATISTICS:
			return maxinfo_statistics(instance, session, queue);
		default:
                    MXS_ERROR("maxinfo: Unexpected MySQL command 0x%x",
                              MYSQL_COMMAND(queue));
		}
	}

	return 1;
}
Exemple #11
0
/**
 * Determine if the packet is a command that must be sent to the branch
 * to maintain the session consistancy. These are COM_INIT_DB,
 * COM_CHANGE_USER and COM_QUIT packets.
 *
 * @param queue		The buffer to check
 * @return 		non-zero if the packet should be sent to the branch
 */
static int
packet_is_required(GWBUF *queue)
{
uint8_t		*ptr;
int		i;

	ptr = GWBUF_DATA(queue);
	if (GWBUF_LENGTH(queue) > 4)
		for (i = 0; required_packets[i]; i++)
			if (ptr[4] == required_packets[i])
				return 1;
	return 0;
}
Exemple #12
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;
}
Exemple #13
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;
}
Exemple #14
0
/**
 * Extract the SQL portion of a COM_QUERY packet
 *
 * NB This sets *sql to point into the packet and does not
 * allocate any new storage. The string pointed to by *sql is
 * not NULL terminated.
 *
 * The number of bytes pointed to *sql is returned in *length
 *
 * The remaining number of bytes required for the complete query string
 * are returned in *residual
 *
 * @param	buf		The packet buffer
 * @param	sql		Pointer that is set to point at the SQL data
 * @param	length		Length of the SQL query data pointed to by sql
 * @param	residual	Any remain part of the query in future packets
 * @return	True if the packet is a COM_QUERY packet
 */
int
modutil_MySQL_Query(GWBUF *buf, char **sql, int *length, int *residual)
{
unsigned char	*ptr;

	if (!modutil_is_SQL(buf))
		return 0;
	ptr = GWBUF_DATA(buf);
	*residual = *ptr++;
	*residual += (*ptr++ << 8);
	*residual += (*ptr++ << 16);
        ptr += 2;  // Skip sequence id	and COM_QUERY byte
	*residual = *residual - 1;
	*length = GWBUF_LENGTH(buf) - 5;
	*residual -= *length;
	*sql = (char *)ptr;
	return 1;
}
Exemple #15
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;
}
Exemple #16
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;
        
}
Exemple #17
0
/**
 * The clientReply entry point. This is passed the response buffer
 * to which the filter should be applied. Once processed the
 * query is passed to the upstream component
 * (filter or router) in the filter chain.
 *
 * The function tries to extract a SQL query response out of the response buffer,
 * adds a timestamp to it and publishes the resulting string on the exchange.
 * The message is tagged with the same identifier that the query was.
 * 
 * @param instance	The filter instance data
 * @param session	The filter session
 * @param reply		The response data
 */
static int clientReply(FILTER* instance, void *session, GWBUF *reply)
{
  MQ_SESSION		*my_session = (MQ_SESSION *)session;
  MQ_INSTANCE		*my_instance = (MQ_INSTANCE *)instance;
  char			t_buf[128],*combined;
  unsigned int		pkt_len = pktlen(reply->sbuf->data), offset = 0;
  amqp_basic_properties_t *prop;

  if (my_session->was_query){

    int packet_ok = 0, was_last = 0;

    my_session->was_query = false;

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

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

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

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

	packet_ok = 1;
	was_last = 1;

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

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

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

	pushMessage(my_instance,prop,combined);

	if(was_last){

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

	} 
      }
    }

  }

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

  spinlock_acquire(my_instance->rconn_lock);

  if(my_instance->conn_stat != AMQP_STATUS_OK){

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

      my_instance->last_rconn = time(NULL);

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

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

  spinlock_release(my_instance->rconn_lock);

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

    int packet_ok = 0, was_last = 0;

    my_session->was_query = 0;

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

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

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

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

	packet_ok = 1;
	was_last = 1;

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

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

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

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

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

	} 
      }
      free(combined);
    }

  }  

  return my_session->up.clientReply(my_session->up.instance,
				    my_session->up.session, reply);
}