in c/src/ssl/schannel.cpp [1768:1859]
static ssize_t process_output_ssl( pn_transport_t *transport, unsigned int layer, char *buffer, size_t max_len)
{
pni_ssl_t *ssl = transport->ssl;
if (!ssl) return PN_EOS;
ssl_log( transport, PN_LEVEL_TRACE, "process_output_ssl( max_len=%zu )",max_len );
ssize_t written = 0;
ssize_t total_app_bytes = 0;
bool work_pending;
if (ssl->state == CLIENT_HELLO) {
// output buffers eclusively for internal handshake use until negotiation complete
client_handshake_init(transport);
if (ssl->state == SSL_CLOSED)
return PN_EOS;
ssl->state = NEGOTIATING;
}
do {
work_pending = false;
if (ssl->network_out_pending > 0) {
size_t wcount = _pni_min(ssl->network_out_pending, max_len);
memmove(buffer, ssl->network_outp, wcount);
ssl->network_outp += wcount;
ssl->network_out_pending -= wcount;
buffer += wcount;
max_len -= wcount;
written += wcount;
}
if (ssl->network_out_pending == 0 && ssl->state == RUNNING && !ssl->app_output_closed) {
// refill the buffer with app data and encrypt it
char *app_data = ssl->sc_outbuf + ssl->sc_sizes.cbHeader;
char *app_outp = app_data;
size_t remaining = ssl->max_data_size;
ssize_t app_bytes;
do {
app_bytes = transport->io_layers[layer+1]->process_output(transport, layer+1, app_outp, remaining);
if (app_bytes > 0) {
app_outp += app_bytes;
remaining -= app_bytes;
ssl_log( transport, PN_LEVEL_TRACE, "Gathered %zd bytes from app to send to peer", app_bytes );
} else {
if (app_bytes < 0) {
ssl_log(transport, PN_LEVEL_WARNING, "Application layer closed its output, error=%d (%d bytes pending send)",
(int) app_bytes, (int) ssl->network_out_pending);
ssl->app_output_closed = app_bytes;
if (ssl->app_input_closed)
ssl->state = SHUTTING_DOWN;
} else if (total_app_bytes == 0 && ssl->app_input_closed) {
// We've drained all the App layer can provide
ssl_log(transport, PN_LEVEL_WARNING, "Application layer blocked on input, closing");
ssl->state = SHUTTING_DOWN;
ssl->app_output_closed = PN_ERR;
}
}
} while (app_bytes > 0);
if (app_outp > app_data) {
work_pending = (max_len > 0);
ssl_encrypt(transport, app_data, app_outp - app_data);
}
}
if (ssl->network_out_pending == 0) {
if (ssl->state == SHUTTING_DOWN) {
if (!ssl->queued_shutdown) {
start_ssl_shutdown(transport);
work_pending = true;
} else {
ssl->state = SSL_CLOSED;
}
}
else if (ssl->state == NEGOTIATING && ssl->app_input_closed) {
ssl->app_output_closed = PN_EOS;
ssl->state = SSL_CLOSED;
}
}
} while (work_pending);
if (written == 0 && ssl->state == SSL_CLOSED) {
written = ssl->app_output_closed ? ssl->app_output_closed : PN_EOS;
if (transport->io_layers[layer]==&ssl_input_closed_layer) {
transport->io_layers[layer] = &ssl_closed_layer;
} else {
transport->io_layers[layer] = &ssl_output_closed_layer;
}
}
ssl_log(transport, PN_LEVEL_TRACE, "process_output_ssl() returning %d", (int) written);
return written;
}