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; }
int tcp_conn_del(struct tcp_conn *conn) { struct flb_in_tcp_config *ctx; ctx = conn->ctx; flb_pack_state_reset(&conn->pack_state); /* Unregister the file descriptior from the event-loop */ mk_event_del(ctx->evl, &conn->event); /* Release resources */ mk_list_del(&conn->_head); close(conn->fd); flb_free(conn->buf_data); flb_free(conn); return 0; }
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; }
/* This routine is called from a co-routine thread */ FLB_INLINE int net_io_write(struct flb_thread *th, struct flb_io_upstream *u, void *data, size_t len, size_t *out_len) { int ret = 0; ssize_t bytes; size_t total = 0; retry: bytes = write(u->fd, data + total, len - total); flb_debug("[io] write(2)=%d", bytes); if (bytes == -1) { if (errno == EAGAIN) { return 0; } else { /* The connection routine may yield */ flb_debug("[io] trying to reconnect"); ret = flb_io_net_connect(u, th); if (ret == -1) { return -1; } /* * Reach here means the connection was successful, let's retry * to write(2). * * note: the flb_io_connect() uses asyncronous sockets, register * the file descriptor with the main event loop and yields until * the main event loop returns the control back (resume), doing a * 'retry' it's pretty safe. */ goto retry; } } /* Update statistics */ //flb_stats_update(out->stats_fd, ret, 0); /* Update counters */ total += bytes; if (total < len) { if (u->event.status == MK_EVENT_NONE) { u->event.mask = MK_EVENT_EMPTY; u->thread = th; ret = mk_event_add(u->evl, u->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(u->fd); return -1; } } flb_thread_yield(th, MK_FALSE); goto retry; } if (u->event.status == MK_EVENT_REGISTERED) { /* We got a notification, remove the event registered */ ret = mk_event_del(u->evl, &u->event); assert(ret == 0); } *out_len = total; return bytes; }
/* * 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; }