/* * It parse a JSON string and convert it to MessagePack format, this packer is * useful when a complete JSON message exists, otherwise it will fail until * the message is complete. * * This routine do not keep a state in the parser, do not use it for big * JSON messages. */ int flb_pack_json(char *js, size_t len, char **buffer, int *size) { int ret; int out; char *buf; struct flb_pack_state state; ret = flb_pack_state_init(&state); if (ret != 0) { return -1; } ret = json_tokenise(js, len, &state); if (ret != 0) { return ret; } buf = tokens_to_msgpack(js, state.tokens, state.tokens_count, &out); if (!buf) { return -1; } *size = out; *buffer = buf; return 0; }
/* Create a new mqtt request instance */ struct tcp_conn *tcp_conn_add(int fd, struct flb_in_tcp_config *ctx) { int ret; struct tcp_conn *conn; struct mk_event *event; conn = flb_malloc(sizeof(struct tcp_conn)); if (!conn) { return NULL; } /* Set data for the event-loop */ event = &conn->event; MK_EVENT_NEW(event); event->fd = fd; event->type = FLB_ENGINE_EV_CUSTOM; event->handler = tcp_conn_event; /* Connection info */ conn->fd = fd; conn->ctx = ctx; conn->buf_len = 0; conn->rest = 0; conn->status = TCP_NEW; conn->buf_data = flb_malloc(ctx->chunk_size); if (!conn->buf_data) { perror("malloc"); close(fd); flb_error("[in_tcp] could not allocate new connection"); flb_free(conn); return NULL; } conn->buf_size = ctx->chunk_size; conn->in = ctx->in; /* Initialize JSON parser */ flb_pack_state_init(&conn->pack_state); /* Register instance into the event loop */ ret = mk_event_add(ctx->evl, fd, FLB_ENGINE_EV_CUSTOM, MK_EVENT_READ, conn); if (ret == -1) { flb_error("[in_tcp] could not register new connection"); close(fd); flb_free(conn->buf_data); flb_free(conn); return NULL; } mk_list_add(&conn->_head, &ctx->connections); return conn; }
/* Initialize plugin */ int in_lib_init(struct flb_input_instance *in, struct flb_config *config, void *data) { int ret; struct flb_in_lib_config *ctx; (void) data; /* Allocate space for the configuration */ ctx = flb_malloc(sizeof(struct flb_in_lib_config)); if (!ctx) { return -1; } ctx->buf_size = LIB_BUF_CHUNK; ctx->buf_data = flb_calloc(1, LIB_BUF_CHUNK); ctx->buf_len = 0; if (!ctx->buf_data) { flb_utils_error_c("Could not allocate initial buf memory buffer"); } ctx->msgp_size = LIB_BUF_CHUNK; ctx->msgp_data = flb_malloc(LIB_BUF_CHUNK); ctx->msgp_len = 0; /* Init communication channel */ flb_input_channel_init(in); ctx->fd = in->channel[0]; if (!ctx->msgp_data) { flb_utils_error_c("Could not allocate initial msgp memory buffer"); } /* Set the context */ flb_input_set_context(in, ctx); /* Collect upon data available on the standard input */ ret = flb_input_set_collector_event(in, in_lib_collect, ctx->fd, config); if (ret == -1) { flb_utils_error_c("Could not set collector for LIB input plugin"); } flb_pack_state_init(&ctx->state); return 0; }
int in_lib_collect(struct flb_config *config, void *in_context) { int n; int ret; int bytes; int out_size; int capacity; int size; char *ptr; char *pack; struct flb_in_lib_config *ctx = in_context; capacity = (ctx->buf_size - ctx->buf_len); /* Allocate memory as required (FIXME: this will be limited in later) */ if (capacity == 0) { size = ctx->buf_size + LIB_BUF_CHUNK; ptr = flb_realloc(ctx->buf_data, size); if (!ptr) { perror("realloc"); return -1; } ctx->buf_data = ptr; ctx->buf_size = size; capacity = LIB_BUF_CHUNK; } bytes = read(ctx->fd, ctx->buf_data + ctx->buf_len, capacity); flb_trace("in_lib read() = %i", bytes); if (bytes == -1) { perror("read"); if (errno == -EPIPE) { return -1; } return 0; } ctx->buf_len += bytes; /* initially we should support json input */ ret = flb_pack_json_state(ctx->buf_data, ctx->buf_len, &pack, &out_size, &ctx->state); if (ret == FLB_ERR_JSON_PART) { flb_warn("lib data incomplete, waiting for more data..."); return 0; } else if (ret == FLB_ERR_JSON_INVAL) { flb_warn("lib data invalid"); flb_pack_state_reset(&ctx->state); flb_pack_state_init(&ctx->state); return -1; } ctx->buf_len = 0; capacity = (ctx->msgp_size - ctx->msgp_len); if (capacity < out_size) { n = ((out_size - capacity) / LIB_BUF_CHUNK) + 1; size = ctx->msgp_size + (LIB_BUF_CHUNK * n); ptr = flb_realloc(ctx->msgp_data, size); if (!ptr) { perror("realloc"); flb_free(pack); flb_pack_state_reset(&ctx->state); flb_pack_state_init(&ctx->state); return -1; } ctx->msgp_data = ptr; ctx->msgp_size = size; } memcpy(ctx->msgp_data + ctx->msgp_len, pack, out_size); ctx->msgp_len += out_size; flb_free(pack); flb_pack_state_reset(&ctx->state); flb_pack_state_init(&ctx->state); return 0; }
/* Callback invoked every time an event is triggered for a connection */ int tcp_conn_event(void *data) { int ret; int bytes; int available; int size; char *tmp; struct mk_event *event; struct tcp_conn *conn = data; struct flb_in_tcp_config *ctx = conn->ctx; jsmntok_t *t; event = &conn->event; if (event->mask & MK_EVENT_READ) { available = (conn->buf_size - conn->buf_len); if (available < 1) { if (conn->buf_size + ctx->chunk_size > ctx->buffer_size) { flb_trace("[in_tcp] fd=%i incoming data exceed limit (%i KB)", event->fd, (ctx->buffer_size / 1024)); tcp_conn_del(conn); return -1; } size = conn->buf_size + ctx->chunk_size; tmp = flb_realloc(conn->buf_data, size); if (!tmp) { perror("realloc"); return -1; } flb_trace("[in_tcp] fd=%i buffer realloc %i -> %i", event->fd, conn->buf_size, size); conn->buf_data = tmp; conn->buf_size = size; available = (conn->buf_size - conn->buf_len); } /* Read data */ bytes = read(conn->fd, conn->buf_data + conn->buf_len, available); if (bytes <= 0) { flb_trace("[in_tcp] fd=%i closed connection", event->fd); tcp_conn_del(conn); return -1; } flb_trace("[in_tcp] read()=%i pre_len=%i now_len=%i", bytes, conn->buf_len, conn->buf_len + bytes); conn->buf_len += bytes; conn->buf_data[conn->buf_len] = '\0'; /* Strip CR or LF if found at first byte */ if (conn->buf_data[0] == '\r' || conn->buf_data[0] == '\n') { /* Skip message with one byte with CR or LF */ flb_trace("[in_tcp] skip one byte message with ASCII code=%i", conn->buf_data[0]); consume_bytes(conn->buf_data, 1, conn->buf_len); conn->buf_len--; } /* JSON Format handler */ char *pack; int out_size; ret = flb_pack_json_state(conn->buf_data, conn->buf_len, &pack, &out_size, &conn->pack_state); if (ret == FLB_ERR_JSON_PART) { flb_debug("[in_serial] JSON incomplete, waiting for more data..."); return 0; } else if (ret == FLB_ERR_JSON_INVAL) { flb_debug("[in_serial] invalid JSON message, skipping"); flb_pack_state_reset(&conn->pack_state); flb_pack_state_init(&conn->pack_state); conn->pack_state.multiple = FLB_TRUE; return -1; } /* * Given the Tokens used for the packaged message, append * the records and then adjust buffer. */ process_pack(conn, pack, out_size); t = &conn->pack_state.tokens[0]; consume_bytes(conn->buf_data, t->end, conn->buf_len); conn->buf_len -= t->end; conn->buf_data[conn->buf_len] = '\0'; flb_pack_state_reset(&conn->pack_state); flb_pack_state_init(&conn->pack_state); conn->pack_state.multiple = FLB_TRUE; flb_free(pack); return bytes; } if (event->mask & MK_EVENT_CLOSE) { flb_trace("[in_tcp] fd=%i hangup", event->fd); tcp_conn_del(conn); return -1; } return 0; }
/* Init serial input */ int in_serial_init(struct flb_input_instance *in, struct flb_config *config, void *data) { int fd; int ret; int br; struct flb_in_serial_config *ctx; (void) data; ctx = flb_calloc(1, sizeof(struct flb_in_serial_config)); if (!ctx) { perror("calloc"); return -1; } ctx->format = FLB_SERIAL_FORMAT_NONE; if (!serial_config_read(ctx, in)) { return -1; } /* Initialize JSON pack state */ if (ctx->format == FLB_SERIAL_FORMAT_JSON) { flb_pack_state_init(&ctx->pack_state); } /* set context */ flb_input_set_context(in, ctx); /* initialize MessagePack buffers */ msgpack_sbuffer_init(&ctx->mp_sbuf); msgpack_packer_init(&ctx->mp_pck, &ctx->mp_sbuf, msgpack_sbuffer_write); /* open device */ fd = open(ctx->file, O_RDWR | O_NOCTTY | O_NONBLOCK); if (fd == -1) { perror("open"); flb_error("[in_serial] Could not open serial port device"); flb_free(ctx); return -1; } ctx->fd = fd; /* Store original settings */ tcgetattr(fd, &ctx->tio_orig); /* Reset for new... */ memset(&ctx->tio, 0, sizeof(ctx->tio)); tcgetattr(fd, &ctx->tio); br = atoi(ctx->bitrate); cfsetospeed(&ctx->tio, (speed_t) flb_serial_speed(br)); cfsetispeed(&ctx->tio, (speed_t) flb_serial_speed(br)); /* Settings */ ctx->tio.c_cflag &= ~PARENB; /* 8N1 */ ctx->tio.c_cflag &= ~CSTOPB; ctx->tio.c_cflag &= ~CSIZE; ctx->tio.c_cflag |= CS8; ctx->tio.c_cflag &= ~CRTSCTS; /* No flow control */ ctx->tio.c_cc[VMIN] = ctx->min_bytes; /* Min number of bytes to read */ ctx->tio.c_cflag |= CREAD | CLOCAL; /* Enable READ & ign ctrl lines */ tcflush(fd, TCIFLUSH); tcsetattr(fd, TCSANOW, &ctx->tio); #if __linux__ /* Set our collector based on a file descriptor event */ ret = flb_input_set_collector_event(in, in_serial_collect, ctx->fd, config); #else /* Set our collector based on a timer event */ ret = flb_input_set_collector_time(in, in_serial_collect, IN_SERIAL_COLLECT_SEC, IN_SERIAL_COLLECT_NSEC, config); #endif return ret; }
/* Callback triggered when some serial msgs are available */ int in_serial_collect(struct flb_config *config, void *in_context) { int ret; int bytes = 0; int available; int len; int hits; char *sep; char *buf; jsmntok_t *t; struct flb_in_serial_config *ctx = in_context; while (1) { available = (sizeof(ctx->buf_data) -1) - ctx->buf_len; if (available > 1) { bytes = read(ctx->fd, ctx->buf_data + ctx->buf_len, available); if (bytes == -1) { if (errno == EPIPE || errno == EINTR) { return -1; } return 0; } else if (bytes == 0) { return 0; } } ctx->buf_len += bytes; /* Always set a delimiter to avoid buffer trash */ ctx->buf_data[ctx->buf_len] = '\0'; /* Check if our buffer is full */ if (ctx->buffer_id + 1 == SERIAL_BUFFER_SIZE) { ret = flb_engine_flush(config, &in_serial_plugin); if (ret == -1) { ctx->buffer_id = 0; } } sep = NULL; buf = ctx->buf_data; len = ctx->buf_len; hits = 0; /* Handle FTDI handshake */ if (ctx->buf_data[0] == '\0') { consume_bytes(ctx->buf_data, 1, ctx->buf_len); ctx->buf_len--; } /* Strip CR or LF if found at first byte */ if (ctx->buf_data[0] == '\r' || ctx->buf_data[0] == '\n') { /* Skip message with one byte with CR or LF */ flb_trace("[in_serial] skip one byte message with ASCII code=%i", ctx->buf_data[0]); consume_bytes(ctx->buf_data, 1, ctx->buf_len); ctx->buf_len--; } /* Handle the case when a Separator is set */ if (ctx->separator) { while ((sep = strstr(ctx->buf_data, ctx->separator))) { len = (sep - ctx->buf_data); if (len > 0) { /* process the line based in the separator position */ process_line(buf, len, ctx); consume_bytes(ctx->buf_data, len + ctx->sep_len, ctx->buf_len); ctx->buf_len -= (len + ctx->sep_len); hits++; } else { consume_bytes(ctx->buf_data, ctx->sep_len, ctx->buf_len); ctx->buf_len -= ctx->sep_len; } ctx->buf_data[ctx->buf_len] = '\0'; } if (hits == 0 && available <= 1) { flb_debug("[in_serial] no separator found, no more space"); ctx->buf_len = 0; return 0; } } else if (ctx->format == FLB_SERIAL_FORMAT_JSON) { /* JSON Format handler */ char *pack; int out_size; ret = flb_pack_json_state(ctx->buf_data, ctx->buf_len, &pack, &out_size, &ctx->pack_state); if (ret == FLB_ERR_JSON_PART) { flb_debug("[in_serial] JSON incomplete, waiting for more data..."); return 0; } else if (ret == FLB_ERR_JSON_INVAL) { flb_debug("[in_serial] invalid JSON message, skipping"); flb_pack_state_reset(&ctx->pack_state); flb_pack_state_init(&ctx->pack_state); ctx->pack_state.multiple = FLB_TRUE; return -1; } /* * Given the Tokens used for the packaged message, append * the records and then adjust buffer. */ process_pack(ctx, pack, out_size); flb_free(pack); t = &ctx->pack_state.tokens[0]; consume_bytes(ctx->buf_data, t->end, ctx->buf_len); ctx->buf_len -= t->end; ctx->buf_data[ctx->buf_len] = '\0'; flb_pack_state_reset(&ctx->pack_state); flb_pack_state_init(&ctx->pack_state); ctx->pack_state.multiple = FLB_TRUE; } else { /* Process and enqueue the received line */ process_line(ctx->buf_data, ctx->buf_len, ctx); ctx->buf_len = 0; } } return 0; }