/** * Converts length-encoded strings to character strings and advanced the pointer to the next unrelated byte. * The caller is responsible for freeing the allocated memory. * @param c Pointer to the first byte of a valid packet. * @return The newly allocated string or NULL of an error occurred */ char* consume_lestr(unsigned char** c) { unsigned int slen = consume_leitoi(c); char *str = calloc((slen + 1), sizeof(char)); if(str){ memcpy(str,*c,slen); *c += slen; } return str; }
/** * 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); }
/** * 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); }