int net_write2(net_t * net, char * buf, unsigned int len) { uv_write_t * req; uv_buf_t uvbuf; int read = 0; req = (uv_write_t *) malloc(sizeof(uv_write_t)); req->data = net; switch (net->use_ssl) { case USE_SSL: tls_write(net->tls, buf, (int)len); do { read = tls_bio_read(net->tls, 0); if (read > 0) { uvbuf = uv_buf_init(net->tls->buf, read); uv_write(req, (uv_stream_t*)net->handle, &uvbuf, 1, net_write_cb); } } while (read > 0); break; case NOT_SSL: uvbuf = uv_buf_init(buf, len); uv_write(req, (uv_stream_t*)net->handle, &uvbuf, 1, net_write_cb); break; } return NET_OK; }
void tls_write_buffer(TLS_CONTEXT ctx, unsigned char *buf, int size) { int ret, err; int pos = 0; while (pos < size) { int bytes = pos + 30000 < size ? 30000 : size - pos; printf("writing %d bytes\n", bytes); ret = tls_write(ctx, buf + pos, bytes); err = tls_get_error(ctx, ret); switch(err) { case SSL_ERROR_NONE: pos += ret; printf("%d bytes written\n", ret); break; case SSL_ERROR_WANT_WRITE: printf("want write\n"); break; case SSL_ERROR_WANT_READ: printf("want read\n"); break; default: printf("TLS error code %d\n", err); } } }
int rpch_in_write(rdpRpch* rpch, uint8* data, int length) { rdpRpchHTTP* http_in = rpch->http_in; rdpTls* tls_in = rpch->tls_in; int status = -1; int sent = 0; LLOGLN(10, ("rpch_in_write:")); if (http_in->remContentLength < length) { printf("RPCH Error: HTTP frame is over.\n"); return -1;/* TODO ChannelRecycling */ } #ifdef WITH_DEBUG_RPCH printf("\nrpch_in_send(): length: %d, remaining content length: %d\n", length, http_in->remContentLength); freerdp_hexdump(data, length); printf("\n"); #endif while (sent < length) { status = tls_write(tls_in, data+sent, length-sent); if (status <= 0) return status;/* TODO no idea how to handle errors */ sent += status; } rpch->BytesSent += sent; http_in->remContentLength -= sent; return sent; }
static const char *done_handshake(struct Worker *w) { int res; size_t outlen = 0; const char *emsg; emsg = check_fp(w, "sha1", w->peer_fingerprint_sha1, 20); if (emsg) return emsg; emsg = check_fp(w, "sha256", w->peer_fingerprint_sha256, 32); if (emsg) return emsg; if (w->show) { if (strcmp(w->show, "ciphers") == 0) { tls_get_connection_info(w->ctx, w->showbuf, sizeof w->showbuf); } else if (strcmp(w->show, "peer-cert") == 0) { struct tls_cert *cert = NULL; tls_get_peer_cert(w->ctx, &cert, NULL); show_cert(cert, w->showbuf, sizeof w->showbuf); tls_cert_free(cert); } else { snprintf(w->showbuf, sizeof w->showbuf, "bad kw: show=%s", w->show); } } if (!w->is_server) { res = tls_write(w->ctx, "PKT", 3, &outlen); if (res != 0 && outlen != 3) return "write!=3"; } return wait_for_event(w, EV_READ); }
static void copy_from_stdin_to_tls(struct tls *ctx, int *fd) { static size_t buf[BUFSIZE]; ssize_t n; int i = 0; dbg("DEBUG: data from STDIN\n"); do { n = read(STDIN_FILENO, buf, sizeof(buf)); dbg("read %zu\n", n); } while (n < 0 && errno == EINTR); if (n < 1) { *fd = -1; return; } while (n > 0) { ssize_t r = tls_write(ctx, &buf[i], n); if (r == TLS_WANT_POLLIN || r == TLS_WANT_POLLOUT) continue; if (r < 0) err(1, "tls_write: %s", tls_error(ctx)); i += r; n -= r; } }
static void https_vprintf(struct tls *tls, const char *fmt, ...) { va_list ap, ap2; char *string; ssize_t nw; int len; va_start(ap, fmt); if (ftp_debug) { va_copy(ap2, ap); fprintf(stderr, ">>> "); vfprintf(stderr, fmt, ap2); va_end(ap2); } if ((len = vasprintf(&string, fmt, ap)) == -1) errx(1, "%s: vasprintf failed", __func__); va_end(ap); again: nw = tls_write(tls, string, len); if (nw == TLS_WANT_POLLIN || nw == TLS_WANT_POLLOUT) goto again; else if (nw < 0) errx(1, "%s: tls_write: %s", __func__, tls_error(tls)); free(string); }
int tls_want_write(tls_t *tls, int events) { if (tls && (events & tls->write_events)) { int ret; void *buf = tls->write_buffer; size_t size = tls->write_buffer_len; tls->write_events = 0; /* remove buf */ tls->write_buffer = NULL; tls->write_buffer_len = 0; ret = tls_write(tls, buf, size); if (ret >= 0) /* Restore buf */ return tls->write_buffer = buf, tls->write_buffer_len = ret; else if (errno == EAGAIN) return 0; else return -1; } return 0; }
void connection_send(Client *client, char *buffer) { uv_write_t *req; uv_buf_t buf; size_t len; len = strlen(buffer); if(len > IRC_MAXLEN - 2) { len = IRC_MAXLEN - 2; } buffer[len++] = '\r'; buffer[len++] = '\n'; buffer[len] = '\0'; buf.base = buffer; buf.len = len; if(client->TlsContext != NULL) { tls_write(client->TlsContext, buffer, len, &len); } else { req = Malloc(sizeof(uv_write_t)); uv_write(req, (uv_stream_t *)client->handle, &buf, 1, connection_write_callback); } }
void credssp_send(rdpCredssp* credssp) { STREAM* s; int length; int ts_request_length; int nego_tokens_length; int pub_key_auth_length; int auth_info_length; nego_tokens_length = (credssp->negoToken.cbBuffer > 0) ? credssp_skip_nego_tokens(credssp->negoToken.cbBuffer) : 0; pub_key_auth_length = (credssp->pubKeyAuth.cbBuffer > 0) ? credssp_skip_pub_key_auth(credssp->pubKeyAuth.cbBuffer) : 0; auth_info_length = (credssp->authInfo.cbBuffer > 0) ? credssp_skip_auth_info(credssp->authInfo.cbBuffer) : 0; length = nego_tokens_length + pub_key_auth_length + auth_info_length; ts_request_length = credssp_skip_ts_request(length); s = stream_new(ts_request_length); /* TSRequest */ length = der_get_content_length(ts_request_length); der_write_sequence_tag(s, length); /* SEQUENCE */ /* [0] version */ ber_write_contextual_tag(s, 0, 3, true); ber_write_integer(s, 2); /* INTEGER */ /* [1] negoTokens (NegoData) */ if (nego_tokens_length > 0) { length = der_get_content_length(nego_tokens_length); length -= der_write_contextual_tag(s, 1, length, true); /* NegoData */ length -= der_write_sequence_tag(s, length); /* SEQUENCE OF NegoDataItem */ length -= der_write_sequence_tag(s, length); /* NegoDataItem */ length -= der_write_contextual_tag(s, 0, length, true); /* [0] negoToken */ der_write_octet_string(s, (uint8*) credssp->negoToken.pvBuffer, length); /* OCTET STRING */ } /* [2] authInfo (OCTET STRING) */ if (auth_info_length > 0) { length = ber_get_content_length(auth_info_length); length -= ber_write_contextual_tag(s, 2, length, true); ber_write_octet_string(s, credssp->authInfo.pvBuffer, credssp->authInfo.cbBuffer); } /* [3] pubKeyAuth (OCTET STRING) */ if (pub_key_auth_length > 0) { length = ber_get_content_length(pub_key_auth_length); length -= ber_write_contextual_tag(s, 3, length, true); ber_write_octet_string(s, credssp->pubKeyAuth.pvBuffer, length); } //printf("Sending TSRequest: (%d)\n", stream_get_length(s)); //freerdp_hexdump(s->data, stream_get_length(s)); tls_write(credssp->tls, s->data, stream_get_length(s)); stream_free(s); }
int transport_write(rdpTransport* transport, STREAM* s) { int status = -1; int length; length = stream_get_length(s); stream_set_pos(s, 0); #ifdef WITH_DEBUG_TRANSPORT if (length > 0) { printf("Local > Remote\n"); winpr_HexDump(s->data, length); } #endif while (length > 0) { if (transport->layer == TRANSPORT_LAYER_TLS) status = tls_write(transport->TlsOut, stream_get_tail(s), length); else if (transport->layer == TRANSPORT_LAYER_TCP) status = tcp_write(transport->TcpOut, stream_get_tail(s), length); else if (transport->layer == TRANSPORT_LAYER_TSG) status = tsg_write(transport->tsg, stream_get_tail(s), length); if (status < 0) break; /* error occurred */ if (status == 0) { /* when sending is blocked in nonblocking mode, the receiving buffer should be checked */ if (!transport->blocking) { /* and in case we do have buffered some data, we set the event so next loop will get it */ if (transport_read_nonblocking(transport) > 0) SetEvent(transport->ReceiveEvent); } if (transport->layer == TRANSPORT_LAYER_TLS) tls_wait_write(transport->TlsOut); else if (transport->layer == TRANSPORT_LAYER_TCP) tcp_wait_write(transport->TcpOut); else USleep(transport->SleepInterval); } length -= status; stream_seek(s, status); } if (status < 0) { /* A write error indicates that the peer has dropped the connection */ transport->layer = TRANSPORT_LAYER_CLOSED; } return status; }
static void worker_cb(int fd, short flags, void *arg) { struct Worker *w = arg; const char *err; char buf[128]; int res; size_t outlen; w->pending = 0; if (w->wstate == HANDSHAKE) { err = do_handshake(w, fd); add_error(w, err); } else if (w->wstate == CONNECTED) { if (flags & EV_READ) { res = tls_read(w->ctx, buf, sizeof buf, &outlen); if (res == TLS_READ_AGAIN) { wait_for_event(w, EV_READ); } else if (res == TLS_WRITE_AGAIN) { wait_for_event(w, EV_WRITE); } else if (res == 0) { if (outlen > 0 && w->is_server) { tls_write(w->ctx, "END", 3, &outlen); w->wstate = CLOSED; } else if (outlen == 0) { w->wstate = CLOSED; } else { wait_for_event(w, EV_READ); } } else { add_error(w, "bad pkt"); } } else { add_error(w, "EV_WRITE?"); } } if (w->wstate == CLOSED && w->ctx) { res = tls_close(w->ctx); if (res == 0) { tls_free(w->ctx); w->ctx = NULL; } else if (res == TLS_READ_AGAIN) { wait_for_event(w, EV_READ); } else if (res == TLS_WRITE_AGAIN) { wait_for_event(w, EV_WRITE); } else { tls_free(w->ctx); w->ctx = NULL; } } if (!w->pending && w->ctx) { errx(1, "missed event setup: %s flags=%d state=%d", w->is_server ? "S":"C", flags, w->wstate); } return; }
int transport_write(rdpTransport* transport, STREAM* s) { int status = -1; if (transport->layer == TRANSPORT_LAYER_TLS) status = tls_write(transport->tls, s->data, stream_get_length(s)); else if (transport->layer == TRANSPORT_LAYER_TCP) status = tcp_write(transport->tcp, s->data, stream_get_length(s)); return status; }
void credssp_send(rdpCredssp* credssp, SEC_BUFFER* negoToken, SEC_BUFFER* authInfo, SEC_BUFFER* pubKeyAuth) { STREAM* s; int length; int ts_request_length; int nego_tokens_length; int pub_key_auth_length; int auth_info_length; nego_tokens_length = (negoToken != NULL) ? credssp_skip_nego_tokens(negoToken->cbBuffer) : 0; pub_key_auth_length = (pubKeyAuth != NULL) ? credssp_skip_pub_key_auth(pubKeyAuth->cbBuffer) : 0; auth_info_length = (authInfo != NULL) ? credssp_skip_auth_info(authInfo->cbBuffer) : 0; length = nego_tokens_length + pub_key_auth_length + auth_info_length; ts_request_length = credssp_skip_ts_request(length); s = stream_new(ts_request_length); /* TSRequest */ length = ber_get_content_length(ts_request_length); ber_write_sequence_tag(s, length); /* SEQUENCE */ ber_write_contextual_tag(s, 0, 3, true); /* [0] version */ ber_write_integer(s, 2); /* INTEGER */ /* [1] negoTokens (NegoData) */ if (nego_tokens_length > 0) { length = ber_get_content_length(nego_tokens_length); length -= ber_write_contextual_tag(s, 1, length, true); /* NegoData */ length -= ber_write_sequence_tag(s, length); /* SEQUENCE OF NegoDataItem */ length -= ber_write_sequence_tag(s, length); /* NegoDataItem */ length -= ber_write_contextual_tag(s, 0, length, true); /* [0] negoToken */ ber_write_octet_string(s, negoToken->pvBuffer, length); /* OCTET STRING */ } /* [2] authInfo (OCTET STRING) */ if (auth_info_length > 0) { length = ber_get_content_length(auth_info_length); length -= ber_write_contextual_tag(s, 2, length, true); ber_write_octet_string(s, authInfo->pvBuffer, authInfo->cbBuffer); } /* [3] pubKeyAuth (OCTET STRING) */ if (pub_key_auth_length > 0) { length = ber_get_content_length(pub_key_auth_length); length -= ber_write_contextual_tag(s, 3, length, true); ber_write_octet_string(s, pubKeyAuth->pvBuffer, length); } tls_write(credssp->tls, s->data, stream_get_length(s)); stream_free(s); }
int evtls_write(struct evbuffer *buffer, int fd, struct tls *ctx) { int n; n = tls_write(ctx, buffer->buffer, buffer->off); if (n <= 0) return (n); evbuffer_drain(buffer, n); return (n); }
int transport_write(rdpTransport* transport, STREAM* s) { int status = -1; int length; int sent = 0; length = stream_get_length(s); stream_set_pos(s, 0); #ifdef WITH_DEBUG_TRANSPORT if (length > 0) { printf("Local > Remote\n"); freerdp_hexdump(s->data, length); } #endif while (sent < length) { if (transport->layer == TRANSPORT_LAYER_TLS) status = tls_write(transport->tls, stream_get_tail(s), length); else if (transport->layer == TRANSPORT_LAYER_TCP) status = tcp_write(transport->tcp, stream_get_tail(s), length); if (status < 0) break; /* error occurred */ if (status == 0) { /* blocking while sending */ freerdp_usleep(transport->usleep_interval); /* when sending is blocked in nonblocking mode, the receiving buffer should be checked */ if (!transport->blocking) { /* and in case we do have buffered some data, we set the event so next loop will get it */ if (transport_read_nonblocking(transport) > 0) wait_obj_set(transport->recv_event); } } sent += status; stream_seek(s, status); } if (status < 0) { /* A write error indicates that the peer has dropped the connection */ transport->layer = TRANSPORT_LAYER_CLOSED; } return status; }
/** * @brief Write formatted data to an TLS connection. * @param tls the SSL connection to which the data will be written. * @param format a format string specifying the data to be written to the SSL connection. * @param va_list a variable argument list containing the data parameters associated with the format string. * @return -1 on error, or the number of bytes written to the SSL connection. */ int tls_print(TLS *tls, const char *format, va_list args) { va_list copy; size_t length = 0; chr_t *buffer = NULL; int result = 0, counter = 0, bytes = 0, position = 0; if (!tls || !format) { return (!tls ? -1 : 0); } // We need to make a copy of the arguments so we can run vsnprintf twice. va_copy(copy, args); // Calculate the length of the result so we can allocate an appropriately sized buffer. length = vsnprintf(NULL, 0, format, copy); va_end(copy); // Make sure the print function succeeded. if (length <= 0) { return length; } // Allocate a large enough buffer. else if (!(buffer = mm_alloc(length + 1))) { return -1; } // Build the output string. else if (vsnprintf(buffer, length + 1, format, args) != length) { mm_free(buffer); return -1; } do { if ((bytes = tls_write(tls, buffer + position, length - position, true)) < 0) { mm_free(buffer); return -1; } position += bytes; } while (position != length && counter++ < 128 && status()); mm_free(buffer); return result; }
static int sock_write(SocketRef const socket, uv_buf_t const *const buf) { if(!socket->secure) return async_write((uv_stream_t *)socket->stream, buf, 1); size_t total = 0; for(;;) { size_t partial = 0; int event = tls_write(socket->secure, buf->base + total, buf->len - total, &partial); total += partial; if(0 == event) break; int rc = tls_poll((uv_stream_t *)socket->stream, event); if(rc < 0) return rc; } return 0; }
void sendOverTLS(struct tls* ctx, const char *buf) { size_t sent; // send Length of buf size_t length = strlen(buf); size_t len = sizeof(length); while (len > 0) { int ret = tls_write(ctx, &length, len, &sent); if (ret == TLS_READ_AGAIN || ret == TLS_WRITE_AGAIN) { syslog(LOG_DEBUG, "READ/WRITE AGAIN\n"); } else if (ret < 0) { syslog(LOG_ERR, "%s\n", tls_error(ctx)); break; } else { len -= sent; } } // send actual buf size_t toSend = length; while (toSend > 0) { int ret = tls_write(ctx, buf, toSend, &sent); if (ret == TLS_READ_AGAIN || ret == TLS_WRITE_AGAIN) { syslog(LOG_DEBUG, "READ/WRITE AGAIN\n"); } else if (ret < 0) { syslog(LOG_ERR, "%s\n", tls_error(ctx)); break; } else { buf += sent; toSend -= sent; } } }
int transport_write(rdpTransport* transport, STREAM* s) { int status = -1; int length; int sent = 0; length = stream_get_length(s); stream_set_pos(s, 0); #ifdef WITH_DEBUG_TRANSPORT if (length > 0) { printf("Client > Server\n"); freerdp_hexdump(s->data, length); } #endif while (sent < length) { if (transport->layer == TRANSPORT_LAYER_TLS) status = tls_write(transport->tls, stream_get_tail(s), length); else if (transport->layer == TRANSPORT_LAYER_TCP) status = tcp_write(transport->tcp, stream_get_tail(s), length); if (status < 0) break; /* error occurred */ if (status == 0) { /* blocking while sending */ nanosleep(&transport->ts, NULL); /* when sending is blocked in nonblocking mode, the receiving buffer should be checked */ if (!transport->blocking) transport_read_nonblocking(transport); } sent += status; stream_seek(s, status); } if (!transport->blocking) transport_check_fds(transport); return status; }
int transport_write(rdpTransport* transport, STREAM* s) { int status = -1; int length; length = stream_get_length(s); stream_set_pos(s, 0); #ifdef WITH_DEBUG_TRANSPORT if (length > 0) { printf("Local > Remote\n"); freerdp_hexdump(s->data, length); } #endif while (length > 0) { if (transport->layer == TRANSPORT_LAYER_TLS) status = tls_write(transport->tls, stream_get_tail(s), length); else if (transport->layer == TRANSPORT_LAYER_TCP) status = tcp_write(transport->tcp, stream_get_tail(s), length); if (status < 0) break; /* error occurred */ if (status == 0) { /* blocking while sending */ freerdp_usleep(transport->usleep_interval); } length -= status; stream_seek(s, status); } if (status < 0) { /* A write error indicates that the peer has dropped the connection */ transport->layer = TRANSPORT_LAYER_CLOSED; } return status; }
static const char *done_handshake(struct Worker *w) { int res; const char *emsg; emsg = check_fp(w, "sha1", w->peer_fingerprint_sha1, 20); if (emsg) return emsg; emsg = check_fp(w, "sha256", w->peer_fingerprint_sha256, 32); if (emsg) return emsg; if (w->show) { if (strcmp(w->show, "ciphers") == 0) { tls_get_connection_info(w->ctx, w->showbuf, sizeof w->showbuf); } else if (strcmp(w->show, "peer-cert") == 0) { struct tls_cert *cert = NULL; tls_get_peer_cert(w->ctx, &cert, NULL); show_cert(cert, w->showbuf, sizeof w->showbuf); tls_cert_free(cert); } else { snprintf(w->showbuf, sizeof w->showbuf, "bad kw: show=%s", w->show); } } if (w->aggressive_close) { close(w->socket); tls_close(w->ctx); w->wstate = CLOSED; return "OK"; } if (!w->is_server) { res = tls_write(w->ctx, "PKT", 3); if (res < 0) { return tls_error(w->ctx); } else if (res == 0) { return "write==0"; } else if (res != 3) { return "write!=3"; } } return wait_for_event(w, EV_READ); }
static void tls_handler(process_event_t ev, process_data_t data){ if (ev == tls_event){ if (tls_connected()){ //raven_lcd_show_text("conn"); connection = (Connection*)data; //TLS_Write(connection, "1", 1); //etimer_set(&et, CLOCK_CONF_SECOND); } /*else if (tls_newdata()){ tls_appdata[5] = 0; TLS_Write(connection, "1", 1); }*/ } else if (ev == PROCESS_EVENT_TIMER){ if (etimer_expired(&et)){ tls_write(connection, "1",1); etimer_set(&et, CLOCK_CONF_SECOND); } } }
int tls_write_all(rdpTls* tls, uint8* data, int length) { int status; int sent = 0; do { status = tls_write(tls, &data[sent], length - sent); if (status > 0) sent += status; if (sent >= length) break; } while (status >= 0); if (status > 0) return length; else return status; }
VMINT vm_tls_write(VMINT res_id, const void* buf, VMINT32 len) { kal_int32 ret; vm_tls_context_t * ctx_p = NULL; MMI_TRACE(TRACE_GROUP_8, TRC_MRE_SSL_S, 6, __LINE__); ctx_p = vm_tls_get_ctx_by_res(res_id); if (NULL == ctx_p) { MMI_TRACE(TRACE_GROUP_8, TRC_MRE_SSL_E1, 6, __LINE__); return VM_TLS_RET_BASE -2; } ret = tls_write((kal_int8)(ctx_p->soc_id), (const void *)buf, (kal_int32)len); if (TLS_ERR_NONE != ret) { MMI_TRACE(TRACE_GROUP_8, TRC_MRE_SSL_E2, 6, ret); return ret; } MMI_TRACE(TRACE_GROUP_8, TRC_MRE_SSL_E, 6, __LINE__); return 0; }
int rpch_out_write(rdpRpch* rpch, uint8* data, int length) { rdpRpchHTTP* http_out = rpch->http_out; rdpTls* tls_out = rpch->tls_out; int status = -1; int sent = 0; LLOGLN(10, ("rpch_out_write: in length %d", length)); if (http_out->remContentLength < length) { LLOGLN(0, ("rpch_out_write: RPCH Error: HTTP frame is over.")); return -1;/* TODO ChannelRecycling */ } #ifdef WITH_DEBUG_RPCH printf("rpch_out_write(): length: %d\n", length); freerdp_hexdump(data, length); printf("\n"); #endif while (sent < length) { status = tls_write(tls_out, data + sent, length - sent); if (status <= 0) { LLOGLN(0, ("rpch_out_write: error")); return status; /* TODO no idea how to handle errors */ } sent += status; } http_out->remContentLength -= sent; LLOGLN(10, ("rpch_out_write: out sent %d", sent)); return sent; }
/* Send data from stream to tcp socket. * Will block until all data has been sent. */ void tcp_send(rdpTcp * tcp, STREAM s) { int sent = 0; int total = 0; int length = s->end - s->data; #ifndef DISABLE_TLS if (tcp->iso->mcs->sec->tls_connected) { tls_write(tcp->iso->mcs->sec->ssl, (char*) s->data, length); } else #endif { while (total < length) { while (total < length) { sent = send(tcp->sock, s->data + total, length - total, MSG_NOSIGNAL); if (sent <= 0) { if (sent == -1 && TCP_BLOCKS) { tcp_can_send(tcp->sock, 100); sent = 0; } else { ui_error(tcp->iso->mcs->sec->rdp->inst, "send: %s\n", TCP_STRERROR); return; } } total += sent; } } } }
/* Write data over TLS connection */ int tls_write(SSL *ssl, char* b, int length) { int write_status; int bytesWritten = 0; write_status = SSL_write(ssl, b, length); switch (SSL_get_error(ssl, write_status)) { case SSL_ERROR_NONE: bytesWritten += write_status; break; default: tls_printf("SSL_write", ssl, write_status); break; } if (bytesWritten < length) return bytesWritten += tls_write(ssl, &b[bytesWritten], length - bytesWritten); else return bytesWritten; }
static void test_context(struct tls *ctx) { char buf[2*1024*1024], *ptr = buf; ssize_t ret, len = sizeof buf; ignore_sigpipe(); memset(buf, 'X', len); buf[len - 4] = ':'; buf[len - 3] = 'x'; buf[len - 2] = '\r'; buf[len - 1] = '\n'; loop: len = sizeof buf; ptr = buf; while (len > 0) { ret = tls_write(ctx, ptr, len); if (ret <= 0) printf("tls_write(%d) = %d\n", (int)len, (int)ret); if (ret > 0) { len -= ret; ptr += ret; } else if (ret == TLS_WANT_POLLIN) { continue; } else if (ret == TLS_WANT_POLLOUT) { continue; } else { printf("tls_write: %s\n", tls_error(ctx)); break; } } if (len == 0) goto loop; printf("final len: %d\n", (int)len); }
static ssize_t tls_writev(struct wrap_io *wio, const iovec_t *iov, int iovcnt) { struct gnutella_socket *s = wio->ctx; ssize_t ret, done; int i; g_assert(socket_uses_tls(s)); g_assert(iovcnt > 0); done = 0; ret = 0; for (i = 0; i < iovcnt; i++) { const size_t size = iovec_len(&iov[i]); ret = tls_write(wio, iovec_base(&iov[i]), size); if ((ssize_t) -1 == ret) break; done += (size_t) ret; if (size != (size_t) ret) break; } return done > 0 ? done : ret; }
/** Run the event loop once. * This function will run send any data that has been queued by * xmpp_send and related functions and run through the Strophe even * loop a single time, and will not wait more than timeout * milliseconds for events. This is provided to support integration * with event loops outside the library, and if used, should be * called regularly to achieve low latency event handling. * * @param ctx a Strophe context object * @param timeout time to wait for events in milliseconds * * @ingroup EventLoop */ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout) { xmpp_connlist_t *connitem; xmpp_conn_t *conn; fd_set rfds, wfds; sock_t max = 0; int ret; struct timeval tv; xmpp_send_queue_t *sq, *tsq; int towrite; char buf[4096]; uint64_t next; long usec; int tls_read_bytes = 0; if (ctx->loop_status == XMPP_LOOP_QUIT) return; ctx->loop_status = XMPP_LOOP_RUNNING; /* send queued data */ connitem = ctx->connlist; while (connitem) { conn = connitem->conn; if (conn->state != XMPP_STATE_CONNECTED) { connitem = connitem->next; continue; } /* if we're running tls, there may be some remaining data waiting to * be sent, so push that out */ if (conn->tls) { ret = tls_clear_pending_write(conn->tls); if (ret < 0 && !tls_is_recoverable(tls_error(conn->tls))) { /* an error occured */ xmpp_debug(ctx, "xmpp", "Send error occured, disconnecting."); conn->error = ECONNABORTED; conn_disconnect(conn); } } /* write all data from the send queue to the socket */ sq = conn->send_queue_head; while (sq) { towrite = sq->len - sq->written; if (conn->tls) { ret = tls_write(conn->tls, &sq->data[sq->written], towrite); if (ret < 0 && !tls_is_recoverable(tls_error(conn->tls))) { /* an error occured */ conn->error = tls_error(conn->tls); break; } else if (ret < towrite) { /* not all data could be sent now */ if (ret >= 0) sq->written += ret; break; } } else { ret = sock_write(conn->sock, &sq->data[sq->written], towrite); if (ret < 0 && !sock_is_recoverable(sock_error())) { /* an error occured */ conn->error = sock_error(); break; } else if (ret < towrite) { /* not all data could be sent now */ if (ret >= 0) sq->written += ret; break; } } /* all data for this queue item written, delete and move on */ xmpp_free(ctx, sq->data); tsq = sq; sq = sq->next; xmpp_free(ctx, tsq); /* pop the top item */ conn->send_queue_head = sq; /* if we've sent everything update the tail */ if (!sq) conn->send_queue_tail = NULL; } /* tear down connection on error */ if (conn->error) { /* FIXME: need to tear down send queues and random other things * maybe this should be abstracted */ xmpp_debug(ctx, "xmpp", "Send error occured, disconnecting."); conn->error = ECONNABORTED; conn_disconnect(conn); } connitem = connitem->next; } /* reset parsers if needed */ for (connitem = ctx->connlist; connitem; connitem = connitem->next) { if (connitem->conn->reset_parser) conn_parser_reset(connitem->conn); } /* fire any ready timed handlers, then make sure we don't wait past the time when timed handlers need to be called */ next = handler_fire_timed(ctx); usec = ((next < timeout) ? next : timeout) * 1000; tv.tv_sec = usec / 1000000; tv.tv_usec = usec % 1000000; FD_ZERO(&rfds); FD_ZERO(&wfds); /* find events to watch */ connitem = ctx->connlist; while (connitem) { conn = connitem->conn; switch (conn->state) { case XMPP_STATE_CONNECTING: /* connect has been called and we're waiting for it to complete */ /* connection will give us write or error events */ /* make sure the timeout hasn't expired */ if (time_elapsed(conn->timeout_stamp, time_stamp()) <= conn->connect_timeout) FD_SET(conn->sock, &wfds); else { conn->error = ETIMEDOUT; xmpp_info(ctx, "xmpp", "Connection attempt timed out."); conn_disconnect(conn); } break; case XMPP_STATE_CONNECTED: FD_SET(conn->sock, &rfds); break; case XMPP_STATE_DISCONNECTED: /* do nothing */ default: break; } /* Check if there is something in the SSL buffer. */ if (conn->tls) { tls_read_bytes += tls_pending(conn->tls); } if (conn->state != XMPP_STATE_DISCONNECTED && conn->sock > max) max = conn->sock; connitem = connitem->next; } /* check for events */ if (max > 0) ret = select(max + 1, &rfds, &wfds, NULL, &tv); else { if (timeout > 0) _sleep(timeout); return; } /* select errored */ if (ret < 0) { if (!sock_is_recoverable(sock_error())) xmpp_error(ctx, "xmpp", "event watcher internal error %d", sock_error()); return; } /* no events happened */ if (ret == 0 && tls_read_bytes == 0) return; /* process events */ connitem = ctx->connlist; while (connitem) { conn = connitem->conn; switch (conn->state) { case XMPP_STATE_CONNECTING: if (FD_ISSET(conn->sock, &wfds)) { /* connection complete */ /* check for error */ ret = sock_connect_error(conn->sock); if (ret != 0) { /* connection failed */ xmpp_debug(ctx, "xmpp", "connection failed, error %d", ret); conn_disconnect(conn); break; } conn->state = XMPP_STATE_CONNECTED; xmpp_debug(ctx, "xmpp", "connection successful"); if (conn->tls_legacy_ssl) { xmpp_debug(ctx, "xmpp", "using legacy SSL connection"); ret = conn_tls_start(conn); if (ret != 0) { conn_disconnect(conn); break; } } /* send stream init */ conn_open_stream(conn); } break; case XMPP_STATE_CONNECTED: if (FD_ISSET(conn->sock, &rfds) || (conn->tls && tls_pending(conn->tls))) { if (conn->tls) { ret = tls_read(conn->tls, buf, 4096); } else { ret = sock_read(conn->sock, buf, 4096); } if (ret > 0) { ret = parser_feed(conn->parser, buf, ret); if (!ret) { /* parse error, we need to shut down */ /* FIXME */ xmpp_debug(ctx, "xmpp", "parse error, disconnecting"); conn_disconnect(conn); } } else { if (conn->tls) { if (!tls_is_recoverable(tls_error(conn->tls))) { xmpp_debug(ctx, "xmpp", "Unrecoverable TLS error, %d.", tls_error(conn->tls)); conn->error = tls_error(conn->tls); conn_disconnect(conn); } } else { /* return of 0 means socket closed by server */ xmpp_debug(ctx, "xmpp", "Socket closed by remote host."); conn->error = ECONNRESET; conn_disconnect(conn); } } } break; case XMPP_STATE_DISCONNECTED: /* do nothing */ default: break; } connitem = connitem->next; } /* fire any ready handlers */ handler_fire_timed(ctx); }