/** * @file server_register.c * @brief OPC UA Server that registers with a Local Discovery Server. * * This program runs an OPC UA server that periodically registers itself with * a remote LDS using the RegisterServer2 service. Encryption is optional for * the server; the client connection to the LDS uses a separate certificate * pair. On shutdown, it deregisters from the LDS. */ #include "common.h" #include "config.h" #include #include #include #include #include #include #include #include volatile UA_Boolean g_running = true; static void _s_stop_handler (int sig) { g_running = false; } /* ======================================================================== * LDS Client Config Helper * ======================================================================== */ /** * Parameters for building a client config that connects to the LDS. * Gathered once in main, then reused for every register/deregister call. */ typedef struct { const char *app_uri; security_config sec; auth_config auth; int log_level; } lds_client_params; /** * Builds a fresh UA_ClientConfig from lds_client_params. * * UA_Server_registerDiscovery / deregisterDiscovery consume (clear) the * client config, so a new one must be created before every call. */ static UA_StatusCode _s_make_lds_client_config (UA_ClientConfig *cc, const lds_client_params *p) { memset (cc, 0, sizeof (UA_ClientConfig)); UA_StatusCode rv; if (p->sec.cert_path) rv = create_secure_client_config (cc, p->app_uri, &p->sec, &p->auth); else rv = create_unsecure_client_config (cc, p->app_uri, &p->auth); if (rv != UA_STATUSCODE_GOOD) return rv; cc->logging->context = (void *)(uintptr_t)p->log_level; return UA_STATUSCODE_GOOD; } /** * Creates a fresh client config and registers with the LDS. */ static UA_StatusCode _s_register_with_lds (UA_Server *server, const lds_client_params *p, const char *endpoint) { UA_ClientConfig cc; UA_StatusCode rv = _s_make_lds_client_config (&cc, p); if (rv != UA_STATUSCODE_GOOD) return rv; UA_String url = UA_STRING_ALLOC (endpoint); rv = UA_Server_registerDiscovery (server, &cc, url, UA_STRING_NULL); UA_String_clear (&url); return rv; } /** * Creates a fresh client config and deregisters from the LDS. */ static UA_StatusCode _s_deregister_from_lds (UA_Server *server, const lds_client_params *p, const char *endpoint) { UA_ClientConfig cc; UA_StatusCode rv = _s_make_lds_client_config (&cc, p); if (rv != UA_STATUSCODE_GOOD) return rv; UA_String url = UA_STRING_ALLOC (endpoint); rv = UA_Server_deregisterDiscovery (server, &cc, url); UA_String_clear (&url); return rv; } /* ======================================================================== * Main * ======================================================================== */ int main (int argc, char **argv) { signal (SIGINT, _s_stop_handler); signal (SIGTERM, _s_stop_handler); if (argc < 4 || argc > 5) { UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Usage: %s " " [log-level]", argv[0]); return EXIT_FAILURE; } const char *discovery_endpoint = argv[3]; const char *log_level_str = (argc == 5) ? argv[4] : "info"; int log_level = parse_log_level (log_level_str); if (log_level < 0) { UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Unknown log level: %s " "(expected trace, debug, info, warning, error, fatal)", log_level_str); return EXIT_FAILURE; } /* ── Load server config ─────────────────────────────────────── */ int rc = EXIT_FAILURE; config server_cfg = { 0 }; config client_cfg = { 0 }; security_config server_sec = { 0 }; security_config client_sec = { 0 }; UA_Server *server = NULL; if (config_load (argv[1], &server_cfg) != 0) goto cleanup; int port = config_require_int (&server_cfg, "port", "ServerRegister"); const char *application_uri = config_require (&server_cfg, "applicationUri", "ServerRegister"); int register_interval = config_require_int (&server_cfg, "registerInterval", "ServerRegister"); if (!application_uri || port < 0 || register_interval < 0) goto cleanup; if (parse_security_config (&server_cfg, "ServerRegister", false, &server_sec) != 0) goto cleanup; auth_config server_auth; if (parse_auth_config (&server_cfg, "ServerRegister", &server_auth) != 0) goto cleanup; /* ── Load client config ────
<?php // Profile editing page: separate forms for username, email, password, and notifications.?>
<div class="profile-page">
    <h1>Profile settings</h1>
    <?php include __DIR__ . '/../partials/flash.php'; ?>

    <section class="profile-section">
        <h2>Username</h2>
        <form method="POST" action="/profile/username" class="profile-form">
            <?= \App\Csrf::field() ?>
            <label for="username">Username</label>
            <input type="text" id="username" name="username"
                   value="<?= htmlspecialchars($user['username']) ?>"
                   required pattern="[a-zA-Z0-9_]{3,20}">
            <button type="submit">Update username</button>
        </form>
    </section>

    <section class="profile-section">
        <h2>Email</h2>
        <p class="hint">Changing your email will require re-verification.</p>
        <form method="POST" action="/profile/email" class="profile-form">
            <?= \App\Csrf::field() ?>
            <label for="email">Email</label>
            <input type="email" id="email" name="email"
                   value="<?= htmlspecialchars($user['email']) ?>" required>
            <button type="submit">Update email</button>
        </form>
    </section>

    <section class="profile-section">
        <h2>Password</h2>
        <form method="POST" action="/profile/password" class="profile-form">
            <?= \App\Csrf::field() ?>
            <label for="current_password">Current password</label>
            <input type="password" id="current_password" name="current_password" required>

            <label for="new_password">New password</label>
            <input type="password" id="new_password" name="new_password" required minlength="8">

            <label for="new_password_confirm">Confirm new password</label>
            <input type="password" id="new_password_confirm" name="new_password_confirm" required minlength="8">

            <button type="submit">Update password</button>
        </form>
    </section>

    <section class="profile-section">
        <h2>Notifications</h2>
        <form method="POST" action="/profile/notifications" class="profile-form">
            <?= \App\Csrf::field() ?>
            <label class="checkbox-label">
                <input type="checkbox" name="notify_comments"
                       <?= $user['notify_comments'] ? 'checked' : '' ?>>
                Email me when someone comments on my posts
            </label>
            <button type="submit">Save preferences</button>
        </form>
    </section>
</div>