in c/experimental/raw_plus_tls2.c [271:352]
static void handle_outgoing(jabber_connection_t* jc) {
// For this simplified example, 1 buffer of application output is dealt
// with at a time.
jabber_t *j = jc->parent;
if (buf_in_use(&jc->out_wire_buf)) {
// See if raw connection done with the buffer
if (1 == pn_raw_connection_take_written_buffers(jc->rawc, &jc->out_wire_buf, 1)) {
buf_reset(&jc->out_wire_buf);
} else {
return; // Nothing to do until notified of future raw connection write completion
}
}
if (!jc->jabber_turn && !jc->tls_has_output && !jc->need_rawc_write_close)
return; // nothing to send at this time
if (!jc->tls) {
line_of_jabber(jc, &jc->out_wire_buf);
if (jc->out_wire_buf.size > 0) {
jc->jabber_turn = false; // Peer gets to do next jabber.
jcheck( pn_raw_connection_write_buffers(jc->rawc, &jc->out_wire_buf, 1) == 1 );
buf_set_in_use(&jc->out_wire_buf, true);
}
// If no more application data to write, start orderly close.
if (j->current_jline == jlines_count) {
pn_raw_connection_write_close(jc->rawc);
jc->orderly_close_initiated = true;
}
} else {
// TLS
// Reacquire encryption buffer if TLS library is done with it.
if (buf_in_use(&jc->out_app_buf) && pn_tls_take_encrypt_input_buffers(jc->tls, &jc->out_app_buf, 1) == 1)
buf_reset(&jc->out_app_buf);
if (pn_tls_is_secure(jc->tls) && jc->jabber_turn && !jc->tls_closing) {
jcheck( jc->alpn_protocol || !jc->parent->alpn_enabled );
// Add jabber data if there is room.
if (buf_unused(&jc->out_app_buf)) {
line_of_jabber(jc, &jc->out_app_buf);
if (jc->out_app_buf.size > 0) {
jc->jabber_turn = false; // Peer gets to do next jabber.
buf_set_in_use(&jc->out_app_buf, true);
size_t consumed = pn_tls_give_encrypt_input_buffers(jc->tls, &jc->out_app_buf, 1);
if (consumed != 1) abort();
// If no more application data to write, start orderly close.
// For TLS, indicate we are done writing to generate the protocol's EOS (closure alert).
if (j->current_jline == jlines_count) {
jc->orderly_close_initiated = true;
jabber_tls_begin_close(jc);
}
jabber_tls_process(jc);
}
}
}
// Even if no application output just queued for processing (i.e. no call to
// pn_tls_give_encrypt_input_buffers()), there may be straggling encrypted output.
// Also possible we are flushing TLS error information to peer.
if (buf_unused(&jc->out_wire_buf) && pn_tls_need_encrypt_output_buffers(jc->tls)) {
pn_tls_give_encrypt_output_buffers(jc->tls, &jc->out_wire_buf, 1);
jabber_tls_process(jc);
jcheck( pn_tls_take_encrypt_output_buffers(jc->tls, &jc->out_wire_buf, 1) == 1 );
// Write the application data we just encrypted.
jcheck( pn_raw_connection_write_buffers(jc->rawc, &jc->out_wire_buf, 1) == 1);
buf_set_in_use(&jc->out_wire_buf, true);
}
// Remember whether we missed some output buffered in the TLS library and need to come back.
jc->tls_has_output = pn_tls_is_encrypt_output_pending(jc->tls) > 0;
if (jc->need_rawc_write_close && !jc->tls_has_output) {
// We have written to the raw connection all the output the TLS library can ever give us.
pn_raw_connection_write_close(jc->rawc);
jc->need_rawc_write_close = false;
}
}
}