aboutsummaryrefslogtreecommitdiffstats
path: root/src/server_lds.c
blob: fc51596709ca748297ee8ae059828970b31ed0c0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/**
 * @file  server_lds.c
 * @brief Local Discovery Server implementation.
 *
 * This program runs an OPC UA Local Discovery Server (LDS) configured with
 * encryption and a configurable cleanup timeout. Other OPC UA servers register
 * with this LDS using the RegisterServer2 service. Clients can query this LDS
 * using the FindServers service to discover registered servers.
 */

#include "common.h"

#include <open62541/plugin/accesscontrol_default.h>
#include <open62541/plugin/log_stdout.h>
#include <open62541/server.h>
#include <open62541/server_config_default.h>

#include <signal.h>
#include <stdlib.h>

UA_Boolean running = true;

static void
stopHandler (int sig)
{
  UA_LOG_INFO (UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "received ctrl-c");
  running = false;
}

int
main (int argc, char *argv[])
{
  signal (SIGINT, stopHandler);
  signal (SIGTERM, stopHandler);

  if (argc < 7)
    {
      UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
                    "Usage: %s\n"
                    "  <port> <applicationUri>\n"
                    "  <server-certificate.der> <private-key.der>\n"
                    "  <cleanup-timeout-seconds>\n"
                    "  <auth-mode> [<username> <password>]\n"
                    "  [<trustlist1.der>, ...]\n"
                    "\n"
                    "Auth modes: anonymous, user",
                    argv[0]);
      return EXIT_FAILURE;
    }

  UA_UInt16 port = (UA_UInt16)atoi (argv[1]);
  int cleanupTimeout = atoi (argv[5]);

  /* The OPC UA specification requires the cleanup timeout to exceed the
     register-server interval.  open62541 enforces a floor of 10 seconds. */
  if (cleanupTimeout <= 10)
    {
      UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
                    "Cleanup timeout must be > 10 seconds (got %d)",
                    cleanupTimeout);
      return EXIT_FAILURE;
    }

  int idx = 6;
  const char *authMode = argv[idx++];
  UA_Boolean allowAnonymous;
  char *username = NULL, *password = NULL;

  if (strcmp (authMode, "anonymous") == 0)
    {
      allowAnonymous = true;
    }
  else if (strcmp (authMode, "user") == 0)
    {
      if (idx + 2 > argc)
        {
          UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
                        "Auth mode 'user' requires <username> <password>");
          return EXIT_FAILURE;
        }
      allowAnonymous = false;
      username = argv[idx++];
      password = argv[idx++];
    }
  else
    {
      UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
                    "Unknown auth mode: %s "
                    "(expected 'anonymous' or 'user')",
                    authMode);
      return EXIT_FAILURE;
    }

  size_t trustSize = (idx < argc) ? (size_t)(argc - idx) : 0;

  UA_StatusCode retval;
  UA_Server *server = createSecureServer (port, argv[2], argv[3], argv[4],
                                          argv + idx, trustSize, &retval);
  if (!server)
    return EXIT_FAILURE;

  UA_ServerConfig *serverConfig = UA_Server_getConfig (server);

  /* Configure access control after server creation because
     UA_ServerConfig_setDefaultWithSecurityPolicies (called by
     createSecureServer) resets the access control plugin.  The credential
     list is deep-copied by UA_AccessControl_default. */
  if (!allowAnonymous)
    {
      UA_UsernamePasswordLogin logins[1];
      logins[0].username = UA_STRING (username);
      logins[0].password = UA_STRING (password);
      retval = UA_AccessControl_default (serverConfig, false, NULL, 1, logins);
      if (retval != UA_STATUSCODE_GOOD)
        {
          UA_Server_delete (server);
          return EXIT_FAILURE;
        }
    }

  /* Mark this server as a Discovery Server so clients can identify it. */
  serverConfig->applicationDescription.applicationType
      = UA_APPLICATIONTYPE_DISCOVERYSERVER;

  /* Time (seconds) after which stale registrations are removed.  Must
     exceed the registering server's re-register interval. */
  serverConfig->discoveryCleanupTimeout = cleanupTimeout;

  retval = UA_Server_run (server, &running);

  UA_Server_delete (server);
  return retval == UA_STATUSCODE_GOOD ? EXIT_SUCCESS : EXIT_FAILURE;
}