FLB_INLINE int net_io_tls_write(struct flb_thread *th, struct flb_io_upstream *u, void *data, size_t len, size_t *out_len) { int ret; size_t total = 0; if (!u->tls_session) { u->tls_session = flb_tls_session_new(u->tls->context); if (!u->tls_session) { flb_error("[io_tls] could not create tls session"); return -1; } ret = flb_io_net_tls_connect(u, th); if (ret == -1) { flb_error("[io_tls] could not connect/initiate TLS session"); return -1; } } retry_write: ret = mbedtls_ssl_write(&u->tls_session->ssl, data + total, len - total); if (ret == MBEDTLS_ERR_SSL_WANT_WRITE) { io_tls_event_switch(u, MK_EVENT_WRITE); flb_thread_yield(th, FLB_FALSE); goto retry_write; } else if (ret == MBEDTLS_ERR_SSL_WANT_READ) { io_tls_event_switch(u, MK_EVENT_READ); flb_thread_yield(th, FLB_FALSE); goto retry_write; } else if (ret < 0) { char err_buf[72]; mbedtls_strerror(ret, err_buf, sizeof(err_buf)); flb_debug("[tls] SSL error: %s", err_buf); /* There was an error transmitting data */ mk_event_del(u->evl, &u->event); tls_session_destroy(u->tls_session); u->tls_session = NULL; return -1; } /* Update statistics */ //flb_stats_update(out->stats_fd, ret, 0); /* Update counter and check if we need to continue writing */ total += ret; if (total < len) { io_tls_event_switch(u, MK_EVENT_WRITE); flb_thread_yield(th, FLB_FALSE); goto retry_write; } mk_event_del(u->evl, &u->event); 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; }
void _io_tls_error(int ret, char *file, int line) { char err_buf[72]; mbedtls_strerror(ret, err_buf, sizeof(err_buf)); flb_error("[io_tls] flb_io_tls.c:%i %s", line, err_buf); }
/* Initialize plugin */ int in_mqtt_init(struct flb_input_instance *in, struct flb_config *config, void *data) { int ret; struct flb_in_mqtt_config *ctx; (void) data; /* Allocate space for the configuration */ ctx = mqtt_config_init(in); if (!ctx) { return -1; } ctx->msgp_len = 0; /* Set the context */ flb_input_set_context(in, ctx); /* Create TCP server */ ctx->server_fd = flb_net_server(ctx->tcp_port, ctx->listen); if (ctx->server_fd > 0) { flb_debug("[in_mqtt] binding %s:%s", ctx->listen, ctx->tcp_port); } else { flb_error("[in_mqtt] could not bind address %s:%s", ctx->listen, ctx->tcp_port); mqtt_config_free(ctx); return -1; } ctx->evl = config->evl; /* Collect upon data available on the standard input */ ret = flb_input_set_collector_event(in, in_mqtt_collect, ctx->server_fd, config); if (ret == -1) { flb_error("[in_mqtt] Could not set collector for MQTT input plugin"); mqtt_config_free(ctx); return -1; } return 0; }
static inline int io_tls_event_switch(struct flb_io_upstream *u, int mask) { int ret; struct mk_event *event; event = &u->event; if (event->mask & ~mask) { ret = mk_event_add(u->evl, event->fd, FLB_ENGINE_EV_THREAD, mask, &u->event); if (ret == -1) { flb_error("[io_tls] error changing mask to %i", mask); return -1; } } return 0; }
/* * For a server event, the collection event means a new client have arrived, we * accept the connection and create a new MQTT instance which will wait for * events/data (MQTT control packages) */ int in_mqtt_collect(struct flb_config *config, void *in_context) { int fd; struct flb_in_mqtt_config *ctx = in_context; struct mqtt_conn *conn; /* Accept the new connection */ fd = flb_net_accept(ctx->server_fd); if (fd == -1) { flb_error("[in_mqtt] could not accept new connection"); return -1; } flb_trace("[in_mqtt] [fd=%i] new TCP connection", fd); conn = mqtt_conn_add(fd, ctx); if (!conn) { return -1; } return 0; }
struct flb_tls_session *flb_tls_session_new(struct flb_tls_context *ctx) { int ret; struct flb_tls_session *session; session = malloc(sizeof(struct flb_tls_session)); if (!session) { return NULL; } mbedtls_ssl_init(&session->ssl); mbedtls_ssl_config_init(&session->conf); ret = mbedtls_ssl_config_defaults(&session->conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT); if (ret != 0) { io_tls_error(ret); } mbedtls_ssl_conf_rng(&session->conf, mbedtls_ctr_drbg_random, &ctx->ctr_drbg); mbedtls_ssl_conf_authmode(&session->conf, MBEDTLS_SSL_VERIFY_NONE); ret = mbedtls_ssl_setup(&session->ssl, &session->conf); if (ret == -1) { flb_error("[tls] ssl_setup"); goto error; } return session; error: free(session); return NULL; }
FLB_INLINE int flb_io_net_connect(struct flb_io_upstream *u, struct flb_thread *th) { int fd; int ret; int error = 0; socklen_t len = sizeof(error); if (u->fd > 0) { close(u->fd); } /* Create the socket */ fd = flb_net_socket_create(AF_INET, FLB_TRUE); if (fd == -1) { flb_error("[io] could not create socket"); return -1; } u->fd = fd; /* Make the socket non-blocking */ flb_net_socket_nonblocking(u->fd); /* Start the connection */ ret = flb_net_tcp_fd_connect(fd, u->tcp_host, u->tcp_port); if (ret == -1) { if (errno == EINPROGRESS) { flb_debug("[upstream] connection in process"); } else { } u->event.mask = MK_EVENT_EMPTY; u->event.status = MK_EVENT_NONE; u->thread = th; ret = mk_event_add(u->evl, fd, FLB_ENGINE_EV_THREAD, MK_EVENT_WRITE, &u->event); if (ret == -1) { /* * If we failed here there no much that we can do, just * let the caller we failed */ close(fd); return -1; } /* * Return the control to the parent caller, we need to wait for * the event loop to get back to us. */ flb_thread_yield(th, FLB_FALSE); /* We got a notification, remove the event registered */ ret = mk_event_del(u->evl, &u->event); assert(ret == 0); /* Check the connection status */ if (u->event.mask & MK_EVENT_WRITE) { ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len); if (ret == -1) { flb_error("[io] could not validate socket status"); return -1; } if (error != 0) { /* Connection is broken, not much to do here */ flb_debug("[io] connection failed"); return -1; } u->event.mask = MK_EVENT_EMPTY; u->event.status = MK_EVENT_NONE; } else { return -1; } } flb_debug("[io] connection OK"); return 0; }
void cb_forward_flush(void *data, size_t bytes, char *tag, int tag_len, struct flb_input_instance *i_ins, void *out_context, struct flb_config *config) { int ret = -1; int entries = 0; size_t off = 0; size_t total; size_t bytes_sent; msgpack_packer mp_pck; msgpack_sbuffer mp_sbuf; msgpack_unpacked result; struct flb_out_forward_config *ctx = out_context; struct flb_upstream_conn *u_conn; (void) i_ins; (void) config; flb_debug("[out_forward] request %lu bytes to flush", bytes); /* Initialize packager */ msgpack_sbuffer_init(&mp_sbuf); msgpack_packer_init(&mp_pck, &mp_sbuf, msgpack_sbuffer_write); /* Count number of entries, is there a better way to do this ? */ msgpack_unpacked_init(&result); while (msgpack_unpack_next(&result, data, bytes, &off)) { entries++; } flb_debug("[out_fw] %i entries tag='%s' tag_len=%i", entries, tag, tag_len); msgpack_unpacked_destroy(&result); /* Output: root array */ msgpack_pack_array(&mp_pck, 2); msgpack_pack_str(&mp_pck, tag_len); msgpack_pack_str_body(&mp_pck, tag, tag_len); msgpack_pack_array(&mp_pck, entries); /* Get a TCP connection instance */ u_conn = flb_upstream_conn_get(ctx->u); if (!u_conn) { flb_error("[out_forward] no upstream connections available"); msgpack_sbuffer_destroy(&mp_sbuf); FLB_OUTPUT_RETURN(FLB_RETRY); } /* Write message header */ ret = flb_io_net_write(u_conn, mp_sbuf.data, mp_sbuf.size, &bytes_sent); if (ret == -1) { flb_error("[out_forward] could not write chunk header"); msgpack_sbuffer_destroy(&mp_sbuf); flb_upstream_conn_release(u_conn); FLB_OUTPUT_RETURN(FLB_RETRY); } msgpack_sbuffer_destroy(&mp_sbuf); total = ret; /* Write body */ ret = flb_io_net_write(u_conn, data, bytes, &bytes_sent); if (ret == -1) { flb_error("[out_forward] error writing content body"); flb_upstream_conn_release(u_conn); FLB_OUTPUT_RETURN(FLB_RETRY); } total += bytes_sent; flb_upstream_conn_release(u_conn); flb_trace("[out_forward] ended write()=%d bytes", total); FLB_OUTPUT_RETURN(FLB_OK); }
/* 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; }
/* * This routine perform a TCP connection and the required TLS/SSL * handshake, */ FLB_INLINE int flb_io_net_tls_connect(struct flb_io_upstream *u, struct flb_thread *th) { int fd; int ret; int error = 0; int flag; socklen_t len = sizeof(error); struct flb_tls_session *session; if (u->fd > 0) { close(u->fd); } /* Create the socket */ fd = flb_net_socket_create(AF_INET, FLB_TRUE); if (fd == -1) { flb_error("[io] could not create socket"); return -1; } u->fd = fd; /* Make the socket non-blocking */ flb_net_socket_nonblocking(u->fd); /* Start the connection */ ret = flb_net_tcp_fd_connect(fd, u->tcp_host, u->tcp_port); if (ret == -1) { if (errno == EINPROGRESS) { flb_debug("[upstream] connection in process"); } else { close(u->fd); if (u->tls_session) { tls_session_destroy(u->tls_session); u->tls_session = NULL; } return -1; } MK_EVENT_NEW(&u->event); u->thread = th; ret = mk_event_add(u->evl, fd, FLB_ENGINE_EV_THREAD, MK_EVENT_WRITE, &u->event); if (ret == -1) { /* * If we failed here there no much that we can do, just * let the caller we failed */ flb_error("[io_tls] connect failed registering event"); close(fd); return -1; } /* * Return the control to the parent caller, we need to wait for * the event loop to get back to us. */ flb_thread_yield(th, FLB_FALSE); /* Check the connection status */ if (u->event.mask & MK_EVENT_WRITE) { ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len); if (ret == -1) { flb_error("[io_tls] could not validate socket status"); goto error; } if (error != 0) { /* Connection is broken, not much to do here */ flb_error("[io_tls] connection failed"); goto error; } } else { return -1; } } /* Configure TLS and prepare handshake */ session = u->tls_session; mbedtls_ssl_set_bio(&session->ssl, u, mbedtls_net_send, mbedtls_net_recv, NULL); retry_handshake: ret = mbedtls_ssl_handshake(&session->ssl); if (ret != 0) { if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { io_tls_error(ret); goto error; } if (ret == MBEDTLS_ERR_SSL_WANT_WRITE) { flag = MK_EVENT_WRITE; } else if (ret == MBEDTLS_ERR_SSL_WANT_READ) { flag = MK_EVENT_READ; } else { } /* * FIXME: if we need multiple reads we are invoking the same * system call multiple times. */ ret = mk_event_add(u->evl, u->event.fd, FLB_ENGINE_EV_THREAD, flag, &u->event); if (ret == -1) { goto error; } flb_thread_yield(th, FLB_FALSE); goto retry_handshake; } else { flb_debug("[io_tls] Handshake OK"); } if (u->event.status == MK_EVENT_REGISTERED) { mk_event_del(u->evl, &u->event); } flb_debug("[io_tls] connection OK"); return 0; error: if (u->event.status == MK_EVENT_REGISTERED) { mk_event_del(u->evl, &u->event); } return -1; }