void tlsio_bearssl_dowork()

in adapters/tlsio_bearssl.c [1255:1403]


void tlsio_bearssl_dowork(CONCRETE_IO_HANDLE tls_io)
{
    unsigned char *buffer;
    size_t bufferLen;
    unsigned long bearResult;
    int lasterr;

    if (tls_io != NULL)
    {
        TLS_IO_INSTANCE *tls_io_instance = (TLS_IO_INSTANCE *)tls_io;

        if (tls_io_instance->tlsio_state == TLSIO_STATE_NOT_OPEN)
        {
            // Not open do nothing
        }
        else 
        {
            if (tls_io_instance->tlsio_state != TLSIO_STATE_OPENING_UNDERLYING_IO && tls_io_instance->tlsio_state != TLSIO_STATE_CLOSING)
            {
                bearResult = br_ssl_engine_current_state(&tls_io_instance->sc.eng);

                if (bearResult & BR_SSL_SENDREC)
                {
                    // The engine has data to send
                    buffer = br_ssl_engine_sendrec_buf(&tls_io_instance->sc.eng, &bufferLen);

                    if (xio_send(tls_io_instance->socket_io, buffer, bufferLen, NULL, NULL) != 0)
                    {
                        LogError("Error in xio_send.");
                        indicate_error(tls_io_instance);
                    }
                    else
                    {
                        br_ssl_engine_sendrec_ack(&tls_io_instance->sc.eng, bufferLen);
                    }
                }

                bearResult = br_ssl_engine_current_state(&tls_io_instance->sc.eng);

                if (bearResult & BR_SSL_RECVREC)
                {
                    // The engine can accept data from the peer if there is any
                    LIST_ITEM_HANDLE first_pending_io = singlylinkedlist_get_head_item(tls_io_instance->pending_todecrypt_list);
                    
                    if (first_pending_io != NULL)
                    {
                        PENDING_TLS_IO *pending_tls_io = (PENDING_TLS_IO*)singlylinkedlist_item_get_value(first_pending_io);

                        if (pending_tls_io != NULL)
                        {
                            buffer = br_ssl_engine_recvrec_buf(&tls_io_instance->sc.eng, &bufferLen);

                            if (bufferLen == 0)
                            {
                                LogError("Zero length buffer returned by BearSSL");
                                indicate_error(tls_io_instance);
                            }
                            else
                            {
                                if (pending_tls_io->size < bufferLen)
                                {
                                    bufferLen = pending_tls_io->size;
                                }
                                memcpy(buffer, pending_tls_io->bytes, bufferLen);
                                br_ssl_engine_recvrec_ack(&tls_io_instance->sc.eng, bufferLen);

                                if (bufferLen < pending_tls_io->size)
                                {
                                    pending_tls_io->size -= bufferLen;
                                    memcpy(pending_tls_io->bytes, pending_tls_io->bytes + bufferLen, pending_tls_io->size);
                                }
                                else
                                {
                                    free(pending_tls_io->bytes);
                                    free(pending_tls_io);
                                    (void)singlylinkedlist_remove(tls_io_instance->pending_todecrypt_list, first_pending_io);
                                }
                            }
                        }
                    }
                }

                bearResult = br_ssl_engine_current_state(&tls_io_instance->sc.eng);

                if (bearResult & BR_SSL_SENDAPP)
                {
                    if (tls_io_instance->tlsio_state == TLSIO_STATE_IN_HANDSHAKE)
                    {
                        tls_io_instance->tlsio_state = TLSIO_STATE_OPEN;
                        indicate_open_complete(tls_io_instance, IO_OPEN_OK);
                    }

                    // Engine is ready for application data - send it if we have any
                    LIST_ITEM_HANDLE first_pending_io = singlylinkedlist_get_head_item(tls_io_instance->pending_toencrypt_list);
                    
                    if (first_pending_io != NULL)
                    {
                        PENDING_TLS_IO *pending_tls_io = (PENDING_TLS_IO*)singlylinkedlist_item_get_value(first_pending_io);

                        if (pending_tls_io != NULL)
                        {
                            buffer = br_ssl_engine_sendapp_buf(&tls_io_instance->sc.eng, &bufferLen);

                            if (pending_tls_io->size < bufferLen)
                            {
                                bufferLen = pending_tls_io->size;
                            }
                            memcpy(buffer, pending_tls_io->bytes, bufferLen);
                            br_ssl_engine_sendapp_ack(&tls_io_instance->sc.eng, bufferLen);

                            if (bufferLen < pending_tls_io->size)
                            {
                                pending_tls_io->size -= bufferLen;
                                memcpy(pending_tls_io->bytes, pending_tls_io->bytes + bufferLen, pending_tls_io->size);
                            }
                            else
                            {
                                pending_tls_io->on_send_complete(pending_tls_io->callback_context, IO_SEND_OK);
                                free(pending_tls_io->bytes);
                                free(pending_tls_io);
                                (void)singlylinkedlist_remove(tls_io_instance->pending_toencrypt_list, first_pending_io);
                                br_ssl_engine_flush(&tls_io_instance->sc.eng, 0);
                            }
                        }
                    }
                    
                }

                bearResult = br_ssl_engine_current_state(&tls_io_instance->sc.eng);

                if (bearResult & BR_SSL_RECVAPP)
                {
                    // Application data is waiting to be forwarded
                    buffer = br_ssl_engine_recvapp_buf(&tls_io_instance->sc.eng, &bufferLen);
                    tls_io_instance->on_bytes_received(tls_io_instance->on_bytes_received_context, buffer, bufferLen);
                    br_ssl_engine_recvapp_ack(&tls_io_instance->sc.eng, bufferLen);
                }
            }

            if ((lasterr = br_ssl_engine_last_error(&tls_io_instance->sc.eng)) != 0)
            {
                LogError("BearSSL reported an error: %d", lasterr);
                indicate_error(tls_io_instance);
            }

            xio_dowork(tls_io_instance->socket_io);
        }
    }
}