Skip to content

is there a demo for this api lws_tls_cert_updated? #3525

@pppaulpeter

Description

@pppaulpeter

Hi @andy,

is the following code the correct way to call lws_tls_cert_updated no matter the backend ssl library(openssl or mbedtls)? this is the '''hotswap''' will not destroy the vhost and will not disconnect the old tls link when update the websocket server side tls certificate file, correct? thanks!

#include <libwebsockets.h>
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

/* ---- pending cert update from cert-manager thread ---- */

struct pending_tls_update {
    int has_update;

    char certpath[256];
    char keypath[256];


    char *mem_cert;
    size_t len_mem_cert;

    char *mem_key;
    size_t len_mem_key;
};

static pthread_mutex_t g_tls_lock = PTHREAD_MUTEX_INITIALIZER;
static struct pending_tls_update g_pending;

static struct lws_context *g_ctx; 

static int read_file_nulterm(const char *path, char **out, size_t *out_len)
{
    FILE *f = fopen(path, "rb");
    if (!f) return -1;

    if (fseek(f, 0, SEEK_END) != 0) { fclose(f); return -1; }
    long sz = ftell(f);
    if (sz < 0) { fclose(f); return -1; }
    rewind(f);

    char *buf = (char*)malloc((size_t)sz + 1);
    if (!buf) { fclose(f); return -1; }

    size_t n = fread(buf, 1, (size_t)sz, f);
    fclose(f);
    if (n != (size_t)sz) { free(buf); return -1; }

    buf[n] = '\0';          /* keep it NUL-terminated */
    *out = buf;
    *out_len = n + 1;       /* include NUL */
    return 0;
}

/* Called by certificate-management module  */
void certmgr_notify_tls_updated(const char *certpath, const char *keypath)
{
    char *mc = NULL, *mk = NULL;
    size_t lc = 0, lk = 0;

    /* Load files now so the lws thread only swaps */
    if (read_file_nulterm(certpath, &mc, &lc) ||
        read_file_nulterm(keypath,  &mk, &lk)) {
        free(mc);
        free(mk);
        return;
    }

    pthread_mutex_lock(&g_tls_lock);

    free(g_pending.mem_cert);
    free(g_pending.mem_key);

    snprintf(g_pending.certpath, sizeof(g_pending.certpath), "%s", certpath);
    snprintf(g_pending.keypath,  sizeof(g_pending.keypath),  "%s", keypath);

    g_pending.mem_cert = mc;
    g_pending.len_mem_cert = lc;
    g_pending.mem_key = mk;
    g_pending.len_mem_key = lk;
    g_pending.has_update = 1;

    pthread_mutex_unlock(&g_tls_lock);

    /* Wake lws service thread safely */
    lws_cancel_service(g_ctx); 
}

/* ---- Apply update ONLY inside the lws service thread ---- */

static void apply_pending_tls_update_in_lws_thread(void)
{
    struct pending_tls_update u;
    memset(&u, 0, sizeof(u));

    pthread_mutex_lock(&g_tls_lock);
    if (g_pending.has_update) {
        u = g_pending;                
        memset(&g_pending, 0, sizeof(g_pending)); 
    }
    pthread_mutex_unlock(&g_tls_lock);

    if (!u.has_update)
        return;


    int rc = lws_tls_cert_updated(g_ctx,
                                 u.certpath, u.keypath,
                                 u.mem_cert, u.len_mem_cert,
                                 u.mem_key,  u.len_mem_key);

    if (rc)
        lwsl_err("TLS reload failed (rc=%d)\n", rc);
    else
        lwsl_notice("TLS reload OK\n");

    free(u.mem_cert);
    free(u.mem_key);
}


static int
callback_wss(struct lws *wsi, enum lws_callback_reasons reason,
             void *user, void *in, size_t len)
{
    (void)wsi; (void)user; (void)in; (void)len;

    switch (reason) {

     ....

    case LWS_CALLBACK_EVENT_WAIT_CANCELLED:
        apply_pending_tls_update_in_lws_thread();
        break;

    default:
        break;
    }

    return 0;
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions