--- /dev/null
+[func*] fdupont
+ The deprecated control agent was removed.
+ (Gitlab #3448)
The Kea Control Agent
*********************
-.. _agent-overview:
+Kea version 3.1,7 removed the obsolete cControl Agent. Please use
+the Kea server control sockets.
-Overview of the Kea Control Agent
-=================================
+.. _migration:
-The Kea Control Agent (CA) is a daemon which exposes a RESTful control
-interface for managing Kea servers. The daemon can receive control
-commands over HTTP and either forward these commands to the respective
-Kea servers or handle these commands on its own. The determination
-whether the command should be handled by the CA or forwarded is made by
-checking the value of the ``service`` parameter, which may be included in
-the command from the controlling client. The details of the supported
-commands, as well as their structures, are provided in
-:ref:`ctrl-channel`.
+Migration
+=========
-The CA can use hook libraries to provide support for additional commands
-or to program custom behavior of existing commands. Such hook libraries must
-implement callouts for the ``control_command_receive`` hook point. Details
-about creating new hook libraries and supported hook points can be found
-in the `Kea Developer's
-Guide <https://reports.kea.isc.org/dev_guide/>`__.
+The HTTP/HTTPS control sockets of kea servers are:
-The CA processes received commands according to the following algorithm:
+- in :ref:`dhcp4-http-ctrl-channel` section for the DHCPv4 server
-- Pass command into any installed hooks (regardless of service
- value(s)). If the command is handled by a hook, return the response.
+- in :ref:`dhcp6-http-ctrl-channel` section for the DHCPv6 server
-- If the service specifies one or more services, forward the command to
- the specified services and return the accumulated responses.
+- in :ref:`d2-http-ctrl-channel` section for the DHCP-DDNS server
-- If the service is not specified or is an empty list, handle the
- command if the CA supports it.
+An entry must be created in ``socket-controls` list with:
-.. note::
+- ``http`` or ``https`` (the second is better when TLS parameters
+ are present) for the ``socket-type``
- The kea-ctrl-agent is deprecated. As of Kea 2.7.2 the Kea servers:
- kea-dhcp4, kea-dhcp6, and kea-dhcp-ddns directly support command API
- connections over HTTPS/HTTP. (:ref:`ctrl-channel-migration`).
+- ``http-host`` becomes ``socket-address``
-.. _agent-configuration:
+- ``http-port`` becomes ``socket-port``
-Configuration
-=============
+All other parameters, ``http-headers``, TLS parameters, basic HTTP
+authentication setup, ..., can go directly in the control socket entry
+of the Kea server configuration with the same syntax and meaning.
-The following example demonstrates the basic CA configuration.
-
-.. code-block:: json
-
- {
- "Control-agent": {
- "http-host": "10.20.30.40",
- "http-port": 8000,
- "http-headers": [
- {
- "name": "Strict-Transport-Security",
- "value": "max-age=31536000"
- }
- ],
- "trust-anchor": "/path/to/the/ca-cert.pem",
- "cert-file": "/path/to/the/agent-cert.pem",
- "key-file": "/path/to/the/agent-key.pem",
- "cert-required": true,
- "authentication": {
- "type": "basic",
- "realm": "kea-control-agent",
- "clients": [
- {
- "user": "admin",
- "password": "1234"
- } ]
- },
-
- "control-sockets": {
- "dhcp4": {
- "comment": "main server",
- "socket-type": "unix",
- "socket-name": "/path/to/the/unix/socket-v4"
- },
- "dhcp6": {
- "socket-type": "unix",
- "socket-name": "/path/to/the/unix/socket-v6",
- "user-context": { "version": 3 }
- },
- "d2": {
- "socket-type": "unix",
- "socket-name": "/path/to/the/unix/socket-d2"
- }
- },
-
- "hooks-libraries": [
- {
- "library": "custom_hooks_example.so",
- "parameters": {
- "param1": "foo"
- }
- } ],
-
- "loggers": [ {
- "name": "kea-ctrl-agent",
- "severity": "INFO"
- } ]
- }
- }
-
-The ``http-host`` and ``http-port`` parameters specify an IP address and
-port to which HTTP service will be bound. In the example configuration
-provided above, the RESTful service will be available at the URL
-``https://10.20.30.40:8000/``. If these parameters are not specified, the
-default URL is ``http://127.0.0.1:8000/``.
-
-When using Kea's HA hook library with multi-threading,
-the address:port combination used for CA must be
-different from the HA peer URLs, which are strictly
-for internal HA traffic between the peers. User commands should
-still be sent via the CA.
-
-Since Kea 2.7.5 the ``http-headers`` parameter specifies a list of
-extra HTTP headers to add to HTTP responses.
-
-The ``trust-anchor``, ``cert-file``, ``key-file``, and ``cert-required``
-parameters specify the TLS setup for HTTP, i.e. HTTPS. If these parameters
-are not specified, HTTP is used. The TLS/HTTPS support in Kea is
-described in :ref:`tls`.
-
-As mentioned in :ref:`agent-overview`, the CA can forward
-received commands to the Kea servers for processing. For example,
-:isccmd:`config-get` is sent to retrieve the configuration of one of the Kea
-services. When the CA receives this command, including a ``service``
-parameter indicating that the client wishes to retrieve the
-configuration of the DHCPv4 server, the CA forwards the command to that
-server and passes the received response back to the client. More about
-the ``service`` parameter and the general structure of commands can be
-found in :ref:`ctrl-channel`.
-
-The CA uses UNIX domain sockets to forward control commands and receive
-responses from other Kea services. The ``dhcp4``, ``dhcp6``, and ``d2``
-maps specify the files to which UNIX domain sockets are bound. In the
-configuration above, the CA connects to the DHCPv4 server via
-``/path/to/the/unix/socket-v4`` to forward the commands to it.
-Obviously, the DHCPv4 server must be configured to listen to connections
-via this same socket. In other words, the command-socket configuration
-for the DHCPv4 server and the CA (for that server) must match. Consult
-:ref:`dhcp4-unix-ctrl-channel`, :ref:`dhcp6-unix-ctrl-channel`, and
-:ref:`d2-unix-ctrl-channel` to learn how the UNIX socket configuration is
-specified for the DHCPv4, DHCPv6, and D2 services.
-
-.. note::
-
- As of Kea 2.7.9, control sockets may only reside in the directory
- determined during compilation as ``"[kea-install-dir]/var/run/kea"``,
- which must also have ``0750`` access rights. This path may be overridden
- at startup by setting the environment variable ``KEA_CONTROL_SOCKET_DIR``
- to the desired path. If a path other than this value is used in
- ``socket-name``, Kea will emit an error and refuse to start or, if already
- running, log an unrecoverable error. For ease of use in simply omit the
- path component from ``socket-name``.
-
-User contexts can store arbitrary data as long as they are in valid JSON
-syntax and their top-level element is a map (i.e. the data must be
-enclosed in curly brackets). Some hook libraries may expect specific
-formatting; please consult the relevant hook library documentation for
-details.
-
-User contexts can be specified on either global scope, control socket,
-basic authentication, or loggers. One other useful feature is the
-ability to store comments or descriptions; the parser translates a
-"comment" entry into a user context with the entry, which allows a
-comment to be attached within the configuration itself.
-
-Basic HTTP authentication protects
-against unauthorized uses of the control agent by local users. For
-protection against remote attackers, HTTPS and reverse proxy of
-:ref:`agent-secure-connection` provide stronger security.
-
-The authentication is described in the ``authentication`` block
-with the mandatory ``type`` parameter, which selects the authentication.
-Currently only the basic HTTP authentication (type basic) is supported.
-
-The ``realm`` authentication parameter is used for error messages when
-the basic HTTP authentication is required but the client is not
-authorized.
-
-When the ``clients`` authentication list is configured and not empty,
-basic HTTP authentication is required. Each element of the list
-specifies a user ID and a password. The user ID is mandatory, must
-not be empty, and must not contain the colon (:) character. The
-password is optional; when it is not specified an empty password
-is used.
-
-.. note::
-
- The basic HTTP authentication user ID and password are encoded
- in UTF-8, but the current Kea JSON syntax only supports the Latin-1
- (i.e. 0x00..0xff) Unicode subset.
-
-To avoid exposing the user ID and/or the associated
-password, these values can be read from files. The syntax is extended by:
-
-- The ``directory`` authentication parameter, which handles the common
- part of file paths. The default value is the empty string.
-
-- The ``password-file`` client parameter, which, alongside the ``directory``
- parameter, specifies the path of a file that can contain the password,
- or when no user ID is given, the whole basic HTTP authentication secret.
-
-- The ``user-file`` client parameter, which, with the ``directory`` parameter,
- specifies the path of a file where the user ID can be read.
-
-When files are used, they are read when the configuration is loaded,
-to detect configuration errors as soon as possible.
-
-Hook libraries can be loaded by :iscman:`kea-ctrl-agent` in the same way as
-they are loaded by :iscman:`kea-dhcp4` and :iscman:`kea-dhcp6`. The CA currently
-supports one hook point - ``control_command_receive`` - which makes it
-possible to delegate the processing of some commands to the hook library.
-The ``hooks-libraries`` list contains the list of hook libraries that
-should be loaded by :iscman:`kea-ctrl-agent`, along with their configuration information
-specified with ``parameters``.
-
-Please consult :ref:`logging` for the details on how to configure
-logging. The CA's root logger's name is :iscman:`kea-ctrl-agent`, as given in
-the example above.
-
-.. _agent-secure-connection:
-
-Secure Connections
-==================
-
-Configuration options related to Kea Control Agent security can be found in the
-:ref:`secure-control-agent` section.
-
-.. _agent-launch:
-
-Starting and Stopping the Control Agent
-=======================================
-
-:iscman:`kea-ctrl-agent` accepts the following command-line switches:
-
-- ``-c file`` - specifies the configuration file.
-
-- ``-d`` - specifies whether the agent logging should be switched to
- debug/verbose mode. In verbose mode, the logging severity and
- debuglevel specified in the configuration file are ignored and
- "debug" severity and the maximum debuglevel (99) are assumed. The
- flag is convenient for temporarily switching the server into maximum
- verbosity, e.g. when debugging.
-
-- ``-t file`` - specifies the configuration file to be tested.
- :iscman:`kea-netconf` attempts to load it and conducts sanity checks;
- certain checks are possible only while running the actual server. The
- actual status is reported with exit code (0 = configuration appears valid,
- 1 = error encountered). Kea prints out log messages to standard
- output and error to standard error when testing the configuration.
-
-- ``-v`` - displays the version of :iscman:`kea-ctrl-agent` and exits.
-
-- ``-V`` - displays the extended version information for :iscman:`kea-ctrl-agent`
- and exits. The listing includes the versions of the libraries
- dynamically linked to Kea.
-
-- ``-W`` - displays the Kea configuration report and exits. The report
- is a copy of the ``config.report`` file produced by ``meson setup``;
- it is embedded in the executable binary.
-
- The contents of the ``config.report`` file may also be accessed by examining
- certain libraries in the installation tree or in the source tree.
-
- .. code-block:: shell
-
- # from installation using libkea-process.so
- $ strings ${prefix}/lib/libkea-process.so | sed -n 's/;;;; //p'
-
- # from sources using libkea-process.so
- $ strings src/lib/process/.libs/libkea-process.so | sed -n 's/;;;; //p'
-
- # from sources using libkea-process.a
- $ strings src/lib/process/.libs/libkea-process.a | sed -n 's/;;;; //p'
-
- # from sources using libcfgrpt.a
- $ strings src/lib/process/cfgrpt/.libs/libcfgrpt.a | sed -n 's/;;;; //p'
-
-- ``-X`` - As of Kea 3.0, disables security restrictions. The server will
- still check for violations but will emit warning logs when they are found
- rather than fail with an error. Please see
- :ref:`sec-kea-runtime-security-policy-checking` for details.
-
-The CA is started by running its binary and specifying the configuration
-file it should use. For example:
-
-.. code-block:: console
-
- $ ./kea-ctrl-agent -c /usr/local/etc/kea/kea-ctrl-agent.conf
-
-It can be started by :iscman:`keactrl` as well (see :ref:`keactrl`).
-
-.. _agent-clients:
-
-Connecting to the Control Agent
-===============================
-
-For an example of a tool that can take advantage of the RESTful API, see
-:ref:`kea-shell`.
[INF] File "kea-dhcp-ddns@2022-07-27.yang" was installed.
[INF] No datastore changes to apply.
[INF] Connection 27 created.
- [INF] Module "kea-ctrl-agent" was installed.
- [INF] File "kea-ctrl-agent@2019-08-12.yang" was installed.
- [INF] No datastore changes to apply.
- [INF] Connection 29 created.
+ [INF] Connection 28 created.
[INF] Module "kea-dhcp4-server" was installed.
[INF] File "kea-dhcp4-server@2022-11-30.yang" was installed.
[INF] No datastore changes to apply.
- [INF] Connection 31 created.
+ [INF] Connection 30 created.
[INF] Module "kea-dhcp6-server" was installed.
[INF] File "kea-dhcp6-server@2022-11-30.yang" was installed.
[INF] No datastore changes to apply.
ietf-yang-metadata | 2016-08-05 | i | | | |
ietf-yang-schema-mount | 2019-01-14 | I | user:user | 644 | |
ietf-yang-types | 2013-07-15 | I | user:user | 444 | |
- kea-ctrl-agent | 2019-08-12 | I | user:user | 600 | |
kea-dhcp-ddns | 2022-07-27 | I | user:user | 600 | |
kea-dhcp-types | 2022-11-30 | I | user:user | 600 | |
kea-dhcp4-server | 2022-11-30 | I | user:user | 600 | |
The currently supported models are ``kea-dhcp4-server`` and
``kea-dhcp6-server``. There is partial support for
``ietf-dhcpv6-server``, but the primary focus of testing has been on Kea DHCP
-servers. Other models (:iscman:`kea-dhcp-ddns` and :iscman:`kea-ctrl-agent`)
-are currently not supported.
+servers. Other models (e.g. :iscman:`kea-dhcp-ddns`) are currently not supported.
.. _using-netconf:
The managed Kea servers and agents are described in the
``managed-servers`` section. Each sub-section begins with the service
-name: ``dhcp4``, ``dhcp6``, ``d2`` (the DHCP-DDNS server does not
-support the control-channel feature yet), and ``ca`` (the control
-agent).
+name: ``dhcp4``, ``dhcp6``, and ``d2``.
+
Each managed server entry may contain:
debugging mode where everything is printed on stdout, and it can also be
used to redirect commands easily. ``unix`` is the standard direct
server control channel, which uses UNIX sockets; ``http`` uses
- a control agent, which accepts HTTP connections.
+ a control channel, which accepts HTTP connections.
- ``socket-name`` - the local socket name for the ``unix`` socket type
(default empty string).
// "stdout" which outputs the configuration on the standard output,
// "unix" which uses the local control channel supported by the
// "dhcp4" and "dhcp6" servers ("d2" support is not yet available),
- // and "http" which uses the Control Agent "ca" to manage itself or
- // to forward commands to "dhcp4" or "dhcp6".
+ // and "http" which uses HTTP/HTTPS control channels.
"managed-servers":
{
// This is how kea-netconf can communicate with the DHCPv4 server.
}
},
- // Of course the Control Agent (CA) supports HTTP.
- "ca":
+ //
+ "dhcp4-http":
{
- "model": "kea-ctrl-agent",
+ "comment": "DHCPv4 server using HTTP",
+ "model": "kea-dhcp4-server",
"control-socket":
{
"socket-type": "http",
High Availability (HA) of the DHCP service is provided by running multiple
cooperating server instances. If any of these instances becomes unavailable for
-any reason (DHCP software crash, Control Agent software crash, power outage,
+any reason (DHCP software crash, power outage,
hardware failure), a surviving server instance can continue providing reliable
service to clients. Many DHCP server implementations include the "DHCP Failover"
protocol, whose most significant features are communication between the servers,
The HTTPS configuration parameters are:
- ``trust-anchor`` - specifies the name of a file or directory where the
- certification authority certificate of a Control Agent can be found.
+ certification authority certificate of a Kea end entity can be found.
- ``cert-file`` - specifies the name of the file containing the end-entity
certificate to use.
As the High Availability hook library is an HTTPS client, there is no
``cert-required`` parameter in this hook configuration.
-This parameter can be set in the Control Agent to require and verify a client
+This parameter can be set at the server side to require and verify a client
certificate in client-server communication. It does not affect communication
between HA peers at the client side; see below for information on the server
side.
-Before Kea 2.1.7 using HTTPS in the HA setup required use of the Control Agent
-on all peers. (See :ref:`tls` for Control Agent TLS configuration).
-
Since Kea 2.1.7 the HTTPS server side is supported:
- the peer entry for the server name is used for the TLS setting.
parameter: when set to ``true``, commands which are not used by the hook are
rejected. The default is ``true`` since Kea 3.0.0.
-The following is an example of an HA server pair and Control Agent configuration
-for ``hot-standby`` with TLS.
+The following is an example of an HA server pair for ``hot-standby`` with TLS.
Server 1:
"pools": [{
"pool": "192.0.3.100 - 192.0.3.250"
}]
- }]
+ }],
+
+ "control-sockets": [{
+ "socket-type": "https",
+ "socket-address": "192.168.56.33",
+ "socket-port": 8000,
+ "trust-anchor": "/var/lib/kea/CA.pem",
+ "cert-file": "/var/lib/kea/server1_cert.pem",
+ "key-file": "/var/lib/kea/server1_key.pem",
+ "cert-required": true
+ }]
}
}
"pools": [{
"pool": "192.0.3.100 - 192.0.3.250"
}]
+ }],
+
+ "control-sockets":[{
+ "socket-type": "https",
+ "socket-address": "192.168.56.66",
+ "socket-port": 8000,
+ "trust-anchor": "/var/lib/kea/CA.pem",
+ "cert-file": "/var/lib/kea/server2_cert.pem",
+ "key-file": "/var/lib/kea/server2_key.pem",
+ "cert-required": true
}]
+
}
}
-Control Agent on Server 1:
-::
-
- {
- "Control-agent": {
- "http-host": "192.168.56.33",
- "http-port": 8000,
- "control-sockets": {
- "dhcp4": {
- "socket-type": "unix",
- "socket-name": "/var/run/kea/control_socket"
- }
- },
- "trust-anchor": "/var/lib/kea/CA.pem",
- "cert-file": "/var/lib/kea/server1_cert.pem",
- "key-file": "/var/lib/kea/server1_key.pem",
- "cert-required": true
- }
- }
-
-Control Agent on Server 2:
-::
-
- {
- "Control-agent": {
- "http-host": "192.168.56.66",
- "http-port": 8000,
- "control-sockets": {
- "dhcp4": {
- "socket-type": "unix",
- "socket-name": "/var/run/kea/control_socket"
- }
- },
- "trust-anchor": "/var/lib/kea/CA.pem",
- "cert-file": "/var/lib/kea/server2_cert.pem",
- "key-file": "/var/lib/kea/server2_key.pem",
- "cert-required": true
- }
- }
-
.. _ha-server-states:
Server States
It may also contain an unlimited number of backup servers. In this example,
there is one backup server which receives lease updates from the active servers.
-Since Kea version 1.9.0, basic HTTP authentication is available
-to protect the Kea control agent against local attackers.
-
These are the parameters specified for each of the peers within this
list:
both pools; it selects the pool which is appropriate for the received query. In
other words, if the query would normally be processed by ``server2`` but this
server is not available, ``server1`` allocates the lease from the pool of
-"192.0.3.200 - 192.0.3.250". The Kea control agent in front of ``server3``
+"192.0.3.200 - 192.0.3.250". The `server3`` HTTP control socket
requires basic HTTP authentication, and authorizes the user ID "foo" with the
password "1234".
It is important to note that extending this ``sync-timeout`` value may sometimes
be insufficient to prevent issues with timeouts during lease-database
-synchronization. The control commands travel via the Control Agent, which also
-monitors incoming (with a synchronizing server) and outgoing (with a DHCP server)
-connections for timeouts. The DHCP server also monitors the connection from the
-Control Agent for timeouts. Those timeouts cannot currently be modified via
+synchronization. The DHCP server also monitors the connection from the
+peer for timeouts. Those timeouts cannot currently be modified via
configuration; extending these timeouts is only possible by modifying them in
the Kea code and recompiling the server. The relevant constants are located in
the Kea source at: ``src/lib/config/timeouts.h``.
``waiting`` state until the state machine of the primary server is resumed
and that server transitions to the ``ready`` state.
-.. _ha-ctrl-agent-config:
-
-Control Agent Configuration
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The :ref:`kea-ctrl-agent` describes in detail the Kea daemon, which provides a
-RESTful interface to control the Kea servers. The same functionality is used by
-the High Availability hook library to establish communication between the HA
-peers. Therefore, the HA library requires that the Control Agent (CA) be started
-for each DHCP instance within the HA setup. If the Control Agent is not started,
-the peers cannot communicate with a particular DHCP server (even if the DHCP
-server itself is online) and may eventually consider this server to be offline.
-
-The following is an example configuration for the CA running on the same
-machine as the primary server. This configuration is valid for both the
-``load-balancing`` and the ``hot-standby`` cases presented in previous sections.
-
-::
-
- {
- "Control-agent": {
- "http-host": "192.168.56.33",
-
- // If enabling HA and multi-threading, the 8000 port is used by the HA
- // hook library http listener. When using HA hook library with
- // multi-threading to function, make sure the port used by dedicated
- // listener is different (e.g. 8001) than the one used by CA. Note
- // the commands should still be sent via CA. The dedicated listener
- // is specifically for HA updates only.
- "http-port": 8000,
-
- "control-sockets": {
- "dhcp4": {
- "socket-type": "unix",
- "socket-name": "kea-dhcp4-ctrl.sock"
- },
- "dhcp6": {
- "socket-type": "unix",
- "socket-name": "kea-dhcp6-ctrl.sock"
- }
- }
- }
- }
-
-Since Kea 1.9.0, basic HTTP authentication is supported.
-
.. _ha-mt-config:
Multi-Threaded Configuration (HA+MT)
multi-threaded communication between peers. We refer to this mode as HA+MT.
With HA+MT enabled, each peer runs its own dedicated, internal HTTP listener
(i.e. server) which receives and responds to commands directly, thus eliminating
-the need for an agent to carry out the HA protocol between peers. In addition, both
+the sequentialization of commands including for the HA protocol between peers. In addition, both
the listener and client components use multi-threading to support multiple
-concurrent connections between peers. By eliminating the agent and executing
+concurrent connections between peers. By eliminating the overloading of
+the control channel and executing
multiple command exchanges in parallel, HA throughput between peers
improves considerably over earlier versions of Kea in most situations.
- ``enable-multi-threading`` - enables or disables multi-threading HA peer
communication (HA+MT). Kea core multi-threading must be enabled for HA+MT to
- operate. When ``false``, the server relies on :iscman:`kea-ctrl-agent` for
+ operate. When ``false``, the server relies on a HTTP control socket for
communication with its peer, and uses single-threaded HTTP client processing.
The default is ``true``.
- ``http-dedicated-listener`` - enables or disables the creation of a dedicated,
internal HTTP listener through which the server receives HA messages from its
- peers. The internal listener replaces the role of :iscman:`kea-ctrl-agent` traffic,
+ peers. The internal listener replaces the role of control socket traffic,
allowing peers to send their HA commands directly to each other. The listener
listens on the peer's ``url``. When ``false``, the server
- relies on :iscman:`kea-ctrl-agent`. This parameter has been provided largely for
+ relies on HTTP control socket. This parameter has been provided largely for
flexibility and testing; running HA+MT without dedicated listeners enabled
will substantially limit HA throughput. The default is ``true``.
to the servers. To ensure that the partner is indeed offline, the administrator
should send the :isccmd:`ha-heartbeat` command to the second server. If sending the
command fails, e.g. due to an inability to establish a TCP connection to the
-Control Agent, or if the Control Agent reports issues with communication with
-the DHCP server, it is very likely that the server is not running.
+DHCP server, it is very likely that the server is not running.
The ``date-time`` parameter conveys the server's notion of time.
server. In particular, it validates the parameters, so an attempt to
insert incorrect data - such as adding a host with a conflicting identifier in the
same subnet - is rejected. Those commands are exposed via the command
-channel (JSON over UNIX sockets) and the Control Agent (JSON over a RESTful
-interface).
+channel (JSON over UNIX or HTTP/HTTPS sockets).
.. note::
document.
All host commands use JSON syntax. They can be issued either using the
-control channel (see :ref:`ctrl-channel`) or via the Control Agent (see
-:ref:`kea-ctrl-agent`).
+control channel (see :ref:`ctrl-channel`).
The library can be loaded similarly to other hook libraries. It
does not take any parameters, and it supports both the DHCPv4 and DHCPv6
- :isccmd:`lease6-write` - writes the IPv6 memfile lease database into a file.
All commands use JSON syntax and can be issued either using the control
-channel (see :ref:`ctrl-channel`) or Control Agent (see
-:ref:`kea-ctrl-agent`).
+channel (see :ref:`ctrl-channel`).
The library can be loaded in the same way as other hook libraries, and
it does not take any parameters. It supports both the DHCPv4 and DHCPv6
available to every Kea user.
All commands use JSON syntax and can be issued directly to the servers
-via either the control channel (see :ref:`ctrl-channel`) or the
-Control Agent (see :ref:`kea-ctrl-agent`).
+via the control channel (see :ref:`ctrl-channel`).
This library is loaded in the same way as other libraries and currently has no
parameters:
The following table provides a list of hook libraries currently available
from ISC. It is important to pay attention to which libraries may be
-loaded by which Kea processes. It is a common mistake to configure the
-:iscman:`kea-ctrl-agent` process to load libraries that should, in fact, be
-loaded by the :iscman:`kea-dhcp4` or :iscman:`kea-dhcp6` processes. If a library
+loaded by which Kea processes. If a library
from ISC does not work as expected, please make sure that it has been
loaded by the correct process per the table below.
| | | parameters, so an attempt to insert incorrect data, e.g. add |
| | | a host with conflicting identifier in the same subnet, is |
| | | rejected. Those commands are exposed via the command channel |
- | | | (JSON over UNIX sockets) and the Control Agent (JSON over |
- | | | RESTful interface). |
+ | | | (JSON over UNIX or HTTP/HTTPS sockets), |
+-----------------------------------------------------------+--------------+--------------------------------------------------------------+
| :ref:`Lease Commands <hooks-lease-cmds>` | Kea open | This hook library offers a number of commands used to |
| | source | manage leases. Kea can store lease information in various |
| | | The accounting mechanism allows a RADIUS server to keep |
| | | track of device activity over time. |
+-----------------------------------------------------------+--------------+--------------------------------------------------------------+
- | :ref:`RBAC <hooks-rbac>` | ISC support | This hook library adds support to the Kea Control Agent |
- | | customers | (kea-ctrl-agent) and Kea servers (kea-dhcp4, kea-dhcp6 and |
- | | | kea-dhcp-ddns) for Role-Based Access Control filtering of |
- | | | commands. |
+ | :ref:`RBAC <hooks-rbac>` | ISC support | This hook library adds support to Kea servers (kea-dhcp4, |
+ | | customers | kea-dhcp6 and kea-dhcp-ddns) for Role-Based Access Control |
+ | | | filtering of commands. |
+-----------------------------------------------------------+--------------+--------------------------------------------------------------+
| :ref:`Run Script <hooks-run-script>` | Kea open | This hook library adds support to run external |
| | source | scripts for specific packet-processing hook points. There |
- ``isc-kea-dhcp-ddns`` — Kea DHCP DDNS server
-- ``isc-kea-ctrl-agent`` — Kea Control Agent for remote configuration
-
- ``isc-kea-admin`` — Kea database administration tools
- ``isc-kea-hooks`` — Kea open source DHCP hooks
Once installed, the services can be managed through the distribution's
service manager. The services are named: :iscman:`kea-dhcp4`, :iscman:`kea-dhcp6`,
-:iscman:`kea-dhcp-ddns`, and :iscman:`kea-ctrl-agent`.
+:iscman:`kea-dhcp-ddns`.
.. note::
The real service names on Debian and Ubuntu use slightly different
systemd service alias is used to allow users to refer to them with shorter
names. Calling ``systemctl enable`` on these services requires
the real service names, which are: ``isc-kea-dhcp4-server``,
- ``isc-kea-dhcp6-server``, ``isc-kea-dhcp-ddns-server``, and
- ``isc-kea-ctrl-agent``.
+ ``isc-kea-dhcp6-server``, ``isc-kea-dhcp-ddns-server``.
Caveats When Upgrading Kea Packages
-----------------------------------
backend. While it can be run standalone, it is normally run as and
when required by the Kea DHCP servers.
-- :iscman:`kea-ctrl-agent` — The Kea Control Agent (CA) is a daemon that exposes
- a RESTful control interface for managing Kea servers.
-
- :iscman:`kea-netconf` - kea-netconf is an agent that provides a
YANG/NETCONF interface for configuring Kea.
:iscman:`keactrl` is a shell script which controls the startup, shutdown, and
reconfiguration of the Kea servers (:iscman:`kea-dhcp4`, :iscman:`kea-dhcp6`,
-:iscman:`kea-dhcp-ddns`, :iscman:`kea-ctrl-agent`, and :iscman:`kea-netconf`). It also
+:iscman:`kea-dhcp-ddns`, and :iscman:`kea-netconf`). It also
provides the means for checking the current status of the servers and
determining the configuration files in use.
kea_dhcp4_config_file=@sysconfdir@/@PACKAGE@/kea-dhcp4.conf
kea_dhcp6_config_file=@sysconfdir@/@PACKAGE@/kea-dhcp6.conf
kea_dhcp_ddns_config_file=@sysconfdir@/@PACKAGE@/kea-dhcp-ddns.conf
- kea_ctrl_agent_config_file=@sysconfdir@/@PACKAGE@/kea-ctrl-agent.conf
kea_netconf_config_file=@sysconfdir@/@PACKAGE@/kea-netconf.conf
# Location of Kea binaries.
dhcp4_srv=@sbindir@/kea-dhcp4
dhcp6_srv=@sbindir@/kea-dhcp6
dhcp_ddns_srv=@sbindir@/kea-dhcp-ddns
- ctrl_agent_srv=@sbindir@/kea-ctrl-agent
netconf_srv=@sbindir@/kea-netconf
# Start DHCPv4 server?
# Start DHCP DDNS server?
dhcp_ddns=no
- # Start Control Agent?
- ctrl_agent=yes
-
# Start Netconf?
netconf=no
In the example above, strings of the form @something@ are replaced by
the appropriate values when Kea is installed.
-Setting the ``dhcp4``, ``dhcp6``, ``dhcp_ddns``, ``ctrl_agent``, and ``netconf``
+Setting the ``dhcp4``, ``dhcp6``, ``dhcp_ddns``, and ``netconf``
parameters set to "yes" configures :iscman:`keactrl` to manage (start,
reconfigure) all servers, i.e. :iscman:`kea-dhcp4`, :iscman:`kea-dhcp6`,
-:iscman:`kea-dhcp-ddns`, :iscman:`kea-ctrl-agent`, and :iscman:`kea-netconf`. When any of
+:iscman:`kea-dhcp-ddns`, and :iscman:`kea-netconf`. When any of
these parameters is set to "no", :iscman:`keactrl` ignores the
corresponding server when starting or reconfiguring Kea. Some daemons
(dhcp_ddns and netconf) are disabled by default.
``"[kea-install-dir]/sbin"``. This should work for most installations. If
the default location needs to be altered, the paths
specified with the ``dhcp4_srv``, ``dhcp6_srv``, ``dhcp_ddns_srv``,
-``ctrl_agent_srv``, and ``netconf_srv`` parameters should be modified.
+and ``netconf_srv`` parameters should be modified.
The ``kea_verbose`` parameter specifies the verbosity of the servers
being started. When ``kea_verbose`` is set to ``yes``, the logging level of
INFO/keactrl: Starting kea-dhcp4 -c /usr/local/etc/kea/kea-dhcp4.conf -d
INFO/keactrl: Starting kea-dhcp6 -c /usr/local/etc/kea/kea-dhcp6.conf -d
INFO/keactrl: Starting kea-dhcp-ddns -c /usr/local/etc/kea/kea-dhcp-ddns.conf -d
- INFO/keactrl: Starting kea-ctrl-agent -c /usr/local/etc/kea/kea-ctrl-agent.conf -d
INFO/keactrl: Starting kea-netconf -c /usr/local/etc/kea/kea-netconf.conf -d
Kea's servers create PID files upon startup. These files are used by
INFO/keactrl: kea-dhcp4 appears to be running, see: PID 10918, PID file: /usr/local/var/run/kea/kea.kea-dhcp4.pid.
INFO/keactrl: kea-dhcp6 appears to be running, see: PID 10924, PID file: /usr/local/var/run/kea/kea.kea-dhcp6.pid.
INFO/keactrl: kea-dhcp-ddns appears to be running, see: PID 10930, PID file: /usr/local/var/run/kea/kea.kea-dhcp-ddns.pid.
- INFO/keactrl: kea-ctrl-agent appears to be running, see: PID 10931, PID file: /usr/local/var/run/kea/kea.kea-ctrl-agent.pid.
INFO/keactrl: kea-netconf appears to be running, see: PID 10123, PID file: /usr/local/var/run/kea/kea.kea-netconf.pid.
During normal shutdowns, these PID files are deleted; they may, however,
INFO/keactrl: Stopping kea-dhcp4...
INFO/keactrl: Stopping kea-dhcp6...
INFO/keactrl: Stopping kea-dhcp-ddns...
- INFO/keactrl: Stopping kea-ctrl-agent...
INFO/keactrl: Stopping kea-netconf...
Note that the ``stop`` command attempts to stop all servers
INFO/keactrl: kea-dhcp4 isn't running.
INFO/keactrl: kea-dhcp6 isn't running.
INFO/keactrl: kea-dhcp-ddns isn't running.
- INFO/keactrl: kea-ctrl-agent isn't running.
INFO/keactrl: kea-netconf isn't running.
As already mentioned, the reconfiguration of each Kea server is
INFO/keactrl: Reloading kea-dhcp4...
INFO/keactrl: Reloading kea-dhcp6...
INFO/keactrl: Reloading kea-dhcp-ddns...
- INFO/keactrl: Reloading kea-ctrl-agent...
If any of the servers are not running, an informational message is
displayed as in the ``reload`` command output below.
INFO/keactrl: kea-dhcp4 isn't running.
INFO/keactrl: kea-dhcp6 isn't running.
INFO/keactrl: kea-dhcp-ddns isn't running.
- INFO/keactrl: kea-ctrl-agent isn't running.
INFO/keactrl: kea-netconf isn't running.
.. note::
DHCPv4 server: active
DHCPv6 server: inactive
DHCP DDNS: active
- Control Agent: active
Netconf agent: inactive
Kea configuration file: /usr/local/etc/kea/kea.conf
Kea DHCPv4 configuration file: /usr/local/etc/kea/kea-dhcp4.conf
Kea DHCPv6 configuration file: /usr/local/etc/kea/kea-dhcp6.conf
Kea DHCP DDNS configuration file: /usr/local/etc/kea/kea-dhcp-ddns.conf
- Kea Control Agent configuration file: /usr/local/etc/kea/kea-ctrl-agent.conf
Kea Netconf configuration file: /usr/local/etc/kea/kea-netconf.conf
keactrl configuration file: /usr/local/etc/kea/keactrl.conf
The optional ``-s`` switch allows the selection of the server(s) to which
the :iscman:`keactrl` command is issued. For example, the following instructs
:iscman:`keactrl` to stop the :iscman:`kea-dhcp4` and :iscman:`kea-dhcp6` servers and
-leave the :iscman:`kea-dhcp-ddns` and :iscman:`kea-ctrl-agent` running:
+leave the :iscman:`kea-dhcp-ddns` running:
.. code-block:: console
$ keactrl stop -s dhcp4,dhcp6
Similarly, the following starts only the :iscman:`kea-dhcp4` and
-:iscman:`kea-dhcp-ddns` servers, but not :iscman:`kea-dhcp6` or :iscman:`kea-ctrl-agent`.
+:iscman:`kea-dhcp-ddns` servers, but not :iscman:`kea-dhcp6`.
.. code-block:: console
- ``dhcp_ddns`` for :iscman:`kea-dhcp-ddns`.
-- ``ctrl_agent`` for :iscman:`kea-ctrl-agent`.
-
- ``netconf`` for :iscman:`kea-netconf`.
- ``all`` for all servers (default).
.. code-block:: console
- # systemctl status kea-ctrl-agent
# systemctl start kea-dhcp4
# systemctl stop kea-dhcp6
# systemctl restart kea-dhcp-ddns
+----------------------------------+---------------------------------------+--------------------------------+
| Logger Name | Software Package | Description |
+==================================+=======================================+================================+
- | ``kea-ctrl-agent`` | core | The root logger for the Control|
- | | | Agent exposing the RESTful |
- | | | control API. All components |
- | | | used by the Control Agent |
- | | | inherit the settings from this |
- | | | logger. |
- +----------------------------------+---------------------------------------+--------------------------------+
- | ``kea-ctrl-agent.auth`` | core | A logger which covers access |
- | | | control details, such as the |
- | | | result of basic HTTP |
- | | | authentication. |
- +----------------------------------+---------------------------------------+--------------------------------+
- | ``kea-ctrl-agent.ctrl-agent`` | core | Used to log results of |
- | | | configuration checks, |
- | | | information about services |
- | | | starting or failing to start, |
- | | | command reception, and |
- | | | forwarding. |
- +----------------------------------+---------------------------------------+--------------------------------+
- | ``kea-ctrl-agent.http`` | core | A logger which outputs log |
- | | | messages related to receiving, |
- | | | parsing, and sending HTTP |
- | | | messages. |
- +----------------------------------+---------------------------------------+--------------------------------+
- | ``kea-ctrl-agent.rbac-hooks`` | :ischooklib:`libdhcp_rbac.so` | Used to log messages related to|
- | | subscriber hook library | the operation of the RBAC hook |
- | | | library. |
- +----------------------------------+---------------------------------------+--------------------------------+
| ``kea-dhcp4`` | core | The root logger for the DHCPv4 |
| | | server. All components used by |
| | | the DHCPv4 server inherit the |
| | | processing messages from |
| | | clients. |
+----------------------------------+---------------------------------------+--------------------------------+
- | ``kea-ctrl-agent.auth``, | core | Used to log malformed HTTP |
- | ``kea-dhcp4.auth``, | | packets when using basic |
- | ``kea-dhcp6.auth`` | | authentication. |
+ | ``kea-dhcp4.auth``, | core | Used to log malformed HTTP |
+ | ``kea-dhcp6.auth`` | | packets when using basic |
+ | | | authentication. |
+----------------------------------+---------------------------------------+--------------------------------+
| ``kea-dhcp4.bad-packets``, | core | Used by the DHCP servers for |
| ``kea-dhcp6.bad-packets`` | | logging inbound client packets |
| | | operation of the BOOTP hook |
| | | library. |
+----------------------------------+---------------------------------------+--------------------------------+
- | ``kea-ctrl-agent.callouts``, | core | Used to log messages pertaining|
- | ``kea-dhcp4.callouts``, | | to the callouts registration |
- | ``kea-dhcp6.callouts``, | | and execution for a particular |
- | ``kea-dhcp-ddns.callouts`` | | hook point. |
+ | ``kea-dhcp4.callouts``, | core | Used to log messages pertaining|
+ | ``kea-dhcp6.callouts``, | | to the callouts registration |
+ | ``kea-dhcp-ddns.callouts`` | | and execution for a particular |
+ | | | hook point. |
+----------------------------------+---------------------------------------+--------------------------------+
| ``kea-dhcp4.cb-cmds-hooks``, | :ischooklib:`libdhcp_cb_cmds.so` | Used to log messages related to|
| ``kea-dhcp6.cb-cmds-hooks`` | subscriber hook library | the operation of the Config |
| ``kea-dhcp6.ha-hooks`` | open-source hook library | the operation of the High |
| | | Availability hook library. |
+----------------------------------+---------------------------------------+--------------------------------+
- | ``kea-ctrl-agent.hooks``, | core | Used to log messages related to|
- | ``kea-dhcp4.hooks``, | | the management of hook |
- | ``kea-dhcp6.hooks``, | | libraries, e.g. registration |
- | ``kea-dhcp-ddns.hooks`` | | and deregistration of the |
+ | ``kea-dhcp4.hooks``, | core | Used to log messages related to|
+ | ``kea-dhcp6.hooks``, | | the management of hook |
+ | ``kea-dhcp-ddns.hooks`` | | libraries, e.g. registration |
+ | | | and deregistration of the |
| | | libraries, and to the |
| | | initialization of the callouts |
| | | execution for various hook |
| | | are configurations for more |
| | | specialized loggers. |
+----------------------------------+---------------------------------------+--------------------------------+
- | ``kea-ctrl-agent.dctl``, | core | Used to log basic information |
- | ``kea-dhcp-ddns.dctl`` | | about the process, received |
+ | ``kea-dhcp-ddns.dctl`` | core | Used to log basic information |
+ | | | about the process, received |
| | | signals, and triggered |
| | | reconfigurations. |
+----------------------------------+---------------------------------------+--------------------------------+
1. Edit the Kea configuration files, which by default are installed in
the ``"[kea-install-dir]/etc/kea/"`` directory. These are:
- ``kea-dhcp4.conf``, ``kea-dhcp6.conf``, ``kea-dhcp-ddns.conf`` and
- ``kea-ctrl-agent.conf``, ``keactrl.conf`` for the DHCPv4 server, DHCPv6 server,
- D2, Control Agent, and keactrl script, respectively.
+ ``kea-dhcp4.conf``, ``kea-dhcp6.conf``, ``kea-dhcp-ddns.conf``, and
+ ``keactrl.conf`` for the DHCPv4 server, DHCPv6 server,
+ D2, and keactrl script, respectively.
2. To start the DHCPv4 server in the background, run the
following command (as root):
A server status of "inactive" may indicate a configuration error.
Please check the log file (by default named
``"[kea-install-dir]/var/log/kea/kea-dhcp4.log"``,
- ``"[kea-install-dir]/var/log/kea/kea-dhcp6.log"``,
- ``"[kea-install-dir]/var/log/kea/kea-ddns.log"``, or
- ``"[kea-install-dir]/var/log/kea/kea-ctrl-agent.log"``) for the details of
+ ``"[kea-install-dir]/var/log/kea/kea-dhcp6.log"``, or
+ ``"[kea-install-dir]/var/log/kea/kea-ddns.log"``) for the details of
any errors.
4. If the server has started successfully, test that it is
It is highly recommended to read the ``openssl.cnf`` manual page,
normally called ``config.5ssl`` and displayed using ``man config``.
-.. _secure-control-agent:
+.. _secure-control-channel:
-Secure Kea Control Agent
-========================
+Secure Kea Control Channel
+==========================
-The Kea Control Agent natively supports secure
+.. note::
+
+ This section was about the now obsolete Kea Control Agent but applies
+ to Kea control HTTPS control sockets supported by Kea servers.
+
+The control sockets of Kea servers natively supports secure
HTTP connections using TLS. This allows protection against users from
the node where the agent runs, something that a reverse proxy cannot
provide. More about TLS/HTTPS support in Kea can be found in :ref:`tls`.
----------------------
The Kea architecture is modular, with separate daemons for separate tasks.
-A Kea deployment may include DHCPv4, DHCPv6, and Dynamic DNS daemons; a Control Agent
-daemon run on each application server; the :iscman:`kea-lfc` utility for doing periodic lease
+A Kea deployment may include DHCPv4, DHCPv6, and Dynamic DNS daemons;
+the :iscman:`kea-lfc` utility for doing periodic lease
file cleanup; MySQL and or PostgreSQL databases, run either locally on the application
servers or accessed over the internal network; a Netconf daemon to perform config and stats
monitoring of Kea servers; and a Stork monitoring system.
capabilities mechanism on Linux systems, Kea can run from an unprivileged account. See
:ref:`non-root` for details on how to run Kea without root access.
-The Control Agent (CA) can accept incoming HTTP or HTTPS connections. The default port is 8000, which
-does not require privileged access.
-
Securing Kea Administrative Access
----------------------------------
running, log an unrecoverable error. For ease of use in simply omit the
path component from ``socket-name``.
-Since Kea version 2.7.2 DHCP servers support HTTP/HTTPS control channels so the Control Agent (CA)
-is no longer needed.
+Since Kea version 2.7.2 DHCP servers support HTTP/HTTPS control channels,
+since Kea version 3.1.7 the Control Agent has been removed.
Since Kea-2.7.6 Kea supports multiple HTTP/HTTPS connections. Both IPv4 and IPv6 addresses can be used.
Security can be enhanced if configuring HTTPS connections for all daemons.
sercurity restrictions have been disabled. Do not use this mode of operation without
careful consideration and taking any necessary precautions. Failure to do so may expose
deployments to security vulnerabilities. This command line option is supported by
- all of the daemons: ``kea-dhcp4``, ``kea-dhcp6``, ``kea-dhcp-ddns``, and
- ``kea-ctrl-agent``.
+ all of the daemons: ``kea-dhcp4``, ``kea-dhcp6``, and ``kea-dhcp-ddns``.
Cryptography Components
-----------------------
The primary use cases for the cryptographic libraries are:
-- TLS support for the Control Agent (CA), introduced in Kea 1.9.6.
+- TLS support for HTTPS control channels, introduced in Kea 1.9.6.
- TSIG signatures when sending DNS updates.
- calculating DHCID records when sending DNS updates.
- random number generation (but not for usage requiring a crypto grade generator).
Remote Administrative Access
----------------------------
-Kea's Control Agent (CA) exposes a RESTful API over HTTP or HTTPS (HTTP over TLS). The CA is an
-optional feature that is disabled by default, but it is very popular. When enabled, it listens on the
+DHCP and DDNS servers exposes a RESTful API over HTTP or HTTPS (HTTP over TLS).
+These control channels are ptional features that are disabled by default, but it is very popular. When enabled, it listens on the
loopback address (127.0.0.1 or ::1) by default, unless configured otherwise. See :ref:`tls`
for information about protecting the TLS traffic. Limiting the incoming connections with a firewall, such as
iptables, is generally a good idea.
-Note that in High Availability (HA) deployments, DHCP partners connect to each other using a CA
-connection.
-
-Since Kea version 2.7.2 DHCP and DDNS servers support HTTP/HTTPS control channels so the Control Agent (CA)
-is no longer needed.
+Note that in High Availability (HA) deployments, a multi-threaded dedicated
+listener can be configured to serve the HA protocol using the RESTful API
+with peers.
-Since Kea-2.7.6 Kea supports multiple HTTP/HTTPS connections. Both IPv4 and IPv6 addresses can be used.
+Kea also supports multiple HTTP/HTTPS connections. Both IPv4 and IPv6 addresses can be used.
Security can be enhanced if configuring HTTPS connections for all daemons.
Authentication for Kea's RESTful API
Kea 1.9.2 introduced a new ``auth`` hook point. With this new hook point, it is possible to develop an external
hook library to extend the access controls, integrate with another authentication authority, or add role-based
-access control to the Control Agent. This hookpoint was renamed as ``http_auth`` and is also supported by the DHCP
+access control to control channels. This hookpoint was renamed as ``http_auth`` and is also supported by the DHCP
and DDNS servers since Kea version 2.7.2.
.. note:
====================================
Runtime security policy checking was initially added to Kea daemons :iscman:`kea-dhcp4`,
-:iscman:`kea-dhcp6`, :iscman:`kea-dhcp-ddns`, :iscman:`kea-ctrl-agent`. in Kea 2.7.9
+:iscman:`kea-dhcp6`, :iscman:`kea-dhcp-ddns`. in Kea 2.7.9
release. In Kea 3.0 additional checks were added. By default, when a daemon detects
a security policy violation it emits an error log and exits. The following checks are
performed:
Overview of the Kea Shell
=========================
-The Kea Control Agent (CA, see
-:ref:`kea-ctrl-agent`) provides a RESTful control interface
+The Kea servers provide a RESTful control interface
over HTTP. That API is typically expected to be used by various IPAMs
and similar management systems. Nevertheless, there may be cases when an
-administrator wants to send a command to the CA directly, and the Kea shell
+administrator wants to send a command to the server directly, and the Kea shell
provides a way to do this. It is a simple command-line,
-scripting-friendly, text client that is able to connect to the CA, send
+scripting-friendly, text client that is able to connect to the server, send
it commands with parameters, retrieve the responses, and display them.
As the primary purpose of the Kea shell is as a tool in a scripting
:iscman:`kea-dhcp-ddns`). The :iscman:`kea-shell` can be used with
these servers, the only difference is the ``--service`` argument becomes
useless and is ignored by Kea servers. Note the result is encapsulated
- in a list for :iscman:`kea-ctrl-agent` compatibility.
+ in a list for backward compatibility.
Shell Usage
===========
.. code-block:: console
- $ kea-shell [--host hostname] [--port number] [--path path] [--auth-user] [--auth-password] [--auth-password-file] [--timeout seconds] [--service service-name] [command]
+ $ kea-shell [--host hostname] [--port number] [--path path] [--auth-user] [--auth-password] [--auth-password-file] [--timeout seconds] [command]
where:
-- ``--host hostname`` specifies the hostname of the CA. If not
+- ``--host hostname`` specifies the hostname of the server. If not
specified, "localhost" is used.
-- ``--port number`` specifies the TCP port on which the CA listens. If
+- ``--port number`` specifies the TCP port on which the server listens. If
not specified, 8000 is used.
- ``--path path`` specifies the path in the URL to connect to. If not
- specified, an empty path is used. As the CA listens at the empty
+ specified, an empty path is used. As the server listens at the empty
path, this parameter is useful only with a reverse proxy.
- ``--auth-user`` specifies the user ID for basic HTTP authentication.
- ``--timeout seconds`` specifies the timeout (in seconds) for the
connection. If not given, 10 seconds is used.
-- ``--service service-name`` specifies the target of a command. If not
- given, the CA is used as the target. This may be used more than once
- to specify multiple targets.
+- ``--service service-name`` is now obsolete but is still recognize for
+ backward compatibility.
- ``command`` specifies the command to be sent. If not specified, the
:isccmd:`list-commands` command is used.
Once started, the shell reads the parameters for the command from standard
input, which are expected to be in JSON format. When all have been read,
-the shell establishes a connection with the CA using HTTP, sends the
+the shell establishes a connection with the server using HTTP, sends the
command, and awaits a response. Once that is received, it is displayed
on standard output.
For a list of available commands, see :ref:`ctrl-channel`;
additional commands may be provided by hook libraries. For a list of
-all supported commands from the CA, use the :isccmd:`list-commands` command.
+all supported commands from the server, use the :isccmd:`list-commands` command.
The following shows a simple example of usage:
.. code-block:: console
- $ kea-shell --host 192.0.2.1 --port 8001 --auth-user foo --auth-password-file secret_file --service dhcp4 list-commands
+ $ kea-shell --host 192.0.2.1 --port 8001 --auth-user foo --auth-password-file secret_file list-commands
^D
After the command line is entered, the program waits for command
parameters to be entered. Since :isccmd:`list-commands` does not take any
arguments, Ctrl-D (represented in the above example by "^D")
indicates end-of-file and terminates the parameter input. The shell
-then contacts the CA and prints out the list of available commands
-returned for the service named ``dhcp4``.
+then contacts the server and prints out the list of available commands
+returned for the server.
The Kea shell will likely be most frequently used in
scripts; the next example shows a simple scripted execution. It sends
-the command :isccmd:`config-write` to the CA (the ``--service`` parameter has not
-been used), along with the parameters specified in param.json. The
+the command :isccmd:`config-write` to the server,
+along with the parameters specified in param.json. The
result will be stored in result.json.
.. code-block:: console
When a reverse proxy is used to de-multiplex requests to different
servers, the default empty path in the URL is not enough, so the
``--path`` parameter should be used. For instance, if requests to the
-"/kea" path are forwarded to the CA this can be used:
+"/kea" path are forwarded to the server this can be used:
.. code-block:: console
'arm/ext-netconf.rst',
'arm/ext-gss-tsig.rst',
'arm/ext-radius.rst',
- 'grammar/grammar-ca-parser.rst',
'grammar/grammar-d2-parser.rst',
'grammar/grammar-dhcp4-parser.rst',
'grammar/grammar-dhcp6-parser.rst',
(master_doc, 'kea-arm', 'Kea Administrator Reference Manual Documentation', [author], 1),
('man/kea-admin.8', 'kea-admin', 'Shell script for managing Kea databases', author, 8),
('man/keactrl.8', 'keactrl', 'Shell script for managing Kea', author, 8),
- ('man/kea-ctrl-agent.8', 'kea-ctrl-agent', 'Control Agent process in Kea', author, 8),
('man/kea-dhcp4.8', 'kea-dhcp4', 'DHCPv4 server in Kea', author, 8),
('man/kea-dhcp6.8', 'kea-dhcp6', 'DHCPv6 server in Kea', author, 8),
('man/kea-dhcp-ddns.8', 'kea-dhcp-ddns', 'DHCP-DDNS process in Kea', author, 8),
('man/kea-lfc.8', 'kea-lfc', 'Lease File Cleanup process in Kea', author, 8),
('man/kea-netconf.8', 'kea-netconf', 'NETCONF agent for configuring Kea', author, 8),
- ('man/kea-shell.8', 'kea-shell', 'Text client for Control Agent process', author, 8),
+ ('man/kea-shell.8', 'kea-shell', 'Text client for control process', author, 8),
('man/perfdhcp.8', 'perfdhcp', 'DHCP benchmarking tool', author, 8),
]
+++ /dev/null
-This grammar is generated from ``agent_parser.yy``. See :ref:`kea-ctrl-agent` for more details.
-
-.. code-block:: BNF
- :linenos:
-
- Grammar
-
- $accept ::= start EOF
-
- start ::= START_JSON json
-
- start ::= START_AGENT agent_syntax_map
-
- start ::= START_SUB_AGENT sub_agent
-
- sub_agent ::= "{" global_params "}"
-
- json ::= value
-
- value ::= INTEGER
- | FLOAT
- | BOOLEAN
- | STRING
- | NULL
- | map
- | list_generic
-
- map ::= "{" map_content "}"
-
- map_value ::= map
-
- map_content ::=
- | not_empty_map
-
- not_empty_map ::= STRING ":" value
- | not_empty_map "," STRING ":" value
- | not_empty_map ","
-
- list_generic ::= "[" list_content "]"
-
- list_content ::=
- | not_empty_list
-
- not_empty_list ::= value
- | not_empty_list "," value
- | not_empty_list ","
-
- unknown_map_entry ::= STRING ":"
-
- agent_syntax_map ::= "{" global_object "}"
-
- global_object ::= "Control-agent" ":" "{" global_params "}"
- | global_object_comma
-
- global_object_comma ::= global_object ","
-
- global_params ::= global_param
- | global_params "," global_param
- | global_params ","
-
- global_param ::= http_host
- | http_port
- | http_headers
- | trust_anchor
- | cert_file
- | key_file
- | cert_required
- | authentication
- | control_sockets
- | hooks_libraries
- | loggers
- | user_context
- | comment
- | unknown_map_entry
-
- http_host ::= "http-host" ":" STRING
-
- http_port ::= "http-port" ":" INTEGER
-
- trust_anchor ::= "trust-anchor" ":" STRING
-
- cert_file ::= "cert-file" ":" STRING
-
- key_file ::= "key-file" ":" STRING
-
- cert_required ::= "cert-required" ":" BOOLEAN
-
- user_context ::= "user-context" ":" map_value
-
- comment ::= "comment" ":" STRING
-
- http_headers ::= "http-headers" ":" "[" http_header_list "]"
-
- http_header_list ::=
- | not_empty_http_header_list
-
- not_empty_http_header_list ::= http_header
- | not_empty_http_header_list "," http_header
- | not_empty_http_header_list ","
-
- http_header ::= "{" http_header_params "}"
-
- http_header_params ::= http_header_param
- | http_header_params "," http_header_param
- | http_header_params ","
-
- http_header_param ::= name
- | header_value
- | user_context
- | comment
- | unknown_map_entry
-
- name ::= "name" ":" STRING
-
- header_value ::= "value" ":" STRING
-
- hooks_libraries ::= "hooks-libraries" ":" "[" hooks_libraries_list "]"
-
- hooks_libraries_list ::=
- | not_empty_hooks_libraries_list
-
- not_empty_hooks_libraries_list ::= hooks_library
- | not_empty_hooks_libraries_list "," hooks_library
- | not_empty_hooks_libraries_list ","
-
- hooks_library ::= "{" hooks_params "}"
-
- hooks_params ::= hooks_param
- | hooks_params "," hooks_param
- | hooks_params ","
- | unknown_map_entry
-
- hooks_param ::= library
- | parameters
-
- library ::= "library" ":" STRING
-
- parameters ::= "parameters" ":" map_value
-
- control_sockets ::= "control-sockets" ":" "{" control_sockets_params "}"
-
- control_sockets_params ::= control_socket
- | control_sockets_params "," control_socket
- | control_sockets_params ","
-
- control_socket ::= dhcp4_server_socket
- | dhcp6_server_socket
- | d2_server_socket
- | unknown_map_entry
-
- dhcp4_server_socket ::= "dhcp4" ":" "{" control_socket_params "}"
-
- dhcp6_server_socket ::= "dhcp6" ":" "{" control_socket_params "}"
-
- d2_server_socket ::= "d2" ":" "{" control_socket_params "}"
-
- control_socket_params ::= control_socket_param
- | control_socket_params "," control_socket_param
- | control_socket_params ","
-
- control_socket_param ::= socket_name
- | socket_type
- | user_context
- | comment
- | unknown_map_entry
-
- socket_name ::= "socket-name" ":" STRING
-
- socket_type ::= "socket-type" ":" socket_type_value
-
- socket_type_value ::= "unix"
-
- authentication ::= "authentication" ":" "{" auth_params "}"
-
- auth_params ::= auth_param
- | auth_params "," auth_param
- | auth_params ","
-
- auth_param ::= auth_type
- | realm
- | directory
- | clients
- | comment
- | user_context
- | unknown_map_entry
-
- auth_type ::= "type" ":" auth_type_value
-
- auth_type_value ::= "basic"
-
- realm ::= "realm" ":" STRING
-
- directory ::= "directory" ":" STRING
-
- clients ::= "clients" ":" "[" clients_list "]"
-
- clients_list ::=
- | not_empty_clients_list
-
- not_empty_clients_list ::= basic_auth
- | not_empty_clients_list "," basic_auth
- | not_empty_clients_list ","
-
- basic_auth ::= "{" clients_params "}"
-
- clients_params ::= clients_param
- | clients_params "," clients_param
- | clients_params ","
-
- clients_param ::= user
- | user_file
- | password
- | password_file
- | user_context
- | comment
- | unknown_map_entry
-
- user ::= "user" ":" STRING
-
- user_file ::= "user-file" ":" STRING
-
- password ::= "password" ":" STRING
-
- password_file ::= "password-file" ":" STRING
-
- loggers ::= "loggers" ":" "[" loggers_entries "]"
-
- loggers_entries ::= logger_entry
- | loggers_entries "," logger_entry
- | loggers_entries ","
-
- logger_entry ::= "{" logger_params "}"
-
- logger_params ::= logger_param
- | logger_params "," logger_param
- | logger_params ","
-
- logger_param ::= name
- | output_options_list
- | debuglevel
- | severity
- | user_context
- | comment
- | unknown_map_entry
-
- debuglevel ::= "debuglevel" ":" INTEGER
-
- severity ::= "severity" ":" STRING
-
- output_options_list ::= "output-options" ":" "[" output_options_list_content "]"
-
- output_options_list_content ::= output_entry
- | output_options_list_content "," output_entry
- | output_options_list_content ","
-
- output_entry ::= "{" output_params_list "}"
-
- output_params_list ::= output_params
- | output_params_list "," output_params
- | output_params_list ","
-
- output_params ::= output
- | flush
- | maxsize
- | maxver
- | pattern
-
- output ::= "output" ":" STRING
-
- flush ::= "flush" ":" BOOLEAN
-
- maxsize ::= "maxsize" ":" INTEGER
-
- maxver ::= "maxver" ":" INTEGER
-
- pattern ::= "pattern" ":" STRING
-
.. include:: grammar-dhcp6-parser.rst
-BNF Grammar for Control Agent
------------------------------
-
-.. include:: grammar-ca-parser.rst
-
BNF Grammar for DHCP-DDNS
-------------------------
This informational message lists all possible config backends that could
be used in config-database[s].
-****
-CTRL
-****
-
-CTRL_AGENT_COMMAND_FORWARDED
-============================
-
-.. code-block:: text
-
- command %1 successfully forwarded to the service %2 from remote address %3
-
-This informational message is issued when the CA successfully forwards
-the control message to the specified Kea service and receives a response.
-
-CTRL_AGENT_COMMAND_FORWARD_BEGIN
-================================
-
-.. code-block:: text
-
- begin forwarding command %1 to service %2
-
-Logged at debug log level 10.
-This debug message is issued when the Control Agent starts forwarding a
-received command to one of the Kea servers.
-
-CTRL_AGENT_COMMAND_FORWARD_FAILED
-=================================
-
-.. code-block:: text
-
- failed forwarding command %1: %2
-
-Logged at debug log level 10.
-This debug message is issued when the Control Agent failed forwarding a
-received command to one of the Kea servers. The second argument provides
-the details of the error.
-
-CTRL_AGENT_COMMAND_RECEIVED
-===========================
-
-.. code-block:: text
-
- command %1 received from remote address %2
-
-This informational message is issued when the CA receives a control message,
-whether it is destined to the control agent itself, or to be forwarded on.
-
-CTRL_AGENT_CONFIG_CHECK_FAIL
-============================
-
-.. code-block:: text
-
- Control Agent configuration check failed: %1
-
-This error message indicates that the CA had failed configuration
-check. Details are provided. Additional details may be available
-in earlier log entries, possibly on lower levels.
-
-CTRL_AGENT_CONFIG_FAIL
-======================
-
-.. code-block:: text
-
- Control Agent configuration failed: %1
-
-This error message indicates that the CA had failed configuration
-attempt. Details are provided. Additional details may be available
-in earlier log entries, possibly on lower levels.
-
-CTRL_AGENT_CONFIG_SYNTAX_WARNING
-================================
-
-.. code-block:: text
-
- Control Agent configuration syntax warning: %1
-
-This warning message indicates that the CA configuration had a minor syntax
-error. The error was displayed and the configuration parsing resumed.
-
-CTRL_AGENT_FAILED
-=================
-
-.. code-block:: text
-
- application experienced a fatal error: %1
-
-This is a fatal error message issued when the Control Agent application
-encounters an unrecoverable error from within the event loop.
-
-CTRL_AGENT_HTTPS_SERVICE_REUSE_FAILED
-=====================================
-
-.. code-block:: text
-
- failed to reuse HTTPS service bound to address: %1 port: %2
-
-This error message indicates that the server has failed to reuse existing
-HTTPS service on the specified address and port. The server cannot switch from
-HTTPS to HTTP sockets using the same address and port.
-
-CTRL_AGENT_HTTPS_SERVICE_STARTED
-================================
-
-.. code-block:: text
-
- HTTPS service bound to address: %1 port: %2
-
-This informational message indicates that the server has started HTTPS service
-on the specified address and port. All control commands should be sent to this
-address and port over a TLS channel.
-
-CTRL_AGENT_HTTPS_SERVICE_UPDATED
-================================
-
-.. code-block:: text
-
- reused HTTPS service bound to address: %1 port: %2 and updated TLS settings
-
-This informational message indicates that the server has reused existing
-HTTPS service on the specified address and port. Note that any change in
-the TLS setup has been applied.
-
-CTRL_AGENT_HTTP_SERVICE_REUSE_FAILED
-====================================
-
-.. code-block:: text
-
- failed to reuse HTTP service bound to address: %1 port: %2
-
-This error message indicates that the server has failed to reuse existing
-HTTP service on the specified address and port. The server cannot switch from
-HTTP to HTTPS sockets using the same address and port.
-
-CTRL_AGENT_HTTP_SERVICE_STARTED
-===============================
-
-.. code-block:: text
-
- HTTP service bound to address: %1 port: %2
-
-This informational message indicates that the server has started HTTP service
-on the specified address and port. All control commands should be sent to this
-address and port.
-
-CTRL_AGENT_HTTP_SERVICE_UPDATED
-===============================
-
-.. code-block:: text
-
- reused HTTP service bound to address: %1 port: %2
-
-This informational message indicates that the server has reused existing
-HTTP service on the specified address and port.
-
-CTRL_AGENT_IS_DEPRECATED
-========================
-
-.. code-block:: text
-
- Kea Control Agent is deprecated. Its function has been moved to Kea servers.
-
-This warning message indicates that the Control Agent has been deprecated.
-All its functions have been moved to Kea servers.
-
-CTRL_AGENT_RUN_EXIT
-===================
-
-.. code-block:: text
-
- application is exiting the event loop
-
-Logged at debug log level 0.
-This is a debug message issued when the Control Agent exits its
-event loop.
-
-CTRL_AGENT_SECURITY_CHECKS_DISABLED
-===================================
-
-.. code-block:: text
-
- Invoked with command line option -X, Security checks are disabled!!
-
-This warning is emitted when internal security checks normally
-performed by kea-ctrl-agent have been disabled via command line option '-X'.
-This means the server is not enforcing restrictions on resource
-paths or permissions. This mode of operation may expose your
-environment to security vulnerabilities and should only be used
-after consideration.
-
-CTRL_AGENT_STARTED
-==================
-
-.. code-block:: text
-
- Kea Control Agent version %1 started
-
-This informational message indicates that the Control Agent has
-processed all configuration information and is ready to begin processing.
-The version is also printed.
-
********
DATABASE
********
~~~~~~~~
:manpage:`kea-dhcp4(8)`, :manpage:`kea-dhcp6(8)`,
-:manpage:`kea-dhcp-ddns(8)`, :manpage:`kea-ctrl-agent(8)`,
+:manpage:`kea-dhcp-ddns(8)`,
:manpage:`keactrl(8)`, :manpage:`perfdhcp(8)`, :manpage:`kea-netconf(8)`,
Kea Administrator Reference Manual.
+++ /dev/null
-..
- Copyright (C) 2019-2024 Internet Systems Consortium, Inc. ("ISC")
-
- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
- See the COPYRIGHT file distributed with this work for additional
- information regarding copyright ownership.
-
-.. iscman:: kea-ctrl-agent
-
-``kea-ctrl-agent`` - Control Agent process in Kea
--------------------------------------------------
-
-Synopsis
-~~~~~~~~
-
-:program:`kea-ctrl-agent` [**-v**] [**-V**] [**-W**] [**-d**] [**-c** config-file] [**-t** config-file]
-
-Description
-~~~~~~~~~~~
-
-The ``kea-ctrl-agent`` provides a REST service for controlling Kea
-services. The received HTTP requests are decapsulated and forwarded to
-the respective Kea services in JSON format. Received JSON responses are
-encapsulated within HTTP responses and returned to the controlling
-entity. Some commands may be handled by the Control Agent directly, and
-not forwarded to any Kea service.
-
-Arguments
-~~~~~~~~~
-
-The arguments are as follows:
-
-``-v``
- Displays the Kea version.
-
-``-V``
- Displays the extended Kea version.
-
-``-W``
- Displays the configuration report.
-
-``-d``
- Sets the logging level to debug with extra verbosity. This is primarily for
- development purposes in stand-alone mode.
-
-``-c config-file``
- Specifies the file with the configuration for the Control Agent
- server. It may also contain configuration entries for other Kea
- services.
-
-``-t config-file``
- Checks the syntax of the configuration file and reports the first error,
- if any. Note that not all parameters are completely checked; in
- particular, service and client sockets are not opened, and hook
- libraries are not loaded.
-
-Documentation
-~~~~~~~~~~~~~
-
-Kea comes with an extensive Kea Administrator Reference Manual that covers
-all aspects of running the Kea software - compilation, installation,
-configuration, configuration examples, and much more. Kea also features a
-Kea Messages Manual, which lists all possible messages Kea can print
-with a brief description for each of them. Both documents are
-available in various formats (.txt, .html, .pdf) with the Kea
-distribution. The Kea documentation is available at
-https://kea.readthedocs.io.
-
-Kea source code is documented in the Kea Developer's Guide,
-available at https://reports.kea.isc.org/dev_guide/.
-
-The Kea project website is available at https://kea.isc.org.
-
-Mailing Lists and Support
-~~~~~~~~~~~~~~~~~~~~~~~~~
-
-There are two public mailing lists available for the Kea project. **kea-users**
-(kea-users at lists.isc.org) is intended for Kea users, while **kea-dev**
-(kea-dev at lists.isc.org) is intended for Kea developers, prospective
-contributors, and other advanced users. Both lists are available at
-https://lists.isc.org. The community provides best-effort support
-on both of those lists.
-
-ISC provides professional support for Kea services. See
-https://www.isc.org/kea/ for details.
-
-History
-~~~~~~~
-
-The ``kea-ctrl-agent`` was first coded in December 2016 by Marcin
-Siodelski.
-
-See Also
-~~~~~~~~
-
-:manpage:`kea-dhcp4(8)`, :manpage:`kea-dhcp6(8)`,
-:manpage:`kea-dhcp-ddns(8)`, :manpage:`kea-admin(8)`, :manpage:`keactrl(8)`,
-:manpage:`perfdhcp(8)`, :manpage:`kea-lfc(8)`, Kea Administrator Reference Manual.
~~~~~~~~
:manpage:`kea-dhcp4(8)`, :manpage:`kea-dhcp6(8)`,
-:manpage:`kea-ctrl-agent(8)`, :manpage:`kea-admin(8)`, :manpage:`keactrl(8)`,
+:manpage:`kea-admin(8)`, :manpage:`keactrl(8)`,
:manpage:`perfdhcp(8)`, :manpage:`kea-netconf(8)`, :manpage:`kea-lfc(8)`,
Kea Administrator Reference Manual.
~~~~~~~~
:manpage:`kea-dhcp6(8)`, :manpage:`kea-dhcp-ddns(8)`,
-:manpage:`kea-ctrl-agent(8)`, :manpage:`kea-admin(8)`, :manpage:`keactrl(8)`,
+:manpage:`kea-admin(8)`, :manpage:`keactrl(8)`,
:manpage:`perfdhcp(8)`, :manpage:`kea-netconf(8)`, :manpage:`kea-lfc(8)`,
Kea Administrator Reference Manual.
~~~~~~~~
:manpage:`kea-dhcp4(8)`, :manpage:`kea-dhcp-ddns(8)`,
-:manpage:`kea-ctrl-agent(8)`, :manpage:`kea-admin(8)`, :manpage:`keactrl(8)`,
+:manpage:`kea-admin(8)`, :manpage:`keactrl(8)`,
:manpage:`perfdhcp(8)`, :manpage:`kea-netconf(8)`, :manpage:`kea-lfc(8)`,
Kea Administrator Reference Manual.
~~~~~~~~
:manpage:`kea-dhcp4(8)`, :manpage:`kea-dhcp6(8)`, :manpage:`kea-dhcp-ddns(8)`,
-:manpage:`kea-ctrl-agent(8)`, :manpage:`kea-admin(8)`, :manpage:`keactrl(8)`,
+:manpage:`kea-admin(8)`, :manpage:`keactrl(8)`,
:manpage:`perfdhcp(8)`, :manpage:`kea-netconf(8)`, Kea Administrator Reference Manual.
~~~~~~~~
:manpage:`kea-dhcp4(8)`, :manpage:`kea-dhcp6(8)`, :manpage:`kea-dhcp-ddns(8)`,
-:manpage:`kea-ctrl-agent(8)`, :manpage:`kea-admin(8)`, :manpage:`keactrl(8)`,
+:manpage:`kea-admin(8)`, :manpage:`keactrl(8)`,
:manpage:`perfdhcp(8)`, :manpage:`kea-lfc(8)`, Kea Administrator Reference Manual.
~~~~~~~~
:manpage:`kea-dhcp4(8)`, :manpage:`kea-dhcp6(8)`, :manpage:`kea-dhcp-ddns(8)`,
-:manpage:`kea-ctrl-agent(8)`, :manpage:`kea-admin(8)`, :manpage:`keactrl(8)`,
+:manpage:`kea-admin(8)`, :manpage:`keactrl(8)`,
:manpage:`perfdhcp(8)`, :manpage:`kea-lfc(8)`, Kea Administrator Reference Manual.
``keactrl`` is a shell script which controls the startup, shutdown, and
reconfiguration of the Kea servers (``kea-dhcp4``, ``kea-dhcp6``,
-``kea-dhcp-ddns``, ``kea-ctrl-agent``, and ``kea-netconf``). It also
+``kea-dhcp-ddns``, and ``kea-netconf``). It also
provides a way to check the current status of the servers and
determine the configuration files in use.
``dhcp_ddns``
DHCP DDNS server (``kea-dhcp-ddns``).
- ``ctrl_agent``
- Control Agent (``kea-ctrl-agent``).
-
``netconf``
NETCONF agent (``kea-netconf``).
~~~~~~~~
:manpage:`kea-dhcp4(8)`, :manpage:`kea-dhcp6(8)`, :manpage:`kea-dhcp-ddns(8)`,
-:manpage:`kea-ctrl-agent(8)`, :manpage:`kea-admin(8)`, :manpage:`kea-netconf(8)`,
+:manpage:`kea-admin(8)`, :manpage:`kea-netconf(8)`,
:manpage:`perfdhcp(8)`, :manpage:`kea-lfc(8)`, Kea Administrator Reference Manual.
~~~~~~~~
:manpage:`kea-dhcp4(8)`, :manpage:`kea-dhcp6(8)`, :manpage:`kea-dhcp-ddns(8)`,
-:manpage:`kea-ctrl-agent(8)`, :manpage:`kea-admin(8)`, :manpage:`kea-netconf(8)`,
+:manpage:`kea-admin(8)`, :manpage:`kea-netconf(8)`,
:manpage:`keactrl(8)`, :manpage:`kea-lfc(8)`, Kea Administrator Reference Manual.
man/kea-dhcp4.8
man/kea-dhcp6.8
- man/kea-ctrl-agent.8
man/keactrl.8
man/kea-admin.8
man/kea-dhcp-ddns.8
+++ /dev/null
-/agent_lexer.cc -diff merge=ours
-/agent_parser.cc -diff merge=ours
-/agent_parser.h -diff merge=ours
-/ca_messages.cc -diff merge=ours
-/ca_messages.h -diff merge=ours
-/location.hh -diff merge=ours
+++ /dev/null
-/agent_parser.report
+++ /dev/null
-// Copyright (C) 2017-2022 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-/**
- @page controlAgent Control Agent Component
-
-Kea 1.2 release has introduced the Control Agent component (CA), which
-is started by the "kea-ctrl-agent" binary. The CA exposes a RESTful API
-which is used by the administrators to manage Kea servers' instances.
-
-In the most typical case, the CA forwards commands received over the
-RESTful API to the respective Kea servers, e.g. DHCPv4 server, DHCPv6
-server etc. The communication between the CA and other servers is
-established with the use of unix domain sockets. This is possible because
-the CA is running on the same system as other Kea services to which
-messages are forwarded.
-
-The CA can forward the same command to multiple Kea services and return
-an aggregated response (from all services) over the RESTful API. The
-"service" parameter included in the client's command can contain one
-or more services at which the command is targeted. The CA will
-iterate over this list and forward the command to each of them
-individually.
-
-In some cases, the commands containing the "service" value can be handled
-directly by the CA. This is usually the case when the CA is running
-with hooks libraries attached. The hooks libraries must implement
-callouts for the "control_command_receive" hook point, which will be
-invoked by the CA when the command is received. If the hooks libraries
-set the 'skip' status, it is an indication to the CA that the command
-has been processed by the CA and that it should return the response created
-by the hooks libraries to the client. An example of the hooks library attached
-to the CA and handling the commands for other services is a library which
-stores or retrieves some data from the SQL database.
-
-The "service" parameter is optional. If it is not included in the command
-(or it is an empty list), this indicates that the command relates to the
-CA and that the CA should handle it, e.g. return its own configuration in
-response to a "config-get" command.
-
-@section ctrlAgentHttp Receiving commands over HTTP
-
-Control Agent uses libkea-http library to establish HTTP connections,
-receive messages and send responses over HTTP. This library uses boost ASIO
-for creating TCP connections and asynchronously receive and send the data
-over the sockets.
-
-The @ref isc::http::HttpListener provides an entry point to this library.
-It is used by the CA to bind the acceptor to the specific address and
-port. When the client connects to this address and port, the acceptor's
-callback function is invoked which opens a new connection and starts
-receiving data over that socket. The @ref isc::http::HttpConnection
-implements the logic to read and parse received data. Each new TCP
-connection is associated with unique instance of the @ref isc::http::HttpConnection
-When a portion of data is received (asynchronously) over
-the socket it is provided to the instance of the
-@ref isc::http::HttpRequestParser object (unique per connection) and
-data parsing is continued until the parser runs out of data or until
-the entire HTTP request has been received. The
-@ref isc::http::HttpRequestParser signals these events using the
-@ref isc::http::HttpRequestParser::needData and
-@ref isc::http::HttpRequestParser::httpParseOk respectively.
-
-libkea-http is designed to handle processing messages carrying different
-content types. The Control Agent uses "application/json" content
-type which describes messages with JSON structures carried within the
-message body. The JSON structures represent commands sent to the Kea
-server(s) by controlling clients. libkea-http provides generic classes
-(derived from @ref isc::http::HttpRequest) which facilitate validation of
-messages holding various content types.
-CA uses @ref isc::http::PostHttpRequestJson, which encapsulate messages
-sent using HTTP POST and including JSON content, to represent received messages.
-
-@section ctrlAgentCreatingResponse Creating HTTP responses
-
-The @ref isc::http::HttpResponseCreatorFactory is an interface which should
-be implemented by components using libkea-http to generate instances of
-the HTTP responses of a desired type. The instance of the factory class is
-provided to the @ref isc::http::HttpListener via its constructor. The listener
-calls an implementation of the
-@ref isc::http::HttpResponseCreatorFactory::create when a new HTTP
-message has been received and parsed.
-
-The CA component includes the @ref isc::agent::CtrlAgentResponseCreatorFactory
-class. Its @c create() method implementation returns
-an instance of the @ref isc::agent::CtrlAgentResponseCreator, which is a
-derivation of the @ref isc::http::HttpResponseCreator. This creator creates
-instances of the @ref isc::http::HttpResponseJson, holding responses to
-the commands in the JSON format.
-
-@section ctrlAgentCommandMgr Handling commands with Command Manager
-
-The @ref isc::agent::CtrlAgentCommandMgr is a derivation of the
-@ref isc::config::HookedCommandMgr which adds the capability to forward
-commands received over HTTP to specific Kea servers. The
-@ref isc::agent::CtrlAgentCommandMgr forwards commands over a Unix domain
-socket, using @ref isc::asiolink::UnixDomainSocket class. All responses
-to a particular command (possibly received from multiple Kea servers) are
-aggregated within a JSON list and sent back to the controlling client over
-HTTP.
-
-In some cases the responses may be generated locally (without forwarding).
-Typically, the command will be generated by the CA when the command sent
-by the client lacks the "service" parameter, which indicates that the
-command is targeted at the CA itself. In some cases the commands can also
-be processed by the hooks libraries attached to the CA.
-
-@section CtrlAgentSecurity Security considerations
-
-The Control Agent doesn't provide any mechanisms to secure the communication
-over the RESTful API. In the design of the CA we have considered including built-in
-HTTPS solutions (HTTP + TLS), making use of crypto libraries supported by Kea.
-It was eventually decided to not implement the secure layer within Kea for the following reasons:
-- additional code complexity which requires maintenance, bug fixing and
- monitoring for security vulnerabilities in the OpenSSL/Botan code,
-- OpenSSL/Botan code may be awkward to use and it is likely we wouldn't
- implement it right,
-- need to support two crypto backends: OpenSSL and Botan which puts significant
- burden on Kea maintenance.
-
-In the installations where securing command channel is critical (most of the
-installations?), a reverse HTTP proxy can be set up using one of the third
-party HTTP server implementations, e.g. Apache, nginx etc.
-
-*/
+++ /dev/null
-// Copyright (C) 2017-2024 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-/**
-@page agentHooks The Hooks API for the Control Agent
-
-@section agentHooksIntroduction Introduction
-The Kea Control Agent features "Hooks" API that allows the user-written
-code to be integrated with the Control Agent and handle some
-of the control commands. The hooks library can be either used to provide
-support for the new commands (not supported natively by the Control Agent)
-or "override" implementation of the existing handlers. The hooks library
-signals to the Control Agent that it has processed the given command by
-setting "next step status" value to SKIP.
-
-The hooks library can also be used to perform some additional tasks
-related to reception of the control command instead of handling it, e.g.
-logging or notifying some external service about reception of the
-command.
-
-@section agentHooksHookPoints Hooks in the Control Agent
-
- @subsection agentHooksAuth http_auth
-
- - @b Arguments:
- - name: @b request, type: isc::http::HttpRequestPtr, direction: <b>in/out</b>
- - name: @b response, type: isc::http::HttpResponseJsonPtr, direction: <b>in/out</b>
-
- - @b Description: this callout is executed when Control Agent receives a
- control command over the RESTful interface (HTTP).
- The "request" argument is a pointer to the request, in fact a
- PostHttpRequestJsonPtr. The "response" argument is the response in case
- of errors. The purpose of this callout is to implement authentication
- and authorization. It is called after basic HTTP authentication.
- The next step status is used only to ask to reset the handle: if the
- response is set the processing will stop and the response is returned.
- In particular the command is not forwarded.
-
- @subsection agentHooksResponse http_response
-
- - @b Arguments:
- - name: @b request, type: isc::http::HttpRequestPtr, direction: <b>in</b>
- - name: @b response, type: isc::http::HttpResponseJsonPtr, direction: <b>in/out</b>
-
- - @b Description: this callout is executed when Control Agent executed
- a control command over the RESTful interface (HTTP).
- The "request" argument is a pointer to the request. It is used as a
- reference and for callout contexts. The "response" argument is the
- response which will be sent back to the requesting client. It is
- called after command processing. The next step status is ignored:
- the response possibly modified will be sent back.
-
-@section agentHooksHandle Handle and hook unload
-
-The callout handle attached to the "request" argument can keep a pointer
-to the hook address space which prevents the hook to be unloaded
-when the "config-get" or "config-reload" command is executed.
-
-The "next step status" of the "auth" callout point can be set to any
-value other than CONTINUE to ask the callout handle to be reset. This
-must be done when the command is "config-get" or "config-reload" or
-when the "response" callout point is not used or when the callout
-context does not transmit values between the "auth" and "response"
-callout points.
-
-*/
+++ /dev/null
-#line 1 "agent_lexer.cc"
-
-#line 3 "agent_lexer.cc"
-
-#define YY_INT_ALIGNED short int
-
-/* A lexical scanner generated by flex */
-
-/* %not-for-header */
-/* %if-c-only */
-/* %if-not-reentrant */
-#define yy_create_buffer agent__create_buffer
-#define yy_delete_buffer agent__delete_buffer
-#define yy_scan_buffer agent__scan_buffer
-#define yy_scan_string agent__scan_string
-#define yy_scan_bytes agent__scan_bytes
-#define yy_init_buffer agent__init_buffer
-#define yy_flush_buffer agent__flush_buffer
-#define yy_load_buffer_state agent__load_buffer_state
-#define yy_switch_to_buffer agent__switch_to_buffer
-#define yypush_buffer_state agent_push_buffer_state
-#define yypop_buffer_state agent_pop_buffer_state
-#define yyensure_buffer_stack agent_ensure_buffer_stack
-#define yy_flex_debug agent__flex_debug
-#define yyin agent_in
-#define yyleng agent_leng
-#define yylex agent_lex
-#define yylineno agent_lineno
-#define yyout agent_out
-#define yyrestart agent_restart
-#define yytext agent_text
-#define yywrap agent_wrap
-#define yyalloc agent_alloc
-#define yyrealloc agent_realloc
-#define yyfree agent_free
-
-/* %endif */
-/* %endif */
-/* %ok-for-header */
-
-#define FLEX_SCANNER
-#define YY_FLEX_MAJOR_VERSION 2
-#define YY_FLEX_MINOR_VERSION 6
-#define YY_FLEX_SUBMINOR_VERSION 4
-#if YY_FLEX_SUBMINOR_VERSION > 0
-#define FLEX_BETA
-#endif
-
-/* %if-c++-only */
-/* %endif */
-
-/* %if-c-only */
-#ifdef yy_create_buffer
-#define agent__create_buffer_ALREADY_DEFINED
-#else
-#define yy_create_buffer agent__create_buffer
-#endif
-
-#ifdef yy_delete_buffer
-#define agent__delete_buffer_ALREADY_DEFINED
-#else
-#define yy_delete_buffer agent__delete_buffer
-#endif
-
-#ifdef yy_scan_buffer
-#define agent__scan_buffer_ALREADY_DEFINED
-#else
-#define yy_scan_buffer agent__scan_buffer
-#endif
-
-#ifdef yy_scan_string
-#define agent__scan_string_ALREADY_DEFINED
-#else
-#define yy_scan_string agent__scan_string
-#endif
-
-#ifdef yy_scan_bytes
-#define agent__scan_bytes_ALREADY_DEFINED
-#else
-#define yy_scan_bytes agent__scan_bytes
-#endif
-
-#ifdef yy_init_buffer
-#define agent__init_buffer_ALREADY_DEFINED
-#else
-#define yy_init_buffer agent__init_buffer
-#endif
-
-#ifdef yy_flush_buffer
-#define agent__flush_buffer_ALREADY_DEFINED
-#else
-#define yy_flush_buffer agent__flush_buffer
-#endif
-
-#ifdef yy_load_buffer_state
-#define agent__load_buffer_state_ALREADY_DEFINED
-#else
-#define yy_load_buffer_state agent__load_buffer_state
-#endif
-
-#ifdef yy_switch_to_buffer
-#define agent__switch_to_buffer_ALREADY_DEFINED
-#else
-#define yy_switch_to_buffer agent__switch_to_buffer
-#endif
-
-#ifdef yypush_buffer_state
-#define agent_push_buffer_state_ALREADY_DEFINED
-#else
-#define yypush_buffer_state agent_push_buffer_state
-#endif
-
-#ifdef yypop_buffer_state
-#define agent_pop_buffer_state_ALREADY_DEFINED
-#else
-#define yypop_buffer_state agent_pop_buffer_state
-#endif
-
-#ifdef yyensure_buffer_stack
-#define agent_ensure_buffer_stack_ALREADY_DEFINED
-#else
-#define yyensure_buffer_stack agent_ensure_buffer_stack
-#endif
-
-#ifdef yylex
-#define agent_lex_ALREADY_DEFINED
-#else
-#define yylex agent_lex
-#endif
-
-#ifdef yyrestart
-#define agent_restart_ALREADY_DEFINED
-#else
-#define yyrestart agent_restart
-#endif
-
-#ifdef yylex_init
-#define agent_lex_init_ALREADY_DEFINED
-#else
-#define yylex_init agent_lex_init
-#endif
-
-#ifdef yylex_init_extra
-#define agent_lex_init_extra_ALREADY_DEFINED
-#else
-#define yylex_init_extra agent_lex_init_extra
-#endif
-
-#ifdef yylex_destroy
-#define agent_lex_destroy_ALREADY_DEFINED
-#else
-#define yylex_destroy agent_lex_destroy
-#endif
-
-#ifdef yyget_debug
-#define agent_get_debug_ALREADY_DEFINED
-#else
-#define yyget_debug agent_get_debug
-#endif
-
-#ifdef yyset_debug
-#define agent_set_debug_ALREADY_DEFINED
-#else
-#define yyset_debug agent_set_debug
-#endif
-
-#ifdef yyget_extra
-#define agent_get_extra_ALREADY_DEFINED
-#else
-#define yyget_extra agent_get_extra
-#endif
-
-#ifdef yyset_extra
-#define agent_set_extra_ALREADY_DEFINED
-#else
-#define yyset_extra agent_set_extra
-#endif
-
-#ifdef yyget_in
-#define agent_get_in_ALREADY_DEFINED
-#else
-#define yyget_in agent_get_in
-#endif
-
-#ifdef yyset_in
-#define agent_set_in_ALREADY_DEFINED
-#else
-#define yyset_in agent_set_in
-#endif
-
-#ifdef yyget_out
-#define agent_get_out_ALREADY_DEFINED
-#else
-#define yyget_out agent_get_out
-#endif
-
-#ifdef yyset_out
-#define agent_set_out_ALREADY_DEFINED
-#else
-#define yyset_out agent_set_out
-#endif
-
-#ifdef yyget_leng
-#define agent_get_leng_ALREADY_DEFINED
-#else
-#define yyget_leng agent_get_leng
-#endif
-
-#ifdef yyget_text
-#define agent_get_text_ALREADY_DEFINED
-#else
-#define yyget_text agent_get_text
-#endif
-
-#ifdef yyget_lineno
-#define agent_get_lineno_ALREADY_DEFINED
-#else
-#define yyget_lineno agent_get_lineno
-#endif
-
-#ifdef yyset_lineno
-#define agent_set_lineno_ALREADY_DEFINED
-#else
-#define yyset_lineno agent_set_lineno
-#endif
-
-#ifdef yywrap
-#define agent_wrap_ALREADY_DEFINED
-#else
-#define yywrap agent_wrap
-#endif
-
-/* %endif */
-
-#ifdef yyalloc
-#define agent_alloc_ALREADY_DEFINED
-#else
-#define yyalloc agent_alloc
-#endif
-
-#ifdef yyrealloc
-#define agent_realloc_ALREADY_DEFINED
-#else
-#define yyrealloc agent_realloc
-#endif
-
-#ifdef yyfree
-#define agent_free_ALREADY_DEFINED
-#else
-#define yyfree agent_free
-#endif
-
-/* %if-c-only */
-
-#ifdef yytext
-#define agent_text_ALREADY_DEFINED
-#else
-#define yytext agent_text
-#endif
-
-#ifdef yyleng
-#define agent_leng_ALREADY_DEFINED
-#else
-#define yyleng agent_leng
-#endif
-
-#ifdef yyin
-#define agent_in_ALREADY_DEFINED
-#else
-#define yyin agent_in
-#endif
-
-#ifdef yyout
-#define agent_out_ALREADY_DEFINED
-#else
-#define yyout agent_out
-#endif
-
-#ifdef yy_flex_debug
-#define agent__flex_debug_ALREADY_DEFINED
-#else
-#define yy_flex_debug agent__flex_debug
-#endif
-
-#ifdef yylineno
-#define agent_lineno_ALREADY_DEFINED
-#else
-#define yylineno agent_lineno
-#endif
-
-/* %endif */
-
-/* First, we deal with platform-specific or compiler-specific issues. */
-
-/* begin standard C headers. */
-/* %if-c-only */
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <stdlib.h>
-/* %endif */
-
-/* %if-tables-serialization */
-/* %endif */
-/* end standard C headers. */
-
-/* %if-c-or-c++ */
-/* flex integer type definitions */
-
-#ifndef FLEXINT_H
-#define FLEXINT_H
-
-/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
-
-#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
-
-/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
- * if you want the limit (max/min) macros for int types.
- */
-#ifndef __STDC_LIMIT_MACROS
-#define __STDC_LIMIT_MACROS 1
-#endif
-
-#include <inttypes.h>
-typedef int8_t flex_int8_t;
-typedef uint8_t flex_uint8_t;
-typedef int16_t flex_int16_t;
-typedef uint16_t flex_uint16_t;
-typedef int32_t flex_int32_t;
-typedef uint32_t flex_uint32_t;
-#else
-typedef signed char flex_int8_t;
-typedef short int flex_int16_t;
-typedef int flex_int32_t;
-typedef unsigned char flex_uint8_t;
-typedef unsigned short int flex_uint16_t;
-typedef unsigned int flex_uint32_t;
-
-/* Limits of integral types. */
-#ifndef INT8_MIN
-#define INT8_MIN (-128)
-#endif
-#ifndef INT16_MIN
-#define INT16_MIN (-32767-1)
-#endif
-#ifndef INT32_MIN
-#define INT32_MIN (-2147483647-1)
-#endif
-#ifndef INT8_MAX
-#define INT8_MAX (127)
-#endif
-#ifndef INT16_MAX
-#define INT16_MAX (32767)
-#endif
-#ifndef INT32_MAX
-#define INT32_MAX (2147483647)
-#endif
-#ifndef UINT8_MAX
-#define UINT8_MAX (255U)
-#endif
-#ifndef UINT16_MAX
-#define UINT16_MAX (65535U)
-#endif
-#ifndef UINT32_MAX
-#define UINT32_MAX (4294967295U)
-#endif
-
-#ifndef SIZE_MAX
-#define SIZE_MAX (~(size_t)0)
-#endif
-
-#endif /* ! C99 */
-
-#endif /* ! FLEXINT_H */
-
-/* %endif */
-
-/* begin standard C++ headers. */
-/* %if-c++-only */
-/* %endif */
-
-/* TODO: this is always defined, so inline it */
-#define yyconst const
-
-#if defined(__GNUC__) && __GNUC__ >= 3
-#define yynoreturn __attribute__((__noreturn__))
-#else
-#define yynoreturn
-#endif
-
-/* %not-for-header */
-/* Returned upon end-of-file. */
-#define YY_NULL 0
-/* %ok-for-header */
-
-/* %not-for-header */
-/* Promotes a possibly negative, possibly signed char to an
- * integer in range [0..255] for use as an array index.
- */
-#define YY_SC_TO_UI(c) ((YY_CHAR) (c))
-/* %ok-for-header */
-
-/* %if-reentrant */
-/* %endif */
-
-/* %if-not-reentrant */
-
-/* %endif */
-
-/* Enter a start condition. This macro really ought to take a parameter,
- * but we do it the disgusting crufty way forced on us by the ()-less
- * definition of BEGIN.
- */
-#define BEGIN (yy_start) = 1 + 2 *
-/* Translate the current start state into a value that can be later handed
- * to BEGIN to return to the state. The YYSTATE alias is for lex
- * compatibility.
- */
-#define YY_START (((yy_start) - 1) / 2)
-#define YYSTATE YY_START
-/* Action number for EOF rule of a given start state. */
-#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
-/* Special action meaning "start processing a new file". */
-#define YY_NEW_FILE yyrestart( yyin )
-#define YY_END_OF_BUFFER_CHAR 0
-
-/* Size of default input buffer. */
-#ifndef YY_BUF_SIZE
-#ifdef __ia64__
-/* On IA-64, the buffer size is 16k, not 8k.
- * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
- * Ditto for the __ia64__ case accordingly.
- */
-#define YY_BUF_SIZE 32768
-#else
-#define YY_BUF_SIZE 16384
-#endif /* __ia64__ */
-#endif
-
-/* The state buf must be large enough to hold one state per character in the main buffer.
- */
-#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
-
-#ifndef YY_TYPEDEF_YY_BUFFER_STATE
-#define YY_TYPEDEF_YY_BUFFER_STATE
-typedef struct yy_buffer_state *YY_BUFFER_STATE;
-#endif
-
-#ifndef YY_TYPEDEF_YY_SIZE_T
-#define YY_TYPEDEF_YY_SIZE_T
-typedef size_t yy_size_t;
-#endif
-
-/* %if-not-reentrant */
-extern int yyleng;
-/* %endif */
-
-/* %if-c-only */
-/* %if-not-reentrant */
-extern FILE *yyin, *yyout;
-/* %endif */
-/* %endif */
-
-#define EOB_ACT_CONTINUE_SCAN 0
-#define EOB_ACT_END_OF_FILE 1
-#define EOB_ACT_LAST_MATCH 2
-
- #define YY_LESS_LINENO(n)
- #define YY_LINENO_REWIND_TO(ptr)
-
-/* Return all but the first "n" matched characters back to the input stream. */
-#define yyless(n) \
- do \
- { \
- /* Undo effects of setting up yytext. */ \
- int yyless_macro_arg = (n); \
- YY_LESS_LINENO(yyless_macro_arg);\
- *yy_cp = (yy_hold_char); \
- YY_RESTORE_YY_MORE_OFFSET \
- (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
- YY_DO_BEFORE_ACTION; /* set up yytext again */ \
- } \
- while ( 0 )
-#define unput(c) yyunput( c, (yytext_ptr) )
-
-#ifndef YY_STRUCT_YY_BUFFER_STATE
-#define YY_STRUCT_YY_BUFFER_STATE
-struct yy_buffer_state
- {
-/* %if-c-only */
- FILE *yy_input_file;
-/* %endif */
-
-/* %if-c++-only */
-/* %endif */
-
- char *yy_ch_buf; /* input buffer */
- char *yy_buf_pos; /* current position in input buffer */
-
- /* Size of input buffer in bytes, not including room for EOB
- * characters.
- */
- int yy_buf_size;
-
- /* Number of characters read into yy_ch_buf, not including EOB
- * characters.
- */
- int yy_n_chars;
-
- /* Whether we "own" the buffer - i.e., we know we created it,
- * and can realloc() it to grow it, and should free() it to
- * delete it.
- */
- int yy_is_our_buffer;
-
- /* Whether this is an "interactive" input source; if so, and
- * if we're using stdio for input, then we want to use getc()
- * instead of fread(), to make sure we stop fetching input after
- * each newline.
- */
- int yy_is_interactive;
-
- /* Whether we're considered to be at the beginning of a line.
- * If so, '^' rules will be active on the next match, otherwise
- * not.
- */
- int yy_at_bol;
-
- int yy_bs_lineno; /**< The line count. */
- int yy_bs_column; /**< The column count. */
-
- /* Whether to try to fill the input buffer when we reach the
- * end of it.
- */
- int yy_fill_buffer;
-
- int yy_buffer_status;
-
-#define YY_BUFFER_NEW 0
-#define YY_BUFFER_NORMAL 1
- /* When an EOF's been seen but there's still some text to process
- * then we mark the buffer as YY_EOF_PENDING, to indicate that we
- * shouldn't try reading from the input source any more. We might
- * still have a bunch of tokens to match, though, because of
- * possible backing-up.
- *
- * When we actually see the EOF, we change the status to "new"
- * (via yyrestart()), so that the user can continue scanning by
- * just pointing yyin at a new input file.
- */
-#define YY_BUFFER_EOF_PENDING 2
-
- };
-#endif /* !YY_STRUCT_YY_BUFFER_STATE */
-
-/* %if-c-only Standard (non-C++) definition */
-/* %not-for-header */
-/* %if-not-reentrant */
-
-/* Stack of input buffers. */
-static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
-static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
-static YY_BUFFER_STATE * yy_buffer_stack = NULL; /**< Stack as an array. */
-/* %endif */
-/* %ok-for-header */
-
-/* %endif */
-
-/* We provide macros for accessing buffer states in case in the
- * future we want to put the buffer states in a more general
- * "scanner state".
- *
- * Returns the top of the stack, or NULL.
- */
-#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
- ? (yy_buffer_stack)[(yy_buffer_stack_top)] \
- : NULL)
-/* Same as previous macro, but useful when we know that the buffer stack is not
- * NULL or when we need an lvalue. For internal use only.
- */
-#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
-
-/* %if-c-only Standard (non-C++) definition */
-
-/* %if-not-reentrant */
-/* %not-for-header */
-/* yy_hold_char holds the character lost when yytext is formed. */
-static char yy_hold_char;
-static int yy_n_chars; /* number of characters read into yy_ch_buf */
-int yyleng;
-
-/* Points to current character in buffer. */
-static char *yy_c_buf_p = NULL;
-static int yy_init = 0; /* whether we need to initialize */
-static int yy_start = 0; /* start state number */
-
-/* Flag which is used to allow yywrap()'s to do buffer switches
- * instead of setting up a fresh yyin. A bit of a hack ...
- */
-static int yy_did_buffer_switch_on_eof;
-/* %ok-for-header */
-
-/* %endif */
-
-void yyrestart ( FILE *input_file );
-void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer );
-YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size );
-void yy_delete_buffer ( YY_BUFFER_STATE b );
-void yy_flush_buffer ( YY_BUFFER_STATE b );
-void yypush_buffer_state ( YY_BUFFER_STATE new_buffer );
-void yypop_buffer_state ( void );
-
-static void yyensure_buffer_stack ( void );
-static void yy_load_buffer_state ( void );
-static void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file );
-#define YY_FLUSH_BUFFER yy_flush_buffer( YY_CURRENT_BUFFER )
-
-YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size );
-YY_BUFFER_STATE yy_scan_string ( const char *yy_str );
-YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len );
-
-/* %endif */
-
-void *yyalloc ( yy_size_t );
-void *yyrealloc ( void *, yy_size_t );
-void yyfree ( void * );
-
-#define yy_new_buffer yy_create_buffer
-#define yy_set_interactive(is_interactive) \
- { \
- if ( ! YY_CURRENT_BUFFER ){ \
- yyensure_buffer_stack (); \
- YY_CURRENT_BUFFER_LVALUE = \
- yy_create_buffer( yyin, YY_BUF_SIZE ); \
- } \
- YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
- }
-#define yy_set_bol(at_bol) \
- { \
- if ( ! YY_CURRENT_BUFFER ){\
- yyensure_buffer_stack (); \
- YY_CURRENT_BUFFER_LVALUE = \
- yy_create_buffer( yyin, YY_BUF_SIZE ); \
- } \
- YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
- }
-#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
-
-/* %% [1.0] yytext/yyin/yyout/yy_state_type/yylineno etc. def's & init go here */
-/* Begin user sect3 */
-
-#define agent_wrap() (/*CONSTCOND*/1)
-#define YY_SKIP_YYWRAP
-
-#define FLEX_DEBUG
-typedef flex_uint8_t YY_CHAR;
-
-FILE *yyin = NULL, *yyout = NULL;
-
-typedef int yy_state_type;
-
-extern int yylineno;
-int yylineno = 1;
-
-extern char *yytext;
-#ifdef yytext_ptr
-#undef yytext_ptr
-#endif
-#define yytext_ptr yytext
-
-/* %% [1.5] DFA */
-
-/* %if-c-only Standard (non-C++) definition */
-
-static yy_state_type yy_get_previous_state ( void );
-static yy_state_type yy_try_NUL_trans ( yy_state_type current_state );
-static int yy_get_next_buffer ( void );
-static void yynoreturn yy_fatal_error ( const char* msg );
-
-/* %endif */
-
-/* Done after the current pattern has been matched and before the
- * corresponding action - sets up yytext.
- */
-#define YY_DO_BEFORE_ACTION \
- (yytext_ptr) = yy_bp; \
-/* %% [2.0] code to fiddle yytext and yyleng for yymore() goes here \ */\
- yyleng = (int) (yy_cp - yy_bp); \
- (yy_hold_char) = *yy_cp; \
- *yy_cp = '\0'; \
-/* %% [3.0] code to copy yytext_ptr to yytext[] goes here, if %array \ */\
- (yy_c_buf_p) = yy_cp;
-/* %% [4.0] data tables for the DFA and the user's section 1 definitions go here */
-#define YY_NUM_RULES 73
-#define YY_END_OF_BUFFER 74
-/* This struct is not used in this scanner,
- but its presence is necessary. */
-struct yy_trans_info
- {
- flex_int32_t yy_verify;
- flex_int32_t yy_nxt;
- };
-static const flex_int16_t yy_accept[430] =
- { 0,
- 66, 66, 0, 0, 0, 0, 0, 0, 0, 0,
- 74, 72, 10, 11, 72, 1, 66, 63, 66, 66,
- 72, 65, 64, 72, 72, 72, 72, 72, 59, 60,
- 72, 72, 72, 61, 62, 5, 5, 5, 72, 72,
- 72, 10, 11, 0, 0, 54, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 1, 66, 66, 0, 65,
- 66, 3, 2, 6, 0, 66, 0, 0, 0, 0,
- 0, 0, 4, 0, 0, 9, 0, 55, 0, 0,
- 0, 57, 0, 0, 0, 0, 0, 0, 0, 0,
-
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 2, 0, 0, 0, 0, 0, 0, 0, 8, 0,
- 0, 56, 58, 0, 0, 0, 0, 0, 0, 0,
- 37, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 71, 69, 0, 68, 67,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- 0, 0, 0, 70, 67, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 18, 0, 0, 0,
- 0, 0, 0, 0, 0, 21, 40, 26, 0, 0,
- 0, 0, 0, 22, 0, 0, 0, 0, 0, 0,
- 35, 36, 0, 48, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 23, 0, 0, 0,
- 0, 0, 19, 7, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 50, 47, 0, 0, 0, 0, 0, 0, 0,
-
- 0, 0, 0, 0, 0, 0, 0, 25, 17, 0,
- 0, 0, 0, 0, 0, 0, 0, 42, 44, 49,
- 0, 0, 0, 0, 51, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 32, 0, 0, 0, 28, 0, 53, 0,
- 0, 0, 0, 0, 0, 0, 31, 0, 0, 0,
- 24, 0, 0, 13, 14, 0, 0, 0, 0, 0,
- 0, 0, 0, 27, 0, 0, 0, 0, 52, 0,
- 0, 0, 0, 43, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 38, 39,
-
- 0, 0, 0, 0, 0, 0, 0, 15, 0, 0,
- 0, 30, 16, 12, 0, 33, 0, 0, 0, 0,
- 29, 20, 0, 0, 46, 45, 34, 41, 0
- } ;
-
-static const YY_CHAR yy_ec[256] =
- { 0,
- 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
- 1, 1, 2, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 4, 5, 6, 7, 5, 5, 5, 5, 5,
- 5, 8, 9, 10, 11, 12, 13, 14, 14, 15,
- 14, 16, 14, 17, 14, 14, 14, 18, 5, 19,
- 5, 20, 21, 5, 22, 23, 24, 23, 25, 26,
- 5, 5, 5, 5, 5, 27, 5, 28, 5, 5,
- 5, 29, 30, 31, 32, 5, 5, 5, 5, 5,
- 33, 34, 35, 5, 36, 5, 37, 38, 39, 40,
-
- 41, 42, 43, 44, 45, 5, 46, 47, 48, 49,
- 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
- 60, 61, 62, 5, 63, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5
- } ;
-
-static const YY_CHAR yy_meta[64] =
- { 0,
- 1, 1, 2, 1, 1, 3, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1
- } ;
-
-static const flex_int16_t yy_base[438] =
- { 0,
- 0, 0, 62, 65, 68, 0, 66, 70, 50, 67,
- 335, 2874, 87, 318, 131, 0, 104, 2874, 110, 125,
- 84, 142, 2874, 296, 91, 106, 58, 107, 2874, 2874,
- 116, 116, 123, 2874, 2874, 2874, 142, 282, 237, 0,
- 217, 145, 229, 155, 189, 2874, 195, 193, 202, 210,
- 216, 237, 253, 259, 267, 273, 282, 288, 296, 309,
- 325, 331, 339, 348, 354, 0, 353, 389, 401, 407,
- 370, 2874, 0, 2874, 289, 347, 147, 173, 170, 183,
- 187, 177, 2874, 189, 218, 2874, 187, 2874, 407, 425,
- 209, 373, 469, 432, 466, 495, 511, 520, 529, 536,
-
- 549, 556, 570, 578, 590, 596, 604, 612, 619, 631,
- 638, 646, 657, 668, 680, 686, 702, 709, 715, 721,
- 0, 223, 245, 200, 266, 297, 226, 160, 2874, 727,
- 158, 2874, 2874, 769, 744, 756, 763, 738, 797, 813,
- 2874, 819, 826, 832, 838, 848, 855, 868, 861, 882,
- 895, 902, 916, 925, 931, 938, 945, 954, 967, 974,
- 980, 988, 996, 1003, 239, 2874, 2874, 288, 2874, 2874,
- 107, 1009, 1049, 1017, 1075, 1023, 1091, 1097, 1105, 1114,
- 1120, 1126, 1140, 1149, 1160, 1166, 1175, 1184, 1190, 1196,
- 1204, 1213, 1220, 1226, 1238, 1247, 1255, 1264, 1272, 1284,
-
- 1290, 1298, 1309, 2874, 2874, 122, 1319, 1356, 1327, 1333,
- 1357, 1382, 1343, 1399, 1405, 1411, 1417, 1423, 1429, 1453,
- 1440, 1459, 1465, 1474, 1480, 1494, 2874, 1500, 1509, 1518,
- 1529, 1536, 1543, 1555, 1563, 2874, 2874, 2874, 1570, 1577,
- 63, 1584, 1590, 2874, 1599, 1613, 1619, 1626, 1633, 1649,
- 2874, 2874, 1655, 2874, 1640, 1662, 1676, 1691, 1698, 1705,
- 1712, 1718, 1734, 1727, 1741, 1754, 2874, 1761, 1770, 1777,
- 1783, 1790, 2874, 2874, 1796, 1807, 1817, 1825, 1836, 1842,
- 1852, 1859, 1865, 1872, 1878, 1886, 1894, 1901, 1907, 1920,
- 1928, 2874, 2874, 1942, 1949, 1955, 1963, 1971, 1978, 1984,
-
- 1992, 2008, 2014, 2021, 2028, 2034, 2043, 2874, 2874, 2050,
- 2068, 2077, 2084, 2090, 2104, 2111, 2126, 2874, 2874, 2874,
- 2133, 2140, 2146, 2152, 2874, 2167, 2175, 2186, 2192, 2201,
- 2213, 2221, 2231, 2237, 2247, 2256, 2271, 2277, 2283, 2292,
- 2298, 2306, 2874, 2313, 2319, 2328, 2874, 2336, 2874, 2342,
- 2349, 2355, 2363, 2378, 2385, 2400, 2874, 2407, 2414, 2422,
- 2874, 2429, 2436, 2874, 2874, 2443, 2456, 2466, 2472, 2478,
- 2490, 2496, 2502, 2874, 2508, 2519, 2526, 2532, 2874, 2538,
- 2546, 2553, 2567, 2874, 2573, 2580, 2587, 2593, 2603, 2609,
- 2622, 2628, 2639, 2647, 2664, 2673, 2681, 2687, 2874, 2874,
-
- 2693, 2699, 2707, 2717, 2723, 2733, 2741, 2874, 2747, 2753,
- 2759, 2874, 2874, 2874, 2768, 2874, 2777, 2783, 2789, 2802,
- 2874, 2874, 2812, 2818, 2874, 2874, 2874, 2874, 2874, 2852,
- 2855, 2858, 97, 2861, 2864, 2867, 2870
- } ;
-
-static const flex_int16_t yy_def[438] =
- { 0,
- 429, 1, 430, 430, 1, 5, 5, 5, 5, 5,
- 429, 429, 429, 429, 431, 432, 429, 429, 429, 429,
- 429, 429, 429, 429, 429, 429, 429, 429, 429, 429,
- 429, 429, 429, 429, 429, 429, 429, 429, 429, 433,
- 429, 429, 429, 434, 431, 429, 431, 435, 431, 431,
- 431, 431, 431, 431, 431, 431, 431, 431, 431, 431,
- 431, 431, 431, 431, 431, 432, 429, 429, 429, 429,
- 429, 429, 436, 429, 429, 429, 429, 429, 429, 429,
- 429, 429, 429, 429, 433, 429, 434, 429, 429, 431,
- 437, 431, 435, 431, 431, 431, 431, 431, 431, 431,
-
- 431, 431, 431, 431, 431, 431, 431, 431, 431, 431,
- 431, 431, 431, 431, 431, 431, 431, 431, 431, 431,
- 436, 429, 429, 429, 429, 429, 429, 429, 429, 431,
- 437, 429, 429, 93, 431, 431, 431, 431, 431, 431,
- 429, 431, 431, 431, 431, 431, 431, 431, 431, 431,
- 431, 431, 431, 431, 431, 431, 431, 431, 431, 431,
- 431, 431, 431, 431, 429, 429, 429, 429, 429, 429,
- 429, 431, 93, 431, 431, 431, 431, 431, 431, 431,
- 431, 431, 431, 431, 431, 431, 431, 431, 431, 431,
- 431, 431, 431, 431, 431, 431, 431, 431, 431, 431,
-
- 431, 431, 431, 429, 429, 429, 431, 93, 431, 431,
- 431, 431, 431, 431, 431, 431, 431, 431, 431, 431,
- 431, 431, 431, 431, 431, 431, 429, 431, 431, 431,
- 431, 431, 431, 431, 431, 429, 429, 429, 431, 431,
- 429, 431, 431, 429, 431, 431, 431, 431, 431, 431,
- 429, 429, 431, 429, 431, 431, 431, 431, 431, 431,
- 431, 431, 431, 431, 431, 431, 429, 431, 431, 431,
- 431, 431, 429, 429, 431, 431, 431, 431, 431, 431,
- 431, 431, 431, 431, 431, 431, 431, 431, 431, 431,
- 431, 429, 429, 431, 431, 431, 431, 431, 431, 431,
-
- 431, 431, 431, 431, 431, 431, 431, 429, 429, 431,
- 431, 431, 431, 431, 431, 431, 431, 429, 429, 429,
- 431, 431, 431, 431, 429, 431, 431, 431, 431, 431,
- 431, 431, 431, 431, 431, 431, 431, 431, 431, 431,
- 431, 431, 429, 431, 431, 431, 429, 431, 429, 431,
- 431, 431, 431, 431, 431, 431, 429, 431, 431, 431,
- 429, 431, 431, 429, 429, 431, 431, 431, 431, 431,
- 431, 431, 431, 429, 431, 431, 431, 431, 429, 431,
- 431, 431, 431, 429, 431, 431, 431, 431, 431, 431,
- 431, 431, 431, 431, 431, 431, 431, 431, 429, 429,
-
- 431, 431, 431, 431, 431, 431, 431, 429, 431, 431,
- 431, 429, 429, 429, 431, 429, 431, 431, 431, 431,
- 429, 429, 431, 431, 429, 429, 429, 429, 0, 429,
- 429, 429, 429, 429, 429, 429, 429
- } ;
-
-static const flex_int16_t yy_nxt[2938] =
- { 0,
- 12, 13, 14, 13, 12, 15, 16, 12, 17, 18,
- 19, 20, 21, 22, 22, 22, 22, 23, 24, 12,
- 12, 12, 12, 12, 25, 26, 12, 27, 12, 12,
- 28, 12, 29, 12, 30, 12, 12, 12, 12, 12,
- 25, 31, 12, 12, 12, 12, 12, 12, 32, 12,
- 12, 12, 12, 12, 33, 12, 12, 12, 12, 12,
- 12, 34, 35, 37, 14, 37, 37, 14, 37, 38,
- 41, 40, 38, 12, 12, 40, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 41, 42, 78,
- 42, 72, 12, 12, 12, 12, 73, 85, 12, 75,
-
- 12, 75, 12, 274, 76, 76, 76, 76, 12, 12,
- 12, 12, 39, 78, 12, 67, 12, 68, 68, 68,
- 68, 67, 12, 70, 70, 70, 70, 77, 69, 12,
- 12, 44, 44, 44, 69, 79, 46, 77, 71, 71,
- 71, 71, 77, 42, 69, 42, 42, 78, 42, 69,
- 69, 79, 80, 67, 47, 70, 70, 70, 70, 79,
- 88, 241, 206, 132, 48, 69, 69, 49, 50, 51,
- 52, 81, 53, 122, 54, 82, 55, 56, 57, 58,
- 59, 60, 69, 61, 62, 63, 64, 65, 89, 44,
- 44, 44, 88, 122, 46, 44, 44, 44, 92, 123,
-
- 46, 124, 44, 44, 44, 45, 171, 46, 124, 122,
- 44, 44, 44, 123, 132, 46, 44, 44, 44, 123,
- 89, 46, 48, 129, 167, 124, 45, 128, 48, 125,
- 45, 43, 127, 126, 45, 48, 86, 44, 44, 44,
- 167, 45, 46, 48, 90, 45, 95, 45, 93, 48,
- 167, 99, 165, 44, 44, 44, 96, 94, 46, 44,
- 44, 44, 97, 204, 46, 98, 170, 44, 44, 44,
- 48, 166, 46, 44, 44, 44, 165, 100, 46, 204,
- 101, 102, 44, 44, 44, 84, 48, 46, 44, 44,
- 44, 166, 48, 46, 83, 165, 44, 44, 44, 103,
-
- 48, 46, 76, 76, 76, 76, 48, 106, 104, 44,
- 44, 44, 204, 105, 46, 48, 74, 107, 109, 168,
- 43, 48, 108, 166, 110, 44, 44, 44, 205, 48,
- 46, 44, 44, 44, 429, 429, 46, 429, 429, 44,
- 44, 44, 48, 169, 46, 112, 429, 429, 44, 44,
- 44, 111, 429, 46, 44, 44, 44, 429, 48, 46,
- 76, 76, 76, 76, 48, 113, 71, 71, 71, 71,
- 429, 114, 48, 44, 44, 44, 429, 69, 46, 429,
- 115, 48, 429, 71, 71, 71, 71, 48, 429, 429,
- 120, 116, 429, 69, 69, 429, 118, 429, 117, 429,
-
- 67, 119, 68, 68, 68, 68, 48, 429, 429, 75,
- 69, 75, 87, 69, 76, 76, 76, 76, 67, 87,
- 70, 70, 70, 70, 429, 44, 44, 44, 429, 69,
- 46, 69, 44, 44, 44, 429, 429, 46, 429, 429,
- 87, 429, 429, 429, 87, 429, 429, 69, 87, 429,
- 429, 429, 429, 429, 429, 87, 429, 429, 48, 87,
- 429, 87, 87, 429, 429, 48, 44, 44, 44, 429,
- 429, 46, 429, 130, 133, 429, 429, 429, 429, 429,
- 429, 429, 134, 134, 134, 134, 135, 429, 429, 429,
- 134, 134, 134, 134, 134, 44, 44, 44, 429, 48,
-
- 46, 429, 429, 429, 429, 134, 134, 134, 134, 134,
- 134, 44, 44, 44, 429, 429, 46, 429, 429, 136,
- 44, 44, 44, 429, 429, 46, 429, 429, 48, 44,
- 44, 44, 429, 429, 141, 429, 44, 44, 44, 429,
- 429, 46, 429, 429, 48, 429, 429, 137, 429, 44,
- 44, 44, 429, 48, 46, 138, 44, 44, 44, 429,
- 429, 46, 48, 429, 429, 429, 429, 139, 140, 48,
- 44, 44, 44, 142, 429, 46, 429, 429, 44, 44,
- 44, 429, 48, 46, 429, 429, 429, 143, 429, 48,
- 44, 44, 44, 429, 429, 46, 44, 44, 44, 429,
-
- 429, 46, 429, 48, 44, 44, 44, 429, 144, 46,
- 429, 48, 44, 44, 44, 429, 429, 46, 429, 44,
- 44, 44, 429, 48, 46, 145, 429, 146, 429, 48,
- 429, 44, 44, 44, 429, 429, 46, 48, 44, 44,
- 44, 149, 429, 46, 147, 48, 44, 44, 44, 429,
- 429, 46, 48, 429, 150, 148, 429, 44, 44, 44,
- 429, 429, 46, 429, 48, 429, 429, 429, 44, 44,
- 44, 48, 429, 46, 429, 429, 429, 151, 152, 48,
- 44, 44, 44, 429, 429, 46, 44, 44, 44, 429,
- 48, 46, 153, 157, 429, 429, 429, 429, 154, 155,
-
- 156, 48, 44, 44, 44, 429, 429, 46, 429, 44,
- 44, 44, 429, 48, 46, 44, 44, 44, 159, 48,
- 46, 44, 44, 44, 158, 429, 46, 44, 44, 44,
- 429, 429, 46, 429, 429, 48, 429, 429, 44, 44,
- 44, 160, 48, 46, 44, 44, 44, 429, 48, 46,
- 429, 429, 161, 162, 48, 163, 44, 44, 44, 429,
- 48, 46, 429, 44, 44, 44, 429, 164, 46, 429,
- 429, 48, 429, 429, 429, 429, 429, 48, 177, 429,
- 429, 172, 173, 173, 173, 173, 429, 174, 429, 48,
- 173, 173, 173, 173, 173, 429, 48, 44, 44, 44,
-
- 175, 429, 46, 429, 429, 173, 173, 173, 173, 173,
- 173, 429, 429, 44, 44, 44, 429, 176, 46, 44,
- 44, 44, 429, 429, 46, 429, 44, 44, 44, 429,
- 48, 46, 44, 44, 44, 429, 429, 46, 44, 44,
- 44, 429, 429, 46, 178, 429, 48, 429, 44, 44,
- 44, 429, 48, 46, 429, 44, 44, 44, 429, 48,
- 46, 44, 44, 44, 429, 48, 46, 179, 44, 44,
- 44, 48, 182, 46, 180, 429, 181, 429, 186, 429,
- 429, 48, 44, 44, 44, 429, 429, 46, 48, 429,
- 429, 183, 429, 184, 48, 44, 44, 44, 429, 429,
-
- 46, 48, 44, 44, 44, 185, 429, 46, 429, 429,
- 429, 429, 429, 187, 429, 48, 44, 44, 44, 429,
- 429, 46, 429, 429, 188, 44, 44, 44, 48, 429,
- 46, 44, 44, 44, 429, 48, 46, 429, 44, 44,
- 44, 429, 191, 46, 429, 44, 44, 44, 189, 48,
- 46, 190, 429, 429, 44, 44, 44, 429, 48, 46,
- 429, 193, 429, 429, 48, 429, 192, 44, 44, 44,
- 429, 48, 46, 429, 44, 44, 44, 429, 48, 46,
- 44, 44, 44, 429, 194, 46, 429, 48, 44, 44,
- 44, 196, 195, 46, 197, 429, 44, 44, 44, 429,
-
- 48, 46, 429, 44, 44, 44, 429, 48, 46, 44,
- 44, 44, 198, 48, 46, 429, 429, 44, 44, 44,
- 200, 48, 46, 44, 44, 44, 429, 199, 46, 48,
- 429, 429, 429, 211, 429, 429, 48, 429, 429, 429,
- 429, 429, 48, 429, 429, 429, 201, 429, 202, 429,
- 48, 429, 429, 429, 429, 429, 48, 209, 203, 429,
- 429, 207, 208, 208, 208, 208, 429, 429, 429, 429,
- 208, 208, 208, 208, 208, 44, 44, 44, 429, 429,
- 46, 429, 429, 429, 429, 208, 208, 208, 208, 208,
- 208, 44, 44, 44, 429, 429, 46, 44, 44, 44,
-
- 429, 429, 46, 429, 429, 44, 44, 44, 48, 429,
- 46, 429, 429, 210, 44, 44, 44, 429, 429, 46,
- 44, 44, 44, 429, 48, 46, 44, 44, 44, 429,
- 48, 46, 429, 429, 429, 216, 217, 213, 48, 212,
- 44, 44, 44, 429, 429, 46, 429, 48, 429, 44,
- 44, 44, 429, 48, 46, 429, 215, 214, 429, 48,
- 44, 44, 44, 429, 218, 46, 44, 44, 44, 429,
- 221, 46, 429, 48, 429, 44, 44, 44, 429, 429,
- 46, 429, 48, 219, 44, 44, 44, 429, 429, 46,
- 44, 44, 44, 48, 429, 46, 44, 44, 44, 48,
-
- 429, 46, 220, 429, 44, 44, 44, 222, 48, 227,
- 429, 223, 429, 44, 44, 44, 429, 48, 46, 429,
- 44, 44, 44, 48, 224, 46, 44, 44, 44, 48,
- 429, 46, 429, 429, 225, 429, 226, 48, 44, 44,
- 44, 429, 429, 46, 429, 429, 48, 44, 44, 44,
- 429, 429, 46, 48, 429, 44, 44, 44, 429, 48,
- 46, 429, 429, 429, 44, 44, 44, 229, 228, 46,
- 429, 48, 44, 44, 44, 429, 429, 46, 231, 429,
- 48, 429, 429, 230, 44, 44, 44, 429, 48, 236,
- 44, 44, 44, 429, 232, 237, 429, 48, 44, 44,
-
- 44, 429, 429, 238, 234, 48, 429, 233, 239, 44,
- 44, 44, 429, 429, 46, 429, 429, 48, 429, 44,
- 44, 44, 429, 48, 46, 429, 235, 44, 44, 44,
- 429, 48, 46, 44, 44, 44, 429, 429, 244, 429,
- 429, 429, 48, 44, 44, 44, 429, 429, 46, 240,
- 429, 429, 48, 429, 429, 429, 429, 44, 44, 44,
- 48, 429, 46, 429, 429, 429, 48, 429, 242, 45,
- 45, 45, 45, 429, 429, 243, 48, 45, 45, 45,
- 45, 45, 44, 44, 44, 429, 429, 46, 429, 429,
- 48, 248, 45, 45, 45, 45, 45, 45, 245, 44,
-
- 44, 44, 429, 429, 46, 44, 44, 44, 429, 246,
- 46, 44, 44, 44, 429, 48, 251, 44, 44, 44,
- 429, 429, 252, 44, 44, 44, 429, 429, 46, 44,
- 44, 44, 48, 429, 254, 429, 247, 429, 48, 429,
- 44, 44, 44, 429, 48, 46, 429, 429, 249, 429,
- 48, 250, 429, 44, 44, 44, 48, 429, 46, 44,
- 44, 44, 48, 255, 46, 44, 44, 44, 429, 429,
- 46, 429, 429, 48, 44, 44, 44, 253, 429, 46,
- 44, 44, 44, 256, 429, 46, 48, 429, 429, 429,
- 257, 429, 48, 429, 44, 44, 44, 429, 48, 46,
-
- 44, 44, 44, 258, 429, 46, 429, 48, 429, 44,
- 44, 44, 429, 48, 46, 429, 429, 259, 44, 44,
- 44, 429, 429, 46, 429, 429, 260, 48, 429, 44,
- 44, 44, 429, 48, 46, 429, 44, 44, 44, 429,
- 261, 267, 48, 44, 44, 44, 262, 429, 46, 264,
- 429, 48, 429, 429, 263, 44, 44, 44, 429, 429,
- 46, 429, 48, 44, 44, 44, 429, 265, 46, 48,
- 44, 44, 44, 270, 429, 46, 48, 44, 44, 44,
- 429, 266, 273, 429, 44, 44, 44, 268, 48, 46,
- 44, 44, 44, 429, 429, 46, 48, 429, 429, 44,
-
- 44, 44, 429, 48, 46, 429, 429, 429, 271, 269,
- 48, 272, 429, 44, 44, 44, 429, 48, 46, 44,
- 44, 44, 429, 48, 46, 429, 44, 44, 44, 429,
- 275, 46, 48, 44, 44, 44, 429, 429, 46, 429,
- 44, 44, 44, 277, 276, 46, 48, 429, 429, 44,
- 44, 44, 48, 278, 46, 44, 44, 44, 429, 48,
- 46, 429, 44, 44, 44, 429, 48, 46, 429, 429,
- 429, 429, 279, 48, 429, 429, 44, 44, 44, 281,
- 280, 46, 48, 429, 429, 429, 284, 429, 48, 282,
- 429, 44, 44, 44, 429, 48, 46, 429, 44, 44,
-
- 44, 429, 285, 46, 283, 44, 44, 44, 429, 48,
- 46, 286, 44, 44, 44, 429, 429, 46, 44, 44,
- 44, 429, 429, 292, 48, 287, 429, 44, 44, 44,
- 429, 48, 46, 429, 44, 44, 44, 288, 48, 293,
- 429, 44, 44, 44, 294, 48, 46, 429, 429, 429,
- 429, 48, 291, 429, 44, 44, 44, 289, 290, 46,
- 48, 44, 44, 44, 429, 429, 46, 48, 429, 295,
- 44, 44, 44, 429, 48, 46, 429, 44, 44, 44,
- 300, 296, 46, 44, 44, 44, 429, 48, 46, 429,
- 44, 44, 44, 297, 48, 46, 44, 44, 44, 429,
-
- 429, 46, 298, 48, 429, 429, 304, 44, 44, 44,
- 48, 429, 46, 301, 429, 299, 48, 44, 44, 44,
- 429, 429, 46, 48, 429, 44, 44, 44, 429, 48,
- 46, 429, 302, 429, 303, 429, 44, 44, 44, 429,
- 48, 308, 44, 44, 44, 429, 429, 309, 429, 429,
- 48, 305, 44, 44, 44, 429, 429, 46, 48, 44,
- 44, 44, 310, 306, 46, 44, 44, 44, 429, 48,
- 46, 429, 44, 44, 44, 48, 307, 46, 44, 44,
- 44, 429, 429, 46, 429, 48, 44, 44, 44, 429,
- 429, 46, 48, 429, 44, 44, 44, 429, 48, 46,
-
- 429, 44, 44, 44, 429, 48, 46, 44, 44, 44,
- 429, 48, 318, 429, 314, 311, 313, 312, 429, 48,
- 44, 44, 44, 429, 429, 319, 429, 48, 44, 44,
- 44, 429, 429, 320, 48, 429, 429, 429, 429, 315,
- 48, 317, 44, 44, 44, 429, 316, 46, 429, 44,
- 44, 44, 429, 48, 46, 44, 44, 44, 429, 429,
- 46, 48, 429, 44, 44, 44, 429, 429, 46, 429,
- 429, 44, 44, 44, 429, 48, 325, 429, 44, 44,
- 44, 429, 48, 46, 44, 44, 44, 429, 48, 46,
- 429, 321, 44, 44, 44, 323, 48, 46, 322, 429,
-
- 429, 429, 324, 429, 48, 429, 429, 429, 44, 44,
- 44, 48, 429, 46, 44, 44, 44, 48, 429, 46,
- 429, 44, 44, 44, 429, 48, 46, 429, 44, 44,
- 44, 429, 327, 46, 44, 44, 44, 326, 328, 46,
- 329, 48, 429, 44, 44, 44, 429, 48, 46, 429,
- 44, 44, 44, 429, 48, 46, 330, 332, 429, 429,
- 331, 48, 429, 429, 429, 429, 333, 48, 44, 44,
- 44, 429, 429, 46, 334, 429, 48, 44, 44, 44,
- 429, 429, 46, 48, 44, 44, 44, 429, 429, 46,
- 44, 44, 44, 429, 429, 46, 429, 429, 335, 429,
-
- 429, 48, 429, 336, 44, 44, 44, 429, 337, 46,
- 48, 44, 44, 44, 429, 429, 46, 48, 429, 429,
- 429, 339, 429, 48, 429, 429, 44, 44, 44, 340,
- 429, 343, 429, 44, 44, 44, 338, 48, 46, 429,
- 44, 44, 44, 429, 48, 46, 44, 44, 44, 429,
- 429, 46, 44, 44, 44, 429, 429, 347, 341, 48,
- 429, 429, 348, 429, 429, 342, 48, 44, 44, 44,
- 429, 429, 349, 48, 429, 44, 44, 44, 429, 48,
- 46, 429, 429, 344, 429, 48, 44, 44, 44, 429,
- 345, 46, 44, 44, 44, 429, 429, 46, 346, 429,
-
- 48, 44, 44, 44, 429, 429, 46, 429, 48, 429,
- 429, 350, 429, 44, 44, 44, 429, 429, 46, 48,
- 429, 44, 44, 44, 429, 48, 46, 429, 429, 429,
- 352, 44, 44, 44, 48, 429, 46, 44, 44, 44,
- 429, 429, 357, 429, 429, 351, 48, 44, 44, 44,
- 429, 429, 46, 354, 48, 353, 44, 44, 44, 429,
- 429, 46, 429, 355, 48, 429, 429, 356, 429, 429,
- 48, 44, 44, 44, 429, 429, 46, 44, 44, 44,
- 48, 429, 361, 44, 44, 44, 429, 429, 46, 48,
- 429, 358, 44, 44, 44, 429, 429, 46, 44, 44,
-
- 44, 429, 429, 364, 48, 359, 44, 44, 44, 429,
- 48, 365, 429, 44, 44, 44, 48, 360, 46, 44,
- 44, 44, 429, 429, 46, 48, 429, 429, 44, 44,
- 44, 48, 363, 46, 429, 362, 44, 44, 44, 48,
- 429, 46, 44, 44, 44, 429, 48, 46, 429, 44,
- 44, 44, 48, 429, 46, 44, 44, 44, 429, 429,
- 46, 48, 429, 44, 44, 44, 429, 366, 46, 48,
- 429, 429, 429, 367, 429, 48, 429, 369, 44, 44,
- 44, 368, 48, 374, 429, 44, 44, 44, 48, 370,
- 46, 429, 429, 429, 429, 429, 48, 429, 372, 371,
-
- 44, 44, 44, 373, 429, 46, 429, 44, 44, 44,
- 429, 48, 46, 429, 44, 44, 44, 429, 48, 46,
- 429, 429, 44, 44, 44, 375, 429, 379, 429, 44,
- 44, 44, 429, 48, 46, 429, 44, 44, 44, 429,
- 48, 46, 429, 44, 44, 44, 429, 48, 46, 429,
- 429, 429, 378, 429, 376, 48, 44, 44, 44, 377,
- 429, 46, 48, 429, 429, 380, 44, 44, 44, 48,
- 429, 384, 44, 44, 44, 429, 48, 46, 44, 44,
- 44, 429, 429, 46, 429, 429, 429, 382, 381, 48,
- 44, 44, 44, 429, 429, 46, 44, 44, 44, 48,
-
- 383, 46, 44, 44, 44, 48, 429, 46, 44, 44,
- 44, 48, 429, 46, 429, 429, 385, 429, 386, 44,
- 44, 44, 429, 48, 46, 429, 44, 44, 44, 48,
- 387, 46, 44, 44, 44, 48, 429, 46, 44, 44,
- 44, 48, 429, 46, 429, 388, 44, 44, 44, 429,
- 429, 46, 48, 44, 44, 44, 390, 429, 46, 48,
- 389, 429, 429, 391, 429, 48, 392, 44, 44, 44,
- 429, 48, 46, 44, 44, 44, 429, 393, 46, 48,
- 44, 44, 44, 429, 429, 399, 48, 44, 44, 44,
- 394, 429, 400, 44, 44, 44, 429, 429, 46, 395,
-
- 48, 429, 396, 44, 44, 44, 48, 429, 46, 44,
- 44, 44, 429, 48, 46, 429, 397, 429, 429, 398,
- 48, 429, 44, 44, 44, 429, 48, 46, 44, 44,
- 44, 429, 429, 46, 429, 429, 48, 429, 429, 44,
- 44, 44, 48, 429, 46, 401, 429, 44, 44, 44,
- 429, 429, 46, 429, 429, 48, 429, 402, 429, 429,
- 429, 48, 429, 403, 44, 44, 44, 405, 429, 408,
- 429, 404, 48, 44, 44, 44, 429, 429, 46, 406,
- 48, 44, 44, 44, 429, 429, 46, 44, 44, 44,
- 429, 407, 46, 44, 44, 44, 429, 48, 412, 44,
-
- 44, 44, 429, 429, 413, 429, 48, 44, 44, 44,
- 429, 429, 414, 429, 48, 429, 429, 44, 44, 44,
- 48, 409, 46, 44, 44, 44, 48, 411, 416, 410,
- 429, 429, 48, 44, 44, 44, 429, 429, 46, 429,
- 48, 44, 44, 44, 429, 429, 46, 44, 44, 44,
- 48, 429, 46, 44, 44, 44, 48, 429, 46, 44,
- 44, 44, 429, 429, 421, 415, 48, 429, 44, 44,
- 44, 429, 429, 422, 48, 429, 429, 44, 44, 44,
- 48, 418, 46, 44, 44, 44, 48, 417, 46, 44,
- 44, 44, 48, 429, 425, 429, 429, 429, 429, 429,
-
- 419, 48, 44, 44, 44, 429, 420, 426, 429, 429,
- 48, 429, 44, 44, 44, 429, 48, 427, 44, 44,
- 44, 429, 48, 428, 429, 429, 429, 429, 429, 429,
- 423, 429, 429, 429, 429, 48, 424, 429, 429, 429,
- 429, 429, 429, 429, 429, 48, 429, 429, 429, 429,
- 429, 48, 36, 36, 36, 45, 45, 45, 66, 429,
- 66, 87, 87, 87, 91, 91, 91, 121, 429, 121,
- 131, 131, 131, 11, 429, 429, 429, 429, 429, 429,
- 429, 429, 429, 429, 429, 429, 429, 429, 429, 429,
- 429, 429, 429, 429, 429, 429, 429, 429, 429, 429,
-
- 429, 429, 429, 429, 429, 429, 429, 429, 429, 429,
- 429, 429, 429, 429, 429, 429, 429, 429, 429, 429,
- 429, 429, 429, 429, 429, 429, 429, 429, 429, 429,
- 429, 429, 429, 429, 429, 429, 429
- } ;
-
-static const flex_int16_t yy_chk[2938] =
- { 0,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 3, 3, 3, 4, 4, 4, 3,
- 9, 7, 4, 5, 5, 8, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 10, 13, 27,
- 13, 21, 5, 5, 9, 5, 21, 433, 5, 25,
-
- 5, 25, 5, 241, 25, 25, 25, 25, 5, 5,
- 7, 10, 5, 27, 8, 17, 5, 17, 17, 17,
- 17, 19, 5, 19, 19, 19, 19, 26, 17, 5,
- 5, 15, 15, 15, 19, 28, 15, 31, 20, 20,
- 20, 20, 26, 37, 17, 37, 42, 32, 42, 20,
- 19, 33, 31, 22, 15, 22, 22, 22, 22, 28,
- 44, 206, 171, 131, 15, 20, 22, 15, 15, 15,
- 15, 32, 15, 77, 15, 33, 15, 15, 15, 15,
- 15, 15, 22, 15, 15, 15, 15, 15, 44, 45,
- 45, 45, 87, 77, 45, 47, 47, 47, 48, 78,
-
- 47, 79, 49, 49, 49, 48, 128, 49, 82, 80,
- 50, 50, 50, 81, 91, 50, 51, 51, 51, 78,
- 87, 51, 45, 85, 124, 79, 48, 84, 47, 80,
- 48, 43, 82, 81, 48, 49, 41, 52, 52, 52,
- 124, 48, 52, 50, 47, 48, 50, 48, 48, 51,
- 127, 52, 122, 53, 53, 53, 51, 49, 53, 54,
- 54, 54, 51, 165, 54, 51, 127, 55, 55, 55,
- 52, 123, 55, 56, 56, 56, 122, 52, 56, 165,
- 52, 52, 57, 57, 57, 39, 53, 57, 58, 58,
- 58, 123, 54, 58, 38, 125, 59, 59, 59, 53,
-
- 55, 59, 75, 75, 75, 75, 56, 55, 54, 60,
- 60, 60, 168, 54, 60, 57, 24, 56, 57, 125,
- 14, 58, 56, 126, 58, 61, 61, 61, 168, 59,
- 61, 62, 62, 62, 11, 0, 62, 0, 0, 63,
- 63, 63, 60, 126, 63, 60, 0, 0, 64, 64,
- 64, 59, 0, 64, 65, 65, 65, 0, 61, 65,
- 76, 76, 76, 76, 62, 61, 67, 67, 67, 67,
- 0, 62, 63, 92, 92, 92, 0, 67, 92, 0,
- 62, 64, 0, 71, 71, 71, 71, 65, 0, 0,
- 65, 63, 0, 67, 71, 0, 64, 0, 63, 0,
-
- 68, 64, 68, 68, 68, 68, 92, 0, 0, 69,
- 71, 69, 89, 68, 69, 69, 69, 69, 70, 89,
- 70, 70, 70, 70, 0, 90, 90, 90, 0, 68,
- 90, 70, 94, 94, 94, 0, 0, 94, 0, 0,
- 89, 0, 0, 0, 89, 0, 0, 70, 89, 0,
- 0, 0, 0, 0, 0, 89, 0, 0, 90, 89,
- 0, 89, 89, 0, 0, 94, 95, 95, 95, 0,
- 0, 95, 0, 90, 93, 0, 0, 0, 0, 0,
- 0, 0, 93, 93, 93, 93, 94, 0, 0, 0,
- 93, 93, 93, 93, 93, 96, 96, 96, 0, 95,
-
- 96, 0, 0, 0, 0, 93, 93, 93, 93, 93,
- 93, 97, 97, 97, 0, 0, 97, 0, 0, 95,
- 98, 98, 98, 0, 0, 98, 0, 0, 96, 99,
- 99, 99, 0, 0, 99, 0, 100, 100, 100, 0,
- 0, 100, 0, 0, 97, 0, 0, 96, 0, 101,
- 101, 101, 0, 98, 101, 97, 102, 102, 102, 0,
- 0, 102, 99, 0, 0, 0, 0, 98, 98, 100,
- 103, 103, 103, 100, 0, 103, 0, 0, 104, 104,
- 104, 0, 101, 104, 0, 0, 0, 101, 0, 102,
- 105, 105, 105, 0, 0, 105, 106, 106, 106, 0,
-
- 0, 106, 0, 103, 107, 107, 107, 0, 102, 107,
- 0, 104, 108, 108, 108, 0, 0, 108, 0, 109,
- 109, 109, 0, 105, 109, 103, 0, 104, 0, 106,
- 0, 110, 110, 110, 0, 0, 110, 107, 111, 111,
- 111, 107, 0, 111, 105, 108, 112, 112, 112, 0,
- 0, 112, 109, 0, 108, 106, 0, 113, 113, 113,
- 0, 0, 113, 0, 110, 0, 0, 0, 114, 114,
- 114, 111, 0, 114, 0, 0, 0, 109, 110, 112,
- 115, 115, 115, 0, 0, 115, 116, 116, 116, 0,
- 113, 116, 111, 113, 0, 0, 0, 0, 112, 112,
-
- 112, 114, 117, 117, 117, 0, 0, 117, 0, 118,
- 118, 118, 0, 115, 118, 119, 119, 119, 115, 116,
- 119, 120, 120, 120, 114, 0, 120, 130, 130, 130,
- 0, 0, 130, 0, 0, 117, 0, 0, 138, 138,
- 138, 116, 118, 138, 135, 135, 135, 0, 119, 135,
- 0, 0, 117, 118, 120, 119, 136, 136, 136, 0,
- 130, 136, 0, 137, 137, 137, 0, 120, 137, 0,
- 0, 138, 0, 0, 0, 0, 0, 135, 138, 0,
- 0, 130, 134, 134, 134, 134, 0, 135, 0, 136,
- 134, 134, 134, 134, 134, 0, 137, 139, 139, 139,
-
- 136, 0, 139, 0, 0, 134, 134, 134, 134, 134,
- 134, 0, 0, 140, 140, 140, 0, 137, 140, 142,
- 142, 142, 0, 0, 142, 0, 143, 143, 143, 0,
- 139, 143, 144, 144, 144, 0, 0, 144, 145, 145,
- 145, 0, 0, 145, 139, 0, 140, 0, 146, 146,
- 146, 0, 142, 146, 0, 147, 147, 147, 0, 143,
- 147, 149, 149, 149, 0, 144, 149, 140, 148, 148,
- 148, 145, 144, 148, 142, 0, 143, 0, 148, 0,
- 0, 146, 150, 150, 150, 0, 0, 150, 147, 0,
- 0, 145, 0, 146, 149, 151, 151, 151, 0, 0,
-
- 151, 148, 152, 152, 152, 147, 0, 152, 0, 0,
- 0, 0, 0, 149, 0, 150, 153, 153, 153, 0,
- 0, 153, 0, 0, 150, 154, 154, 154, 151, 0,
- 154, 155, 155, 155, 0, 152, 155, 0, 156, 156,
- 156, 0, 152, 156, 0, 157, 157, 157, 151, 153,
- 157, 151, 0, 0, 158, 158, 158, 0, 154, 158,
- 0, 154, 0, 0, 155, 0, 153, 159, 159, 159,
- 0, 156, 159, 0, 160, 160, 160, 0, 157, 160,
- 161, 161, 161, 0, 155, 161, 0, 158, 162, 162,
- 162, 157, 156, 162, 158, 0, 163, 163, 163, 0,
-
- 159, 163, 0, 164, 164, 164, 0, 160, 164, 172,
- 172, 172, 159, 161, 172, 0, 0, 174, 174, 174,
- 161, 162, 174, 176, 176, 176, 0, 160, 176, 163,
- 0, 0, 0, 176, 0, 0, 164, 0, 0, 0,
- 0, 0, 172, 0, 0, 0, 162, 0, 163, 0,
- 174, 0, 0, 0, 0, 0, 176, 174, 164, 0,
- 0, 172, 173, 173, 173, 173, 0, 0, 0, 0,
- 173, 173, 173, 173, 173, 175, 175, 175, 0, 0,
- 175, 0, 0, 0, 0, 173, 173, 173, 173, 173,
- 173, 177, 177, 177, 0, 0, 177, 178, 178, 178,
-
- 0, 0, 178, 0, 0, 179, 179, 179, 175, 0,
- 179, 0, 0, 175, 180, 180, 180, 0, 0, 180,
- 181, 181, 181, 0, 177, 181, 182, 182, 182, 0,
- 178, 182, 0, 0, 0, 181, 181, 178, 179, 177,
- 183, 183, 183, 0, 0, 183, 0, 180, 0, 184,
- 184, 184, 0, 181, 184, 0, 180, 179, 0, 182,
- 185, 185, 185, 0, 182, 185, 186, 186, 186, 0,
- 185, 186, 0, 183, 0, 187, 187, 187, 0, 0,
- 187, 0, 184, 183, 188, 188, 188, 0, 0, 188,
- 189, 189, 189, 185, 0, 189, 190, 190, 190, 186,
-
- 0, 190, 184, 0, 191, 191, 191, 186, 187, 191,
- 0, 187, 0, 192, 192, 192, 0, 188, 192, 0,
- 193, 193, 193, 189, 188, 193, 194, 194, 194, 190,
- 0, 194, 0, 0, 189, 0, 190, 191, 195, 195,
- 195, 0, 0, 195, 0, 0, 192, 196, 196, 196,
- 0, 0, 196, 193, 0, 197, 197, 197, 0, 194,
- 197, 0, 0, 0, 198, 198, 198, 193, 192, 198,
- 0, 195, 199, 199, 199, 0, 0, 199, 195, 0,
- 196, 0, 0, 194, 200, 200, 200, 0, 197, 200,
- 201, 201, 201, 0, 196, 201, 0, 198, 202, 202,
-
- 202, 0, 0, 202, 198, 199, 0, 197, 202, 203,
- 203, 203, 0, 0, 203, 0, 0, 200, 0, 207,
- 207, 207, 0, 201, 207, 0, 199, 209, 209, 209,
- 0, 202, 209, 210, 210, 210, 0, 0, 210, 0,
- 0, 0, 203, 213, 213, 213, 0, 0, 213, 203,
- 0, 0, 207, 0, 0, 0, 0, 211, 211, 211,
- 209, 0, 211, 0, 0, 0, 210, 0, 207, 208,
- 208, 208, 208, 0, 0, 209, 213, 208, 208, 208,
- 208, 208, 212, 212, 212, 0, 0, 212, 0, 0,
- 211, 213, 208, 208, 208, 208, 208, 208, 211, 214,
-
- 214, 214, 0, 0, 214, 215, 215, 215, 0, 211,
- 215, 216, 216, 216, 0, 212, 216, 217, 217, 217,
- 0, 0, 217, 218, 218, 218, 0, 0, 218, 219,
- 219, 219, 214, 0, 219, 0, 212, 0, 215, 0,
- 221, 221, 221, 0, 216, 221, 0, 0, 214, 0,
- 217, 215, 0, 220, 220, 220, 218, 0, 220, 222,
- 222, 222, 219, 220, 222, 223, 223, 223, 0, 0,
- 223, 0, 0, 221, 224, 224, 224, 218, 0, 224,
- 225, 225, 225, 221, 0, 225, 220, 0, 0, 0,
- 221, 0, 222, 0, 226, 226, 226, 0, 223, 226,
-
- 228, 228, 228, 222, 0, 228, 0, 224, 0, 229,
- 229, 229, 0, 225, 229, 0, 0, 223, 230, 230,
- 230, 0, 0, 230, 0, 0, 224, 226, 0, 231,
- 231, 231, 0, 228, 231, 0, 232, 232, 232, 0,
- 225, 232, 229, 233, 233, 233, 226, 0, 233, 229,
- 0, 230, 0, 0, 228, 234, 234, 234, 0, 0,
- 234, 0, 231, 235, 235, 235, 0, 230, 235, 232,
- 239, 239, 239, 235, 0, 239, 233, 240, 240, 240,
- 0, 231, 240, 0, 242, 242, 242, 233, 234, 242,
- 243, 243, 243, 0, 0, 243, 235, 0, 0, 245,
-
- 245, 245, 0, 239, 245, 0, 0, 0, 239, 234,
- 240, 239, 0, 246, 246, 246, 0, 242, 246, 247,
- 247, 247, 0, 243, 247, 0, 248, 248, 248, 0,
- 242, 248, 245, 249, 249, 249, 0, 0, 249, 0,
- 255, 255, 255, 245, 243, 255, 246, 0, 0, 250,
- 250, 250, 247, 246, 250, 253, 253, 253, 0, 248,
- 253, 0, 256, 256, 256, 0, 249, 256, 0, 0,
- 0, 0, 247, 255, 0, 0, 257, 257, 257, 249,
- 248, 257, 250, 0, 0, 0, 255, 0, 253, 250,
- 0, 258, 258, 258, 0, 256, 258, 0, 259, 259,
-
- 259, 0, 256, 259, 253, 260, 260, 260, 0, 257,
- 260, 256, 261, 261, 261, 0, 0, 261, 262, 262,
- 262, 0, 0, 262, 258, 257, 0, 264, 264, 264,
- 0, 259, 264, 0, 263, 263, 263, 258, 260, 263,
- 0, 265, 265, 265, 263, 261, 265, 0, 0, 0,
- 0, 262, 261, 0, 266, 266, 266, 259, 260, 266,
- 264, 268, 268, 268, 0, 0, 268, 263, 0, 263,
- 269, 269, 269, 0, 265, 269, 0, 270, 270, 270,
- 269, 264, 270, 271, 271, 271, 0, 266, 271, 0,
- 272, 272, 272, 265, 268, 272, 275, 275, 275, 0,
-
- 0, 275, 266, 269, 0, 0, 275, 276, 276, 276,
- 270, 0, 276, 270, 0, 268, 271, 277, 277, 277,
- 0, 0, 277, 272, 0, 278, 278, 278, 0, 275,
- 278, 0, 271, 0, 272, 0, 279, 279, 279, 0,
- 276, 279, 280, 280, 280, 0, 0, 280, 0, 0,
- 277, 276, 281, 281, 281, 0, 0, 281, 278, 282,
- 282, 282, 281, 277, 282, 283, 283, 283, 0, 279,
- 283, 0, 284, 284, 284, 280, 278, 284, 285, 285,
- 285, 0, 0, 285, 0, 281, 286, 286, 286, 0,
- 0, 286, 282, 0, 287, 287, 287, 0, 283, 287,
-
- 0, 288, 288, 288, 0, 284, 288, 289, 289, 289,
- 0, 285, 289, 0, 285, 282, 284, 283, 0, 286,
- 290, 290, 290, 0, 0, 290, 0, 287, 291, 291,
- 291, 0, 0, 291, 288, 0, 0, 0, 0, 286,
- 289, 288, 294, 294, 294, 0, 287, 294, 0, 295,
- 295, 295, 0, 290, 295, 296, 296, 296, 0, 0,
- 296, 291, 0, 297, 297, 297, 0, 0, 297, 0,
- 0, 298, 298, 298, 0, 294, 298, 0, 299, 299,
- 299, 0, 295, 299, 300, 300, 300, 0, 296, 300,
- 0, 294, 301, 301, 301, 296, 297, 301, 295, 0,
-
- 0, 0, 297, 0, 298, 0, 0, 0, 302, 302,
- 302, 299, 0, 302, 303, 303, 303, 300, 0, 303,
- 0, 304, 304, 304, 0, 301, 304, 0, 305, 305,
- 305, 0, 300, 305, 306, 306, 306, 299, 300, 306,
- 301, 302, 0, 307, 307, 307, 0, 303, 307, 0,
- 310, 310, 310, 0, 304, 310, 302, 304, 0, 0,
- 303, 305, 0, 0, 0, 0, 305, 306, 311, 311,
- 311, 0, 0, 311, 306, 0, 307, 312, 312, 312,
- 0, 0, 312, 310, 313, 313, 313, 0, 0, 313,
- 314, 314, 314, 0, 0, 314, 0, 0, 307, 0,
-
- 0, 311, 0, 310, 315, 315, 315, 0, 311, 315,
- 312, 316, 316, 316, 0, 0, 316, 313, 0, 0,
- 0, 313, 0, 314, 0, 0, 317, 317, 317, 314,
- 0, 317, 0, 321, 321, 321, 312, 315, 321, 0,
- 322, 322, 322, 0, 316, 322, 323, 323, 323, 0,
- 0, 323, 324, 324, 324, 0, 0, 324, 315, 317,
- 0, 0, 324, 0, 0, 316, 321, 326, 326, 326,
- 0, 0, 326, 322, 0, 327, 327, 327, 0, 323,
- 327, 0, 0, 321, 0, 324, 328, 328, 328, 0,
- 322, 328, 329, 329, 329, 0, 0, 329, 323, 0,
-
- 326, 330, 330, 330, 0, 0, 330, 0, 327, 0,
- 0, 327, 0, 331, 331, 331, 0, 0, 331, 328,
- 0, 332, 332, 332, 0, 329, 332, 0, 0, 0,
- 329, 333, 333, 333, 330, 0, 333, 334, 334, 334,
- 0, 0, 334, 0, 0, 328, 331, 335, 335, 335,
- 0, 0, 335, 331, 332, 330, 336, 336, 336, 0,
- 0, 336, 0, 332, 333, 0, 0, 333, 0, 0,
- 334, 337, 337, 337, 0, 0, 337, 338, 338, 338,
- 335, 0, 338, 339, 339, 339, 0, 0, 339, 336,
- 0, 335, 340, 340, 340, 0, 0, 340, 341, 341,
-
- 341, 0, 0, 341, 337, 336, 342, 342, 342, 0,
- 338, 342, 0, 344, 344, 344, 339, 337, 344, 345,
- 345, 345, 0, 0, 345, 340, 0, 0, 346, 346,
- 346, 341, 340, 346, 0, 339, 348, 348, 348, 342,
- 0, 348, 350, 350, 350, 0, 344, 350, 0, 351,
- 351, 351, 345, 0, 351, 352, 352, 352, 0, 0,
- 352, 346, 0, 353, 353, 353, 0, 344, 353, 348,
- 0, 0, 0, 345, 0, 350, 0, 348, 354, 354,
- 354, 346, 351, 354, 0, 355, 355, 355, 352, 350,
- 355, 0, 0, 0, 0, 0, 353, 0, 352, 351,
-
- 356, 356, 356, 353, 0, 356, 0, 358, 358, 358,
- 0, 354, 358, 0, 359, 359, 359, 0, 355, 359,
- 0, 0, 360, 360, 360, 355, 0, 360, 0, 362,
- 362, 362, 0, 356, 362, 0, 363, 363, 363, 0,
- 358, 363, 0, 366, 366, 366, 0, 359, 366, 0,
- 0, 0, 359, 0, 356, 360, 367, 367, 367, 358,
- 0, 367, 362, 0, 0, 362, 368, 368, 368, 363,
- 0, 368, 369, 369, 369, 0, 366, 369, 370, 370,
- 370, 0, 0, 370, 0, 0, 0, 366, 363, 367,
- 371, 371, 371, 0, 0, 371, 372, 372, 372, 368,
-
- 367, 372, 373, 373, 373, 369, 0, 373, 375, 375,
- 375, 370, 0, 375, 0, 0, 369, 0, 370, 376,
- 376, 376, 0, 371, 376, 0, 377, 377, 377, 372,
- 371, 377, 378, 378, 378, 373, 0, 378, 380, 380,
- 380, 375, 0, 380, 0, 372, 381, 381, 381, 0,
- 0, 381, 376, 382, 382, 382, 375, 0, 382, 377,
- 373, 0, 0, 376, 0, 378, 377, 383, 383, 383,
- 0, 380, 383, 385, 385, 385, 0, 378, 385, 381,
- 386, 386, 386, 0, 0, 386, 382, 387, 387, 387,
- 380, 0, 387, 388, 388, 388, 0, 0, 388, 381,
-
- 383, 0, 382, 389, 389, 389, 385, 0, 389, 390,
- 390, 390, 0, 386, 390, 0, 383, 0, 0, 385,
- 387, 0, 391, 391, 391, 0, 388, 391, 392, 392,
- 392, 0, 0, 392, 0, 0, 389, 0, 0, 393,
- 393, 393, 390, 0, 393, 388, 0, 394, 394, 394,
- 0, 0, 394, 0, 0, 391, 0, 389, 0, 0,
- 0, 392, 0, 390, 395, 395, 395, 392, 0, 395,
- 0, 391, 393, 396, 396, 396, 0, 0, 396, 393,
- 394, 397, 397, 397, 0, 0, 397, 398, 398, 398,
- 0, 394, 398, 401, 401, 401, 0, 395, 401, 402,
-
- 402, 402, 0, 0, 402, 0, 396, 403, 403, 403,
- 0, 0, 403, 0, 397, 0, 0, 404, 404, 404,
- 398, 396, 404, 405, 405, 405, 401, 398, 405, 397,
- 0, 0, 402, 406, 406, 406, 0, 0, 406, 0,
- 403, 407, 407, 407, 0, 0, 407, 409, 409, 409,
- 404, 0, 409, 410, 410, 410, 405, 0, 410, 411,
- 411, 411, 0, 0, 411, 404, 406, 0, 415, 415,
- 415, 0, 0, 415, 407, 0, 0, 417, 417, 417,
- 409, 407, 417, 418, 418, 418, 410, 406, 418, 419,
- 419, 419, 411, 0, 419, 0, 0, 0, 0, 0,
-
- 409, 415, 420, 420, 420, 0, 410, 420, 0, 0,
- 417, 0, 423, 423, 423, 0, 418, 423, 424, 424,
- 424, 0, 419, 424, 0, 0, 0, 0, 0, 0,
- 417, 0, 0, 0, 0, 420, 418, 0, 0, 0,
- 0, 0, 0, 0, 0, 423, 0, 0, 0, 0,
- 0, 424, 430, 430, 430, 431, 431, 431, 432, 0,
- 432, 434, 434, 434, 435, 435, 435, 436, 0, 436,
- 437, 437, 437, 429, 429, 429, 429, 429, 429, 429,
- 429, 429, 429, 429, 429, 429, 429, 429, 429, 429,
- 429, 429, 429, 429, 429, 429, 429, 429, 429, 429,
-
- 429, 429, 429, 429, 429, 429, 429, 429, 429, 429,
- 429, 429, 429, 429, 429, 429, 429, 429, 429, 429,
- 429, 429, 429, 429, 429, 429, 429, 429, 429, 429,
- 429, 429, 429, 429, 429, 429, 429
- } ;
-
-static yy_state_type yy_last_accepting_state;
-static char *yy_last_accepting_cpos;
-
-extern int yy_flex_debug;
-int yy_flex_debug = 1;
-
-static const flex_int16_t yy_rule_linenum[73] =
- { 0,
- 135, 137, 139, 144, 145, 150, 151, 152, 164, 167,
- 172, 179, 188, 197, 206, 215, 229, 243, 253, 262,
- 271, 280, 289, 298, 307, 316, 325, 334, 343, 352,
- 361, 370, 379, 388, 397, 406, 415, 424, 433, 442,
- 451, 460, 469, 478, 487, 496, 505, 514, 523, 532,
- 541, 550, 559, 568, 669, 685, 734, 742, 757, 758,
- 759, 760, 761, 762, 764, 782, 795, 800, 804, 806,
- 808, 810
- } ;
-
-/* The intent behind this definition is that it'll catch
- * any uses of REJECT which flex missed.
- */
-#define REJECT reject_used_but_not_detected
-#define yymore() yymore_used_but_not_detected
-#define YY_MORE_ADJ 0
-#define YY_RESTORE_YY_MORE_OFFSET
-char *yytext;
-#line 1 "agent_lexer.ll"
-/* Copyright (C) 2017-2025 Internet Systems Consortium, Inc. ("ISC")
-
- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-#line 8 "agent_lexer.ll"
-
-/* Generated files do not make clang static analyser so happy */
-#ifndef __clang_analyzer__
-
-#include <cctype>
-#include <cerrno>
-#include <climits>
-#include <cstdint>
-#include <cstdlib>
-#include <string>
-#include <agent/parser_context.h>
-#include <asiolink/io_address.h>
-#include <boost/lexical_cast.hpp>
-#include <exceptions/exceptions.h>
-#include <cc/dhcp_config_error.h>
-
-/* Please avoid C++ style comments (// ... eol) as they break flex 2.6.2 */
-
-/* Work around an incompatibility in flex (at least versions
- 2.5.31 through 2.5.33): it generates code that does
- not conform to C89. See Debian bug 333231
- <http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=333231>. */
-# undef yywrap
-# define yywrap() 1
-
-namespace {
-
-bool start_token_flag = false;
-
-isc::agent::ParserContext::ParserType start_token_value;
-unsigned int comment_start_line = 0;
-
-using namespace isc;
-using isc::agent::AgentParser;
-
-};
-
-/* To avoid the call to exit... oops! */
-#define YY_FATAL_ERROR(msg) isc::agent::ParserContext::fatal(msg)
-#line 1627 "agent_lexer.cc"
-/* noyywrap disables automatic rewinding for the next file to parse. Since we
- always parse only a single string, there's no need to do any wraps. And
- using yywrap requires linking with -lfl, which provides the default yywrap
- implementation that always returns 1 anyway. */
-/* nounput simplifies the lexer, by removing support for putting a character
- back into the input stream. We never use such capability anyway. */
-/* batch means that we'll never use the generated lexer interactively. */
-/* avoid to get static global variables to remain with C++. */
-/* in last resort %option reentrant */
-/* Enables debug mode. To see the debug messages, one needs to also set
- yy_flex_debug to 1, then the debug messages will be printed on stderr. */
-/* I have no idea what this option does, except it was specified in the bison
- examples and Postgres folks added it to remove gcc 4.3 warnings. Let's
- be on the safe side and keep it. */
-#define YY_NO_INPUT 1
-
-/* These are not token expressions yet, just convenience expressions that
- can be used during actual token definitions. Note some can match
- incorrect inputs (e.g., IP addresses) which must be checked. */
-/* for errors */
-#line 98 "agent_lexer.ll"
-/* This code run each time a pattern is matched. It updates the location
- by moving it ahead by yyleng bytes. yyleng specifies the length of the
- currently matched token. */
-#define YY_USER_ACTION driver.loc_.columns(yyleng);
-#line 1653 "agent_lexer.cc"
-#line 1654 "agent_lexer.cc"
-
-#define INITIAL 0
-#define COMMENT 1
-#define DIR_ENTER 2
-#define DIR_INCLUDE 3
-#define DIR_EXIT 4
-
-#ifndef YY_NO_UNISTD_H
-/* Special case for "unistd.h", since it is non-ANSI. We include it way
- * down here because we want the user's section 1 to have been scanned first.
- * The user has a chance to override it with an option.
- */
-/* %if-c-only */
-#include <unistd.h>
-/* %endif */
-/* %if-c++-only */
-/* %endif */
-#endif
-
-#ifndef YY_EXTRA_TYPE
-#define YY_EXTRA_TYPE void *
-#endif
-
-/* %if-c-only Reentrant structure and macros (non-C++). */
-/* %if-reentrant */
-/* %if-c-only */
-
-static int yy_init_globals ( void );
-
-/* %endif */
-/* %if-reentrant */
-/* %endif */
-/* %endif End reentrant structures and macros. */
-
-/* Accessor methods to globals.
- These are made visible to non-reentrant scanners for convenience. */
-
-int yylex_destroy ( void );
-
-int yyget_debug ( void );
-
-void yyset_debug ( int debug_flag );
-
-YY_EXTRA_TYPE yyget_extra ( void );
-
-void yyset_extra ( YY_EXTRA_TYPE user_defined );
-
-FILE *yyget_in ( void );
-
-void yyset_in ( FILE * _in_str );
-
-FILE *yyget_out ( void );
-
-void yyset_out ( FILE * _out_str );
-
- int yyget_leng ( void );
-
-char *yyget_text ( void );
-
-int yyget_lineno ( void );
-
-void yyset_lineno ( int _line_number );
-
-/* %if-bison-bridge */
-/* %endif */
-
-/* Macros after this point can all be overridden by user definitions in
- * section 1.
- */
-
-#ifndef YY_SKIP_YYWRAP
-#ifdef __cplusplus
-extern "C" int yywrap ( void );
-#else
-extern int yywrap ( void );
-#endif
-#endif
-
-/* %not-for-header */
-#ifndef YY_NO_UNPUT
-
-#endif
-/* %ok-for-header */
-
-/* %endif */
-
-#ifndef yytext_ptr
-static void yy_flex_strncpy ( char *, const char *, int );
-#endif
-
-#ifdef YY_NEED_STRLEN
-static int yy_flex_strlen ( const char * );
-#endif
-
-#ifndef YY_NO_INPUT
-/* %if-c-only Standard (non-C++) definition */
-/* %not-for-header */
-#ifdef __cplusplus
-static int yyinput ( void );
-#else
-static int input ( void );
-#endif
-/* %ok-for-header */
-
-/* %endif */
-#endif
-
-/* %if-c-only */
-
-/* %endif */
-
-/* Amount of stuff to slurp up with each read. */
-#ifndef YY_READ_BUF_SIZE
-#ifdef __ia64__
-/* On IA-64, the buffer size is 16k, not 8k */
-#define YY_READ_BUF_SIZE 16384
-#else
-#define YY_READ_BUF_SIZE 8192
-#endif /* __ia64__ */
-#endif
-
-/* Copy whatever the last rule matched to the standard output. */
-#ifndef ECHO
-/* %if-c-only Standard (non-C++) definition */
-/* This used to be an fputs(), but since the string might contain NUL's,
- * we now use fwrite().
- */
-#define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0)
-/* %endif */
-/* %if-c++-only C++ definition */
-/* %endif */
-#endif
-
-/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
- * is returned in "result".
- */
-#ifndef YY_INPUT
-#define YY_INPUT(buf,result,max_size) \
-/* %% [5.0] fread()/read() definition of YY_INPUT goes here unless we're doing C++ \ */\
- if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
- { \
- int c = '*'; \
- int n; \
- for ( n = 0; n < max_size && \
- (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
- buf[n] = (char) c; \
- if ( c == '\n' ) \
- buf[n++] = (char) c; \
- if ( c == EOF && ferror( yyin ) ) \
- YY_FATAL_ERROR( "input in flex scanner failed" ); \
- result = n; \
- } \
- else \
- { \
- errno=0; \
- while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \
- { \
- if( errno != EINTR) \
- { \
- YY_FATAL_ERROR( "input in flex scanner failed" ); \
- break; \
- } \
- errno=0; \
- clearerr(yyin); \
- } \
- }\
-\
-/* %if-c++-only C++ definition \ */\
-/* %endif */
-
-#endif
-
-/* No semi-colon after return; correct usage is to write "yyterminate();" -
- * we don't want an extra ';' after the "return" because that will cause
- * some compilers to complain about unreachable statements.
- */
-#ifndef yyterminate
-#define yyterminate() return YY_NULL
-#endif
-
-/* Number of entries by which start-condition stack grows. */
-#ifndef YY_START_STACK_INCR
-#define YY_START_STACK_INCR 25
-#endif
-
-/* Report a fatal error. */
-#ifndef YY_FATAL_ERROR
-/* %if-c-only */
-#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
-/* %endif */
-/* %if-c++-only */
-/* %endif */
-#endif
-
-/* %if-tables-serialization structures and prototypes */
-/* %not-for-header */
-/* %ok-for-header */
-
-/* %not-for-header */
-/* %tables-yydmap generated elements */
-/* %endif */
-/* end tables serialization structures and prototypes */
-
-/* %ok-for-header */
-
-/* Default declaration of generated scanner - a define so the user can
- * easily add parameters.
- */
-#ifndef YY_DECL
-#define YY_DECL_IS_OURS 1
-/* %if-c-only Standard (non-C++) definition */
-
-extern int yylex (void);
-
-#define YY_DECL int yylex (void)
-/* %endif */
-/* %if-c++-only C++ definition */
-/* %endif */
-#endif /* !YY_DECL */
-
-/* Code executed at the beginning of each rule, after yytext and yyleng
- * have been set up.
- */
-#ifndef YY_USER_ACTION
-#define YY_USER_ACTION
-#endif
-
-/* Code executed at the end of each rule. */
-#ifndef YY_BREAK
-#define YY_BREAK /*LINTED*/break;
-#endif
-
-/* %% [6.0] YY_RULE_SETUP definition goes here */
-#define YY_RULE_SETUP \
- YY_USER_ACTION
-
-/* %not-for-header */
-/** The main scanner function which does all the work.
- */
-YY_DECL
-{
- yy_state_type yy_current_state;
- char *yy_cp, *yy_bp;
- int yy_act;
-
- if ( !(yy_init) )
- {
- (yy_init) = 1;
-
-#ifdef YY_USER_INIT
- YY_USER_INIT;
-#endif
-
- if ( ! (yy_start) )
- (yy_start) = 1; /* first start state */
-
- if ( ! yyin )
-/* %if-c-only */
- yyin = stdin;
-/* %endif */
-/* %if-c++-only */
-/* %endif */
-
- if ( ! yyout )
-/* %if-c-only */
- yyout = stdout;
-/* %endif */
-/* %if-c++-only */
-/* %endif */
-
- if ( ! YY_CURRENT_BUFFER ) {
- yyensure_buffer_stack ();
- YY_CURRENT_BUFFER_LVALUE =
- yy_create_buffer( yyin, YY_BUF_SIZE );
- }
-
- yy_load_buffer_state( );
- }
-
- {
-/* %% [7.0] user's declarations go here */
-#line 104 "agent_lexer.ll"
-
-
-
-#line 108 "agent_lexer.ll"
- /* This part of the code is copied over to the verbatim to the top
- of the generated yylex function. Explanation:
- http://www.gnu.org/software/bison/manual/html_node/Multiple-start_002dsymbols.html */
-
- /* Code run each time yylex is called. */
- driver.loc_.step();
-
- /* We currently have 3 points of entries defined:
- START_JSON - which expects any valid JSON
- START_AGENT - which expects full configuration (with outer map and Control-agent
- object in it.
- START_SUB_AGENT - which expects only content of the Control-agent, this is
- primarily useful for testing. */
- if (start_token_flag) {
- start_token_flag = false;
- switch (start_token_value) {
- case ParserContext::PARSER_JSON:
- default:
- return isc::agent::AgentParser::make_START_JSON(driver.loc_);
- case ParserContext::PARSER_AGENT:
- return isc::agent::AgentParser::make_START_AGENT(driver.loc_);
- case ParserContext::PARSER_SUB_AGENT:
- return isc::agent::AgentParser::make_START_SUB_AGENT(driver.loc_);
- }
- }
-
-
-#line 1968 "agent_lexer.cc"
-
- while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */
- {
-/* %% [8.0] yymore()-related code goes here */
- yy_cp = (yy_c_buf_p);
-
- /* Support of yytext. */
- *yy_cp = (yy_hold_char);
-
- /* yy_bp points to the position in yy_ch_buf of the start of
- * the current run.
- */
- yy_bp = yy_cp;
-
-/* %% [9.0] code to set up and find next match goes here */
- yy_current_state = (yy_start);
-yy_match:
- do
- {
- YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ;
- if ( yy_accept[yy_current_state] )
- {
- (yy_last_accepting_state) = yy_current_state;
- (yy_last_accepting_cpos) = yy_cp;
- }
- while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
- {
- yy_current_state = (int) yy_def[yy_current_state];
- if ( yy_current_state >= 430 )
- yy_c = yy_meta[yy_c];
- }
- yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
- ++yy_cp;
- }
- while ( yy_current_state != 429 );
- yy_cp = (yy_last_accepting_cpos);
- yy_current_state = (yy_last_accepting_state);
-
-yy_find_action:
-/* %% [10.0] code to find the action number goes here */
- yy_act = yy_accept[yy_current_state];
-
- YY_DO_BEFORE_ACTION;
-
-/* %% [11.0] code for yylineno update goes here */
-
-do_action: /* This label is used only to access EOF actions. */
-
-/* %% [12.0] debug code goes here */
- if ( yy_flex_debug )
- {
- if ( yy_act == 0 )
- fprintf( stderr, "--scanner backing up\n" );
- else if ( yy_act < 73 )
- fprintf( stderr, "--accepting rule at line %ld (\"%s\")\n",
- (long)yy_rule_linenum[yy_act], yytext );
- else if ( yy_act == 73 )
- fprintf( stderr, "--accepting default rule (\"%s\")\n",
- yytext );
- else if ( yy_act == 74 )
- fprintf( stderr, "--(end of buffer or a NUL)\n" );
- else
- fprintf( stderr, "--EOF (start condition %d)\n", YY_START );
- }
-
- switch ( yy_act )
- { /* beginning of action switch */
-/* %% [13.0] actions go here */
- case 0: /* must back up */
- /* undo the effects of YY_DO_BEFORE_ACTION */
- *yy_cp = (yy_hold_char);
- yy_cp = (yy_last_accepting_cpos);
- yy_current_state = (yy_last_accepting_state);
- goto yy_find_action;
-
-case 1:
-YY_RULE_SETUP
-#line 135 "agent_lexer.ll"
-;
- YY_BREAK
-case 2:
-YY_RULE_SETUP
-#line 137 "agent_lexer.ll"
-;
- YY_BREAK
-case 3:
-YY_RULE_SETUP
-#line 139 "agent_lexer.ll"
-{
- BEGIN(COMMENT);
- comment_start_line = driver.loc_.end.line;;
-}
- YY_BREAK
-case 4:
-YY_RULE_SETUP
-#line 144 "agent_lexer.ll"
-BEGIN(INITIAL);
- YY_BREAK
-case 5:
-YY_RULE_SETUP
-#line 145 "agent_lexer.ll"
-;
- YY_BREAK
-case YY_STATE_EOF(COMMENT):
-#line 146 "agent_lexer.ll"
-{
- isc_throw(ParseError, "Comment not closed. (/* in line " << comment_start_line);
-}
- YY_BREAK
-case 6:
-YY_RULE_SETUP
-#line 150 "agent_lexer.ll"
-BEGIN(DIR_ENTER);
- YY_BREAK
-case 7:
-YY_RULE_SETUP
-#line 151 "agent_lexer.ll"
-BEGIN(DIR_INCLUDE);
- YY_BREAK
-case 8:
-YY_RULE_SETUP
-#line 152 "agent_lexer.ll"
-{
- /* Include directive. */
-
- /* Extract the filename. */
- std::string tmp(yytext+1);
- tmp.resize(tmp.size() - 1);
-
- driver.includeFile(tmp);
-}
- YY_BREAK
-case YY_STATE_EOF(DIR_ENTER):
-case YY_STATE_EOF(DIR_INCLUDE):
-case YY_STATE_EOF(DIR_EXIT):
-#line 161 "agent_lexer.ll"
-{
- isc_throw(ParseError, "Directive not closed.");
-}
- YY_BREAK
-case 9:
-YY_RULE_SETUP
-#line 164 "agent_lexer.ll"
-BEGIN(INITIAL);
- YY_BREAK
-case 10:
-YY_RULE_SETUP
-#line 167 "agent_lexer.ll"
-{
- /* Ok, we found a with space. Let's ignore it and update loc variable. */
- driver.loc_.step();
-}
- YY_BREAK
-case 11:
-/* rule 11 can match eol */
-YY_RULE_SETUP
-#line 172 "agent_lexer.ll"
-{
- /* Newline found. Let's update the location and continue. */
- driver.loc_.lines(yyleng);
- driver.loc_.step();
-}
- YY_BREAK
-case 12:
-YY_RULE_SETUP
-#line 179 "agent_lexer.ll"
-{
- switch(driver.ctx_) {
- case ParserContext::CONFIG:
- return AgentParser::make_CONTROL_AGENT(driver.loc_);
- default:
- return AgentParser::make_STRING("Control-agent", driver.loc_);
- }
-}
- YY_BREAK
-case 13:
-YY_RULE_SETUP
-#line 188 "agent_lexer.ll"
-{
- switch(driver.ctx_) {
- case ParserContext::AGENT:
- return AgentParser::make_HTTP_HOST(driver.loc_);
- default:
- return AgentParser::make_STRING("http-host", driver.loc_);
- }
-}
- YY_BREAK
-case 14:
-YY_RULE_SETUP
-#line 197 "agent_lexer.ll"
-{
- switch(driver.ctx_) {
- case ParserContext::AGENT:
- return AgentParser::make_HTTP_PORT(driver.loc_);
- default:
- return AgentParser::make_STRING("http-port", driver.loc_);
- }
-}
- YY_BREAK
-case 15:
-YY_RULE_SETUP
-#line 206 "agent_lexer.ll"
-{
- switch(driver.ctx_) {
- case ParserContext::AGENT:
- return AgentParser::make_HTTP_HEADERS(driver.loc_);
- default:
- return AgentParser::make_STRING("http-headers", driver.loc_);
- }
-}
- YY_BREAK
-case 16:
-YY_RULE_SETUP
-#line 215 "agent_lexer.ll"
-{
- switch(driver.ctx_) {
- case ParserContext::AGENT:
- case ParserContext::HTTP_HEADERS:
- case ParserContext::AUTHENTICATION:
- case ParserContext::CLIENTS:
- case ParserContext::SERVER:
- case ParserContext::LOGGERS:
- return AgentParser::make_USER_CONTEXT(driver.loc_);
- default:
- return AgentParser::make_STRING("user-context", driver.loc_);
- }
-}
- YY_BREAK
-case 17:
-YY_RULE_SETUP
-#line 229 "agent_lexer.ll"
-{
- switch(driver.ctx_) {
- case ParserContext::AGENT:
- case ParserContext::HTTP_HEADERS:
- case ParserContext::AUTHENTICATION:
- case ParserContext::CLIENTS:
- case ParserContext::SERVER:
- case ParserContext::LOGGERS:
- return AgentParser::make_COMMENT(driver.loc_);
- default:
- return AgentParser::make_STRING("comment", driver.loc_);
- }
-}
- YY_BREAK
-case 18:
-YY_RULE_SETUP
-#line 243 "agent_lexer.ll"
-{
- switch(driver.ctx_) {
- case ParserContext::LOGGERS:
- case ParserContext::HTTP_HEADERS:
- return AgentParser::make_NAME(driver.loc_);
- default:
- return AgentParser::make_STRING("name", driver.loc_);
- }
-}
- YY_BREAK
-case 19:
-YY_RULE_SETUP
-#line 253 "agent_lexer.ll"
-{
- switch(driver.ctx_) {
- case ParserContext::HTTP_HEADERS:
- return AgentParser::make_VALUE(driver.loc_);
- default:
- return AgentParser::make_STRING("value", driver.loc_);
- }
-}
- YY_BREAK
-case 20:
-YY_RULE_SETUP
-#line 262 "agent_lexer.ll"
-{
- switch(driver.ctx_) {
- case ParserContext::AGENT:
- return AgentParser::make_AUTHENTICATION(driver.loc_);
- default:
- return AgentParser::make_STRING("authentication", driver.loc_);
- }
-}
- YY_BREAK
-case 21:
-YY_RULE_SETUP
-#line 271 "agent_lexer.ll"
-{
- switch(driver.ctx_) {
- case ParserContext::AUTHENTICATION:
- return AgentParser::make_TYPE(driver.loc_);
- default:
- return AgentParser::make_STRING("type", driver.loc_);
- }
-}
- YY_BREAK
-case 22:
-YY_RULE_SETUP
-#line 280 "agent_lexer.ll"
-{
- switch(driver.ctx_) {
- case ParserContext::AUTH_TYPE:
- return AgentParser::make_BASIC(driver.loc_);
- default:
- return AgentParser::make_STRING("basic", driver.loc_);
- }
-}
- YY_BREAK
-case 23:
-YY_RULE_SETUP
-#line 289 "agent_lexer.ll"
-{
- switch(driver.ctx_) {
- case ParserContext::AUTHENTICATION:
- return AgentParser::make_REALM(driver.loc_);
- default:
- return AgentParser::make_STRING("realm", driver.loc_);
- }
-}
- YY_BREAK
-case 24:
-YY_RULE_SETUP
-#line 298 "agent_lexer.ll"
-{
- switch(driver.ctx_) {
- case ParserContext::AUTHENTICATION:
- return AgentParser::make_DIRECTORY(driver.loc_);
- default:
- return AgentParser::make_STRING("directory", driver.loc_);
- }
-}
- YY_BREAK
-case 25:
-YY_RULE_SETUP
-#line 307 "agent_lexer.ll"
-{
- switch(driver.ctx_) {
- case ParserContext::AUTHENTICATION:
- return AgentParser::make_CLIENTS(driver.loc_);
- default:
- return AgentParser::make_STRING("clients", driver.loc_);
- }
-}
- YY_BREAK
-case 26:
-YY_RULE_SETUP
-#line 316 "agent_lexer.ll"
-{
- switch(driver.ctx_) {
- case ParserContext::CLIENTS:
- return AgentParser::make_USER(driver.loc_);
- default:
- return AgentParser::make_STRING("user", driver.loc_);
- }
-}
- YY_BREAK
-case 27:
-YY_RULE_SETUP
-#line 325 "agent_lexer.ll"
-{
- switch(driver.ctx_) {
- case ParserContext::CLIENTS:
- return AgentParser::make_USER_FILE(driver.loc_);
- default:
- return AgentParser::make_STRING("user-file", driver.loc_);
- }
-}
- YY_BREAK
-case 28:
-YY_RULE_SETUP
-#line 334 "agent_lexer.ll"
-{
- switch(driver.ctx_) {
- case ParserContext::CLIENTS:
- return AgentParser::make_PASSWORD(driver.loc_);
- default:
- return AgentParser::make_STRING("password", driver.loc_);
- }
-}
- YY_BREAK
-case 29:
-YY_RULE_SETUP
-#line 343 "agent_lexer.ll"
-{
- switch(driver.ctx_) {
- case ParserContext::CLIENTS:
- return AgentParser::make_PASSWORD_FILE(driver.loc_);
- default:
- return AgentParser::make_STRING("password-file", driver.loc_);
- }
-}
- YY_BREAK
-case 30:
-YY_RULE_SETUP
-#line 352 "agent_lexer.ll"
-{
- switch(driver.ctx_) {
- case ParserContext::AGENT:
- return AgentParser::make_TRUST_ANCHOR(driver.loc_);
- default:
- return AgentParser::make_STRING("trust-anchor", driver.loc_);
- }
-}
- YY_BREAK
-case 31:
-YY_RULE_SETUP
-#line 361 "agent_lexer.ll"
-{
- switch(driver.ctx_) {
- case ParserContext::AGENT:
- return AgentParser::make_CERT_FILE(driver.loc_);
- default:
- return AgentParser::make_STRING("cert-file", driver.loc_);
- }
-}
- YY_BREAK
-case 32:
-YY_RULE_SETUP
-#line 370 "agent_lexer.ll"
-{
- switch(driver.ctx_) {
- case ParserContext::AGENT:
- return AgentParser::make_KEY_FILE(driver.loc_);
- default:
- return AgentParser::make_STRING("key-file", driver.loc_);
- }
-}
- YY_BREAK
-case 33:
-YY_RULE_SETUP
-#line 379 "agent_lexer.ll"
-{
- switch(driver.ctx_) {
- case ParserContext::AGENT:
- return AgentParser::make_CERT_REQUIRED(driver.loc_);
- default:
- return AgentParser::make_STRING("cert-required", driver.loc_);
- }
-}
- YY_BREAK
-case 34:
-YY_RULE_SETUP
-#line 388 "agent_lexer.ll"
-{
- switch(driver.ctx_) {
- case ParserContext::AGENT:
- return AgentParser::make_CONTROL_SOCKETS(driver.loc_);
- default:
- return AgentParser::make_STRING("control-sockets", driver.loc_);
- }
-}
- YY_BREAK
-case 35:
-YY_RULE_SETUP
-#line 397 "agent_lexer.ll"
-{
- switch(driver.ctx_) {
- case ParserContext::CONTROL_SOCKETS:
- return AgentParser::make_DHCP4_SERVER(driver.loc_);
- default:
- return AgentParser::make_STRING("dhcp4", driver.loc_);
- }
-}
- YY_BREAK
-case 36:
-YY_RULE_SETUP
-#line 406 "agent_lexer.ll"
-{
- switch(driver.ctx_) {
- case ParserContext::CONTROL_SOCKETS:
- return AgentParser::make_DHCP6_SERVER(driver.loc_);
- default:
- return AgentParser::make_STRING("dhcp6", driver.loc_);
- }
-}
- YY_BREAK
-case 37:
-YY_RULE_SETUP
-#line 415 "agent_lexer.ll"
-{
- switch(driver.ctx_) {
- case ParserContext::CONTROL_SOCKETS:
- return AgentParser::make_D2_SERVER(driver.loc_);
- default:
- return AgentParser::make_STRING("d2", driver.loc_);
- }
-}
- YY_BREAK
-case 38:
-YY_RULE_SETUP
-#line 424 "agent_lexer.ll"
-{
- switch(driver.ctx_) {
- case ParserContext::SERVER:
- return AgentParser::make_SOCKET_NAME(driver.loc_);
- default:
- return AgentParser::make_STRING("socket-name", driver.loc_);
- }
-}
- YY_BREAK
-case 39:
-YY_RULE_SETUP
-#line 433 "agent_lexer.ll"
-{
- switch(driver.ctx_) {
- case ParserContext::SERVER:
- return AgentParser::make_SOCKET_TYPE(driver.loc_);
- default:
- return AgentParser::make_STRING("socket-type", driver.loc_);
- }
-}
- YY_BREAK
-case 40:
-YY_RULE_SETUP
-#line 442 "agent_lexer.ll"
-{
- switch(driver.ctx_) {
- case ParserContext::SOCKET_TYPE:
- return AgentParser::make_UNIX(driver.loc_);
- default:
- return AgentParser::make_STRING("unix", driver.loc_);
- }
-}
- YY_BREAK
-case 41:
-YY_RULE_SETUP
-#line 451 "agent_lexer.ll"
-{
- switch(driver.ctx_) {
- case ParserContext::AGENT:
- return AgentParser::make_HOOKS_LIBRARIES(driver.loc_);
- default:
- return AgentParser::make_STRING("hooks-libraries", driver.loc_);
- }
-}
- YY_BREAK
-case 42:
-YY_RULE_SETUP
-#line 460 "agent_lexer.ll"
-{
- switch(driver.ctx_) {
- case ParserContext::HOOKS_LIBRARIES:
- return AgentParser::make_LIBRARY(driver.loc_);
- default:
- return AgentParser::make_STRING("library", driver.loc_);
- }
-}
- YY_BREAK
-case 43:
-YY_RULE_SETUP
-#line 469 "agent_lexer.ll"
-{
- switch(driver.ctx_) {
- case ParserContext::HOOKS_LIBRARIES:
- return AgentParser::make_PARAMETERS(driver.loc_);
- default:
- return AgentParser::make_STRING("parameters", driver.loc_);
- }
-}
- YY_BREAK
-case 44:
-YY_RULE_SETUP
-#line 478 "agent_lexer.ll"
-{
- switch(driver.ctx_) {
- case ParserContext::AGENT:
- return AgentParser::make_LOGGERS(driver.loc_);
- default:
- return AgentParser::make_STRING("loggers", driver.loc_);
- }
-}
- YY_BREAK
-case 45:
-YY_RULE_SETUP
-#line 487 "agent_lexer.ll"
-{
- switch(driver.ctx_) {
- case ParserContext::LOGGERS:
- return AgentParser::make_OUTPUT_OPTIONS(driver.loc_);
- default:
- return AgentParser::make_STRING("output_options", driver.loc_);
- }
-}
- YY_BREAK
-case 46:
-YY_RULE_SETUP
-#line 496 "agent_lexer.ll"
-{
- switch(driver.ctx_) {
- case ParserContext::LOGGERS:
- return AgentParser::make_OUTPUT_OPTIONS(driver.loc_);
- default:
- return AgentParser::make_STRING("output-options", driver.loc_);
- }
-}
- YY_BREAK
-case 47:
-YY_RULE_SETUP
-#line 505 "agent_lexer.ll"
-{
- switch(driver.ctx_) {
- case ParserContext::OUTPUT_OPTIONS:
- return AgentParser::make_OUTPUT(driver.loc_);
- default:
- return AgentParser::make_STRING("output", driver.loc_);
- }
-}
- YY_BREAK
-case 48:
-YY_RULE_SETUP
-#line 514 "agent_lexer.ll"
-{
- switch(driver.ctx_) {
- case ParserContext::OUTPUT_OPTIONS:
- return AgentParser::make_FLUSH(driver.loc_);
- default:
- return AgentParser::make_STRING("flush", driver.loc_);
- }
-}
- YY_BREAK
-case 49:
-YY_RULE_SETUP
-#line 523 "agent_lexer.ll"
-{
- switch(driver.ctx_) {
- case ParserContext::OUTPUT_OPTIONS:
- return AgentParser::make_MAXSIZE(driver.loc_);
- default:
- return AgentParser::make_STRING("maxsize", driver.loc_);
- }
-}
- YY_BREAK
-case 50:
-YY_RULE_SETUP
-#line 532 "agent_lexer.ll"
-{
- switch(driver.ctx_) {
- case ParserContext::OUTPUT_OPTIONS:
- return AgentParser::make_MAXVER(driver.loc_);
- default:
- return AgentParser::make_STRING("maxver", driver.loc_);
- }
-}
- YY_BREAK
-case 51:
-YY_RULE_SETUP
-#line 541 "agent_lexer.ll"
-{
- switch(driver.ctx_) {
- case ParserContext::OUTPUT_OPTIONS:
- return AgentParser::make_PATTERN(driver.loc_);
- default:
- return AgentParser::make_STRING("pattern", driver.loc_);
- }
-}
- YY_BREAK
-case 52:
-YY_RULE_SETUP
-#line 550 "agent_lexer.ll"
-{
- switch(driver.ctx_) {
- case ParserContext::LOGGERS:
- return AgentParser::make_DEBUGLEVEL(driver.loc_);
- default:
- return AgentParser::make_STRING("debuglevel", driver.loc_);
- }
-}
- YY_BREAK
-case 53:
-YY_RULE_SETUP
-#line 559 "agent_lexer.ll"
-{
- switch(driver.ctx_) {
- case ParserContext::LOGGERS:
- return AgentParser::make_SEVERITY(driver.loc_);
- default:
- return AgentParser::make_STRING("severity", driver.loc_);
- }
-}
- YY_BREAK
-case 54:
-YY_RULE_SETUP
-#line 568 "agent_lexer.ll"
-{
- /* A string has been matched. It contains the actual string and single quotes.
- We need to get those quotes out of the way and just use its content, e.g.
- for 'foo' we should get foo */
- std::string raw(yytext+1);
- size_t len = raw.size() - 1;
- raw.resize(len);
- std::string decoded;
- decoded.reserve(len);
- for (size_t pos = 0; pos < len; ++pos) {
- int b = 0;
- char c = raw[pos];
- switch (c) {
- case '"':
- /* impossible condition */
- driver.error(driver.loc_, "Bad quote in \"" + raw + "\"");
- break;
- case '\\':
- ++pos;
- if (pos >= len) {
- /* impossible condition */
- driver.error(driver.loc_, "Overflow escape in \"" + raw + "\"");
- }
- c = raw[pos];
- switch (c) {
- case '"':
- case '\\':
- case '/':
- decoded.push_back(c);
- break;
- case 'b':
- decoded.push_back('\b');
- break;
- case 'f':
- decoded.push_back('\f');
- break;
- case 'n':
- decoded.push_back('\n');
- break;
- case 'r':
- decoded.push_back('\r');
- break;
- case 't':
- decoded.push_back('\t');
- break;
- case 'u':
- /* support only \u0000 to \u00ff */
- ++pos;
- if (pos + 4 > len) {
- /* impossible condition */
- driver.error(driver.loc_,
- "Overflow unicode escape in \"" + raw + "\"");
- }
- if ((raw[pos] != '0') || (raw[pos + 1] != '0')) {
- driver.error(driver.loc_,
- "Unsupported unicode escape in \"" + raw + "\"",
- pos + 1);
- }
- pos += 2;
- c = raw[pos];
- if ((c >= '0') && (c <= '9')) {
- b = (c - '0') << 4;
- } else if ((c >= 'A') && (c <= 'F')) {
- b = (c - 'A' + 10) << 4;
- } else if ((c >= 'a') && (c <= 'f')) {
- b = (c - 'a' + 10) << 4;
- } else {
- /* impossible condition */
- driver.error(driver.loc_, "Not hexadecimal in unicode escape in \"" + raw + "\"");
- }
- pos++;
- c = raw[pos];
- if ((c >= '0') && (c <= '9')) {
- b |= c - '0';
- } else if ((c >= 'A') && (c <= 'F')) {
- b |= c - 'A' + 10;
- } else if ((c >= 'a') && (c <= 'f')) {
- b |= c - 'a' + 10;
- } else {
- /* impossible condition */
- driver.error(driver.loc_, "Not hexadecimal in unicode escape in \"" + raw + "\"");
- }
- decoded.push_back(static_cast<char>(b & 0xff));
- break;
- default:
- /* impossible condition */
- driver.error(driver.loc_, "Bad escape in \"" + raw + "\"");
- }
- break;
- default:
- if ((c >= 0) && (c < 0x20)) {
- /* impossible condition */
- driver.error(driver.loc_, "Invalid control in \"" + raw + "\"");
- }
- decoded.push_back(c);
- }
- }
-
- return AgentParser::make_STRING(decoded, driver.loc_);
-}
- YY_BREAK
-case 55:
-/* rule 55 can match eol */
-YY_RULE_SETUP
-#line 669 "agent_lexer.ll"
-{
- /* Bad string with a forbidden control character inside */
- std::string raw(yytext+1);
- size_t len = raw.size() - 1;
- size_t pos = 0;
- for (; pos < len; ++pos) {
- char c = raw[pos];
- if ((c >= 0) && (c < 0x20)) {
- break;
- }
- }
- driver.error(driver.loc_,
- "Invalid control in " + std::string(yytext),
- pos + 1);
-}
- YY_BREAK
-case 56:
-/* rule 56 can match eol */
-YY_RULE_SETUP
-#line 685 "agent_lexer.ll"
-{
- /* Bad string with a bad escape inside */
- std::string raw(yytext+1);
- size_t len = raw.size() - 1;
- size_t pos = 0;
- bool found = false;
- for (; pos < len; ++pos) {
- if (found) {
- break;
- }
- char c = raw[pos];
- if (c == '\\') {
- ++pos;
- c = raw[pos];
- switch (c) {
- case '"':
- case '\\':
- case '/':
- case 'b':
- case 'f':
- case 'n':
- case 'r':
- case 't':
- break;
- case 'u':
- if ((pos + 4 > len) ||
- !std::isxdigit(raw[pos + 1]) ||
- !std::isxdigit(raw[pos + 2]) ||
- !std::isxdigit(raw[pos + 3]) ||
- !std::isxdigit(raw[pos + 4])) {
- found = true;
- }
- break;
- default:
- found = true;
- break;
- }
- }
- }
- /* The rule stops on the first " including on \" so add ... in this case */
- std::string trailer = "";
- if (raw[len - 1] == '\\') {
- trailer = "...";
- }
- driver.error(driver.loc_,
- "Bad escape in " + std::string(yytext) + trailer,
- pos);
-}
- YY_BREAK
-case 57:
-YY_RULE_SETUP
-#line 734 "agent_lexer.ll"
-{
- /* Bad string with an open escape at the end */
- std::string raw(yytext+1);
- driver.error(driver.loc_,
- "Overflow escape in " + std::string(yytext),
- raw.size() + 1);
-}
- YY_BREAK
-case 58:
-YY_RULE_SETUP
-#line 742 "agent_lexer.ll"
-{
- /* Bad string with an open unicode escape at the end */
- std::string raw(yytext+1);
- size_t pos = raw.size() - 1;
- for (; pos > 0; --pos) {
- char c = raw[pos];
- if (c == 'u') {
- break;
- }
- }
- driver.error(driver.loc_,
- "Overflow unicode escape in " + std::string(yytext),
- pos + 1);
-}
- YY_BREAK
-case 59:
-YY_RULE_SETUP
-#line 757 "agent_lexer.ll"
-{ return AgentParser::make_LSQUARE_BRACKET(driver.loc_); }
- YY_BREAK
-case 60:
-YY_RULE_SETUP
-#line 758 "agent_lexer.ll"
-{ return AgentParser::make_RSQUARE_BRACKET(driver.loc_); }
- YY_BREAK
-case 61:
-YY_RULE_SETUP
-#line 759 "agent_lexer.ll"
-{ return AgentParser::make_LCURLY_BRACKET(driver.loc_); }
- YY_BREAK
-case 62:
-YY_RULE_SETUP
-#line 760 "agent_lexer.ll"
-{ return AgentParser::make_RCURLY_BRACKET(driver.loc_); }
- YY_BREAK
-case 63:
-YY_RULE_SETUP
-#line 761 "agent_lexer.ll"
-{ return AgentParser::make_COMMA(driver.loc_); }
- YY_BREAK
-case 64:
-YY_RULE_SETUP
-#line 762 "agent_lexer.ll"
-{ return AgentParser::make_COLON(driver.loc_); }
- YY_BREAK
-case 65:
-YY_RULE_SETUP
-#line 764 "agent_lexer.ll"
-{
- /* An integer was found. */
- std::string tmp(yytext);
- int64_t integer = 0;
- try {
- /* In substring we want to use negative values (e.g. -1).
- In enterprise-id we need to use values up to 0xffffffff.
- To cover both of those use cases, we need at least
- int64_t. */
- integer = boost::lexical_cast<int64_t>(tmp);
- } catch (const boost::bad_lexical_cast &) {
- driver.error(driver.loc_, "Failed to convert " + tmp + " to an integer.");
- }
-
- /* The parser needs the string form as double conversion is no lossless */
- return AgentParser::make_INTEGER(integer, driver.loc_);
-}
- YY_BREAK
-case 66:
-YY_RULE_SETUP
-#line 782 "agent_lexer.ll"
-{
- /* A floating point was found. */
- std::string tmp(yytext);
- double fp = 0.0;
- try {
- fp = boost::lexical_cast<double>(tmp);
- } catch (const boost::bad_lexical_cast &) {
- driver.error(driver.loc_, "Failed to convert " + tmp + " to a floating point.");
- }
-
- return AgentParser::make_FLOAT(fp, driver.loc_);
-}
- YY_BREAK
-case 67:
-YY_RULE_SETUP
-#line 795 "agent_lexer.ll"
-{
- string tmp(yytext);
- return AgentParser::make_BOOLEAN(tmp == "true", driver.loc_);
-}
- YY_BREAK
-case 68:
-YY_RULE_SETUP
-#line 800 "agent_lexer.ll"
-{
- return AgentParser::make_NULL_TYPE(driver.loc_);
-}
- YY_BREAK
-case 69:
-YY_RULE_SETUP
-#line 804 "agent_lexer.ll"
-driver.error (driver.loc_, "JSON true reserved keyword is lower case only");
- YY_BREAK
-case 70:
-YY_RULE_SETUP
-#line 806 "agent_lexer.ll"
-driver.error (driver.loc_, "JSON false reserved keyword is lower case only");
- YY_BREAK
-case 71:
-YY_RULE_SETUP
-#line 808 "agent_lexer.ll"
-driver.error (driver.loc_, "JSON null reserved keyword is lower case only");
- YY_BREAK
-case 72:
-YY_RULE_SETUP
-#line 810 "agent_lexer.ll"
-driver.error (driver.loc_, "Invalid character: " + std::string(yytext));
- YY_BREAK
-case YY_STATE_EOF(INITIAL):
-#line 812 "agent_lexer.ll"
-{
- if (driver.states_.empty()) {
- return AgentParser::make_END(driver.loc_);
- }
- driver.loc_ = driver.locs_.back();
- driver.locs_.pop_back();
- driver.file_ = driver.files_.back();
- driver.files_.pop_back();
- if (driver.sfile_) {
- fclose(driver.sfile_);
- driver.sfile_ = 0;
- }
- if (!driver.sfiles_.empty()) {
- driver.sfile_ = driver.sfiles_.back();
- driver.sfiles_.pop_back();
- }
- agent__delete_buffer(YY_CURRENT_BUFFER);
- agent__switch_to_buffer(driver.states_.back());
- driver.states_.pop_back();
-
- BEGIN(DIR_EXIT);
-}
- YY_BREAK
-case 73:
-YY_RULE_SETUP
-#line 835 "agent_lexer.ll"
-ECHO;
- YY_BREAK
-#line 2985 "agent_lexer.cc"
-
- case YY_END_OF_BUFFER:
- {
- /* Amount of text matched not including the EOB char. */
- int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;
-
- /* Undo the effects of YY_DO_BEFORE_ACTION. */
- *yy_cp = (yy_hold_char);
- YY_RESTORE_YY_MORE_OFFSET
-
- if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
- {
- /* We're scanning a new file or input source. It's
- * possible that this happened because the user
- * just pointed yyin at a new source and called
- * yylex(). If so, then we have to assure
- * consistency between YY_CURRENT_BUFFER and our
- * globals. Here is the right place to do so, because
- * this is the first action (other than possibly a
- * back-up) that will match for the new input source.
- */
- (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
-/* %if-c-only */
- YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
-/* %endif */
-/* %if-c++-only */
-/* %endif */
- YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
- }
-
- /* Note that here we test for yy_c_buf_p "<=" to the position
- * of the first EOB in the buffer, since yy_c_buf_p will
- * already have been incremented past the NUL character
- * (since all states make transitions on EOB to the
- * end-of-buffer state). Contrast this with the test
- * in input().
- */
- if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
- { /* This was really a NUL. */
- yy_state_type yy_next_state;
-
- (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;
-
- yy_current_state = yy_get_previous_state( );
-
- /* Okay, we're now positioned to make the NUL
- * transition. We couldn't have
- * yy_get_previous_state() go ahead and do it
- * for us because it doesn't know how to deal
- * with the possibility of jamming (and we don't
- * want to build jamming into it because then it
- * will run more slowly).
- */
-
- yy_next_state = yy_try_NUL_trans( yy_current_state );
-
- yy_bp = (yytext_ptr) + YY_MORE_ADJ;
-
- if ( yy_next_state )
- {
- /* Consume the NUL. */
- yy_cp = ++(yy_c_buf_p);
- yy_current_state = yy_next_state;
- goto yy_match;
- }
-
- else
- {
-/* %% [14.0] code to do back-up for compressed tables and set up yy_cp goes here */
- yy_cp = (yy_last_accepting_cpos);
- yy_current_state = (yy_last_accepting_state);
- goto yy_find_action;
- }
- }
-
- else switch ( yy_get_next_buffer( ) )
- {
- case EOB_ACT_END_OF_FILE:
- {
- (yy_did_buffer_switch_on_eof) = 0;
-
- if ( yywrap( ) )
- {
- /* Note: because we've taken care in
- * yy_get_next_buffer() to have set up
- * yytext, we can now set up
- * yy_c_buf_p so that if some total
- * hoser (like flex itself) wants to
- * call the scanner after we return the
- * YY_NULL, it'll still work - another
- * YY_NULL will get returned.
- */
- (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ;
-
- yy_act = YY_STATE_EOF(YY_START);
- goto do_action;
- }
-
- else
- {
- if ( ! (yy_did_buffer_switch_on_eof) )
- YY_NEW_FILE;
- }
- break;
- }
-
- case EOB_ACT_CONTINUE_SCAN:
- (yy_c_buf_p) =
- (yytext_ptr) + yy_amount_of_matched_text;
-
- yy_current_state = yy_get_previous_state( );
-
- yy_cp = (yy_c_buf_p);
- yy_bp = (yytext_ptr) + YY_MORE_ADJ;
- goto yy_match;
-
- case EOB_ACT_LAST_MATCH:
- (yy_c_buf_p) =
- &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];
-
- yy_current_state = yy_get_previous_state( );
-
- yy_cp = (yy_c_buf_p);
- yy_bp = (yytext_ptr) + YY_MORE_ADJ;
- goto yy_find_action;
- }
- break;
- }
-
- default:
- YY_FATAL_ERROR(
- "fatal flex scanner internal error--no action found" );
- } /* end of action switch */
- } /* end of scanning one token */
- } /* end of user's declarations */
-} /* end of yylex */
-/* %ok-for-header */
-
-/* %if-c++-only */
-/* %not-for-header */
-/* %ok-for-header */
-
-/* %endif */
-
-/* yy_get_next_buffer - try to read in a new buffer
- *
- * Returns a code representing an action:
- * EOB_ACT_LAST_MATCH -
- * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
- * EOB_ACT_END_OF_FILE - end of file
- */
-/* %if-c-only */
-static int yy_get_next_buffer (void)
-/* %endif */
-/* %if-c++-only */
-/* %endif */
-{
- char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
- char *source = (yytext_ptr);
- int number_to_move, i;
- int ret_val;
-
- if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
- YY_FATAL_ERROR(
- "fatal flex scanner internal error--end of buffer missed" );
-
- if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
- { /* Don't try to fill the buffer, so this is an EOF. */
- if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 )
- {
- /* We matched a single character, the EOB, so
- * treat this as a final EOF.
- */
- return EOB_ACT_END_OF_FILE;
- }
-
- else
- {
- /* We matched some text prior to the EOB, first
- * process it.
- */
- return EOB_ACT_LAST_MATCH;
- }
- }
-
- /* Try to read more data. */
-
- /* First move last chars to start of buffer. */
- number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr) - 1);
-
- for ( i = 0; i < number_to_move; ++i )
- *(dest++) = *(source++);
-
- if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
- /* don't do the read, it's not guaranteed to return an EOF,
- * just force an EOF
- */
- YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0;
-
- else
- {
- int num_to_read =
- YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
-
- while ( num_to_read <= 0 )
- { /* Not enough room in the buffer - grow it. */
-
- /* just a shorter name for the current buffer */
- YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE;
-
- int yy_c_buf_p_offset =
- (int) ((yy_c_buf_p) - b->yy_ch_buf);
-
- if ( b->yy_is_our_buffer )
- {
- int new_size = b->yy_buf_size * 2;
-
- if ( new_size <= 0 )
- b->yy_buf_size += b->yy_buf_size / 8;
- else
- b->yy_buf_size *= 2;
-
- b->yy_ch_buf = (char *)
- /* Include room in for 2 EOB chars. */
- yyrealloc( (void *) b->yy_ch_buf,
- (yy_size_t) (b->yy_buf_size + 2) );
- }
- else
- /* Can't grow it, we don't own it. */
- b->yy_ch_buf = NULL;
-
- if ( ! b->yy_ch_buf )
- YY_FATAL_ERROR(
- "fatal error - scanner input buffer overflow" );
-
- (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset];
-
- num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
- number_to_move - 1;
-
- }
-
- if ( num_to_read > YY_READ_BUF_SIZE )
- num_to_read = YY_READ_BUF_SIZE;
-
- /* Read in more data. */
- YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
- (yy_n_chars), num_to_read );
-
- YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
- }
-
- if ( (yy_n_chars) == 0 )
- {
- if ( number_to_move == YY_MORE_ADJ )
- {
- ret_val = EOB_ACT_END_OF_FILE;
- yyrestart( yyin );
- }
-
- else
- {
- ret_val = EOB_ACT_LAST_MATCH;
- YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
- YY_BUFFER_EOF_PENDING;
- }
- }
-
- else
- ret_val = EOB_ACT_CONTINUE_SCAN;
-
- if (((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
- /* Extend the array by 50%, plus the number we really need. */
- int new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
- YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc(
- (void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size );
- if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
- YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
- /* "- 2" to take care of EOB's */
- YY_CURRENT_BUFFER_LVALUE->yy_buf_size = (int) (new_size - 2);
- }
-
- (yy_n_chars) += number_to_move;
- YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
- YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
-
- (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
-
- return ret_val;
-}
-
-/* yy_get_previous_state - get the state just before the EOB char was reached */
-
-/* %if-c-only */
-/* %not-for-header */
- static yy_state_type yy_get_previous_state (void)
-/* %endif */
-/* %if-c++-only */
-/* %endif */
-{
- yy_state_type yy_current_state;
- char *yy_cp;
-
-/* %% [15.0] code to get the start state into yy_current_state goes here */
- yy_current_state = (yy_start);
-
- for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
- {
-/* %% [16.0] code to find the next state goes here */
- YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
- if ( yy_accept[yy_current_state] )
- {
- (yy_last_accepting_state) = yy_current_state;
- (yy_last_accepting_cpos) = yy_cp;
- }
- while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
- {
- yy_current_state = (int) yy_def[yy_current_state];
- if ( yy_current_state >= 430 )
- yy_c = yy_meta[yy_c];
- }
- yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
- }
-
- return yy_current_state;
-}
-
-/* yy_try_NUL_trans - try to make a transition on the NUL character
- *
- * synopsis
- * next_state = yy_try_NUL_trans( current_state );
- */
-/* %if-c-only */
- static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state )
-/* %endif */
-/* %if-c++-only */
-/* %endif */
-{
- int yy_is_jam;
- /* %% [17.0] code to find the next state, and perhaps do backing up, goes here */
- char *yy_cp = (yy_c_buf_p);
-
- YY_CHAR yy_c = 1;
- if ( yy_accept[yy_current_state] )
- {
- (yy_last_accepting_state) = yy_current_state;
- (yy_last_accepting_cpos) = yy_cp;
- }
- while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
- {
- yy_current_state = (int) yy_def[yy_current_state];
- if ( yy_current_state >= 430 )
- yy_c = yy_meta[yy_c];
- }
- yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
- yy_is_jam = (yy_current_state == 429);
-
- return yy_is_jam ? 0 : yy_current_state;
-}
-
-#ifndef YY_NO_UNPUT
-/* %if-c-only */
-
-/* %endif */
-#endif
-
-/* %if-c-only */
-#ifndef YY_NO_INPUT
-#ifdef __cplusplus
- static int yyinput (void)
-#else
- static int input (void)
-#endif
-
-/* %endif */
-/* %if-c++-only */
-/* %endif */
-{
- int c;
-
- *(yy_c_buf_p) = (yy_hold_char);
-
- if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR )
- {
- /* yy_c_buf_p now points to the character we want to return.
- * If this occurs *before* the EOB characters, then it's a
- * valid NUL; if not, then we've hit the end of the buffer.
- */
- if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
- /* This was really a NUL. */
- *(yy_c_buf_p) = '\0';
-
- else
- { /* need more input */
- int offset = (int) ((yy_c_buf_p) - (yytext_ptr));
- ++(yy_c_buf_p);
-
- switch ( yy_get_next_buffer( ) )
- {
- case EOB_ACT_LAST_MATCH:
- /* This happens because yy_g_n_b()
- * sees that we've accumulated a
- * token and flags that we need to
- * try matching the token before
- * proceeding. But for input(),
- * there's no matching to consider.
- * So convert the EOB_ACT_LAST_MATCH
- * to EOB_ACT_END_OF_FILE.
- */
-
- /* Reset buffer status. */
- yyrestart( yyin );
-
- /*FALLTHROUGH*/
-
- case EOB_ACT_END_OF_FILE:
- {
- if ( yywrap( ) )
- return 0;
-
- if ( ! (yy_did_buffer_switch_on_eof) )
- YY_NEW_FILE;
-#ifdef __cplusplus
- return yyinput();
-#else
- return input();
-#endif
- }
-
- case EOB_ACT_CONTINUE_SCAN:
- (yy_c_buf_p) = (yytext_ptr) + offset;
- break;
- }
- }
- }
-
- c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */
- *(yy_c_buf_p) = '\0'; /* preserve yytext */
- (yy_hold_char) = *++(yy_c_buf_p);
-
-/* %% [19.0] update BOL and yylineno */
-
- return c;
-}
-/* %if-c-only */
-#endif /* ifndef YY_NO_INPUT */
-/* %endif */
-
-/** Immediately switch to a different input stream.
- * @param input_file A readable stream.
- *
- * @note This function does not reset the start condition to @c INITIAL .
- */
-/* %if-c-only */
- void yyrestart (FILE * input_file )
-/* %endif */
-/* %if-c++-only */
-/* %endif */
-{
-
- if ( ! YY_CURRENT_BUFFER ){
- yyensure_buffer_stack ();
- YY_CURRENT_BUFFER_LVALUE =
- yy_create_buffer( yyin, YY_BUF_SIZE );
- }
-
- yy_init_buffer( YY_CURRENT_BUFFER, input_file );
- yy_load_buffer_state( );
-}
-
-/* %if-c++-only */
-/* %endif */
-
-/** Switch to a different input buffer.
- * @param new_buffer The new input buffer.
- *
- */
-/* %if-c-only */
- void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer )
-/* %endif */
-/* %if-c++-only */
-/* %endif */
-{
-
- /* TODO. We should be able to replace this entire function body
- * with
- * yypop_buffer_state();
- * yypush_buffer_state(new_buffer);
- */
- yyensure_buffer_stack ();
- if ( YY_CURRENT_BUFFER == new_buffer )
- return;
-
- if ( YY_CURRENT_BUFFER )
- {
- /* Flush out information for old buffer. */
- *(yy_c_buf_p) = (yy_hold_char);
- YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
- YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
- }
-
- YY_CURRENT_BUFFER_LVALUE = new_buffer;
- yy_load_buffer_state( );
-
- /* We don't actually know whether we did this switch during
- * EOF (yywrap()) processing, but the only time this flag
- * is looked at is after yywrap() is called, so it's safe
- * to go ahead and always set it.
- */
- (yy_did_buffer_switch_on_eof) = 1;
-}
-
-/* %if-c-only */
-static void yy_load_buffer_state (void)
-/* %endif */
-/* %if-c++-only */
-/* %endif */
-{
- (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
- (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
-/* %if-c-only */
- yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
-/* %endif */
-/* %if-c++-only */
-/* %endif */
- (yy_hold_char) = *(yy_c_buf_p);
-}
-
-/** Allocate and initialize an input buffer state.
- * @param file A readable stream.
- * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
- *
- * @return the allocated buffer state.
- */
-/* %if-c-only */
- YY_BUFFER_STATE yy_create_buffer (FILE * file, int size )
-/* %endif */
-/* %if-c++-only */
-/* %endif */
-{
- YY_BUFFER_STATE b;
-
- b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) );
- if ( ! b )
- YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
-
- b->yy_buf_size = size;
-
- /* yy_ch_buf has to be 2 characters longer than the size given because
- * we need to put in 2 end-of-buffer characters.
- */
- b->yy_ch_buf = (char *) yyalloc( (yy_size_t) (b->yy_buf_size + 2) );
- if ( ! b->yy_ch_buf )
- YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
-
- b->yy_is_our_buffer = 1;
-
- yy_init_buffer( b, file );
-
- return b;
-}
-
-/* %if-c++-only */
-/* %endif */
-
-/** Destroy the buffer.
- * @param b a buffer created with yy_create_buffer()
- *
- */
-/* %if-c-only */
- void yy_delete_buffer (YY_BUFFER_STATE b )
-/* %endif */
-/* %if-c++-only */
-/* %endif */
-{
-
- if ( ! b )
- return;
-
- if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
- YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
-
- if ( b->yy_is_our_buffer )
- yyfree( (void *) b->yy_ch_buf );
-
- yyfree( (void *) b );
-}
-
-/* Initializes or reinitializes a buffer.
- * This function is sometimes called more than once on the same buffer,
- * such as during a yyrestart() or at EOF.
- */
-/* %if-c-only */
- static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file )
-/* %endif */
-/* %if-c++-only */
-/* %endif */
-
-{
- int oerrno = errno;
-
- yy_flush_buffer( b );
-
-/* %if-c-only */
- b->yy_input_file = file;
-/* %endif */
-/* %if-c++-only */
-/* %endif */
- b->yy_fill_buffer = 1;
-
- /* If b is the current buffer, then yy_init_buffer was _probably_
- * called from yyrestart() or through yy_get_next_buffer.
- * In that case, we don't want to reset the lineno or column.
- */
- if (b != YY_CURRENT_BUFFER){
- b->yy_bs_lineno = 1;
- b->yy_bs_column = 0;
- }
-
-/* %if-c-only */
-
- b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
-
-/* %endif */
-/* %if-c++-only */
-/* %endif */
- errno = oerrno;
-}
-
-/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
- * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
- *
- */
-/* %if-c-only */
- void yy_flush_buffer (YY_BUFFER_STATE b )
-/* %endif */
-/* %if-c++-only */
-/* %endif */
-{
- if ( ! b )
- return;
-
- b->yy_n_chars = 0;
-
- /* We always need two end-of-buffer characters. The first causes
- * a transition to the end-of-buffer state. The second causes
- * a jam in that state.
- */
- b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
- b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
-
- b->yy_buf_pos = &b->yy_ch_buf[0];
-
- b->yy_at_bol = 1;
- b->yy_buffer_status = YY_BUFFER_NEW;
-
- if ( b == YY_CURRENT_BUFFER )
- yy_load_buffer_state( );
-}
-
-/* %if-c-or-c++ */
-/** Pushes the new state onto the stack. The new state becomes
- * the current state. This function will allocate the stack
- * if necessary.
- * @param new_buffer The new state.
- *
- */
-/* %if-c-only */
-void yypush_buffer_state (YY_BUFFER_STATE new_buffer )
-/* %endif */
-/* %if-c++-only */
-/* %endif */
-{
- if (new_buffer == NULL)
- return;
-
- yyensure_buffer_stack();
-
- /* This block is copied from yy_switch_to_buffer. */
- if ( YY_CURRENT_BUFFER )
- {
- /* Flush out information for old buffer. */
- *(yy_c_buf_p) = (yy_hold_char);
- YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
- YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
- }
-
- /* Only push if top exists. Otherwise, replace top. */
- if (YY_CURRENT_BUFFER)
- (yy_buffer_stack_top)++;
- YY_CURRENT_BUFFER_LVALUE = new_buffer;
-
- /* copied from yy_switch_to_buffer. */
- yy_load_buffer_state( );
- (yy_did_buffer_switch_on_eof) = 1;
-}
-/* %endif */
-
-/* %if-c-or-c++ */
-/** Removes and deletes the top of the stack, if present.
- * The next element becomes the new top.
- *
- */
-/* %if-c-only */
-void yypop_buffer_state (void)
-/* %endif */
-/* %if-c++-only */
-/* %endif */
-{
- if (!YY_CURRENT_BUFFER)
- return;
-
- yy_delete_buffer(YY_CURRENT_BUFFER );
- YY_CURRENT_BUFFER_LVALUE = NULL;
- if ((yy_buffer_stack_top) > 0)
- --(yy_buffer_stack_top);
-
- if (YY_CURRENT_BUFFER) {
- yy_load_buffer_state( );
- (yy_did_buffer_switch_on_eof) = 1;
- }
-}
-/* %endif */
-
-/* %if-c-or-c++ */
-/* Allocates the stack if it does not exist.
- * Guarantees space for at least one push.
- */
-/* %if-c-only */
-static void yyensure_buffer_stack (void)
-/* %endif */
-/* %if-c++-only */
-/* %endif */
-{
- yy_size_t num_to_alloc;
-
- if (!(yy_buffer_stack)) {
-
- /* First allocation is just for 2 elements, since we don't know if this
- * scanner will even need a stack. We use 2 instead of 1 to avoid an
- * immediate realloc on the next call.
- */
- num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */
- (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc
- (num_to_alloc * sizeof(struct yy_buffer_state*)
- );
- if ( ! (yy_buffer_stack) )
- YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
-
- memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
-
- (yy_buffer_stack_max) = num_to_alloc;
- (yy_buffer_stack_top) = 0;
- return;
- }
-
- if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
-
- /* Increase the buffer to prepare for a possible push. */
- yy_size_t grow_size = 8 /* arbitrary grow size */;
-
- num_to_alloc = (yy_buffer_stack_max) + grow_size;
- (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc
- ((yy_buffer_stack),
- num_to_alloc * sizeof(struct yy_buffer_state*)
- );
- if ( ! (yy_buffer_stack) )
- YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
-
- /* zero only the new slots.*/
- memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
- (yy_buffer_stack_max) = num_to_alloc;
- }
-}
-/* %endif */
-
-/* %if-c-only */
-/** Setup the input buffer state to scan directly from a user-specified character buffer.
- * @param base the character buffer
- * @param size the size in bytes of the character buffer
- *
- * @return the newly allocated buffer state object.
- */
-YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size )
-{
- YY_BUFFER_STATE b;
-
- if ( size < 2 ||
- base[size-2] != YY_END_OF_BUFFER_CHAR ||
- base[size-1] != YY_END_OF_BUFFER_CHAR )
- /* They forgot to leave room for the EOB's. */
- return NULL;
-
- b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) );
- if ( ! b )
- YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
-
- b->yy_buf_size = (int) (size - 2); /* "- 2" to take care of EOB's */
- b->yy_buf_pos = b->yy_ch_buf = base;
- b->yy_is_our_buffer = 0;
- b->yy_input_file = NULL;
- b->yy_n_chars = b->yy_buf_size;
- b->yy_is_interactive = 0;
- b->yy_at_bol = 1;
- b->yy_fill_buffer = 0;
- b->yy_buffer_status = YY_BUFFER_NEW;
-
- yy_switch_to_buffer( b );
-
- return b;
-}
-/* %endif */
-
-/* %if-c-only */
-/** Setup the input buffer state to scan a string. The next call to yylex() will
- * scan from a @e copy of @a str.
- * @param yystr a NUL-terminated string to scan
- *
- * @return the newly allocated buffer state object.
- * @note If you want to scan bytes that may contain NUL values, then use
- * yy_scan_bytes() instead.
- */
-YY_BUFFER_STATE yy_scan_string (const char * yystr )
-{
-
- return yy_scan_bytes( yystr, (int) strlen(yystr) );
-}
-/* %endif */
-
-/* %if-c-only */
-/** Setup the input buffer state to scan the given bytes. The next call to yylex() will
- * scan from a @e copy of @a bytes.
- * @param yybytes the byte buffer to scan
- * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
- *
- * @return the newly allocated buffer state object.
- */
-YY_BUFFER_STATE yy_scan_bytes (const char * yybytes, int _yybytes_len )
-{
- YY_BUFFER_STATE b;
- char *buf;
- yy_size_t n;
- int i;
-
- /* Get memory for full buffer, including space for trailing EOB's. */
- n = (yy_size_t) (_yybytes_len + 2);
- buf = (char *) yyalloc( n );
- if ( ! buf )
- YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
-
- for ( i = 0; i < _yybytes_len; ++i )
- buf[i] = yybytes[i];
-
- buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
-
- b = yy_scan_buffer( buf, n );
- if ( ! b )
- YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
-
- /* It's okay to grow etc. this buffer, and we should throw it
- * away when we're done.
- */
- b->yy_is_our_buffer = 1;
-
- return b;
-}
-/* %endif */
-
-#ifndef YY_EXIT_FAILURE
-#define YY_EXIT_FAILURE 2
-#endif
-
-/* %if-c-only */
-static void yynoreturn yy_fatal_error (const char* msg )
-{
- fprintf( stderr, "%s\n", msg );
- exit( YY_EXIT_FAILURE );
-}
-/* %endif */
-/* %if-c++-only */
-/* %endif */
-
-/* Redefine yyless() so it works in section 3 code. */
-
-#undef yyless
-#define yyless(n) \
- do \
- { \
- /* Undo effects of setting up yytext. */ \
- int yyless_macro_arg = (n); \
- YY_LESS_LINENO(yyless_macro_arg);\
- yytext[yyleng] = (yy_hold_char); \
- (yy_c_buf_p) = yytext + yyless_macro_arg; \
- (yy_hold_char) = *(yy_c_buf_p); \
- *(yy_c_buf_p) = '\0'; \
- yyleng = yyless_macro_arg; \
- } \
- while ( 0 )
-
-/* Accessor methods (get/set functions) to struct members. */
-
-/* %if-c-only */
-/* %if-reentrant */
-/* %endif */
-
-/** Get the current line number.
- *
- */
-int yyget_lineno (void)
-{
-
- return yylineno;
-}
-
-/** Get the input stream.
- *
- */
-FILE *yyget_in (void)
-{
- return yyin;
-}
-
-/** Get the output stream.
- *
- */
-FILE *yyget_out (void)
-{
- return yyout;
-}
-
-/** Get the length of the current token.
- *
- */
-int yyget_leng (void)
-{
- return yyleng;
-}
-
-/** Get the current token.
- *
- */
-
-char *yyget_text (void)
-{
- return yytext;
-}
-
-/* %if-reentrant */
-/* %endif */
-
-/** Set the current line number.
- * @param _line_number line number
- *
- */
-void yyset_lineno (int _line_number )
-{
-
- yylineno = _line_number;
-}
-
-/** Set the input stream. This does not discard the current
- * input buffer.
- * @param _in_str A readable stream.
- *
- * @see yy_switch_to_buffer
- */
-void yyset_in (FILE * _in_str )
-{
- yyin = _in_str ;
-}
-
-void yyset_out (FILE * _out_str )
-{
- yyout = _out_str ;
-}
-
-int yyget_debug (void)
-{
- return yy_flex_debug;
-}
-
-void yyset_debug (int _bdebug )
-{
- yy_flex_debug = _bdebug ;
-}
-
-/* %endif */
-
-/* %if-reentrant */
-/* %if-bison-bridge */
-/* %endif */
-/* %endif if-c-only */
-
-/* %if-c-only */
-static int yy_init_globals (void)
-{
- /* Initialization is the same as for the non-reentrant scanner.
- * This function is called from yylex_destroy(), so don't allocate here.
- */
-
- (yy_buffer_stack) = NULL;
- (yy_buffer_stack_top) = 0;
- (yy_buffer_stack_max) = 0;
- (yy_c_buf_p) = NULL;
- (yy_init) = 0;
- (yy_start) = 0;
-
-/* Defined in main.c */
-#ifdef YY_STDINIT
- yyin = stdin;
- yyout = stdout;
-#else
- yyin = NULL;
- yyout = NULL;
-#endif
-
- /* For future reference: Set errno on error, since we are called by
- * yylex_init()
- */
- return 0;
-}
-/* %endif */
-
-/* %if-c-only SNIP! this currently causes conflicts with the c++ scanner */
-/* yylex_destroy is for both reentrant and non-reentrant scanners. */
-int yylex_destroy (void)
-{
-
- /* Pop the buffer stack, destroying each element. */
- while(YY_CURRENT_BUFFER){
- yy_delete_buffer( YY_CURRENT_BUFFER );
- YY_CURRENT_BUFFER_LVALUE = NULL;
- yypop_buffer_state();
- }
-
- /* Destroy the stack itself. */
- yyfree((yy_buffer_stack) );
- (yy_buffer_stack) = NULL;
-
- /* Reset the globals. This is important in a non-reentrant scanner so the next time
- * yylex() is called, initialization will occur. */
- yy_init_globals( );
-
-/* %if-reentrant */
-/* %endif */
- return 0;
-}
-/* %endif */
-
-/*
- * Internal utility routines.
- */
-
-#ifndef yytext_ptr
-static void yy_flex_strncpy (char* s1, const char * s2, int n )
-{
-
- int i;
- for ( i = 0; i < n; ++i )
- s1[i] = s2[i];
-}
-#endif
-
-#ifdef YY_NEED_STRLEN
-static int yy_flex_strlen (const char * s )
-{
- int n;
- for ( n = 0; s[n]; ++n )
- ;
-
- return n;
-}
-#endif
-
-void *yyalloc (yy_size_t size )
-{
- return malloc(size);
-}
-
-void *yyrealloc (void * ptr, yy_size_t size )
-{
-
- /* The cast to (char *) in the following accommodates both
- * implementations that use char* generic pointers, and those
- * that use void* generic pointers. It works with the latter
- * because both ANSI C and C++ allow castless assignment from
- * any pointer type to void*, and deal with argument conversions
- * as though doing an assignment.
- */
- return realloc(ptr, size);
-}
-
-void yyfree (void * ptr )
-{
- free( (char *) ptr ); /* see yyrealloc() for (char *) cast */
-}
-
-/* %if-tables-serialization definitions */
-/* %define-yytables The name for this specific scanner's tables. */
-#define YYTABLES_NAME "yytables"
-/* %endif */
-
-/* %ok-for-header */
-
-#line 835 "agent_lexer.ll"
-
-
-using namespace isc::dhcp;
-
-void
-ParserContext::scanStringBegin(const std::string& str, ParserType parser_type)
-{
- start_token_flag = true;
- start_token_value = parser_type;
-
- file_ = "<string>";
- sfile_ = 0;
- loc_.initialize(&file_);
- yy_flex_debug = trace_scanning_;
- YY_BUFFER_STATE buffer;
- buffer = agent__scan_bytes(str.c_str(), str.size());
- if (!buffer) {
- fatal("cannot scan string");
- /* fatal() throws an exception so this can't be reached */
- }
-}
-
-void
-ParserContext::scanFileBegin(FILE * f,
- const std::string& filename,
- ParserType parser_type)
-{
- start_token_flag = true;
- start_token_value = parser_type;
-
- file_ = filename;
- sfile_ = f;
- loc_.initialize(&file_);
- yy_flex_debug = trace_scanning_;
- YY_BUFFER_STATE buffer;
-
- /* See agent_lexer.cc header for available definitions */
- buffer = agent__create_buffer(f, 65536 /*buffer size*/);
- if (!buffer) {
- fatal("cannot scan file " + filename);
- }
- agent__switch_to_buffer(buffer);
-}
-
-void
-ParserContext::scanEnd() {
- if (sfile_)
- fclose(sfile_);
- sfile_ = 0;
- static_cast<void>(agent_lex_destroy());
- /* Close files */
- while (!sfiles_.empty()) {
- FILE* f = sfiles_.back();
- if (f) {
- fclose(f);
- }
- sfiles_.pop_back();
- }
- /* Delete states */
- while (!states_.empty()) {
- agent__delete_buffer(states_.back());
- states_.pop_back();
- }
-}
-
-void
-ParserContext::includeFile(const std::string& filename) {
- if (states_.size() > 10) {
- fatal("Too many nested include.");
- }
-
- FILE* f = fopen(filename.c_str(), "r");
- if (!f) {
- fatal("Can't open include file " + filename);
- }
- if (sfile_) {
- sfiles_.push_back(sfile_);
- }
- sfile_ = f;
- states_.push_back(YY_CURRENT_BUFFER);
- YY_BUFFER_STATE buffer;
- buffer = agent__create_buffer(f, 65536 /*buffer size*/);
- if (!buffer) {
- fatal( "Can't scan include file " + filename);
- }
- agent__switch_to_buffer(buffer);
- files_.push_back(file_);
- file_ = filename;
- locs_.push_back(loc_);
- loc_.initialize(&file_);
-
- BEGIN(INITIAL);
-}
-
-namespace {
-/** To avoid unused function error */
-class Dummy {
- /* cppcheck-suppress unusedPrivateFunction */
- void dummy() { yy_fatal_error("Fix me: how to disable its definition?"); }
-};
-}
-#endif /* !__clang_analyzer__ */
-
+++ /dev/null
-/* Copyright (C) 2017-2025 Internet Systems Consortium, Inc. ("ISC")
-
- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-%{ /* -*- C++ -*- */
-
-/* Generated files do not make clang static analyser so happy */
-#ifndef __clang_analyzer__
-
-#include <cctype>
-#include <cerrno>
-#include <climits>
-#include <cstdint>
-#include <cstdlib>
-#include <string>
-#include <agent/parser_context.h>
-#include <asiolink/io_address.h>
-#include <boost/lexical_cast.hpp>
-#include <exceptions/exceptions.h>
-#include <cc/dhcp_config_error.h>
-
-/* Please avoid C++ style comments (// ... eol) as they break flex 2.6.2 */
-
-/* Work around an incompatibility in flex (at least versions
- 2.5.31 through 2.5.33): it generates code that does
- not conform to C89. See Debian bug 333231
- <http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=333231>. */
-# undef yywrap
-# define yywrap() 1
-
-namespace {
-
-bool start_token_flag = false;
-
-isc::agent::ParserContext::ParserType start_token_value;
-unsigned int comment_start_line = 0;
-
-using namespace isc;
-using isc::agent::AgentParser;
-
-};
-
-/* To avoid the call to exit... oops! */
-#define YY_FATAL_ERROR(msg) isc::agent::ParserContext::fatal(msg)
-%}
-
-/* noyywrap disables automatic rewinding for the next file to parse. Since we
- always parse only a single string, there's no need to do any wraps. And
- using yywrap requires linking with -lfl, which provides the default yywrap
- implementation that always returns 1 anyway. */
-%option noyywrap
-
-/* nounput simplifies the lexer, by removing support for putting a character
- back into the input stream. We never use such capability anyway. */
-%option nounput
-
-/* batch means that we'll never use the generated lexer interactively. */
-%option batch
-
-/* avoid to get static global variables to remain with C++. */
-/* in last resort %option reentrant */
-
-/* Enables debug mode. To see the debug messages, one needs to also set
- yy_flex_debug to 1, then the debug messages will be printed on stderr. */
-%option debug
-
-/* I have no idea what this option does, except it was specified in the bison
- examples and Postgres folks added it to remove gcc 4.3 warnings. Let's
- be on the safe side and keep it. */
-%option noinput
-
-%x COMMENT
-%x DIR_ENTER DIR_INCLUDE DIR_EXIT
-
-/* These are not token expressions yet, just convenience expressions that
- can be used during actual token definitions. Note some can match
- incorrect inputs (e.g., IP addresses) which must be checked. */
-int \-?[0-9]+
-blank [ \t\r]
-
-UnicodeEscapeSequence u[0-9A-Fa-f]{4}
-JSONEscapeCharacter ["\\/bfnrt]
-JSONEscapeSequence {JSONEscapeCharacter}|{UnicodeEscapeSequence}
-JSONStandardCharacter [^\x00-\x1f"\\]
-JSONStringCharacter {JSONStandardCharacter}|\\{JSONEscapeSequence}
-JSONString \"{JSONStringCharacter}*\"
-
-/* for errors */
-
-BadUnicodeEscapeSequence u[0-9A-Fa-f]{0,3}[^0-9A-Fa-f"]
-BadJSONEscapeSequence [^"\\/bfnrtu]|{BadUnicodeEscapeSequence}
-ControlCharacter [\x00-\x1f]
-ControlCharacterFill [^"\\]|\\["\\/bfnrtu]
-
-%{
-/* This code run each time a pattern is matched. It updates the location
- by moving it ahead by yyleng bytes. yyleng specifies the length of the
- currently matched token. */
-#define YY_USER_ACTION driver.loc_.columns(yyleng);
-%}
-
-%%
-
-%{
- /* This part of the code is copied over to the verbatim to the top
- of the generated yylex function. Explanation:
- http://www.gnu.org/software/bison/manual/html_node/Multiple-start_002dsymbols.html */
-
- /* Code run each time yylex is called. */
- driver.loc_.step();
-
- /* We currently have 3 points of entries defined:
- START_JSON - which expects any valid JSON
- START_AGENT - which expects full configuration (with outer map and Control-agent
- object in it.
- START_SUB_AGENT - which expects only content of the Control-agent, this is
- primarily useful for testing. */
- if (start_token_flag) {
- start_token_flag = false;
- switch (start_token_value) {
- case ParserContext::PARSER_JSON:
- default:
- return isc::agent::AgentParser::make_START_JSON(driver.loc_);
- case ParserContext::PARSER_AGENT:
- return isc::agent::AgentParser::make_START_AGENT(driver.loc_);
- case ParserContext::PARSER_SUB_AGENT:
- return isc::agent::AgentParser::make_START_SUB_AGENT(driver.loc_);
- }
- }
-%}
-
-#.* ;
-
-"//"(.*) ;
-
-"/*" {
- BEGIN(COMMENT);
- comment_start_line = driver.loc_.end.line;;
-}
-
-<COMMENT>"*/" BEGIN(INITIAL);
-<COMMENT>. ;
-<COMMENT><<EOF>> {
- isc_throw(ParseError, "Comment not closed. (/* in line " << comment_start_line);
-}
-
-"<?" BEGIN(DIR_ENTER);
-<DIR_ENTER>"include" BEGIN(DIR_INCLUDE);
-<DIR_INCLUDE>\"([^\"\n])+\" {
- /* Include directive. */
-
- /* Extract the filename. */
- std::string tmp(yytext+1);
- tmp.resize(tmp.size() - 1);
-
- driver.includeFile(tmp);
-}
-<DIR_ENTER,DIR_INCLUDE,DIR_EXIT><<EOF>> {
- isc_throw(ParseError, "Directive not closed.");
-}
-<DIR_EXIT>"?>" BEGIN(INITIAL);
-
-
-<*>{blank}+ {
- /* Ok, we found a with space. Let's ignore it and update loc variable. */
- driver.loc_.step();
-}
-
-<*>[\n]+ {
- /* Newline found. Let's update the location and continue. */
- driver.loc_.lines(yyleng);
- driver.loc_.step();
-}
-
-
-\"Control-agent\" {
- switch(driver.ctx_) {
- case ParserContext::CONFIG:
- return AgentParser::make_CONTROL_AGENT(driver.loc_);
- default:
- return AgentParser::make_STRING("Control-agent", driver.loc_);
- }
-}
-
-\"http-host\" {
- switch(driver.ctx_) {
- case ParserContext::AGENT:
- return AgentParser::make_HTTP_HOST(driver.loc_);
- default:
- return AgentParser::make_STRING("http-host", driver.loc_);
- }
-}
-
-\"http-port\" {
- switch(driver.ctx_) {
- case ParserContext::AGENT:
- return AgentParser::make_HTTP_PORT(driver.loc_);
- default:
- return AgentParser::make_STRING("http-port", driver.loc_);
- }
-}
-
-\"http-headers\" {
- switch(driver.ctx_) {
- case ParserContext::AGENT:
- return AgentParser::make_HTTP_HEADERS(driver.loc_);
- default:
- return AgentParser::make_STRING("http-headers", driver.loc_);
- }
-}
-
-\"user-context\" {
- switch(driver.ctx_) {
- case ParserContext::AGENT:
- case ParserContext::HTTP_HEADERS:
- case ParserContext::AUTHENTICATION:
- case ParserContext::CLIENTS:
- case ParserContext::SERVER:
- case ParserContext::LOGGERS:
- return AgentParser::make_USER_CONTEXT(driver.loc_);
- default:
- return AgentParser::make_STRING("user-context", driver.loc_);
- }
-}
-
-\"comment\" {
- switch(driver.ctx_) {
- case ParserContext::AGENT:
- case ParserContext::HTTP_HEADERS:
- case ParserContext::AUTHENTICATION:
- case ParserContext::CLIENTS:
- case ParserContext::SERVER:
- case ParserContext::LOGGERS:
- return AgentParser::make_COMMENT(driver.loc_);
- default:
- return AgentParser::make_STRING("comment", driver.loc_);
- }
-}
-
-\"name\" {
- switch(driver.ctx_) {
- case ParserContext::LOGGERS:
- case ParserContext::HTTP_HEADERS:
- return AgentParser::make_NAME(driver.loc_);
- default:
- return AgentParser::make_STRING("name", driver.loc_);
- }
-}
-
-\"value\" {
- switch(driver.ctx_) {
- case ParserContext::HTTP_HEADERS:
- return AgentParser::make_VALUE(driver.loc_);
- default:
- return AgentParser::make_STRING("value", driver.loc_);
- }
-}
-
-\"authentication\" {
- switch(driver.ctx_) {
- case ParserContext::AGENT:
- return AgentParser::make_AUTHENTICATION(driver.loc_);
- default:
- return AgentParser::make_STRING("authentication", driver.loc_);
- }
-}
-
-\"type\" {
- switch(driver.ctx_) {
- case ParserContext::AUTHENTICATION:
- return AgentParser::make_TYPE(driver.loc_);
- default:
- return AgentParser::make_STRING("type", driver.loc_);
- }
-}
-
-\"basic\" {
- switch(driver.ctx_) {
- case ParserContext::AUTH_TYPE:
- return AgentParser::make_BASIC(driver.loc_);
- default:
- return AgentParser::make_STRING("basic", driver.loc_);
- }
-}
-
-\"realm\" {
- switch(driver.ctx_) {
- case ParserContext::AUTHENTICATION:
- return AgentParser::make_REALM(driver.loc_);
- default:
- return AgentParser::make_STRING("realm", driver.loc_);
- }
-}
-
-\"directory\" {
- switch(driver.ctx_) {
- case ParserContext::AUTHENTICATION:
- return AgentParser::make_DIRECTORY(driver.loc_);
- default:
- return AgentParser::make_STRING("directory", driver.loc_);
- }
-}
-
-\"clients\" {
- switch(driver.ctx_) {
- case ParserContext::AUTHENTICATION:
- return AgentParser::make_CLIENTS(driver.loc_);
- default:
- return AgentParser::make_STRING("clients", driver.loc_);
- }
-}
-
-\"user\" {
- switch(driver.ctx_) {
- case ParserContext::CLIENTS:
- return AgentParser::make_USER(driver.loc_);
- default:
- return AgentParser::make_STRING("user", driver.loc_);
- }
-}
-
-\"user-file\" {
- switch(driver.ctx_) {
- case ParserContext::CLIENTS:
- return AgentParser::make_USER_FILE(driver.loc_);
- default:
- return AgentParser::make_STRING("user-file", driver.loc_);
- }
-}
-
-\"password\" {
- switch(driver.ctx_) {
- case ParserContext::CLIENTS:
- return AgentParser::make_PASSWORD(driver.loc_);
- default:
- return AgentParser::make_STRING("password", driver.loc_);
- }
-}
-
-\"password-file\" {
- switch(driver.ctx_) {
- case ParserContext::CLIENTS:
- return AgentParser::make_PASSWORD_FILE(driver.loc_);
- default:
- return AgentParser::make_STRING("password-file", driver.loc_);
- }
-}
-
-\"trust-anchor\" {
- switch(driver.ctx_) {
- case ParserContext::AGENT:
- return AgentParser::make_TRUST_ANCHOR(driver.loc_);
- default:
- return AgentParser::make_STRING("trust-anchor", driver.loc_);
- }
-}
-
-\"cert-file\" {
- switch(driver.ctx_) {
- case ParserContext::AGENT:
- return AgentParser::make_CERT_FILE(driver.loc_);
- default:
- return AgentParser::make_STRING("cert-file", driver.loc_);
- }
-}
-
-\"key-file\" {
- switch(driver.ctx_) {
- case ParserContext::AGENT:
- return AgentParser::make_KEY_FILE(driver.loc_);
- default:
- return AgentParser::make_STRING("key-file", driver.loc_);
- }
-}
-
-\"cert-required\" {
- switch(driver.ctx_) {
- case ParserContext::AGENT:
- return AgentParser::make_CERT_REQUIRED(driver.loc_);
- default:
- return AgentParser::make_STRING("cert-required", driver.loc_);
- }
-}
-
-\"control-sockets\" {
- switch(driver.ctx_) {
- case ParserContext::AGENT:
- return AgentParser::make_CONTROL_SOCKETS(driver.loc_);
- default:
- return AgentParser::make_STRING("control-sockets", driver.loc_);
- }
-}
-
-\"dhcp4\" {
- switch(driver.ctx_) {
- case ParserContext::CONTROL_SOCKETS:
- return AgentParser::make_DHCP4_SERVER(driver.loc_);
- default:
- return AgentParser::make_STRING("dhcp4", driver.loc_);
- }
-}
-
-\"dhcp6\" {
- switch(driver.ctx_) {
- case ParserContext::CONTROL_SOCKETS:
- return AgentParser::make_DHCP6_SERVER(driver.loc_);
- default:
- return AgentParser::make_STRING("dhcp6", driver.loc_);
- }
-}
-
-\"d2\" {
- switch(driver.ctx_) {
- case ParserContext::CONTROL_SOCKETS:
- return AgentParser::make_D2_SERVER(driver.loc_);
- default:
- return AgentParser::make_STRING("d2", driver.loc_);
- }
-}
-
-\"socket-name\" {
- switch(driver.ctx_) {
- case ParserContext::SERVER:
- return AgentParser::make_SOCKET_NAME(driver.loc_);
- default:
- return AgentParser::make_STRING("socket-name", driver.loc_);
- }
-}
-
-\"socket-type\" {
- switch(driver.ctx_) {
- case ParserContext::SERVER:
- return AgentParser::make_SOCKET_TYPE(driver.loc_);
- default:
- return AgentParser::make_STRING("socket-type", driver.loc_);
- }
-}
-
-\"unix\" {
- switch(driver.ctx_) {
- case ParserContext::SOCKET_TYPE:
- return AgentParser::make_UNIX(driver.loc_);
- default:
- return AgentParser::make_STRING("unix", driver.loc_);
- }
-}
-
-\"hooks-libraries\" {
- switch(driver.ctx_) {
- case ParserContext::AGENT:
- return AgentParser::make_HOOKS_LIBRARIES(driver.loc_);
- default:
- return AgentParser::make_STRING("hooks-libraries", driver.loc_);
- }
-}
-
-\"library\" {
- switch(driver.ctx_) {
- case ParserContext::HOOKS_LIBRARIES:
- return AgentParser::make_LIBRARY(driver.loc_);
- default:
- return AgentParser::make_STRING("library", driver.loc_);
- }
-}
-
-\"parameters\" {
- switch(driver.ctx_) {
- case ParserContext::HOOKS_LIBRARIES:
- return AgentParser::make_PARAMETERS(driver.loc_);
- default:
- return AgentParser::make_STRING("parameters", driver.loc_);
- }
-}
-
-\"loggers\" {
- switch(driver.ctx_) {
- case ParserContext::AGENT:
- return AgentParser::make_LOGGERS(driver.loc_);
- default:
- return AgentParser::make_STRING("loggers", driver.loc_);
- }
-}
-
-\"output_options\" {
- switch(driver.ctx_) {
- case ParserContext::LOGGERS:
- return AgentParser::make_OUTPUT_OPTIONS(driver.loc_);
- default:
- return AgentParser::make_STRING("output_options", driver.loc_);
- }
-}
-
-\"output-options\" {
- switch(driver.ctx_) {
- case ParserContext::LOGGERS:
- return AgentParser::make_OUTPUT_OPTIONS(driver.loc_);
- default:
- return AgentParser::make_STRING("output-options", driver.loc_);
- }
-}
-
-\"output\" {
- switch(driver.ctx_) {
- case ParserContext::OUTPUT_OPTIONS:
- return AgentParser::make_OUTPUT(driver.loc_);
- default:
- return AgentParser::make_STRING("output", driver.loc_);
- }
-}
-
-\"flush\" {
- switch(driver.ctx_) {
- case ParserContext::OUTPUT_OPTIONS:
- return AgentParser::make_FLUSH(driver.loc_);
- default:
- return AgentParser::make_STRING("flush", driver.loc_);
- }
-}
-
-\"maxsize\" {
- switch(driver.ctx_) {
- case ParserContext::OUTPUT_OPTIONS:
- return AgentParser::make_MAXSIZE(driver.loc_);
- default:
- return AgentParser::make_STRING("maxsize", driver.loc_);
- }
-}
-
-\"maxver\" {
- switch(driver.ctx_) {
- case ParserContext::OUTPUT_OPTIONS:
- return AgentParser::make_MAXVER(driver.loc_);
- default:
- return AgentParser::make_STRING("maxver", driver.loc_);
- }
-}
-
-\"pattern\" {
- switch(driver.ctx_) {
- case ParserContext::OUTPUT_OPTIONS:
- return AgentParser::make_PATTERN(driver.loc_);
- default:
- return AgentParser::make_STRING("pattern", driver.loc_);
- }
-}
-
-\"debuglevel\" {
- switch(driver.ctx_) {
- case ParserContext::LOGGERS:
- return AgentParser::make_DEBUGLEVEL(driver.loc_);
- default:
- return AgentParser::make_STRING("debuglevel", driver.loc_);
- }
-}
-
-\"severity\" {
- switch(driver.ctx_) {
- case ParserContext::LOGGERS:
- return AgentParser::make_SEVERITY(driver.loc_);
- default:
- return AgentParser::make_STRING("severity", driver.loc_);
- }
-}
-
-{JSONString} {
- /* A string has been matched. It contains the actual string and single quotes.
- We need to get those quotes out of the way and just use its content, e.g.
- for 'foo' we should get foo */
- std::string raw(yytext+1);
- size_t len = raw.size() - 1;
- raw.resize(len);
- std::string decoded;
- decoded.reserve(len);
- for (size_t pos = 0; pos < len; ++pos) {
- int b = 0;
- char c = raw[pos];
- switch (c) {
- case '"':
- /* impossible condition */
- driver.error(driver.loc_, "Bad quote in \"" + raw + "\"");
- break;
- case '\\':
- ++pos;
- if (pos >= len) {
- /* impossible condition */
- driver.error(driver.loc_, "Overflow escape in \"" + raw + "\"");
- }
- c = raw[pos];
- switch (c) {
- case '"':
- case '\\':
- case '/':
- decoded.push_back(c);
- break;
- case 'b':
- decoded.push_back('\b');
- break;
- case 'f':
- decoded.push_back('\f');
- break;
- case 'n':
- decoded.push_back('\n');
- break;
- case 'r':
- decoded.push_back('\r');
- break;
- case 't':
- decoded.push_back('\t');
- break;
- case 'u':
- /* support only \u0000 to \u00ff */
- ++pos;
- if (pos + 4 > len) {
- /* impossible condition */
- driver.error(driver.loc_,
- "Overflow unicode escape in \"" + raw + "\"");
- }
- if ((raw[pos] != '0') || (raw[pos + 1] != '0')) {
- driver.error(driver.loc_,
- "Unsupported unicode escape in \"" + raw + "\"",
- pos + 1);
- }
- pos += 2;
- c = raw[pos];
- if ((c >= '0') && (c <= '9')) {
- b = (c - '0') << 4;
- } else if ((c >= 'A') && (c <= 'F')) {
- b = (c - 'A' + 10) << 4;
- } else if ((c >= 'a') && (c <= 'f')) {
- b = (c - 'a' + 10) << 4;
- } else {
- /* impossible condition */
- driver.error(driver.loc_, "Not hexadecimal in unicode escape in \"" + raw + "\"");
- }
- pos++;
- c = raw[pos];
- if ((c >= '0') && (c <= '9')) {
- b |= c - '0';
- } else if ((c >= 'A') && (c <= 'F')) {
- b |= c - 'A' + 10;
- } else if ((c >= 'a') && (c <= 'f')) {
- b |= c - 'a' + 10;
- } else {
- /* impossible condition */
- driver.error(driver.loc_, "Not hexadecimal in unicode escape in \"" + raw + "\"");
- }
- decoded.push_back(static_cast<char>(b & 0xff));
- break;
- default:
- /* impossible condition */
- driver.error(driver.loc_, "Bad escape in \"" + raw + "\"");
- }
- break;
- default:
- if ((c >= 0) && (c < 0x20)) {
- /* impossible condition */
- driver.error(driver.loc_, "Invalid control in \"" + raw + "\"");
- }
- decoded.push_back(c);
- }
- }
-
- return AgentParser::make_STRING(decoded, driver.loc_);
-}
-
-\"{JSONStringCharacter}*{ControlCharacter}{ControlCharacterFill}*\" {
- /* Bad string with a forbidden control character inside */
- std::string raw(yytext+1);
- size_t len = raw.size() - 1;
- size_t pos = 0;
- for (; pos < len; ++pos) {
- char c = raw[pos];
- if ((c >= 0) && (c < 0x20)) {
- break;
- }
- }
- driver.error(driver.loc_,
- "Invalid control in " + std::string(yytext),
- pos + 1);
-}
-
-\"{JSONStringCharacter}*\\{BadJSONEscapeSequence}[^"]*\" {
- /* Bad string with a bad escape inside */
- std::string raw(yytext+1);
- size_t len = raw.size() - 1;
- size_t pos = 0;
- bool found = false;
- for (; pos < len; ++pos) {
- if (found) {
- break;
- }
- char c = raw[pos];
- if (c == '\\') {
- ++pos;
- c = raw[pos];
- switch (c) {
- case '"':
- case '\\':
- case '/':
- case 'b':
- case 'f':
- case 'n':
- case 'r':
- case 't':
- break;
- case 'u':
- if ((pos + 4 > len) ||
- !std::isxdigit(raw[pos + 1]) ||
- !std::isxdigit(raw[pos + 2]) ||
- !std::isxdigit(raw[pos + 3]) ||
- !std::isxdigit(raw[pos + 4])) {
- found = true;
- }
- break;
- default:
- found = true;
- break;
- }
- }
- }
- /* The rule stops on the first " including on \" so add ... in this case */
- std::string trailer = "";
- if (raw[len - 1] == '\\') {
- trailer = "...";
- }
- driver.error(driver.loc_,
- "Bad escape in " + std::string(yytext) + trailer,
- pos);
-}
-
-\"{JSONStringCharacter}*\\\" {
- /* Bad string with an open escape at the end */
- std::string raw(yytext+1);
- driver.error(driver.loc_,
- "Overflow escape in " + std::string(yytext),
- raw.size() + 1);
-}
-
-\"{JSONStringCharacter}*\\u[0-9A-Fa-f]{0,3}\" {
- /* Bad string with an open unicode escape at the end */
- std::string raw(yytext+1);
- size_t pos = raw.size() - 1;
- for (; pos > 0; --pos) {
- char c = raw[pos];
- if (c == 'u') {
- break;
- }
- }
- driver.error(driver.loc_,
- "Overflow unicode escape in " + std::string(yytext),
- pos + 1);
-}
-
-"[" { return AgentParser::make_LSQUARE_BRACKET(driver.loc_); }
-"]" { return AgentParser::make_RSQUARE_BRACKET(driver.loc_); }
-"{" { return AgentParser::make_LCURLY_BRACKET(driver.loc_); }
-"}" { return AgentParser::make_RCURLY_BRACKET(driver.loc_); }
-"," { return AgentParser::make_COMMA(driver.loc_); }
-":" { return AgentParser::make_COLON(driver.loc_); }
-
-{int} {
- /* An integer was found. */
- std::string tmp(yytext);
- int64_t integer = 0;
- try {
- /* In substring we want to use negative values (e.g. -1).
- In enterprise-id we need to use values up to 0xffffffff.
- To cover both of those use cases, we need at least
- int64_t. */
- integer = boost::lexical_cast<int64_t>(tmp);
- } catch (const boost::bad_lexical_cast &) {
- driver.error(driver.loc_, "Failed to convert " + tmp + " to an integer.");
- }
-
- /* The parser needs the string form as double conversion is no lossless */
- return AgentParser::make_INTEGER(integer, driver.loc_);
-}
-
-[-+]?[0-9]*\.?[0-9]*([eE][-+]?[0-9]+)? {
- /* A floating point was found. */
- std::string tmp(yytext);
- double fp = 0.0;
- try {
- fp = boost::lexical_cast<double>(tmp);
- } catch (const boost::bad_lexical_cast &) {
- driver.error(driver.loc_, "Failed to convert " + tmp + " to a floating point.");
- }
-
- return AgentParser::make_FLOAT(fp, driver.loc_);
-}
-
-true|false {
- string tmp(yytext);
- return AgentParser::make_BOOLEAN(tmp == "true", driver.loc_);
-}
-
-null {
- return AgentParser::make_NULL_TYPE(driver.loc_);
-}
-
-(?i:true) driver.error (driver.loc_, "JSON true reserved keyword is lower case only");
-
-(?i:false) driver.error (driver.loc_, "JSON false reserved keyword is lower case only");
-
-(?i:null) driver.error (driver.loc_, "JSON null reserved keyword is lower case only");
-
-<*>. driver.error (driver.loc_, "Invalid character: " + std::string(yytext));
-
-<<EOF>> {
- if (driver.states_.empty()) {
- return AgentParser::make_END(driver.loc_);
- }
- driver.loc_ = driver.locs_.back();
- driver.locs_.pop_back();
- driver.file_ = driver.files_.back();
- driver.files_.pop_back();
- if (driver.sfile_) {
- fclose(driver.sfile_);
- driver.sfile_ = 0;
- }
- if (!driver.sfiles_.empty()) {
- driver.sfile_ = driver.sfiles_.back();
- driver.sfiles_.pop_back();
- }
- agent__delete_buffer(YY_CURRENT_BUFFER);
- agent__switch_to_buffer(driver.states_.back());
- driver.states_.pop_back();
-
- BEGIN(DIR_EXIT);
-}
-
-%%
-
-using namespace isc::dhcp;
-
-void
-ParserContext::scanStringBegin(const std::string& str, ParserType parser_type)
-{
- start_token_flag = true;
- start_token_value = parser_type;
-
- file_ = "<string>";
- sfile_ = 0;
- loc_.initialize(&file_);
- yy_flex_debug = trace_scanning_;
- YY_BUFFER_STATE buffer;
- buffer = agent__scan_bytes(str.c_str(), str.size());
- if (!buffer) {
- fatal("cannot scan string");
- /* fatal() throws an exception so this can't be reached */
- }
-}
-
-void
-ParserContext::scanFileBegin(FILE * f,
- const std::string& filename,
- ParserType parser_type)
-{
- start_token_flag = true;
- start_token_value = parser_type;
-
- file_ = filename;
- sfile_ = f;
- loc_.initialize(&file_);
- yy_flex_debug = trace_scanning_;
- YY_BUFFER_STATE buffer;
-
- /* See agent_lexer.cc header for available definitions */
- buffer = agent__create_buffer(f, 65536 /*buffer size*/);
- if (!buffer) {
- fatal("cannot scan file " + filename);
- }
- agent__switch_to_buffer(buffer);
-}
-
-void
-ParserContext::scanEnd() {
- if (sfile_)
- fclose(sfile_);
- sfile_ = 0;
- static_cast<void>(agent_lex_destroy());
- /* Close files */
- while (!sfiles_.empty()) {
- FILE* f = sfiles_.back();
- if (f) {
- fclose(f);
- }
- sfiles_.pop_back();
- }
- /* Delete states */
- while (!states_.empty()) {
- agent__delete_buffer(states_.back());
- states_.pop_back();
- }
-}
-
-void
-ParserContext::includeFile(const std::string& filename) {
- if (states_.size() > 10) {
- fatal("Too many nested include.");
- }
-
- FILE* f = fopen(filename.c_str(), "r");
- if (!f) {
- fatal("Can't open include file " + filename);
- }
- if (sfile_) {
- sfiles_.push_back(sfile_);
- }
- sfile_ = f;
- states_.push_back(YY_CURRENT_BUFFER);
- YY_BUFFER_STATE buffer;
- buffer = agent__create_buffer(f, 65536 /*buffer size*/);
- if (!buffer) {
- fatal( "Can't scan include file " + filename);
- }
- agent__switch_to_buffer(buffer);
- files_.push_back(file_);
- file_ = filename;
- locs_.push_back(loc_);
- loc_.initialize(&file_);
-
- BEGIN(INITIAL);
-}
-
-namespace {
-/** To avoid unused function error */
-class Dummy {
- /* cppcheck-suppress unusedPrivateFunction */
- void dummy() { yy_fatal_error("Fix me: how to disable its definition?"); }
-};
-}
-#endif /* !__clang_analyzer__ */
+++ /dev/null
-// A Bison parser, made by GNU Bison 3.8.2.
-
-// Skeleton implementation for Bison LALR(1) parsers in C++
-
-// Copyright (C) 2002-2015, 2018-2021 Free Software Foundation, Inc.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <https://www.gnu.org/licenses/>.
-
-// As a special exception, you may create a larger work that contains
-// part or all of the Bison parser skeleton and distribute that work
-// under terms of your choice, so long as that work isn't itself a
-// parser generator using the skeleton or a modified version thereof
-// as a parser skeleton. Alternatively, if you modify or redistribute
-// the parser skeleton itself, you may (at your option) remove this
-// special exception, which will cause the skeleton and the resulting
-// Bison output files to be licensed under the GNU General Public
-// License without this special exception.
-
-// This special exception was added by the Free Software Foundation in
-// version 2.2 of Bison.
-
-// DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual,
-// especially those whose name start with YY_ or yy_. They are
-// private implementation details that can be changed or removed.
-
-
-// Take the name prefix into account.
-#define yylex agent_lex
-
-
-
-#include "agent_parser.h"
-
-
-// Unqualified %code blocks.
-#line 33 "agent_parser.yy"
-
-#include <agent/parser_context.h>
-
-// Avoid warnings with the error counter.
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
-#endif
-
-#line 57 "agent_parser.cc"
-
-
-#ifndef YY_
-# if defined YYENABLE_NLS && YYENABLE_NLS
-# if ENABLE_NLS
-# include <libintl.h> // FIXME: INFRINGES ON USER NAME SPACE.
-# define YY_(msgid) dgettext ("bison-runtime", msgid)
-# endif
-# endif
-# ifndef YY_
-# define YY_(msgid) msgid
-# endif
-#endif
-
-
-// Whether we are compiled with exception support.
-#ifndef YY_EXCEPTIONS
-# if defined __GNUC__ && !defined __EXCEPTIONS
-# define YY_EXCEPTIONS 0
-# else
-# define YY_EXCEPTIONS 1
-# endif
-#endif
-
-#define YYRHSLOC(Rhs, K) ((Rhs)[K].location)
-/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
- If N is 0, then set CURRENT to the empty location which ends
- the previous symbol: RHS[0] (always defined). */
-
-# ifndef YYLLOC_DEFAULT
-# define YYLLOC_DEFAULT(Current, Rhs, N) \
- do \
- if (N) \
- { \
- (Current).begin = YYRHSLOC (Rhs, 1).begin; \
- (Current).end = YYRHSLOC (Rhs, N).end; \
- } \
- else \
- { \
- (Current).begin = (Current).end = YYRHSLOC (Rhs, 0).end; \
- } \
- while (false)
-# endif
-
-
-// Enable debugging if requested.
-#if AGENT_DEBUG
-
-// A pseudo ostream that takes yydebug_ into account.
-# define YYCDEBUG if (yydebug_) (*yycdebug_)
-
-# define YY_SYMBOL_PRINT(Title, Symbol) \
- do { \
- if (yydebug_) \
- { \
- *yycdebug_ << Title << ' '; \
- yy_print_ (*yycdebug_, Symbol); \
- *yycdebug_ << '\n'; \
- } \
- } while (false)
-
-# define YY_REDUCE_PRINT(Rule) \
- do { \
- if (yydebug_) \
- yy_reduce_print_ (Rule); \
- } while (false)
-
-# define YY_STACK_PRINT() \
- do { \
- if (yydebug_) \
- yy_stack_print_ (); \
- } while (false)
-
-#else // !AGENT_DEBUG
-
-# define YYCDEBUG if (false) std::cerr
-# define YY_SYMBOL_PRINT(Title, Symbol) YY_USE (Symbol)
-# define YY_REDUCE_PRINT(Rule) static_cast<void> (0)
-# define YY_STACK_PRINT() static_cast<void> (0)
-
-#endif // !AGENT_DEBUG
-
-#define yyerrok (yyerrstatus_ = 0)
-#define yyclearin (yyla.clear ())
-
-#define YYACCEPT goto yyacceptlab
-#define YYABORT goto yyabortlab
-#define YYERROR goto yyerrorlab
-#define YYRECOVERING() (!!yyerrstatus_)
-
-#line 14 "agent_parser.yy"
-namespace isc { namespace agent {
-#line 150 "agent_parser.cc"
-
- /// Build a parser object.
- AgentParser::AgentParser (isc::agent::ParserContext& ctx_yyarg)
-#if AGENT_DEBUG
- : yydebug_ (false),
- yycdebug_ (&std::cerr),
-#else
- :
-#endif
- ctx (ctx_yyarg)
- {}
-
- AgentParser::~AgentParser ()
- {}
-
- AgentParser::syntax_error::~syntax_error () YY_NOEXCEPT YY_NOTHROW
- {}
-
- /*---------.
- | symbol. |
- `---------*/
-
-
-
- // by_state.
- AgentParser::by_state::by_state () YY_NOEXCEPT
- : state (empty_state)
- {}
-
- AgentParser::by_state::by_state (const by_state& that) YY_NOEXCEPT
- : state (that.state)
- {}
-
- void
- AgentParser::by_state::clear () YY_NOEXCEPT
- {
- state = empty_state;
- }
-
- void
- AgentParser::by_state::move (by_state& that)
- {
- state = that.state;
- that.clear ();
- }
-
- AgentParser::by_state::by_state (state_type s) YY_NOEXCEPT
- : state (s)
- {}
-
- AgentParser::symbol_kind_type
- AgentParser::by_state::kind () const YY_NOEXCEPT
- {
- if (state == empty_state)
- return symbol_kind::S_YYEMPTY;
- else
- return YY_CAST (symbol_kind_type, yystos_[+state]);
- }
-
- AgentParser::stack_symbol_type::stack_symbol_type ()
- {}
-
- AgentParser::stack_symbol_type::stack_symbol_type (YY_RVREF (stack_symbol_type) that)
- : super_type (YY_MOVE (that.state), YY_MOVE (that.location))
- {
- switch (that.kind ())
- {
- case symbol_kind::S_value: // value
- case symbol_kind::S_map_value: // map_value
- case symbol_kind::S_socket_type_value: // socket_type_value
- case symbol_kind::S_auth_type_value: // auth_type_value
- value.YY_MOVE_OR_COPY< ElementPtr > (YY_MOVE (that.value));
- break;
-
- case symbol_kind::S_BOOLEAN: // "boolean"
- value.YY_MOVE_OR_COPY< bool > (YY_MOVE (that.value));
- break;
-
- case symbol_kind::S_FLOAT: // "floating point"
- value.YY_MOVE_OR_COPY< double > (YY_MOVE (that.value));
- break;
-
- case symbol_kind::S_INTEGER: // "integer"
- value.YY_MOVE_OR_COPY< int64_t > (YY_MOVE (that.value));
- break;
-
- case symbol_kind::S_STRING: // "constant string"
- value.YY_MOVE_OR_COPY< std::string > (YY_MOVE (that.value));
- break;
-
- default:
- break;
- }
-
-#if 201103L <= YY_CPLUSPLUS
- // that is emptied.
- that.state = empty_state;
-#endif
- }
-
- AgentParser::stack_symbol_type::stack_symbol_type (state_type s, YY_MOVE_REF (symbol_type) that)
- : super_type (s, YY_MOVE (that.location))
- {
- switch (that.kind ())
- {
- case symbol_kind::S_value: // value
- case symbol_kind::S_map_value: // map_value
- case symbol_kind::S_socket_type_value: // socket_type_value
- case symbol_kind::S_auth_type_value: // auth_type_value
- value.move< ElementPtr > (YY_MOVE (that.value));
- break;
-
- case symbol_kind::S_BOOLEAN: // "boolean"
- value.move< bool > (YY_MOVE (that.value));
- break;
-
- case symbol_kind::S_FLOAT: // "floating point"
- value.move< double > (YY_MOVE (that.value));
- break;
-
- case symbol_kind::S_INTEGER: // "integer"
- value.move< int64_t > (YY_MOVE (that.value));
- break;
-
- case symbol_kind::S_STRING: // "constant string"
- value.move< std::string > (YY_MOVE (that.value));
- break;
-
- default:
- break;
- }
-
- // that is emptied.
- that.kind_ = symbol_kind::S_YYEMPTY;
- }
-
-#if YY_CPLUSPLUS < 201103L
- AgentParser::stack_symbol_type&
- AgentParser::stack_symbol_type::operator= (const stack_symbol_type& that)
- {
- state = that.state;
- switch (that.kind ())
- {
- case symbol_kind::S_value: // value
- case symbol_kind::S_map_value: // map_value
- case symbol_kind::S_socket_type_value: // socket_type_value
- case symbol_kind::S_auth_type_value: // auth_type_value
- value.copy< ElementPtr > (that.value);
- break;
-
- case symbol_kind::S_BOOLEAN: // "boolean"
- value.copy< bool > (that.value);
- break;
-
- case symbol_kind::S_FLOAT: // "floating point"
- value.copy< double > (that.value);
- break;
-
- case symbol_kind::S_INTEGER: // "integer"
- value.copy< int64_t > (that.value);
- break;
-
- case symbol_kind::S_STRING: // "constant string"
- value.copy< std::string > (that.value);
- break;
-
- default:
- break;
- }
-
- location = that.location;
- return *this;
- }
-
- AgentParser::stack_symbol_type&
- AgentParser::stack_symbol_type::operator= (stack_symbol_type& that)
- {
- state = that.state;
- switch (that.kind ())
- {
- case symbol_kind::S_value: // value
- case symbol_kind::S_map_value: // map_value
- case symbol_kind::S_socket_type_value: // socket_type_value
- case symbol_kind::S_auth_type_value: // auth_type_value
- value.move< ElementPtr > (that.value);
- break;
-
- case symbol_kind::S_BOOLEAN: // "boolean"
- value.move< bool > (that.value);
- break;
-
- case symbol_kind::S_FLOAT: // "floating point"
- value.move< double > (that.value);
- break;
-
- case symbol_kind::S_INTEGER: // "integer"
- value.move< int64_t > (that.value);
- break;
-
- case symbol_kind::S_STRING: // "constant string"
- value.move< std::string > (that.value);
- break;
-
- default:
- break;
- }
-
- location = that.location;
- // that is emptied.
- that.state = empty_state;
- return *this;
- }
-#endif
-
- template <typename Base>
- void
- AgentParser::yy_destroy_ (const char* yymsg, basic_symbol<Base>& yysym) const
- {
- if (yymsg)
- YY_SYMBOL_PRINT (yymsg, yysym);
- }
-
-#if AGENT_DEBUG
- template <typename Base>
- void
- AgentParser::yy_print_ (std::ostream& yyo, const basic_symbol<Base>& yysym) const
- {
- std::ostream& yyoutput = yyo;
- YY_USE (yyoutput);
- if (yysym.empty ())
- yyo << "empty symbol";
- else
- {
- symbol_kind_type yykind = yysym.kind ();
- yyo << (yykind < YYNTOKENS ? "token" : "nterm")
- << ' ' << yysym.name () << " ("
- << yysym.location << ": ";
- switch (yykind)
- {
- case symbol_kind::S_STRING: // "constant string"
-#line 124 "agent_parser.yy"
- { yyoutput << yysym.value.template as < std::string > (); }
-#line 393 "agent_parser.cc"
- break;
-
- case symbol_kind::S_INTEGER: // "integer"
-#line 124 "agent_parser.yy"
- { yyoutput << yysym.value.template as < int64_t > (); }
-#line 399 "agent_parser.cc"
- break;
-
- case symbol_kind::S_FLOAT: // "floating point"
-#line 124 "agent_parser.yy"
- { yyoutput << yysym.value.template as < double > (); }
-#line 405 "agent_parser.cc"
- break;
-
- case symbol_kind::S_BOOLEAN: // "boolean"
-#line 124 "agent_parser.yy"
- { yyoutput << yysym.value.template as < bool > (); }
-#line 411 "agent_parser.cc"
- break;
-
- case symbol_kind::S_value: // value
-#line 124 "agent_parser.yy"
- { yyoutput << yysym.value.template as < ElementPtr > (); }
-#line 417 "agent_parser.cc"
- break;
-
- case symbol_kind::S_map_value: // map_value
-#line 124 "agent_parser.yy"
- { yyoutput << yysym.value.template as < ElementPtr > (); }
-#line 423 "agent_parser.cc"
- break;
-
- case symbol_kind::S_socket_type_value: // socket_type_value
-#line 124 "agent_parser.yy"
- { yyoutput << yysym.value.template as < ElementPtr > (); }
-#line 429 "agent_parser.cc"
- break;
-
- case symbol_kind::S_auth_type_value: // auth_type_value
-#line 124 "agent_parser.yy"
- { yyoutput << yysym.value.template as < ElementPtr > (); }
-#line 435 "agent_parser.cc"
- break;
-
- default:
- break;
- }
- yyo << ')';
- }
- }
-#endif
-
- void
- AgentParser::yypush_ (const char* m, YY_MOVE_REF (stack_symbol_type) sym)
- {
- if (m)
- YY_SYMBOL_PRINT (m, sym);
- yystack_.push (YY_MOVE (sym));
- }
-
- void
- AgentParser::yypush_ (const char* m, state_type s, YY_MOVE_REF (symbol_type) sym)
- {
-#if 201103L <= YY_CPLUSPLUS
- yypush_ (m, stack_symbol_type (s, std::move (sym)));
-#else
- stack_symbol_type ss (s, sym);
- yypush_ (m, ss);
-#endif
- }
-
- void
- AgentParser::yypop_ (int n) YY_NOEXCEPT
- {
- yystack_.pop (n);
- }
-
-#if AGENT_DEBUG
- std::ostream&
- AgentParser::debug_stream () const
- {
- return *yycdebug_;
- }
-
- void
- AgentParser::set_debug_stream (std::ostream& o)
- {
- yycdebug_ = &o;
- }
-
-
- AgentParser::debug_level_type
- AgentParser::debug_level () const
- {
- return yydebug_;
- }
-
- void
- AgentParser::set_debug_level (debug_level_type l)
- {
- yydebug_ = l;
- }
-#endif // AGENT_DEBUG
-
- AgentParser::state_type
- AgentParser::yy_lr_goto_state_ (state_type yystate, int yysym)
- {
- int yyr = yypgoto_[yysym - YYNTOKENS] + yystate;
- if (0 <= yyr && yyr <= yylast_ && yycheck_[yyr] == yystate)
- return yytable_[yyr];
- else
- return yydefgoto_[yysym - YYNTOKENS];
- }
-
- bool
- AgentParser::yy_pact_value_is_default_ (int yyvalue) YY_NOEXCEPT
- {
- return yyvalue == yypact_ninf_;
- }
-
- bool
- AgentParser::yy_table_value_is_error_ (int yyvalue) YY_NOEXCEPT
- {
- return yyvalue == yytable_ninf_;
- }
-
- int
- AgentParser::operator() ()
- {
- return parse ();
- }
-
- int
- AgentParser::parse ()
- {
- int yyn;
- /// Length of the RHS of the rule being reduced.
- int yylen = 0;
-
- // Error handling.
- int yynerrs_ = 0;
- int yyerrstatus_ = 0;
-
- /// The lookahead symbol.
- symbol_type yyla;
-
- /// The locations where the error started and ended.
- stack_symbol_type yyerror_range[3];
-
- /// The return value of parse ().
- int yyresult;
-
-#if YY_EXCEPTIONS
- try
-#endif // YY_EXCEPTIONS
- {
- YYCDEBUG << "Starting parse\n";
-
-
- /* Initialize the stack. The initial state will be set in
- yynewstate, since the latter expects the semantical and the
- location values to have been already stored, initialize these
- stacks with a primary value. */
- yystack_.clear ();
- yypush_ (YY_NULLPTR, 0, YY_MOVE (yyla));
-
- /*-----------------------------------------------.
- | yynewstate -- push a new symbol on the stack. |
- `-----------------------------------------------*/
- yynewstate:
- YYCDEBUG << "Entering state " << int (yystack_[0].state) << '\n';
- YY_STACK_PRINT ();
-
- // Accept?
- if (yystack_[0].state == yyfinal_)
- YYACCEPT;
-
- goto yybackup;
-
-
- /*-----------.
- | yybackup. |
- `-----------*/
- yybackup:
- // Try to take a decision without lookahead.
- yyn = yypact_[+yystack_[0].state];
- if (yy_pact_value_is_default_ (yyn))
- goto yydefault;
-
- // Read a lookahead token.
- if (yyla.empty ())
- {
- YYCDEBUG << "Reading a token\n";
-#if YY_EXCEPTIONS
- try
-#endif // YY_EXCEPTIONS
- {
- symbol_type yylookahead (yylex (ctx));
- yyla.move (yylookahead);
- }
-#if YY_EXCEPTIONS
- catch (const syntax_error& yyexc)
- {
- YYCDEBUG << "Caught exception: " << yyexc.what() << '\n';
- error (yyexc);
- goto yyerrlab1;
- }
-#endif // YY_EXCEPTIONS
- }
- YY_SYMBOL_PRINT ("Next token is", yyla);
-
- if (yyla.kind () == symbol_kind::S_YYerror)
- {
- // The scanner already issued an error message, process directly
- // to error recovery. But do not keep the error token as
- // lookahead, it is too special and may lead us to an endless
- // loop in error recovery. */
- yyla.kind_ = symbol_kind::S_YYUNDEF;
- goto yyerrlab1;
- }
-
- /* If the proper action on seeing token YYLA.TYPE is to reduce or
- to detect an error, take that action. */
- yyn += yyla.kind ();
- if (yyn < 0 || yylast_ < yyn || yycheck_[yyn] != yyla.kind ())
- {
- goto yydefault;
- }
-
- // Reduce or error.
- yyn = yytable_[yyn];
- if (yyn <= 0)
- {
- if (yy_table_value_is_error_ (yyn))
- goto yyerrlab;
- yyn = -yyn;
- goto yyreduce;
- }
-
- // Count tokens shifted since error; after three, turn off error status.
- if (yyerrstatus_)
- --yyerrstatus_;
-
- // Shift the lookahead token.
- yypush_ ("Shifting", state_type (yyn), YY_MOVE (yyla));
- goto yynewstate;
-
-
- /*-----------------------------------------------------------.
- | yydefault -- do the default action for the current state. |
- `-----------------------------------------------------------*/
- yydefault:
- yyn = yydefact_[+yystack_[0].state];
- if (yyn == 0)
- goto yyerrlab;
- goto yyreduce;
-
-
- /*-----------------------------.
- | yyreduce -- do a reduction. |
- `-----------------------------*/
- yyreduce:
- yylen = yyr2_[yyn];
- {
- stack_symbol_type yylhs;
- yylhs.state = yy_lr_goto_state_ (yystack_[yylen].state, yyr1_[yyn]);
- /* Variants are always initialized to an empty instance of the
- correct type. The default '$$ = $1' action is NOT applied
- when using variants. */
- switch (yyr1_[yyn])
- {
- case symbol_kind::S_value: // value
- case symbol_kind::S_map_value: // map_value
- case symbol_kind::S_socket_type_value: // socket_type_value
- case symbol_kind::S_auth_type_value: // auth_type_value
- yylhs.value.emplace< ElementPtr > ();
- break;
-
- case symbol_kind::S_BOOLEAN: // "boolean"
- yylhs.value.emplace< bool > ();
- break;
-
- case symbol_kind::S_FLOAT: // "floating point"
- yylhs.value.emplace< double > ();
- break;
-
- case symbol_kind::S_INTEGER: // "integer"
- yylhs.value.emplace< int64_t > ();
- break;
-
- case symbol_kind::S_STRING: // "constant string"
- yylhs.value.emplace< std::string > ();
- break;
-
- default:
- break;
- }
-
-
- // Default location.
- {
- stack_type::slice range (yystack_, yylen);
- YYLLOC_DEFAULT (yylhs.location, range, yylen);
- yyerror_range[1].location = yylhs.location;
- }
-
- // Perform the reduction.
- YY_REDUCE_PRINT (yyn);
-#if YY_EXCEPTIONS
- try
-#endif // YY_EXCEPTIONS
- {
- switch (yyn)
- {
- case 2: // $@1: %empty
-#line 135 "agent_parser.yy"
- { ctx.ctx_ = ctx.NO_KEYWORDS; }
-#line 711 "agent_parser.cc"
- break;
-
- case 4: // $@2: %empty
-#line 136 "agent_parser.yy"
- { ctx.ctx_ = ctx.CONFIG; }
-#line 717 "agent_parser.cc"
- break;
-
- case 6: // $@3: %empty
-#line 137 "agent_parser.yy"
- { ctx.ctx_ = ctx.AGENT; }
-#line 723 "agent_parser.cc"
- break;
-
- case 8: // $@4: %empty
-#line 145 "agent_parser.yy"
- {
- // Parse the Control-agent map
- ElementPtr m(new MapElement(ctx.loc2pos(yystack_[0].location)));
- ctx.stack_.push_back(m);
-}
-#line 733 "agent_parser.cc"
- break;
-
- case 9: // sub_agent: "{" $@4 global_params "}"
-#line 149 "agent_parser.yy"
- {
- // parsing completed
-}
-#line 741 "agent_parser.cc"
- break;
-
- case 10: // json: value
-#line 156 "agent_parser.yy"
- {
- // Push back the JSON value on the stack
- ctx.stack_.push_back(yystack_[0].value.as < ElementPtr > ());
-}
-#line 750 "agent_parser.cc"
- break;
-
- case 11: // value: "integer"
-#line 162 "agent_parser.yy"
- { yylhs.value.as < ElementPtr > () = ElementPtr(new IntElement(yystack_[0].value.as < int64_t > (), ctx.loc2pos(yystack_[0].location))); }
-#line 756 "agent_parser.cc"
- break;
-
- case 12: // value: "floating point"
-#line 163 "agent_parser.yy"
- { yylhs.value.as < ElementPtr > () = ElementPtr(new DoubleElement(yystack_[0].value.as < double > (), ctx.loc2pos(yystack_[0].location))); }
-#line 762 "agent_parser.cc"
- break;
-
- case 13: // value: "boolean"
-#line 164 "agent_parser.yy"
- { yylhs.value.as < ElementPtr > () = ElementPtr(new BoolElement(yystack_[0].value.as < bool > (), ctx.loc2pos(yystack_[0].location))); }
-#line 768 "agent_parser.cc"
- break;
-
- case 14: // value: "constant string"
-#line 165 "agent_parser.yy"
- { yylhs.value.as < ElementPtr > () = ElementPtr(new StringElement(yystack_[0].value.as < std::string > (), ctx.loc2pos(yystack_[0].location))); }
-#line 774 "agent_parser.cc"
- break;
-
- case 15: // value: "null"
-#line 166 "agent_parser.yy"
- { yylhs.value.as < ElementPtr > () = ElementPtr(new NullElement(ctx.loc2pos(yystack_[0].location))); }
-#line 780 "agent_parser.cc"
- break;
-
- case 16: // value: map
-#line 167 "agent_parser.yy"
- { yylhs.value.as < ElementPtr > () = ctx.stack_.back(); ctx.stack_.pop_back(); }
-#line 786 "agent_parser.cc"
- break;
-
- case 17: // value: list_generic
-#line 168 "agent_parser.yy"
- { yylhs.value.as < ElementPtr > () = ctx.stack_.back(); ctx.stack_.pop_back(); }
-#line 792 "agent_parser.cc"
- break;
-
- case 18: // $@5: %empty
-#line 172 "agent_parser.yy"
- {
- // This code is executed when we're about to start parsing
- // the content of the map
- ElementPtr m(new MapElement(ctx.loc2pos(yystack_[0].location)));
- ctx.stack_.push_back(m);
-}
-#line 803 "agent_parser.cc"
- break;
-
- case 19: // map: "{" $@5 map_content "}"
-#line 177 "agent_parser.yy"
- {
- // map parsing completed. If we ever want to do any wrap up
- // (maybe some sanity checking), this would be the best place
- // for it.
-}
-#line 813 "agent_parser.cc"
- break;
-
- case 20: // map_value: map
-#line 183 "agent_parser.yy"
- { yylhs.value.as < ElementPtr > () = ctx.stack_.back(); ctx.stack_.pop_back(); }
-#line 819 "agent_parser.cc"
- break;
-
- case 23: // not_empty_map: "constant string" ":" value
-#line 197 "agent_parser.yy"
- {
- // map containing a single entry
- ctx.unique(yystack_[2].value.as < std::string > (), ctx.loc2pos(yystack_[2].location));
- ctx.stack_.back()->set(yystack_[2].value.as < std::string > (), yystack_[0].value.as < ElementPtr > ());
- }
-#line 829 "agent_parser.cc"
- break;
-
- case 24: // not_empty_map: not_empty_map "," "constant string" ":" value
-#line 202 "agent_parser.yy"
- {
- // map consisting of a shorter map followed by
- // comma and string:value
- ctx.unique(yystack_[2].value.as < std::string > (), ctx.loc2pos(yystack_[2].location));
- ctx.stack_.back()->set(yystack_[2].value.as < std::string > (), yystack_[0].value.as < ElementPtr > ());
- }
-#line 840 "agent_parser.cc"
- break;
-
- case 25: // not_empty_map: not_empty_map ","
-#line 208 "agent_parser.yy"
- {
- ctx.warnAboutExtraCommas(yystack_[0].location);
- }
-#line 848 "agent_parser.cc"
- break;
-
- case 26: // $@6: %empty
-#line 213 "agent_parser.yy"
- {
- ElementPtr l(new ListElement(ctx.loc2pos(yystack_[0].location)));
- ctx.stack_.push_back(l);
-}
-#line 857 "agent_parser.cc"
- break;
-
- case 27: // list_generic: "[" $@6 list_content "]"
-#line 216 "agent_parser.yy"
- {
-}
-#line 864 "agent_parser.cc"
- break;
-
- case 30: // not_empty_list: value
-#line 223 "agent_parser.yy"
- {
- // List consisting of a single element.
- ctx.stack_.back()->add(yystack_[0].value.as < ElementPtr > ());
- }
-#line 873 "agent_parser.cc"
- break;
-
- case 31: // not_empty_list: not_empty_list "," value
-#line 227 "agent_parser.yy"
- {
- // List ending with , and a value.
- ctx.stack_.back()->add(yystack_[0].value.as < ElementPtr > ());
- }
-#line 882 "agent_parser.cc"
- break;
-
- case 32: // not_empty_list: not_empty_list ","
-#line 231 "agent_parser.yy"
- {
- ctx.warnAboutExtraCommas(yystack_[0].location);
- }
-#line 890 "agent_parser.cc"
- break;
-
- case 33: // unknown_map_entry: "constant string" ":"
-#line 243 "agent_parser.yy"
- {
- const std::string& where = ctx.contextName();
- const std::string& keyword = yystack_[1].value.as < std::string > ();
- error(yystack_[1].location,
- "got unexpected keyword \"" + keyword + "\" in " + where + " map.");
-}
-#line 901 "agent_parser.cc"
- break;
-
- case 34: // $@7: %empty
-#line 251 "agent_parser.yy"
- {
- // This code is executed when we're about to start parsing
- // the content of the map
- ElementPtr m(new MapElement(ctx.loc2pos(yystack_[0].location)));
- ctx.stack_.push_back(m);
-}
-#line 912 "agent_parser.cc"
- break;
-
- case 35: // agent_syntax_map: "{" $@7 global_object "}"
-#line 256 "agent_parser.yy"
- {
- // map parsing completed. If we ever want to do any wrap up
- // (maybe some sanity checking), this would be the best place
- // for it.
-}
-#line 922 "agent_parser.cc"
- break;
-
- case 36: // $@8: %empty
-#line 263 "agent_parser.yy"
- {
- // Let's create a MapElement that will represent it, add it to the
- // top level map (that's already on the stack) and put the new map
- // on the stack as well, so child elements will be able to add
- // themselves to it.
- ctx.unique("Control-agent", ctx.loc2pos(yystack_[0].location));
- ElementPtr m(new MapElement(ctx.loc2pos(yystack_[0].location)));
- ctx.stack_.back()->set("Control-agent", m);
- ctx.stack_.push_back(m);
- ctx.enter(ctx.AGENT);
-}
-#line 938 "agent_parser.cc"
- break;
-
- case 37: // global_object: "Control-agent" $@8 ":" "{" global_params "}"
-#line 273 "agent_parser.yy"
- {
- // Ok, we're done with parsing control-agent. Let's take the map
- // off the stack.
- ctx.stack_.pop_back();
- ctx.leave();
-}
-#line 949 "agent_parser.cc"
- break;
-
- case 39: // global_object_comma: global_object ","
-#line 282 "agent_parser.yy"
- {
- ctx.warnAboutExtraCommas(yystack_[0].location);
-}
-#line 957 "agent_parser.cc"
- break;
-
- case 42: // global_params: global_params ","
-#line 288 "agent_parser.yy"
- {
- ctx.warnAboutExtraCommas(yystack_[0].location);
- }
-#line 965 "agent_parser.cc"
- break;
-
- case 57: // $@9: %empty
-#line 311 "agent_parser.yy"
- {
- ctx.unique("http-host", ctx.loc2pos(yystack_[0].location));
- ctx.enter(ctx.NO_KEYWORDS);
-}
-#line 974 "agent_parser.cc"
- break;
-
- case 58: // http_host: "http-host" $@9 ":" "constant string"
-#line 314 "agent_parser.yy"
- {
- ElementPtr host(new StringElement(yystack_[0].value.as < std::string > (), ctx.loc2pos(yystack_[0].location)));
- ctx.stack_.back()->set("http-host", host);
- ctx.leave();
-}
-#line 984 "agent_parser.cc"
- break;
-
- case 59: // http_port: "http-port" ":" "integer"
-#line 320 "agent_parser.yy"
- {
- ctx.unique("http-port", ctx.loc2pos(yystack_[2].location));
- ElementPtr prf(new IntElement(yystack_[0].value.as < int64_t > (), ctx.loc2pos(yystack_[0].location)));
- ctx.stack_.back()->set("http-port", prf);
-}
-#line 994 "agent_parser.cc"
- break;
-
- case 60: // $@10: %empty
-#line 326 "agent_parser.yy"
- {
- ctx.unique("trust-anchor", ctx.loc2pos(yystack_[0].location));
- ctx.enter(ctx.NO_KEYWORDS);
-}
-#line 1003 "agent_parser.cc"
- break;
-
- case 61: // trust_anchor: "trust-anchor" $@10 ":" "constant string"
-#line 329 "agent_parser.yy"
- {
- ElementPtr ca(new StringElement(yystack_[0].value.as < std::string > (), ctx.loc2pos(yystack_[0].location)));
- ctx.stack_.back()->set("trust-anchor", ca);
- ctx.leave();
-}
-#line 1013 "agent_parser.cc"
- break;
-
- case 62: // $@11: %empty
-#line 335 "agent_parser.yy"
- {
- ctx.unique("cert-file", ctx.loc2pos(yystack_[0].location));
- ctx.enter(ctx.NO_KEYWORDS);
-}
-#line 1022 "agent_parser.cc"
- break;
-
- case 63: // cert_file: "cert-file" $@11 ":" "constant string"
-#line 338 "agent_parser.yy"
- {
- ElementPtr cert(new StringElement(yystack_[0].value.as < std::string > (), ctx.loc2pos(yystack_[0].location)));
- ctx.stack_.back()->set("cert-file", cert);
- ctx.leave();
-}
-#line 1032 "agent_parser.cc"
- break;
-
- case 64: // $@12: %empty
-#line 344 "agent_parser.yy"
- {
- ctx.unique("key-file", ctx.loc2pos(yystack_[0].location));
- ctx.enter(ctx.NO_KEYWORDS);
-}
-#line 1041 "agent_parser.cc"
- break;
-
- case 65: // key_file: "key-file" $@12 ":" "constant string"
-#line 347 "agent_parser.yy"
- {
- ElementPtr key(new StringElement(yystack_[0].value.as < std::string > (), ctx.loc2pos(yystack_[0].location)));
- ctx.stack_.back()->set("key-file", key);
- ctx.leave();
-}
-#line 1051 "agent_parser.cc"
- break;
-
- case 66: // cert_required: "cert-required" ":" "boolean"
-#line 353 "agent_parser.yy"
- {
- ctx.unique("cert-required", ctx.loc2pos(yystack_[2].location));
- ElementPtr req(new BoolElement(yystack_[0].value.as < bool > (), ctx.loc2pos(yystack_[0].location)));
- ctx.stack_.back()->set("cert-required", req);
-}
-#line 1061 "agent_parser.cc"
- break;
-
- case 67: // $@13: %empty
-#line 359 "agent_parser.yy"
- {
- ctx.enter(ctx.NO_KEYWORDS);
-}
-#line 1069 "agent_parser.cc"
- break;
-
- case 68: // user_context: "user-context" $@13 ":" map_value
-#line 361 "agent_parser.yy"
- {
- ElementPtr parent = ctx.stack_.back();
- ElementPtr user_context = yystack_[0].value.as < ElementPtr > ();
- ConstElementPtr old = parent->get("user-context");
-
- // Handle already existing user context
- if (old) {
- // Check if it was a comment or a duplicate
- if ((old->size() != 1) || !old->contains("comment")) {
- std::stringstream msg;
- msg << "duplicate user-context entries (previous at "
- << old->getPosition().str() << ")";
- error(yystack_[3].location, msg.str());
- }
- // Merge the comment
- user_context->set("comment", old->get("comment"));
- }
-
- // Set the user context
- parent->set("user-context", user_context);
- ctx.leave();
-}
-#line 1096 "agent_parser.cc"
- break;
-
- case 69: // $@14: %empty
-#line 384 "agent_parser.yy"
- {
- ctx.enter(ctx.NO_KEYWORDS);
-}
-#line 1104 "agent_parser.cc"
- break;
-
- case 70: // comment: "comment" $@14 ":" "constant string"
-#line 386 "agent_parser.yy"
- {
- ElementPtr parent = ctx.stack_.back();
- ElementPtr user_context(new MapElement(ctx.loc2pos(yystack_[3].location)));
- ElementPtr comment(new StringElement(yystack_[0].value.as < std::string > (), ctx.loc2pos(yystack_[0].location)));
- user_context->set("comment", comment);
-
- // Handle already existing user context
- ConstElementPtr old = parent->get("user-context");
- if (old) {
- // Check for duplicate comment
- if (old->contains("comment")) {
- std::stringstream msg;
- msg << "duplicate user-context/comment entries (previous at "
- << old->getPosition().str() << ")";
- error(yystack_[3].location, msg.str());
- }
- // Merge the user context in the comment
- merge(user_context, old);
- }
-
- // Set the user context
- parent->set("user-context", user_context);
- ctx.leave();
-}
-#line 1133 "agent_parser.cc"
- break;
-
- case 71: // $@15: %empty
-#line 411 "agent_parser.yy"
- {
- ctx.unique("http-headers", ctx.loc2pos(yystack_[0].location));
- ElementPtr l(new ListElement(ctx.loc2pos(yystack_[0].location)));
- ctx.stack_.back()->set("http-headers", l);
- ctx.stack_.push_back(l);
- ctx.enter(ctx.HTTP_HEADERS);
-}
-#line 1145 "agent_parser.cc"
- break;
-
- case 72: // http_headers: "http-headers" $@15 ":" "[" http_header_list "]"
-#line 417 "agent_parser.yy"
- {
- ctx.stack_.pop_back();
- ctx.leave();
-}
-#line 1154 "agent_parser.cc"
- break;
-
- case 77: // not_empty_http_header_list: not_empty_http_header_list ","
-#line 428 "agent_parser.yy"
- {
- ctx.warnAboutExtraCommas(yystack_[0].location);
- }
-#line 1162 "agent_parser.cc"
- break;
-
- case 78: // $@16: %empty
-#line 433 "agent_parser.yy"
- {
- ElementPtr m(new MapElement(ctx.loc2pos(yystack_[0].location)));
- ctx.stack_.back()->add(m);
- ctx.stack_.push_back(m);
-}
-#line 1172 "agent_parser.cc"
- break;
-
- case 79: // http_header: "{" $@16 http_header_params "}"
-#line 437 "agent_parser.yy"
- {
- ctx.stack_.pop_back();
-}
-#line 1180 "agent_parser.cc"
- break;
-
- case 82: // http_header_params: http_header_params ","
-#line 443 "agent_parser.yy"
- {
- ctx.warnAboutExtraCommas(yystack_[0].location);
- }
-#line 1188 "agent_parser.cc"
- break;
-
- case 88: // $@17: %empty
-#line 455 "agent_parser.yy"
- {
- ctx.unique("name", ctx.loc2pos(yystack_[0].location));
- ctx.enter(ctx.NO_KEYWORDS);
-}
-#line 1197 "agent_parser.cc"
- break;
-
- case 89: // name: "name" $@17 ":" "constant string"
-#line 458 "agent_parser.yy"
- {
- ElementPtr name(new StringElement(yystack_[0].value.as < std::string > (), ctx.loc2pos(yystack_[0].location)));
- ctx.stack_.back()->set("name", name);
- ctx.leave();
-}
-#line 1207 "agent_parser.cc"
- break;
-
- case 90: // $@18: %empty
-#line 464 "agent_parser.yy"
- {
- ctx.unique("value", ctx.loc2pos(yystack_[0].location));
- ctx.enter(ctx.NO_KEYWORDS);
-}
-#line 1216 "agent_parser.cc"
- break;
-
- case 91: // header_value: "value" $@18 ":" "constant string"
-#line 467 "agent_parser.yy"
- {
- ElementPtr value(new StringElement(yystack_[0].value.as < std::string > (), ctx.loc2pos(yystack_[0].location)));
- ctx.stack_.back()->set("value", value);
- ctx.leave();
-}
-#line 1226 "agent_parser.cc"
- break;
-
- case 92: // $@19: %empty
-#line 474 "agent_parser.yy"
- {
- ctx.unique("hooks-libraries", ctx.loc2pos(yystack_[0].location));
- ElementPtr l(new ListElement(ctx.loc2pos(yystack_[0].location)));
- ctx.stack_.back()->set("hooks-libraries", l);
- ctx.stack_.push_back(l);
- ctx.enter(ctx.HOOKS_LIBRARIES);
-}
-#line 1238 "agent_parser.cc"
- break;
-
- case 93: // hooks_libraries: "hooks-libraries" $@19 ":" "[" hooks_libraries_list "]"
-#line 480 "agent_parser.yy"
- {
- ctx.stack_.pop_back();
- ctx.leave();
-}
-#line 1247 "agent_parser.cc"
- break;
-
- case 98: // not_empty_hooks_libraries_list: not_empty_hooks_libraries_list ","
-#line 491 "agent_parser.yy"
- {
- ctx.warnAboutExtraCommas(yystack_[0].location);
- }
-#line 1255 "agent_parser.cc"
- break;
-
- case 99: // $@20: %empty
-#line 496 "agent_parser.yy"
- {
- ElementPtr m(new MapElement(ctx.loc2pos(yystack_[0].location)));
- ctx.stack_.back()->add(m);
- ctx.stack_.push_back(m);
-}
-#line 1265 "agent_parser.cc"
- break;
-
- case 100: // hooks_library: "{" $@20 hooks_params "}"
-#line 500 "agent_parser.yy"
- {
- ctx.stack_.pop_back();
-}
-#line 1273 "agent_parser.cc"
- break;
-
- case 103: // hooks_params: hooks_params ","
-#line 506 "agent_parser.yy"
- {
- ctx.warnAboutExtraCommas(yystack_[0].location);
- }
-#line 1281 "agent_parser.cc"
- break;
-
- case 107: // $@21: %empty
-#line 516 "agent_parser.yy"
- {
- ctx.unique("library", ctx.loc2pos(yystack_[0].location));
- ctx.enter(ctx.NO_KEYWORDS);
-}
-#line 1290 "agent_parser.cc"
- break;
-
- case 108: // library: "library" $@21 ":" "constant string"
-#line 519 "agent_parser.yy"
- {
- ElementPtr lib(new StringElement(yystack_[0].value.as < std::string > (), ctx.loc2pos(yystack_[0].location)));
- ctx.stack_.back()->set("library", lib);
- ctx.leave();
-}
-#line 1300 "agent_parser.cc"
- break;
-
- case 109: // $@22: %empty
-#line 525 "agent_parser.yy"
- {
- ctx.unique("parameters", ctx.loc2pos(yystack_[0].location));
- ctx.enter(ctx.NO_KEYWORDS);
-}
-#line 1309 "agent_parser.cc"
- break;
-
- case 110: // parameters: "parameters" $@22 ":" map_value
-#line 528 "agent_parser.yy"
- {
- ctx.stack_.back()->set("parameters", yystack_[0].value.as < ElementPtr > ());
- ctx.leave();
-}
-#line 1318 "agent_parser.cc"
- break;
-
- case 111: // $@23: %empty
-#line 536 "agent_parser.yy"
- {
- ctx.unique("control-sockets", ctx.loc2pos(yystack_[2].location));
- ElementPtr m(new MapElement(ctx.loc2pos(yystack_[2].location)));
- ctx.stack_.back()->set("control-sockets", m);
- ctx.stack_.push_back(m);
- ctx.enter(ctx.CONTROL_SOCKETS);
-}
-#line 1330 "agent_parser.cc"
- break;
-
- case 112: // control_sockets: "control-sockets" ":" "{" $@23 control_sockets_params "}"
-#line 542 "agent_parser.yy"
- {
- ctx.stack_.pop_back();
- ctx.leave();
-}
-#line 1339 "agent_parser.cc"
- break;
-
- case 115: // control_sockets_params: control_sockets_params ","
-#line 552 "agent_parser.yy"
- {
- ctx.warnAboutExtraCommas(yystack_[0].location);
- }
-#line 1347 "agent_parser.cc"
- break;
-
- case 120: // $@24: %empty
-#line 566 "agent_parser.yy"
- {
- ctx.unique("dhcp4", ctx.loc2pos(yystack_[0].location));
- ElementPtr m(new MapElement(ctx.loc2pos(yystack_[0].location)));
- ctx.stack_.back()->set("dhcp4", m);
- ctx.stack_.push_back(m);
- ctx.enter(ctx.SERVER);
-}
-#line 1359 "agent_parser.cc"
- break;
-
- case 121: // dhcp4_server_socket: "dhcp4" $@24 ":" "{" control_socket_params "}"
-#line 572 "agent_parser.yy"
- {
- ctx.stack_.pop_back();
- ctx.leave();
-}
-#line 1368 "agent_parser.cc"
- break;
-
- case 122: // $@25: %empty
-#line 578 "agent_parser.yy"
- {
- ctx.unique("dhcp6", ctx.loc2pos(yystack_[0].location));
- ElementPtr m(new MapElement(ctx.loc2pos(yystack_[0].location)));
- ctx.stack_.back()->set("dhcp6", m);
- ctx.stack_.push_back(m);
- ctx.enter(ctx.SERVER);
-}
-#line 1380 "agent_parser.cc"
- break;
-
- case 123: // dhcp6_server_socket: "dhcp6" $@25 ":" "{" control_socket_params "}"
-#line 584 "agent_parser.yy"
- {
- ctx.stack_.pop_back();
- ctx.leave();
-}
-#line 1389 "agent_parser.cc"
- break;
-
- case 124: // $@26: %empty
-#line 590 "agent_parser.yy"
- {
- ctx.unique("d2", ctx.loc2pos(yystack_[0].location));
- ElementPtr m(new MapElement(ctx.loc2pos(yystack_[0].location)));
- ctx.stack_.back()->set("d2", m);
- ctx.stack_.push_back(m);
- ctx.enter(ctx.SERVER);
-}
-#line 1401 "agent_parser.cc"
- break;
-
- case 125: // d2_server_socket: "d2" $@26 ":" "{" control_socket_params "}"
-#line 596 "agent_parser.yy"
- {
- ctx.stack_.pop_back();
- ctx.leave();
-}
-#line 1410 "agent_parser.cc"
- break;
-
- case 128: // control_socket_params: control_socket_params ","
-#line 604 "agent_parser.yy"
- {
- ctx.warnAboutExtraCommas(yystack_[0].location);
- }
-#line 1418 "agent_parser.cc"
- break;
-
- case 134: // $@27: %empty
-#line 618 "agent_parser.yy"
- {
- ctx.unique("socket-name", ctx.loc2pos(yystack_[0].location));
- ctx.enter(ctx.NO_KEYWORDS);
-}
-#line 1427 "agent_parser.cc"
- break;
-
- case 135: // socket_name: "socket-name" $@27 ":" "constant string"
-#line 621 "agent_parser.yy"
- {
- ElementPtr name(new StringElement(yystack_[0].value.as < std::string > (), ctx.loc2pos(yystack_[0].location)));
- ctx.stack_.back()->set("socket-name", name);
- ctx.leave();
-}
-#line 1437 "agent_parser.cc"
- break;
-
- case 136: // $@28: %empty
-#line 628 "agent_parser.yy"
- {
- ctx.unique("socket-type", ctx.loc2pos(yystack_[0].location));
- ctx.enter(ctx.SOCKET_TYPE);
-}
-#line 1446 "agent_parser.cc"
- break;
-
- case 137: // socket_type: "socket-type" $@28 ":" socket_type_value
-#line 631 "agent_parser.yy"
- {
- ctx.stack_.back()->set("socket-type", yystack_[0].value.as < ElementPtr > ());
- ctx.leave();
-}
-#line 1455 "agent_parser.cc"
- break;
-
- case 138: // socket_type_value: "unix"
-#line 637 "agent_parser.yy"
- { yylhs.value.as < ElementPtr > () = ElementPtr(new StringElement("unix", ctx.loc2pos(yystack_[0].location))); }
-#line 1461 "agent_parser.cc"
- break;
-
- case 139: // $@29: %empty
-#line 644 "agent_parser.yy"
- {
- ctx.unique("authentication", ctx.loc2pos(yystack_[0].location));
- ElementPtr m(new MapElement(ctx.loc2pos(yystack_[0].location)));
- ctx.stack_.back()->set("authentication", m);
- ctx.stack_.push_back(m);
- ctx.enter(ctx.AUTHENTICATION);
-}
-#line 1473 "agent_parser.cc"
- break;
-
- case 140: // authentication: "authentication" $@29 ":" "{" auth_params "}"
-#line 650 "agent_parser.yy"
- {
- // The type parameter is required
- ctx.require("type", ctx.loc2pos(yystack_[2].location), ctx.loc2pos(yystack_[0].location));
- ctx.stack_.pop_back();
- ctx.leave();
-}
-#line 1484 "agent_parser.cc"
- break;
-
- case 143: // auth_params: auth_params ","
-#line 659 "agent_parser.yy"
- {
- ctx.warnAboutExtraCommas(yystack_[0].location);
- }
-#line 1492 "agent_parser.cc"
- break;
-
- case 151: // $@30: %empty
-#line 673 "agent_parser.yy"
- {
- ctx.unique("type", ctx.loc2pos(yystack_[0].location));
- ctx.enter(ctx.AUTH_TYPE);
-}
-#line 1501 "agent_parser.cc"
- break;
-
- case 152: // auth_type: "type" $@30 ":" auth_type_value
-#line 676 "agent_parser.yy"
- {
- ctx.stack_.back()->set("type", yystack_[0].value.as < ElementPtr > ());
- ctx.leave();
-}
-#line 1510 "agent_parser.cc"
- break;
-
- case 153: // auth_type_value: "basic"
-#line 681 "agent_parser.yy"
- { yylhs.value.as < ElementPtr > () = ElementPtr(new StringElement("basic", ctx.loc2pos(yystack_[0].location))); }
-#line 1516 "agent_parser.cc"
- break;
-
- case 154: // $@31: %empty
-#line 684 "agent_parser.yy"
- {
- ctx.unique("realm", ctx.loc2pos(yystack_[0].location));
- ctx.enter(ctx.NO_KEYWORDS);
-}
-#line 1525 "agent_parser.cc"
- break;
-
- case 155: // realm: "realm" $@31 ":" "constant string"
-#line 687 "agent_parser.yy"
- {
- ElementPtr realm(new StringElement(yystack_[0].value.as < std::string > (), ctx.loc2pos(yystack_[0].location)));
- ctx.stack_.back()->set("realm", realm);
- ctx.leave();
-}
-#line 1535 "agent_parser.cc"
- break;
-
- case 156: // $@32: %empty
-#line 693 "agent_parser.yy"
- {
- ctx.unique("directory", ctx.loc2pos(yystack_[0].location));
- ctx.enter(ctx.NO_KEYWORDS);
-}
-#line 1544 "agent_parser.cc"
- break;
-
- case 157: // directory: "directory" $@32 ":" "constant string"
-#line 696 "agent_parser.yy"
- {
- ElementPtr directory(new StringElement(yystack_[0].value.as < std::string > (), ctx.loc2pos(yystack_[0].location)));
- ctx.stack_.back()->set("directory", directory);
- ctx.leave();
-}
-#line 1554 "agent_parser.cc"
- break;
-
- case 158: // $@33: %empty
-#line 702 "agent_parser.yy"
- {
- ctx.unique("clients", ctx.loc2pos(yystack_[0].location));
- ElementPtr l(new ListElement(ctx.loc2pos(yystack_[0].location)));
- ctx.stack_.back()->set("clients", l);
- ctx.stack_.push_back(l);
- ctx.enter(ctx.CLIENTS);
-}
-#line 1566 "agent_parser.cc"
- break;
-
- case 159: // clients: "clients" $@33 ":" "[" clients_list "]"
-#line 708 "agent_parser.yy"
- {
- ctx.stack_.pop_back();
- ctx.leave();
-}
-#line 1575 "agent_parser.cc"
- break;
-
- case 164: // not_empty_clients_list: not_empty_clients_list ","
-#line 719 "agent_parser.yy"
- {
- ctx.warnAboutExtraCommas(yystack_[0].location);
- }
-#line 1583 "agent_parser.cc"
- break;
-
- case 165: // $@34: %empty
-#line 724 "agent_parser.yy"
- {
- ElementPtr m(new MapElement(ctx.loc2pos(yystack_[0].location)));
- ctx.stack_.back()->add(m);
- ctx.stack_.push_back(m);
-}
-#line 1593 "agent_parser.cc"
- break;
-
- case 166: // basic_auth: "{" $@34 clients_params "}"
-#line 728 "agent_parser.yy"
- {
- ctx.stack_.pop_back();
-}
-#line 1601 "agent_parser.cc"
- break;
-
- case 169: // clients_params: clients_params ","
-#line 734 "agent_parser.yy"
- {
- ctx.warnAboutExtraCommas(yystack_[0].location);
- }
-#line 1609 "agent_parser.cc"
- break;
-
- case 177: // $@35: %empty
-#line 748 "agent_parser.yy"
- {
- ctx.unique("user", ctx.loc2pos(yystack_[0].location));
- ctx.enter(ctx.NO_KEYWORDS);
-}
-#line 1618 "agent_parser.cc"
- break;
-
- case 178: // user: "user" $@35 ":" "constant string"
-#line 751 "agent_parser.yy"
- {
- ElementPtr user(new StringElement(yystack_[0].value.as < std::string > (), ctx.loc2pos(yystack_[0].location)));
- ctx.stack_.back()->set("user", user);
- ctx.leave();
-}
-#line 1628 "agent_parser.cc"
- break;
-
- case 179: // $@36: %empty
-#line 757 "agent_parser.yy"
- {
- ctx.unique("user-file", ctx.loc2pos(yystack_[0].location));
- ctx.enter(ctx.NO_KEYWORDS);
-}
-#line 1637 "agent_parser.cc"
- break;
-
- case 180: // user_file: "user-file" $@36 ":" "constant string"
-#line 760 "agent_parser.yy"
- {
- ElementPtr user(new StringElement(yystack_[0].value.as < std::string > (), ctx.loc2pos(yystack_[0].location)));
- ctx.stack_.back()->set("user-file", user);
- ctx.leave();
-}
-#line 1647 "agent_parser.cc"
- break;
-
- case 181: // $@37: %empty
-#line 766 "agent_parser.yy"
- {
- ctx.unique("password", ctx.loc2pos(yystack_[0].location));
- ctx.enter(ctx.NO_KEYWORDS);
-}
-#line 1656 "agent_parser.cc"
- break;
-
- case 182: // password: "password" $@37 ":" "constant string"
-#line 769 "agent_parser.yy"
- {
- ElementPtr password(new StringElement(yystack_[0].value.as < std::string > (), ctx.loc2pos(yystack_[0].location)));
- ctx.stack_.back()->set("password", password);
- ctx.leave();
-}
-#line 1666 "agent_parser.cc"
- break;
-
- case 183: // $@38: %empty
-#line 775 "agent_parser.yy"
- {
- ctx.unique("password-file", ctx.loc2pos(yystack_[0].location));
- ctx.enter(ctx.NO_KEYWORDS);
-}
-#line 1675 "agent_parser.cc"
- break;
-
- case 184: // password_file: "password-file" $@38 ":" "constant string"
-#line 778 "agent_parser.yy"
- {
- ElementPtr password(new StringElement(yystack_[0].value.as < std::string > (), ctx.loc2pos(yystack_[0].location)));
- ctx.stack_.back()->set("password-file", password);
- ctx.leave();
-}
-#line 1685 "agent_parser.cc"
- break;
-
- case 185: // $@39: %empty
-#line 788 "agent_parser.yy"
- {
- ctx.unique("loggers", ctx.loc2pos(yystack_[0].location));
- ElementPtr l(new ListElement(ctx.loc2pos(yystack_[0].location)));
- ctx.stack_.back()->set("loggers", l);
- ctx.stack_.push_back(l);
- ctx.enter(ctx.LOGGERS);
-}
-#line 1697 "agent_parser.cc"
- break;
-
- case 186: // loggers: "loggers" $@39 ":" "[" loggers_entries "]"
-#line 794 "agent_parser.yy"
- {
- ctx.stack_.pop_back();
- ctx.leave();
-}
-#line 1706 "agent_parser.cc"
- break;
-
- case 189: // loggers_entries: loggers_entries ","
-#line 803 "agent_parser.yy"
- {
- ctx.warnAboutExtraCommas(yystack_[0].location);
- }
-#line 1714 "agent_parser.cc"
- break;
-
- case 190: // $@40: %empty
-#line 809 "agent_parser.yy"
- {
- ElementPtr l(new MapElement(ctx.loc2pos(yystack_[0].location)));
- ctx.stack_.back()->add(l);
- ctx.stack_.push_back(l);
-}
-#line 1724 "agent_parser.cc"
- break;
-
- case 191: // logger_entry: "{" $@40 logger_params "}"
-#line 813 "agent_parser.yy"
- {
- ctx.stack_.pop_back();
-}
-#line 1732 "agent_parser.cc"
- break;
-
- case 194: // logger_params: logger_params ","
-#line 819 "agent_parser.yy"
- {
- ctx.warnAboutExtraCommas(yystack_[0].location);
- }
-#line 1740 "agent_parser.cc"
- break;
-
- case 202: // debuglevel: "debuglevel" ":" "integer"
-#line 833 "agent_parser.yy"
- {
- ctx.unique("debuglevel", ctx.loc2pos(yystack_[2].location));
- ElementPtr dl(new IntElement(yystack_[0].value.as < int64_t > (), ctx.loc2pos(yystack_[0].location)));
- ctx.stack_.back()->set("debuglevel", dl);
-}
-#line 1750 "agent_parser.cc"
- break;
-
- case 203: // $@41: %empty
-#line 839 "agent_parser.yy"
- {
- ctx.unique("severity", ctx.loc2pos(yystack_[0].location));
- ctx.enter(ctx.NO_KEYWORDS);
-}
-#line 1759 "agent_parser.cc"
- break;
-
- case 204: // severity: "severity" $@41 ":" "constant string"
-#line 842 "agent_parser.yy"
- {
- ElementPtr sev(new StringElement(yystack_[0].value.as < std::string > (), ctx.loc2pos(yystack_[0].location)));
- ctx.stack_.back()->set("severity", sev);
- ctx.leave();
-}
-#line 1769 "agent_parser.cc"
- break;
-
- case 205: // $@42: %empty
-#line 848 "agent_parser.yy"
- {
- ctx.unique("output-options", ctx.loc2pos(yystack_[0].location));
- ElementPtr l(new ListElement(ctx.loc2pos(yystack_[0].location)));
- ctx.stack_.back()->set("output-options", l);
- ctx.stack_.push_back(l);
- ctx.enter(ctx.OUTPUT_OPTIONS);
-}
-#line 1781 "agent_parser.cc"
- break;
-
- case 206: // output_options_list: "output-options" $@42 ":" "[" output_options_list_content "]"
-#line 854 "agent_parser.yy"
- {
- ctx.stack_.pop_back();
- ctx.leave();
-}
-#line 1790 "agent_parser.cc"
- break;
-
- case 209: // output_options_list_content: output_options_list_content ","
-#line 861 "agent_parser.yy"
- {
- ctx.warnAboutExtraCommas(yystack_[0].location);
- }
-#line 1798 "agent_parser.cc"
- break;
-
- case 210: // $@43: %empty
-#line 866 "agent_parser.yy"
- {
- ElementPtr m(new MapElement(ctx.loc2pos(yystack_[0].location)));
- ctx.stack_.back()->add(m);
- ctx.stack_.push_back(m);
-}
-#line 1808 "agent_parser.cc"
- break;
-
- case 211: // output_entry: "{" $@43 output_params_list "}"
-#line 870 "agent_parser.yy"
- {
- ctx.stack_.pop_back();
-}
-#line 1816 "agent_parser.cc"
- break;
-
- case 214: // output_params_list: output_params_list ","
-#line 876 "agent_parser.yy"
- {
- ctx.warnAboutExtraCommas(yystack_[0].location);
- }
-#line 1824 "agent_parser.cc"
- break;
-
- case 220: // $@44: %empty
-#line 888 "agent_parser.yy"
- {
- ctx.unique("output", ctx.loc2pos(yystack_[0].location));
- ctx.enter(ctx.NO_KEYWORDS);
-}
-#line 1833 "agent_parser.cc"
- break;
-
- case 221: // output: "output" $@44 ":" "constant string"
-#line 891 "agent_parser.yy"
- {
- ElementPtr sev(new StringElement(yystack_[0].value.as < std::string > (), ctx.loc2pos(yystack_[0].location)));
- ctx.stack_.back()->set("output", sev);
- ctx.leave();
-}
-#line 1843 "agent_parser.cc"
- break;
-
- case 222: // flush: "flush" ":" "boolean"
-#line 897 "agent_parser.yy"
- {
- ctx.unique("flush", ctx.loc2pos(yystack_[2].location));
- ElementPtr flush(new BoolElement(yystack_[0].value.as < bool > (), ctx.loc2pos(yystack_[0].location)));
- ctx.stack_.back()->set("flush", flush);
-}
-#line 1853 "agent_parser.cc"
- break;
-
- case 223: // maxsize: "maxsize" ":" "integer"
-#line 903 "agent_parser.yy"
- {
- ctx.unique("maxsize", ctx.loc2pos(yystack_[2].location));
- ElementPtr maxsize(new IntElement(yystack_[0].value.as < int64_t > (), ctx.loc2pos(yystack_[0].location)));
- ctx.stack_.back()->set("maxsize", maxsize);
-}
-#line 1863 "agent_parser.cc"
- break;
-
- case 224: // maxver: "maxver" ":" "integer"
-#line 909 "agent_parser.yy"
- {
- ctx.unique("maxver", ctx.loc2pos(yystack_[2].location));
- ElementPtr maxver(new IntElement(yystack_[0].value.as < int64_t > (), ctx.loc2pos(yystack_[0].location)));
- ctx.stack_.back()->set("maxver", maxver);
-}
-#line 1873 "agent_parser.cc"
- break;
-
- case 225: // $@45: %empty
-#line 915 "agent_parser.yy"
- {
- ctx.unique("pattern", ctx.loc2pos(yystack_[0].location));
- ctx.enter(ctx.NO_KEYWORDS);
-}
-#line 1882 "agent_parser.cc"
- break;
-
- case 226: // pattern: "pattern" $@45 ":" "constant string"
-#line 918 "agent_parser.yy"
- {
- ElementPtr sev(new StringElement(yystack_[0].value.as < std::string > (), ctx.loc2pos(yystack_[0].location)));
- ctx.stack_.back()->set("pattern", sev);
- ctx.leave();
-}
-#line 1892 "agent_parser.cc"
- break;
-
-
-#line 1896 "agent_parser.cc"
-
- default:
- break;
- }
- }
-#if YY_EXCEPTIONS
- catch (const syntax_error& yyexc)
- {
- YYCDEBUG << "Caught exception: " << yyexc.what() << '\n';
- error (yyexc);
- YYERROR;
- }
-#endif // YY_EXCEPTIONS
- YY_SYMBOL_PRINT ("-> $$ =", yylhs);
- yypop_ (yylen);
- yylen = 0;
-
- // Shift the result of the reduction.
- yypush_ (YY_NULLPTR, YY_MOVE (yylhs));
- }
- goto yynewstate;
-
-
- /*--------------------------------------.
- | yyerrlab -- here on detecting error. |
- `--------------------------------------*/
- yyerrlab:
- // If not already recovering from an error, report this error.
- if (!yyerrstatus_)
- {
- ++yynerrs_;
- context yyctx (*this, yyla);
- std::string msg = yysyntax_error_ (yyctx);
- error (yyla.location, YY_MOVE (msg));
- }
-
-
- yyerror_range[1].location = yyla.location;
- if (yyerrstatus_ == 3)
- {
- /* If just tried and failed to reuse lookahead token after an
- error, discard it. */
-
- // Return failure if at end of input.
- if (yyla.kind () == symbol_kind::S_YYEOF)
- YYABORT;
- else if (!yyla.empty ())
- {
- yy_destroy_ ("Error: discarding", yyla);
- yyla.clear ();
- }
- }
-
- // Else will try to reuse lookahead token after shifting the error token.
- goto yyerrlab1;
-
-
- /*---------------------------------------------------.
- | yyerrorlab -- error raised explicitly by YYERROR. |
- `---------------------------------------------------*/
- yyerrorlab:
- /* Pacify compilers when the user code never invokes YYERROR and
- the label yyerrorlab therefore never appears in user code. */
- if (false)
- YYERROR;
-
- /* Do not reclaim the symbols of the rule whose action triggered
- this YYERROR. */
- yypop_ (yylen);
- yylen = 0;
- YY_STACK_PRINT ();
- goto yyerrlab1;
-
-
- /*-------------------------------------------------------------.
- | yyerrlab1 -- common code for both syntax error and YYERROR. |
- `-------------------------------------------------------------*/
- yyerrlab1:
- yyerrstatus_ = 3; // Each real token shifted decrements this.
- // Pop stack until we find a state that shifts the error token.
- for (;;)
- {
- yyn = yypact_[+yystack_[0].state];
- if (!yy_pact_value_is_default_ (yyn))
- {
- yyn += symbol_kind::S_YYerror;
- if (0 <= yyn && yyn <= yylast_
- && yycheck_[yyn] == symbol_kind::S_YYerror)
- {
- yyn = yytable_[yyn];
- if (0 < yyn)
- break;
- }
- }
-
- // Pop the current state because it cannot handle the error token.
- if (yystack_.size () == 1)
- YYABORT;
-
- yyerror_range[1].location = yystack_[0].location;
- yy_destroy_ ("Error: popping", yystack_[0]);
- yypop_ ();
- YY_STACK_PRINT ();
- }
- {
- stack_symbol_type error_token;
-
- yyerror_range[2].location = yyla.location;
- YYLLOC_DEFAULT (error_token.location, yyerror_range, 2);
-
- // Shift the error token.
- error_token.state = state_type (yyn);
- yypush_ ("Shifting", YY_MOVE (error_token));
- }
- goto yynewstate;
-
-
- /*-------------------------------------.
- | yyacceptlab -- YYACCEPT comes here. |
- `-------------------------------------*/
- yyacceptlab:
- yyresult = 0;
- goto yyreturn;
-
-
- /*-----------------------------------.
- | yyabortlab -- YYABORT comes here. |
- `-----------------------------------*/
- yyabortlab:
- yyresult = 1;
- goto yyreturn;
-
-
- /*-----------------------------------------------------.
- | yyreturn -- parsing is finished, return the result. |
- `-----------------------------------------------------*/
- yyreturn:
- if (!yyla.empty ())
- yy_destroy_ ("Cleanup: discarding lookahead", yyla);
-
- /* Do not reclaim the symbols of the rule whose action triggered
- this YYABORT or YYACCEPT. */
- yypop_ (yylen);
- YY_STACK_PRINT ();
- while (1 < yystack_.size ())
- {
- yy_destroy_ ("Cleanup: popping", yystack_[0]);
- yypop_ ();
- }
-
- return yyresult;
- }
-#if YY_EXCEPTIONS
- catch (...)
- {
- YYCDEBUG << "Exception caught: cleaning lookahead and stack\n";
- // Do not try to display the values of the reclaimed symbols,
- // as their printers might throw an exception.
- if (!yyla.empty ())
- yy_destroy_ (YY_NULLPTR, yyla);
-
- while (1 < yystack_.size ())
- {
- yy_destroy_ (YY_NULLPTR, yystack_[0]);
- yypop_ ();
- }
- throw;
- }
-#endif // YY_EXCEPTIONS
- }
-
- void
- AgentParser::error (const syntax_error& yyexc)
- {
- error (yyexc.location, yyexc.what ());
- }
-
- /* Return YYSTR after stripping away unnecessary quotes and
- backslashes, so that it's suitable for yyerror. The heuristic is
- that double-quoting is unnecessary unless the string contains an
- apostrophe, a comma, or backslash (other than backslash-backslash).
- YYSTR is taken from yytname. */
- std::string
- AgentParser::yytnamerr_ (const char *yystr)
- {
- if (*yystr == '"')
- {
- std::string yyr;
- char const *yyp = yystr;
-
- for (;;)
- switch (*++yyp)
- {
- case '\'':
- case ',':
- goto do_not_strip_quotes;
-
- case '\\':
- if (*++yyp != '\\')
- goto do_not_strip_quotes;
- else
- goto append;
-
- append:
- default:
- yyr += *yyp;
- break;
-
- case '"':
- return yyr;
- }
- do_not_strip_quotes: ;
- }
-
- return yystr;
- }
-
- std::string
- AgentParser::symbol_name (symbol_kind_type yysymbol)
- {
- return yytnamerr_ (yytname_[yysymbol]);
- }
-
-
-
- // AgentParser::context.
- AgentParser::context::context (const AgentParser& yyparser, const symbol_type& yyla)
- : yyparser_ (yyparser)
- , yyla_ (yyla)
- {}
-
- int
- AgentParser::context::expected_tokens (symbol_kind_type yyarg[], int yyargn) const
- {
- // Actual number of expected tokens
- int yycount = 0;
-
- const int yyn = yypact_[+yyparser_.yystack_[0].state];
- if (!yy_pact_value_is_default_ (yyn))
- {
- /* Start YYX at -YYN if negative to avoid negative indexes in
- YYCHECK. In other words, skip the first -YYN actions for
- this state because they are default actions. */
- const int yyxbegin = yyn < 0 ? -yyn : 0;
- // Stay within bounds of both yycheck and yytname.
- const int yychecklim = yylast_ - yyn + 1;
- const int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
- for (int yyx = yyxbegin; yyx < yyxend; ++yyx)
- if (yycheck_[yyx + yyn] == yyx && yyx != symbol_kind::S_YYerror
- && !yy_table_value_is_error_ (yytable_[yyx + yyn]))
- {
- if (!yyarg)
- ++yycount;
- else if (yycount == yyargn)
- return 0;
- else
- yyarg[yycount++] = YY_CAST (symbol_kind_type, yyx);
- }
- }
-
- if (yyarg && yycount == 0 && 0 < yyargn)
- yyarg[0] = symbol_kind::S_YYEMPTY;
- return yycount;
- }
-
-
-
-
-
-
- int
- AgentParser::yy_syntax_error_arguments_ (const context& yyctx,
- symbol_kind_type yyarg[], int yyargn) const
- {
- /* There are many possibilities here to consider:
- - If this state is a consistent state with a default action, then
- the only way this function was invoked is if the default action
- is an error action. In that case, don't check for expected
- tokens because there are none.
- - The only way there can be no lookahead present (in yyla) is
- if this state is a consistent state with a default action.
- Thus, detecting the absence of a lookahead is sufficient to
- determine that there is no unexpected or expected token to
- report. In that case, just report a simple "syntax error".
- - Don't assume there isn't a lookahead just because this state is
- a consistent state with a default action. There might have
- been a previous inconsistent state, consistent state with a
- non-default action, or user semantic action that manipulated
- yyla. (However, yyla is currently not documented for users.)
- - Of course, the expected token list depends on states to have
- correct lookahead information, and it depends on the parser not
- to perform extra reductions after fetching a lookahead from the
- scanner and before detecting a syntax error. Thus, state merging
- (from LALR or IELR) and default reductions corrupt the expected
- token list. However, the list is correct for canonical LR with
- one exception: it will still contain any token that will not be
- accepted due to an error action in a later state.
- */
-
- if (!yyctx.lookahead ().empty ())
- {
- if (yyarg)
- yyarg[0] = yyctx.token ();
- int yyn = yyctx.expected_tokens (yyarg ? yyarg + 1 : yyarg, yyargn - 1);
- return yyn + 1;
- }
- return 0;
- }
-
- // Generate an error message.
- std::string
- AgentParser::yysyntax_error_ (const context& yyctx) const
- {
- // Its maximum.
- enum { YYARGS_MAX = 5 };
- // Arguments of yyformat.
- symbol_kind_type yyarg[YYARGS_MAX];
- int yycount = yy_syntax_error_arguments_ (yyctx, yyarg, YYARGS_MAX);
-
- char const* yyformat = YY_NULLPTR;
- switch (yycount)
- {
-#define YYCASE_(N, S) \
- case N: \
- yyformat = S; \
- break
- default: // Avoid compiler warnings.
- YYCASE_ (0, YY_("syntax error"));
- YYCASE_ (1, YY_("syntax error, unexpected %s"));
- YYCASE_ (2, YY_("syntax error, unexpected %s, expecting %s"));
- YYCASE_ (3, YY_("syntax error, unexpected %s, expecting %s or %s"));
- YYCASE_ (4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
- YYCASE_ (5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
-#undef YYCASE_
- }
-
- std::string yyres;
- // Argument number.
- std::ptrdiff_t yyi = 0;
- for (char const* yyp = yyformat; *yyp; ++yyp)
- if (yyp[0] == '%' && yyp[1] == 's' && yyi < yycount)
- {
- yyres += symbol_name (yyarg[yyi++]);
- ++yyp;
- }
- else
- yyres += *yyp;
- return yyres;
- }
-
-
- const short AgentParser::yypact_ninf_ = -205;
-
- const signed char AgentParser::yytable_ninf_ = -1;
-
- const short
- AgentParser::yypact_[] =
- {
- 76, -205, -205, -205, 5, 1, 2, 20, -205, -205,
- -205, -205, -205, -205, -205, -205, -205, -205, -205, -205,
- -205, -205, -205, -205, 1, -20, 25, 0, -205, 34,
- 35, 63, 41, 85, -205, 79, -205, -205, 90, -205,
- -205, -205, -205, -205, -205, -205, 93, 131, -205, -205,
- 132, -205, 102, -205, -205, -205, -205, -205, -205, -205,
- -205, -205, -205, -205, -205, -205, -205, -205, 1, 1,
- -205, 84, 139, -205, -205, 141, 53, 143, 144, 148,
- 149, 150, 151, 152, 100, 153, 154, 155, -205, 0,
- -205, -205, -205, 157, 156, 108, -205, 160, 159, 117,
- 161, 118, 119, 120, -205, -205, 162, 164, -205, 1,
- 0, -205, 163, -205, -205, -205, 22, -205, -205, -205,
- 46, 168, 169, -205, 103, -205, 171, 175, -205, -205,
- -205, -205, -205, -205, -205, -205, 104, -205, -205, -205,
- -205, -205, -205, -205, -205, -205, 106, -205, -205, -205,
- -205, -205, 173, 177, -205, -205, 47, -205, -205, 7,
- -205, 163, 178, 179, 180, 181, 22, -205, 182, 183,
- 184, 46, -205, -21, -205, 168, 32, 169, -205, -205,
- -205, -205, -205, -205, 112, -205, -205, -205, -205, 170,
- 127, 135, 186, -205, 185, 190, 191, -205, -205, -205,
- -205, 113, -205, -205, -205, -205, -205, 189, -205, -205,
- -205, -205, -205, 114, -205, -205, -205, -205, -205, 195,
- 196, 7, -205, -205, -205, -205, -205, 194, 59, 59,
- 59, 198, 199, -24, -205, 200, 165, 201, 32, -205,
- 167, 172, -205, -205, 202, 203, -205, -205, -205, -205,
- -205, -205, 115, -205, -205, -205, 116, 122, 174, 159,
- -205, 204, -205, 176, -205, -205, -205, 45, -205, 194,
- 206, 210, 59, -205, -205, -205, -205, -205, 208, -205,
- -205, -205, -205, -205, -205, -205, -205, 123, -205, -205,
- -205, -205, -205, -205, 192, 187, -205, -205, 62, -205,
- 212, 213, 214, 215, 45, -205, -205, -205, -205, 54,
- 208, -205, 193, 197, 205, 207, -205, -205, 218, 219,
- 220, -205, 134, -205, -205, -205, -205, -205, -205, -205,
- -205, -205, -205, -205, 223, 188, 209, 211, 225, 54,
- -205, 216, -205, -205, -205, 217, -205, -205, -205
- };
-
- const unsigned char
- AgentParser::yydefact_[] =
- {
- 0, 2, 4, 6, 0, 0, 0, 0, 1, 26,
- 18, 15, 14, 11, 12, 13, 3, 10, 16, 17,
- 34, 5, 8, 7, 28, 21, 0, 0, 30, 0,
- 29, 0, 0, 22, 36, 0, 38, 57, 0, 71,
- 67, 69, 139, 60, 62, 64, 0, 0, 92, 185,
- 0, 56, 0, 40, 43, 44, 46, 47, 48, 49,
- 54, 55, 45, 52, 51, 50, 53, 27, 32, 0,
- 19, 25, 0, 39, 35, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 33, 42,
- 9, 31, 23, 0, 0, 0, 59, 0, 0, 0,
- 0, 0, 0, 0, 66, 111, 0, 0, 41, 0,
- 0, 58, 73, 20, 68, 70, 0, 61, 63, 65,
- 0, 94, 0, 24, 0, 78, 0, 74, 75, 151,
- 154, 156, 158, 150, 149, 148, 0, 141, 144, 145,
- 146, 147, 120, 122, 124, 119, 0, 113, 116, 117,
- 118, 99, 0, 95, 96, 190, 0, 187, 37, 0,
- 72, 77, 0, 0, 0, 0, 143, 140, 0, 0,
- 0, 115, 112, 0, 93, 98, 0, 189, 186, 88,
- 90, 87, 85, 86, 0, 80, 83, 84, 76, 0,
- 0, 0, 0, 142, 0, 0, 0, 114, 107, 109,
- 104, 0, 101, 105, 106, 97, 205, 0, 203, 201,
- 199, 200, 195, 0, 192, 197, 198, 196, 188, 0,
- 0, 82, 79, 153, 152, 155, 157, 160, 0, 0,
- 0, 0, 0, 103, 100, 0, 0, 0, 194, 191,
- 0, 0, 81, 165, 0, 161, 162, 134, 136, 133,
- 131, 132, 0, 126, 129, 130, 0, 0, 0, 0,
- 102, 0, 202, 0, 193, 89, 91, 0, 159, 164,
- 0, 0, 128, 121, 123, 125, 108, 110, 0, 204,
- 177, 179, 181, 183, 176, 174, 175, 0, 167, 170,
- 171, 172, 173, 163, 0, 0, 127, 210, 0, 207,
- 0, 0, 0, 0, 169, 166, 135, 138, 137, 0,
- 209, 206, 0, 0, 0, 0, 168, 220, 0, 0,
- 0, 225, 0, 212, 215, 216, 217, 218, 219, 208,
- 178, 180, 182, 184, 0, 0, 0, 0, 0, 214,
- 211, 0, 222, 223, 224, 0, 213, 221, 226
- };
-
- const short
- AgentParser::yypgoto_[] =
- {
- -205, -205, -205, -205, -205, -205, -205, -205, -17, -95,
- -205, -52, -205, -205, -205, -205, -205, -205, -27, -205,
- -205, -205, -205, -205, 121, 145, -205, -205, -205, -205,
- -205, -205, -205, -205, -205, -205, -26, -205, -25, -205,
- -205, -205, -205, -205, 71, -205, -205, 12, -172, -205,
- -205, -205, -205, -205, -205, -205, 60, -205, -205, 3,
- -205, -205, -205, -205, -205, -205, -205, 66, -205, -205,
- -205, -205, -205, -205, -204, -34, -205, -205, -205, -205,
- -205, -205, -205, -205, 73, -205, -205, -205, -205, -205,
- -205, -205, -205, -205, -205, -205, -19, -205, -205, -61,
- -205, -205, -205, -205, -205, -205, -205, -205, -205, -205,
- -205, 67, -205, -205, 10, -205, -205, -205, -205, -205,
- -205, -58, -205, -205, -90, -205, -205, -205, -205, -205,
- -205, -205
- };
-
- const short
- AgentParser::yydefgoto_[] =
- {
- 0, 4, 5, 6, 7, 23, 27, 16, 17, 18,
- 25, 114, 32, 33, 19, 24, 29, 30, 249, 21,
- 26, 35, 72, 36, 52, 53, 54, 75, 55, 56,
- 81, 57, 82, 58, 83, 59, 250, 78, 251, 79,
- 62, 77, 126, 127, 128, 159, 184, 185, 186, 219,
- 187, 220, 63, 86, 152, 153, 154, 173, 201, 202,
- 203, 231, 204, 232, 64, 120, 146, 147, 148, 168,
- 149, 169, 150, 170, 252, 253, 254, 270, 255, 271,
- 308, 65, 80, 136, 137, 138, 162, 224, 139, 163,
- 140, 164, 141, 165, 244, 245, 246, 267, 287, 288,
- 289, 300, 290, 301, 291, 302, 292, 303, 66, 87,
- 156, 157, 176, 213, 214, 215, 216, 237, 217, 235,
- 298, 299, 309, 322, 323, 324, 334, 325, 326, 327,
- 328, 338
- };
-
- const short
- AgentParser::yytable_[] =
- {
- 51, 60, 61, 113, 212, 8, 9, 28, 10, 20,
- 11, 37, 38, 39, 40, 41, 198, 199, 42, 198,
- 199, 40, 41, 179, 180, 256, 257, 22, 43, 44,
- 45, 46, 47, 50, 31, 34, 40, 41, 68, 48,
- 67, 129, 49, 130, 131, 132, 40, 41, 179, 70,
- 177, 91, 92, 178, 50, 12, 13, 14, 15, 40,
- 41, 50, 51, 60, 61, 310, 212, 69, 311, 280,
- 281, 282, 283, 40, 41, 206, 50, 207, 208, 142,
- 143, 144, 73, 51, 60, 61, 50, 74, 71, 133,
- 134, 135, 123, 145, 76, 247, 248, 84, 317, 50,
- 50, 318, 319, 320, 321, 89, 89, 166, 96, 171,
- 90, 158, 167, 50, 172, 221, 233, 238, 272, 272,
- 222, 234, 239, 273, 274, 272, 304, 1, 2, 3,
- 275, 305, 181, 182, 183, 85, 88, 339, 93, 133,
- 134, 135, 340, 94, 145, 95, 200, 97, 98, 209,
- 210, 211, 99, 100, 101, 102, 103, 104, 106, 107,
- 105, 109, 111, 110, 113, 112, 10, 121, 116, 122,
- 125, 115, 117, 118, 119, 151, 155, 160, 161, 174,
- 175, 225, 189, 190, 191, 192, 194, 195, 196, 226,
- 223, 227, 228, 236, 181, 182, 183, 229, 230, 240,
- 241, 243, 258, 259, 261, 263, 269, 277, 268, 278,
- 294, 209, 210, 211, 295, 297, 312, 313, 314, 315,
- 262, 265, 335, 336, 337, 307, 266, 341, 276, 345,
- 279, 124, 188, 242, 108, 205, 260, 197, 296, 193,
- 284, 285, 286, 316, 218, 342, 306, 330, 264, 346,
- 293, 331, 329, 0, 0, 0, 0, 0, 0, 332,
- 0, 333, 0, 0, 343, 0, 344, 0, 0, 0,
- 347, 348, 0, 0, 0, 0, 0, 284, 285, 286
- };
-
- const short
- AgentParser::yycheck_[] =
- {
- 27, 27, 27, 98, 176, 0, 5, 24, 7, 7,
- 9, 11, 12, 13, 14, 15, 40, 41, 18, 40,
- 41, 14, 15, 16, 17, 229, 230, 7, 28, 29,
- 30, 31, 32, 54, 54, 10, 14, 15, 3, 39,
- 6, 19, 42, 21, 22, 23, 14, 15, 16, 8,
- 3, 68, 69, 6, 54, 54, 55, 56, 57, 14,
- 15, 54, 89, 89, 89, 3, 238, 4, 6, 24,
- 25, 26, 27, 14, 15, 43, 54, 45, 46, 33,
- 34, 35, 3, 110, 110, 110, 54, 8, 3, 116,
- 116, 116, 109, 120, 4, 36, 37, 4, 44, 54,
- 54, 47, 48, 49, 50, 3, 3, 3, 55, 3,
- 8, 8, 8, 54, 8, 3, 3, 3, 3, 3,
- 8, 8, 8, 8, 8, 3, 3, 51, 52, 53,
- 8, 8, 159, 159, 159, 4, 4, 3, 54, 166,
- 166, 166, 8, 4, 171, 4, 173, 4, 4, 176,
- 176, 176, 4, 4, 4, 4, 4, 57, 4, 4,
- 7, 4, 54, 7, 259, 5, 7, 5, 7, 5,
- 7, 54, 54, 54, 54, 7, 7, 6, 3, 6,
- 3, 54, 4, 4, 4, 4, 4, 4, 4, 54,
- 20, 5, 7, 4, 221, 221, 221, 7, 7, 4,
- 4, 7, 4, 4, 4, 4, 3, 259, 6, 5,
- 4, 238, 238, 238, 4, 7, 4, 4, 4, 4,
- 55, 54, 4, 4, 4, 38, 54, 4, 54, 4,
- 54, 110, 161, 221, 89, 175, 233, 171, 272, 166,
- 267, 267, 267, 304, 177, 57, 54, 54, 238, 339,
- 269, 54, 310, -1, -1, -1, -1, -1, -1, 54,
- -1, 54, -1, -1, 55, -1, 55, -1, -1, -1,
- 54, 54, -1, -1, -1, -1, -1, 304, 304, 304
- };
-
- const unsigned char
- AgentParser::yystos_[] =
- {
- 0, 51, 52, 53, 59, 60, 61, 62, 0, 5,
- 7, 9, 54, 55, 56, 57, 65, 66, 67, 72,
- 7, 77, 7, 63, 73, 68, 78, 64, 66, 74,
- 75, 54, 70, 71, 10, 79, 81, 11, 12, 13,
- 14, 15, 18, 28, 29, 30, 31, 32, 39, 42,
- 54, 76, 82, 83, 84, 86, 87, 89, 91, 93,
- 94, 96, 98, 110, 122, 139, 166, 6, 3, 4,
- 8, 3, 80, 3, 8, 85, 4, 99, 95, 97,
- 140, 88, 90, 92, 4, 4, 111, 167, 4, 3,
- 8, 66, 66, 54, 4, 4, 55, 4, 4, 4,
- 4, 4, 4, 4, 57, 7, 4, 4, 83, 4,
- 7, 54, 5, 67, 69, 54, 7, 54, 54, 54,
- 123, 5, 5, 66, 82, 7, 100, 101, 102, 19,
- 21, 22, 23, 76, 94, 96, 141, 142, 143, 146,
- 148, 150, 33, 34, 35, 76, 124, 125, 126, 128,
- 130, 7, 112, 113, 114, 7, 168, 169, 8, 103,
- 6, 3, 144, 147, 149, 151, 3, 8, 127, 129,
- 131, 3, 8, 115, 6, 3, 170, 3, 6, 16,
- 17, 76, 94, 96, 104, 105, 106, 108, 102, 4,
- 4, 4, 4, 142, 4, 4, 4, 125, 40, 41,
- 76, 116, 117, 118, 120, 114, 43, 45, 46, 76,
- 94, 96, 106, 171, 172, 173, 174, 176, 169, 107,
- 109, 3, 8, 20, 145, 54, 54, 5, 7, 7,
- 7, 119, 121, 3, 8, 177, 4, 175, 3, 8,
- 4, 4, 105, 7, 152, 153, 154, 36, 37, 76,
- 94, 96, 132, 133, 134, 136, 132, 132, 4, 4,
- 117, 4, 55, 4, 172, 54, 54, 155, 6, 3,
- 135, 137, 3, 8, 8, 8, 54, 69, 5, 54,
- 24, 25, 26, 27, 76, 94, 96, 156, 157, 158,
- 160, 162, 164, 154, 4, 4, 133, 7, 178, 179,
- 159, 161, 163, 165, 3, 8, 54, 38, 138, 180,
- 3, 6, 4, 4, 4, 4, 157, 44, 47, 48,
- 49, 50, 181, 182, 183, 185, 186, 187, 188, 179,
- 54, 54, 54, 54, 184, 4, 4, 4, 189, 3,
- 8, 4, 57, 55, 55, 4, 182, 54, 54
- };
-
- const unsigned char
- AgentParser::yyr1_[] =
- {
- 0, 58, 60, 59, 61, 59, 62, 59, 64, 63,
- 65, 66, 66, 66, 66, 66, 66, 66, 68, 67,
- 69, 70, 70, 71, 71, 71, 73, 72, 74, 74,
- 75, 75, 75, 76, 78, 77, 80, 79, 79, 81,
- 82, 82, 82, 83, 83, 83, 83, 83, 83, 83,
- 83, 83, 83, 83, 83, 83, 83, 85, 84, 86,
- 88, 87, 90, 89, 92, 91, 93, 95, 94, 97,
- 96, 99, 98, 100, 100, 101, 101, 101, 103, 102,
- 104, 104, 104, 105, 105, 105, 105, 105, 107, 106,
- 109, 108, 111, 110, 112, 112, 113, 113, 113, 115,
- 114, 116, 116, 116, 116, 117, 117, 119, 118, 121,
- 120, 123, 122, 124, 124, 124, 125, 125, 125, 125,
- 127, 126, 129, 128, 131, 130, 132, 132, 132, 133,
- 133, 133, 133, 133, 135, 134, 137, 136, 138, 140,
- 139, 141, 141, 141, 142, 142, 142, 142, 142, 142,
- 142, 144, 143, 145, 147, 146, 149, 148, 151, 150,
- 152, 152, 153, 153, 153, 155, 154, 156, 156, 156,
- 157, 157, 157, 157, 157, 157, 157, 159, 158, 161,
- 160, 163, 162, 165, 164, 167, 166, 168, 168, 168,
- 170, 169, 171, 171, 171, 172, 172, 172, 172, 172,
- 172, 172, 173, 175, 174, 177, 176, 178, 178, 178,
- 180, 179, 181, 181, 181, 182, 182, 182, 182, 182,
- 184, 183, 185, 186, 187, 189, 188
- };
-
- const signed char
- AgentParser::yyr2_[] =
- {
- 0, 2, 0, 3, 0, 3, 0, 3, 0, 4,
- 1, 1, 1, 1, 1, 1, 1, 1, 0, 4,
- 1, 0, 1, 3, 5, 2, 0, 4, 0, 1,
- 1, 3, 2, 2, 0, 4, 0, 6, 1, 2,
- 1, 3, 2, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 0, 4, 3,
- 0, 4, 0, 4, 0, 4, 3, 0, 4, 0,
- 4, 0, 6, 0, 1, 1, 3, 2, 0, 4,
- 1, 3, 2, 1, 1, 1, 1, 1, 0, 4,
- 0, 4, 0, 6, 0, 1, 1, 3, 2, 0,
- 4, 1, 3, 2, 1, 1, 1, 0, 4, 0,
- 4, 0, 6, 1, 3, 2, 1, 1, 1, 1,
- 0, 6, 0, 6, 0, 6, 1, 3, 2, 1,
- 1, 1, 1, 1, 0, 4, 0, 4, 1, 0,
- 6, 1, 3, 2, 1, 1, 1, 1, 1, 1,
- 1, 0, 4, 1, 0, 4, 0, 4, 0, 6,
- 0, 1, 1, 3, 2, 0, 4, 1, 3, 2,
- 1, 1, 1, 1, 1, 1, 1, 0, 4, 0,
- 4, 0, 4, 0, 4, 0, 6, 1, 3, 2,
- 0, 4, 1, 3, 2, 1, 1, 1, 1, 1,
- 1, 1, 3, 0, 4, 0, 6, 1, 3, 2,
- 0, 4, 1, 3, 2, 1, 1, 1, 1, 1,
- 0, 4, 3, 3, 3, 0, 4
- };
-
-
-#if AGENT_DEBUG || 1
- // YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
- // First, the terminals, then, starting at \a YYNTOKENS, nonterminals.
- const char*
- const AgentParser::yytname_[] =
- {
- "\"end of file\"", "error", "\"invalid token\"", "\",\"", "\":\"",
- "\"[\"", "\"]\"", "\"{\"", "\"}\"", "\"null\"", "\"Control-agent\"",
- "\"http-host\"", "\"http-port\"", "\"http-headers\"", "\"user-context\"",
- "\"comment\"", "\"name\"", "\"value\"", "\"authentication\"", "\"type\"",
- "\"basic\"", "\"realm\"", "\"directory\"", "\"clients\"", "\"user\"",
- "\"user-file\"", "\"password\"", "\"password-file\"", "\"trust-anchor\"",
- "\"cert-file\"", "\"key-file\"", "\"cert-required\"",
- "\"control-sockets\"", "\"dhcp4\"", "\"dhcp6\"", "\"d2\"",
- "\"socket-name\"", "\"socket-type\"", "\"unix\"", "\"hooks-libraries\"",
- "\"library\"", "\"parameters\"", "\"loggers\"", "\"output-options\"",
- "\"output\"", "\"debuglevel\"", "\"severity\"", "\"flush\"",
- "\"maxsize\"", "\"maxver\"", "\"pattern\"", "START_JSON", "START_AGENT",
- "START_SUB_AGENT", "\"constant string\"", "\"integer\"",
- "\"floating point\"", "\"boolean\"", "$accept", "start", "$@1", "$@2",
- "$@3", "sub_agent", "$@4", "json", "value", "map", "$@5", "map_value",
- "map_content", "not_empty_map", "list_generic", "$@6", "list_content",
- "not_empty_list", "unknown_map_entry", "agent_syntax_map", "$@7",
- "global_object", "$@8", "global_object_comma", "global_params",
- "global_param", "http_host", "$@9", "http_port", "trust_anchor", "$@10",
- "cert_file", "$@11", "key_file", "$@12", "cert_required", "user_context",
- "$@13", "comment", "$@14", "http_headers", "$@15", "http_header_list",
- "not_empty_http_header_list", "http_header", "$@16",
- "http_header_params", "http_header_param", "name", "$@17",
- "header_value", "$@18", "hooks_libraries", "$@19",
- "hooks_libraries_list", "not_empty_hooks_libraries_list",
- "hooks_library", "$@20", "hooks_params", "hooks_param", "library",
- "$@21", "parameters", "$@22", "control_sockets", "$@23",
- "control_sockets_params", "control_socket", "dhcp4_server_socket",
- "$@24", "dhcp6_server_socket", "$@25", "d2_server_socket", "$@26",
- "control_socket_params", "control_socket_param", "socket_name", "$@27",
- "socket_type", "$@28", "socket_type_value", "authentication", "$@29",
- "auth_params", "auth_param", "auth_type", "$@30", "auth_type_value",
- "realm", "$@31", "directory", "$@32", "clients", "$@33", "clients_list",
- "not_empty_clients_list", "basic_auth", "$@34", "clients_params",
- "clients_param", "user", "$@35", "user_file", "$@36", "password", "$@37",
- "password_file", "$@38", "loggers", "$@39", "loggers_entries",
- "logger_entry", "$@40", "logger_params", "logger_param", "debuglevel",
- "severity", "$@41", "output_options_list", "$@42",
- "output_options_list_content", "output_entry", "$@43",
- "output_params_list", "output_params", "output", "$@44", "flush",
- "maxsize", "maxver", "pattern", "$@45", YY_NULLPTR
- };
-#endif
-
-
-#if AGENT_DEBUG
- const short
- AgentParser::yyrline_[] =
- {
- 0, 135, 135, 135, 136, 136, 137, 137, 145, 145,
- 156, 162, 163, 164, 165, 166, 167, 168, 172, 172,
- 183, 188, 189, 197, 202, 208, 213, 213, 219, 220,
- 223, 227, 231, 243, 251, 251, 263, 263, 279, 282,
- 286, 287, 288, 295, 296, 297, 298, 299, 300, 301,
- 302, 303, 304, 305, 306, 307, 308, 311, 311, 320,
- 326, 326, 335, 335, 344, 344, 353, 359, 359, 384,
- 384, 411, 411, 422, 423, 426, 427, 428, 433, 433,
- 441, 442, 443, 448, 449, 450, 451, 452, 455, 455,
- 464, 464, 474, 474, 485, 486, 489, 490, 491, 496,
- 496, 504, 505, 506, 509, 512, 513, 516, 516, 525,
- 525, 536, 536, 550, 551, 552, 559, 560, 561, 562,
- 566, 566, 578, 578, 590, 590, 602, 603, 604, 610,
- 611, 612, 613, 614, 618, 618, 628, 628, 637, 644,
- 644, 657, 658, 659, 664, 665, 666, 667, 668, 669,
- 670, 673, 673, 681, 684, 684, 693, 693, 702, 702,
- 713, 714, 717, 718, 719, 724, 724, 732, 733, 734,
- 739, 740, 741, 742, 743, 744, 745, 748, 748, 757,
- 757, 766, 766, 775, 775, 788, 788, 801, 802, 803,
- 809, 809, 817, 818, 819, 824, 825, 826, 827, 828,
- 829, 830, 833, 839, 839, 848, 848, 859, 860, 861,
- 866, 866, 874, 875, 876, 881, 882, 883, 884, 885,
- 888, 888, 897, 903, 909, 915, 915
- };
-
- void
- AgentParser::yy_stack_print_ () const
- {
- *yycdebug_ << "Stack now";
- for (stack_type::const_iterator
- i = yystack_.begin (),
- i_end = yystack_.end ();
- i != i_end; ++i)
- *yycdebug_ << ' ' << int (i->state);
- *yycdebug_ << '\n';
- }
-
- void
- AgentParser::yy_reduce_print_ (int yyrule) const
- {
- int yylno = yyrline_[yyrule];
- int yynrhs = yyr2_[yyrule];
- // Print the symbols being reduced, and their result.
- *yycdebug_ << "Reducing stack by rule " << yyrule - 1
- << " (line " << yylno << "):\n";
- // The symbols being reduced.
- for (int yyi = 0; yyi < yynrhs; yyi++)
- YY_SYMBOL_PRINT (" $" << yyi + 1 << " =",
- yystack_[(yynrhs) - (yyi + 1)]);
- }
-#endif // AGENT_DEBUG
-
-
-#line 14 "agent_parser.yy"
-} } // isc::agent
-#line 2643 "agent_parser.cc"
-
-#line 924 "agent_parser.yy"
-
-
-void
-isc::agent::AgentParser::error(const location_type& loc,
- const std::string& what)
-{
- ctx.error(loc, what);
-}
+++ /dev/null
-// A Bison parser, made by GNU Bison 3.8.2.
-
-// Skeleton interface for Bison LALR(1) parsers in C++
-
-// Copyright (C) 2002-2015, 2018-2021 Free Software Foundation, Inc.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <https://www.gnu.org/licenses/>.
-
-// As a special exception, you may create a larger work that contains
-// part or all of the Bison parser skeleton and distribute that work
-// under terms of your choice, so long as that work isn't itself a
-// parser generator using the skeleton or a modified version thereof
-// as a parser skeleton. Alternatively, if you modify or redistribute
-// the parser skeleton itself, you may (at your option) remove this
-// special exception, which will cause the skeleton and the resulting
-// Bison output files to be licensed under the GNU General Public
-// License without this special exception.
-
-// This special exception was added by the Free Software Foundation in
-// version 2.2 of Bison.
-
-
-/**
- ** \file agent_parser.h
- ** Define the isc::agent::parser class.
- */
-
-// C++ LALR(1) parser skeleton written by Akim Demaille.
-
-// DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual,
-// especially those whose name start with YY_ or yy_. They are
-// private implementation details that can be changed or removed.
-
-#ifndef YY_AGENT_AGENT_PARSER_H_INCLUDED
-# define YY_AGENT_AGENT_PARSER_H_INCLUDED
-// "%code requires" blocks.
-#line 17 "agent_parser.yy"
-
-#include <string>
-#include <cc/data.h>
-#include <boost/lexical_cast.hpp>
-#include <agent/parser_context_decl.h>
-
-using namespace isc::agent;
-using namespace isc::data;
-using namespace std;
-
-#line 60 "agent_parser.h"
-
-# include <cassert>
-# include <cstdlib> // std::abort
-# include <iostream>
-# include <stdexcept>
-# include <string>
-# include <vector>
-
-#if defined __cplusplus
-# define YY_CPLUSPLUS __cplusplus
-#else
-# define YY_CPLUSPLUS 199711L
-#endif
-
-// Support move semantics when possible.
-#if 201103L <= YY_CPLUSPLUS
-# define YY_MOVE std::move
-# define YY_MOVE_OR_COPY move
-# define YY_MOVE_REF(Type) Type&&
-# define YY_RVREF(Type) Type&&
-# define YY_COPY(Type) Type
-#else
-# define YY_MOVE
-# define YY_MOVE_OR_COPY copy
-# define YY_MOVE_REF(Type) Type&
-# define YY_RVREF(Type) const Type&
-# define YY_COPY(Type) const Type&
-#endif
-
-// Support noexcept when possible.
-#if 201103L <= YY_CPLUSPLUS
-# define YY_NOEXCEPT noexcept
-# define YY_NOTHROW
-#else
-# define YY_NOEXCEPT
-# define YY_NOTHROW throw ()
-#endif
-
-// Support constexpr when possible.
-#if 201703 <= YY_CPLUSPLUS
-# define YY_CONSTEXPR constexpr
-#else
-# define YY_CONSTEXPR
-#endif
-# include "location.hh"
-#include <typeinfo>
-#ifndef AGENT__ASSERT
-# include <cassert>
-# define AGENT__ASSERT assert
-#endif
-
-
-#ifndef YY_ATTRIBUTE_PURE
-# if defined __GNUC__ && 2 < __GNUC__ + (96 <= __GNUC_MINOR__)
-# define YY_ATTRIBUTE_PURE __attribute__ ((__pure__))
-# else
-# define YY_ATTRIBUTE_PURE
-# endif
-#endif
-
-#ifndef YY_ATTRIBUTE_UNUSED
-# if defined __GNUC__ && 2 < __GNUC__ + (7 <= __GNUC_MINOR__)
-# define YY_ATTRIBUTE_UNUSED __attribute__ ((__unused__))
-# else
-# define YY_ATTRIBUTE_UNUSED
-# endif
-#endif
-
-/* Suppress unused-variable warnings by "using" E. */
-#if ! defined lint || defined __GNUC__
-# define YY_USE(E) ((void) (E))
-#else
-# define YY_USE(E) /* empty */
-#endif
-
-/* Suppress an incorrect diagnostic about yylval being uninitialized. */
-#if defined __GNUC__ && ! defined __ICC && 406 <= __GNUC__ * 100 + __GNUC_MINOR__
-# if __GNUC__ * 100 + __GNUC_MINOR__ < 407
-# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \
- _Pragma ("GCC diagnostic push") \
- _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")
-# else
-# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \
- _Pragma ("GCC diagnostic push") \
- _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") \
- _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
-# endif
-# define YY_IGNORE_MAYBE_UNINITIALIZED_END \
- _Pragma ("GCC diagnostic pop")
-#else
-# define YY_INITIAL_VALUE(Value) Value
-#endif
-#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
-# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
-# define YY_IGNORE_MAYBE_UNINITIALIZED_END
-#endif
-#ifndef YY_INITIAL_VALUE
-# define YY_INITIAL_VALUE(Value) /* Nothing. */
-#endif
-
-#if defined __cplusplus && defined __GNUC__ && ! defined __ICC && 6 <= __GNUC__
-# define YY_IGNORE_USELESS_CAST_BEGIN \
- _Pragma ("GCC diagnostic push") \
- _Pragma ("GCC diagnostic ignored \"-Wuseless-cast\"")
-# define YY_IGNORE_USELESS_CAST_END \
- _Pragma ("GCC diagnostic pop")
-#endif
-#ifndef YY_IGNORE_USELESS_CAST_BEGIN
-# define YY_IGNORE_USELESS_CAST_BEGIN
-# define YY_IGNORE_USELESS_CAST_END
-#endif
-
-# ifndef YY_CAST
-# ifdef __cplusplus
-# define YY_CAST(Type, Val) static_cast<Type> (Val)
-# define YY_REINTERPRET_CAST(Type, Val) reinterpret_cast<Type> (Val)
-# else
-# define YY_CAST(Type, Val) ((Type) (Val))
-# define YY_REINTERPRET_CAST(Type, Val) ((Type) (Val))
-# endif
-# endif
-# ifndef YY_NULLPTR
-# if defined __cplusplus
-# if 201103L <= __cplusplus
-# define YY_NULLPTR nullptr
-# else
-# define YY_NULLPTR 0
-# endif
-# else
-# define YY_NULLPTR ((void*)0)
-# endif
-# endif
-
-/* Debug traces. */
-#ifndef AGENT_DEBUG
-# if defined YYDEBUG
-#if YYDEBUG
-# define AGENT_DEBUG 1
-# else
-# define AGENT_DEBUG 0
-# endif
-# else /* ! defined YYDEBUG */
-# define AGENT_DEBUG 1
-# endif /* ! defined YYDEBUG */
-#endif /* ! defined AGENT_DEBUG */
-
-#line 14 "agent_parser.yy"
-namespace isc { namespace agent {
-#line 209 "agent_parser.h"
-
-
-
-
- /// A Bison parser.
- class AgentParser
- {
- public:
-#ifdef AGENT_STYPE
-# ifdef __GNUC__
-# pragma GCC message "bison: do not #define AGENT_STYPE in C++, use %define api.value.type"
-# endif
- typedef AGENT_STYPE value_type;
-#else
- /// A buffer to store and retrieve objects.
- ///
- /// Sort of a variant, but does not keep track of the nature
- /// of the stored data, since that knowledge is available
- /// via the current parser state.
- class value_type
- {
- public:
- /// Type of *this.
- typedef value_type self_type;
-
- /// Empty construction.
- value_type () YY_NOEXCEPT
- : yyraw_ ()
- , yytypeid_ (YY_NULLPTR)
- {}
-
- /// Construct and fill.
- template <typename T>
- value_type (YY_RVREF (T) t)
- : yytypeid_ (&typeid (T))
- {
- AGENT__ASSERT (sizeof (T) <= size);
- new (yyas_<T> ()) T (YY_MOVE (t));
- }
-
-#if 201103L <= YY_CPLUSPLUS
- /// Non copyable.
- value_type (const self_type&) = delete;
- /// Non copyable.
- self_type& operator= (const self_type&) = delete;
-#endif
-
- /// Destruction, allowed only if empty.
- ~value_type () YY_NOEXCEPT
- {
- AGENT__ASSERT (!yytypeid_);
- }
-
-# if 201103L <= YY_CPLUSPLUS
- /// Instantiate a \a T in here from \a t.
- template <typename T, typename... U>
- T&
- emplace (U&&... u)
- {
- AGENT__ASSERT (!yytypeid_);
- AGENT__ASSERT (sizeof (T) <= size);
- yytypeid_ = & typeid (T);
- return *new (yyas_<T> ()) T (std::forward <U>(u)...);
- }
-# else
- /// Instantiate an empty \a T in here.
- template <typename T>
- T&
- emplace ()
- {
- AGENT__ASSERT (!yytypeid_);
- AGENT__ASSERT (sizeof (T) <= size);
- yytypeid_ = & typeid (T);
- return *new (yyas_<T> ()) T ();
- }
-
- /// Instantiate a \a T in here from \a t.
- template <typename T>
- T&
- emplace (const T& t)
- {
- AGENT__ASSERT (!yytypeid_);
- AGENT__ASSERT (sizeof (T) <= size);
- yytypeid_ = & typeid (T);
- return *new (yyas_<T> ()) T (t);
- }
-# endif
-
- /// Instantiate an empty \a T in here.
- /// Obsolete, use emplace.
- template <typename T>
- T&
- build ()
- {
- return emplace<T> ();
- }
-
- /// Instantiate a \a T in here from \a t.
- /// Obsolete, use emplace.
- template <typename T>
- T&
- build (const T& t)
- {
- return emplace<T> (t);
- }
-
- /// Accessor to a built \a T.
- template <typename T>
- T&
- as () YY_NOEXCEPT
- {
- AGENT__ASSERT (yytypeid_);
- AGENT__ASSERT (*yytypeid_ == typeid (T));
- AGENT__ASSERT (sizeof (T) <= size);
- return *yyas_<T> ();
- }
-
- /// Const accessor to a built \a T (for %printer).
- template <typename T>
- const T&
- as () const YY_NOEXCEPT
- {
- AGENT__ASSERT (yytypeid_);
- AGENT__ASSERT (*yytypeid_ == typeid (T));
- AGENT__ASSERT (sizeof (T) <= size);
- return *yyas_<T> ();
- }
-
- /// Swap the content with \a that, of same type.
- ///
- /// Both variants must be built beforehand, because swapping the actual
- /// data requires reading it (with as()), and this is not possible on
- /// unconstructed variants: it would require some dynamic testing, which
- /// should not be the variant's responsibility.
- /// Swapping between built and (possibly) non-built is done with
- /// self_type::move ().
- template <typename T>
- void
- swap (self_type& that) YY_NOEXCEPT
- {
- AGENT__ASSERT (yytypeid_);
- AGENT__ASSERT (*yytypeid_ == *that.yytypeid_);
- std::swap (as<T> (), that.as<T> ());
- }
-
- /// Move the content of \a that to this.
- ///
- /// Destroys \a that.
- template <typename T>
- void
- move (self_type& that)
- {
-# if 201103L <= YY_CPLUSPLUS
- emplace<T> (std::move (that.as<T> ()));
-# else
- emplace<T> ();
- swap<T> (that);
-# endif
- that.destroy<T> ();
- }
-
-# if 201103L <= YY_CPLUSPLUS
- /// Move the content of \a that to this.
- template <typename T>
- void
- move (self_type&& that)
- {
- emplace<T> (std::move (that.as<T> ()));
- that.destroy<T> ();
- }
-#endif
-
- /// Copy the content of \a that to this.
- template <typename T>
- void
- copy (const self_type& that)
- {
- emplace<T> (that.as<T> ());
- }
-
- /// Destroy the stored \a T.
- template <typename T>
- void
- destroy ()
- {
- as<T> ().~T ();
- yytypeid_ = YY_NULLPTR;
- }
-
- private:
-#if YY_CPLUSPLUS < 201103L
- /// Non copyable.
- value_type (const self_type&);
- /// Non copyable.
- self_type& operator= (const self_type&);
-#endif
-
- /// Accessor to raw memory as \a T.
- template <typename T>
- T*
- yyas_ () YY_NOEXCEPT
- {
- void *yyp = yyraw_;
- return static_cast<T*> (yyp);
- }
-
- /// Const accessor to raw memory as \a T.
- template <typename T>
- const T*
- yyas_ () const YY_NOEXCEPT
- {
- const void *yyp = yyraw_;
- return static_cast<const T*> (yyp);
- }
-
- /// An auxiliary type to compute the largest semantic type.
- union union_type
- {
- // value
- // map_value
- // socket_type_value
- // auth_type_value
- char dummy1[sizeof (ElementPtr)];
-
- // "boolean"
- char dummy2[sizeof (bool)];
-
- // "floating point"
- char dummy3[sizeof (double)];
-
- // "integer"
- char dummy4[sizeof (int64_t)];
-
- // "constant string"
- char dummy5[sizeof (std::string)];
- };
-
- /// The size of the largest semantic type.
- enum { size = sizeof (union_type) };
-
- /// A buffer to store semantic values.
- union
- {
- /// Strongest alignment constraints.
- long double yyalign_me_;
- /// A buffer large enough to store any of the semantic values.
- char yyraw_[size];
- };
-
- /// Whether the content is built: if defined, the name of the stored type.
- const std::type_info *yytypeid_;
- };
-
-#endif
- /// Backward compatibility (Bison 3.8).
- typedef value_type semantic_type;
-
- /// Symbol locations.
- typedef location location_type;
-
- /// Syntax errors thrown from user actions.
- struct syntax_error : std::runtime_error
- {
- syntax_error (const location_type& l, const std::string& m)
- : std::runtime_error (m)
- , location (l)
- {}
-
- syntax_error (const syntax_error& s)
- : std::runtime_error (s.what ())
- , location (s.location)
- {}
-
- ~syntax_error () YY_NOEXCEPT YY_NOTHROW;
-
- location_type location;
- };
-
- /// Token kinds.
- struct token
- {
- enum token_kind_type
- {
- TOKEN_AGENT_EMPTY = -2,
- TOKEN_END = 0, // "end of file"
- TOKEN_AGENT_error = 256, // error
- TOKEN_AGENT_UNDEF = 257, // "invalid token"
- TOKEN_COMMA = 258, // ","
- TOKEN_COLON = 259, // ":"
- TOKEN_LSQUARE_BRACKET = 260, // "["
- TOKEN_RSQUARE_BRACKET = 261, // "]"
- TOKEN_LCURLY_BRACKET = 262, // "{"
- TOKEN_RCURLY_BRACKET = 263, // "}"
- TOKEN_NULL_TYPE = 264, // "null"
- TOKEN_CONTROL_AGENT = 265, // "Control-agent"
- TOKEN_HTTP_HOST = 266, // "http-host"
- TOKEN_HTTP_PORT = 267, // "http-port"
- TOKEN_HTTP_HEADERS = 268, // "http-headers"
- TOKEN_USER_CONTEXT = 269, // "user-context"
- TOKEN_COMMENT = 270, // "comment"
- TOKEN_NAME = 271, // "name"
- TOKEN_VALUE = 272, // "value"
- TOKEN_AUTHENTICATION = 273, // "authentication"
- TOKEN_TYPE = 274, // "type"
- TOKEN_BASIC = 275, // "basic"
- TOKEN_REALM = 276, // "realm"
- TOKEN_DIRECTORY = 277, // "directory"
- TOKEN_CLIENTS = 278, // "clients"
- TOKEN_USER = 279, // "user"
- TOKEN_USER_FILE = 280, // "user-file"
- TOKEN_PASSWORD = 281, // "password"
- TOKEN_PASSWORD_FILE = 282, // "password-file"
- TOKEN_TRUST_ANCHOR = 283, // "trust-anchor"
- TOKEN_CERT_FILE = 284, // "cert-file"
- TOKEN_KEY_FILE = 285, // "key-file"
- TOKEN_CERT_REQUIRED = 286, // "cert-required"
- TOKEN_CONTROL_SOCKETS = 287, // "control-sockets"
- TOKEN_DHCP4_SERVER = 288, // "dhcp4"
- TOKEN_DHCP6_SERVER = 289, // "dhcp6"
- TOKEN_D2_SERVER = 290, // "d2"
- TOKEN_SOCKET_NAME = 291, // "socket-name"
- TOKEN_SOCKET_TYPE = 292, // "socket-type"
- TOKEN_UNIX = 293, // "unix"
- TOKEN_HOOKS_LIBRARIES = 294, // "hooks-libraries"
- TOKEN_LIBRARY = 295, // "library"
- TOKEN_PARAMETERS = 296, // "parameters"
- TOKEN_LOGGERS = 297, // "loggers"
- TOKEN_OUTPUT_OPTIONS = 298, // "output-options"
- TOKEN_OUTPUT = 299, // "output"
- TOKEN_DEBUGLEVEL = 300, // "debuglevel"
- TOKEN_SEVERITY = 301, // "severity"
- TOKEN_FLUSH = 302, // "flush"
- TOKEN_MAXSIZE = 303, // "maxsize"
- TOKEN_MAXVER = 304, // "maxver"
- TOKEN_PATTERN = 305, // "pattern"
- TOKEN_START_JSON = 306, // START_JSON
- TOKEN_START_AGENT = 307, // START_AGENT
- TOKEN_START_SUB_AGENT = 308, // START_SUB_AGENT
- TOKEN_STRING = 309, // "constant string"
- TOKEN_INTEGER = 310, // "integer"
- TOKEN_FLOAT = 311, // "floating point"
- TOKEN_BOOLEAN = 312 // "boolean"
- };
- /// Backward compatibility alias (Bison 3.6).
- typedef token_kind_type yytokentype;
- };
-
- /// Token kind, as returned by yylex.
- typedef token::token_kind_type token_kind_type;
-
- /// Backward compatibility alias (Bison 3.6).
- typedef token_kind_type token_type;
-
- /// Symbol kinds.
- struct symbol_kind
- {
- enum symbol_kind_type
- {
- YYNTOKENS = 58, ///< Number of tokens.
- S_YYEMPTY = -2,
- S_YYEOF = 0, // "end of file"
- S_YYerror = 1, // error
- S_YYUNDEF = 2, // "invalid token"
- S_COMMA = 3, // ","
- S_COLON = 4, // ":"
- S_LSQUARE_BRACKET = 5, // "["
- S_RSQUARE_BRACKET = 6, // "]"
- S_LCURLY_BRACKET = 7, // "{"
- S_RCURLY_BRACKET = 8, // "}"
- S_NULL_TYPE = 9, // "null"
- S_CONTROL_AGENT = 10, // "Control-agent"
- S_HTTP_HOST = 11, // "http-host"
- S_HTTP_PORT = 12, // "http-port"
- S_HTTP_HEADERS = 13, // "http-headers"
- S_USER_CONTEXT = 14, // "user-context"
- S_COMMENT = 15, // "comment"
- S_NAME = 16, // "name"
- S_VALUE = 17, // "value"
- S_AUTHENTICATION = 18, // "authentication"
- S_TYPE = 19, // "type"
- S_BASIC = 20, // "basic"
- S_REALM = 21, // "realm"
- S_DIRECTORY = 22, // "directory"
- S_CLIENTS = 23, // "clients"
- S_USER = 24, // "user"
- S_USER_FILE = 25, // "user-file"
- S_PASSWORD = 26, // "password"
- S_PASSWORD_FILE = 27, // "password-file"
- S_TRUST_ANCHOR = 28, // "trust-anchor"
- S_CERT_FILE = 29, // "cert-file"
- S_KEY_FILE = 30, // "key-file"
- S_CERT_REQUIRED = 31, // "cert-required"
- S_CONTROL_SOCKETS = 32, // "control-sockets"
- S_DHCP4_SERVER = 33, // "dhcp4"
- S_DHCP6_SERVER = 34, // "dhcp6"
- S_D2_SERVER = 35, // "d2"
- S_SOCKET_NAME = 36, // "socket-name"
- S_SOCKET_TYPE = 37, // "socket-type"
- S_UNIX = 38, // "unix"
- S_HOOKS_LIBRARIES = 39, // "hooks-libraries"
- S_LIBRARY = 40, // "library"
- S_PARAMETERS = 41, // "parameters"
- S_LOGGERS = 42, // "loggers"
- S_OUTPUT_OPTIONS = 43, // "output-options"
- S_OUTPUT = 44, // "output"
- S_DEBUGLEVEL = 45, // "debuglevel"
- S_SEVERITY = 46, // "severity"
- S_FLUSH = 47, // "flush"
- S_MAXSIZE = 48, // "maxsize"
- S_MAXVER = 49, // "maxver"
- S_PATTERN = 50, // "pattern"
- S_START_JSON = 51, // START_JSON
- S_START_AGENT = 52, // START_AGENT
- S_START_SUB_AGENT = 53, // START_SUB_AGENT
- S_STRING = 54, // "constant string"
- S_INTEGER = 55, // "integer"
- S_FLOAT = 56, // "floating point"
- S_BOOLEAN = 57, // "boolean"
- S_YYACCEPT = 58, // $accept
- S_start = 59, // start
- S_60_1 = 60, // $@1
- S_61_2 = 61, // $@2
- S_62_3 = 62, // $@3
- S_sub_agent = 63, // sub_agent
- S_64_4 = 64, // $@4
- S_json = 65, // json
- S_value = 66, // value
- S_map = 67, // map
- S_68_5 = 68, // $@5
- S_map_value = 69, // map_value
- S_map_content = 70, // map_content
- S_not_empty_map = 71, // not_empty_map
- S_list_generic = 72, // list_generic
- S_73_6 = 73, // $@6
- S_list_content = 74, // list_content
- S_not_empty_list = 75, // not_empty_list
- S_unknown_map_entry = 76, // unknown_map_entry
- S_agent_syntax_map = 77, // agent_syntax_map
- S_78_7 = 78, // $@7
- S_global_object = 79, // global_object
- S_80_8 = 80, // $@8
- S_global_object_comma = 81, // global_object_comma
- S_global_params = 82, // global_params
- S_global_param = 83, // global_param
- S_http_host = 84, // http_host
- S_85_9 = 85, // $@9
- S_http_port = 86, // http_port
- S_trust_anchor = 87, // trust_anchor
- S_88_10 = 88, // $@10
- S_cert_file = 89, // cert_file
- S_90_11 = 90, // $@11
- S_key_file = 91, // key_file
- S_92_12 = 92, // $@12
- S_cert_required = 93, // cert_required
- S_user_context = 94, // user_context
- S_95_13 = 95, // $@13
- S_comment = 96, // comment
- S_97_14 = 97, // $@14
- S_http_headers = 98, // http_headers
- S_99_15 = 99, // $@15
- S_http_header_list = 100, // http_header_list
- S_not_empty_http_header_list = 101, // not_empty_http_header_list
- S_http_header = 102, // http_header
- S_103_16 = 103, // $@16
- S_http_header_params = 104, // http_header_params
- S_http_header_param = 105, // http_header_param
- S_name = 106, // name
- S_107_17 = 107, // $@17
- S_header_value = 108, // header_value
- S_109_18 = 109, // $@18
- S_hooks_libraries = 110, // hooks_libraries
- S_111_19 = 111, // $@19
- S_hooks_libraries_list = 112, // hooks_libraries_list
- S_not_empty_hooks_libraries_list = 113, // not_empty_hooks_libraries_list
- S_hooks_library = 114, // hooks_library
- S_115_20 = 115, // $@20
- S_hooks_params = 116, // hooks_params
- S_hooks_param = 117, // hooks_param
- S_library = 118, // library
- S_119_21 = 119, // $@21
- S_parameters = 120, // parameters
- S_121_22 = 121, // $@22
- S_control_sockets = 122, // control_sockets
- S_123_23 = 123, // $@23
- S_control_sockets_params = 124, // control_sockets_params
- S_control_socket = 125, // control_socket
- S_dhcp4_server_socket = 126, // dhcp4_server_socket
- S_127_24 = 127, // $@24
- S_dhcp6_server_socket = 128, // dhcp6_server_socket
- S_129_25 = 129, // $@25
- S_d2_server_socket = 130, // d2_server_socket
- S_131_26 = 131, // $@26
- S_control_socket_params = 132, // control_socket_params
- S_control_socket_param = 133, // control_socket_param
- S_socket_name = 134, // socket_name
- S_135_27 = 135, // $@27
- S_socket_type = 136, // socket_type
- S_137_28 = 137, // $@28
- S_socket_type_value = 138, // socket_type_value
- S_authentication = 139, // authentication
- S_140_29 = 140, // $@29
- S_auth_params = 141, // auth_params
- S_auth_param = 142, // auth_param
- S_auth_type = 143, // auth_type
- S_144_30 = 144, // $@30
- S_auth_type_value = 145, // auth_type_value
- S_realm = 146, // realm
- S_147_31 = 147, // $@31
- S_directory = 148, // directory
- S_149_32 = 149, // $@32
- S_clients = 150, // clients
- S_151_33 = 151, // $@33
- S_clients_list = 152, // clients_list
- S_not_empty_clients_list = 153, // not_empty_clients_list
- S_basic_auth = 154, // basic_auth
- S_155_34 = 155, // $@34
- S_clients_params = 156, // clients_params
- S_clients_param = 157, // clients_param
- S_user = 158, // user
- S_159_35 = 159, // $@35
- S_user_file = 160, // user_file
- S_161_36 = 161, // $@36
- S_password = 162, // password
- S_163_37 = 163, // $@37
- S_password_file = 164, // password_file
- S_165_38 = 165, // $@38
- S_loggers = 166, // loggers
- S_167_39 = 167, // $@39
- S_loggers_entries = 168, // loggers_entries
- S_logger_entry = 169, // logger_entry
- S_170_40 = 170, // $@40
- S_logger_params = 171, // logger_params
- S_logger_param = 172, // logger_param
- S_debuglevel = 173, // debuglevel
- S_severity = 174, // severity
- S_175_41 = 175, // $@41
- S_output_options_list = 176, // output_options_list
- S_177_42 = 177, // $@42
- S_output_options_list_content = 178, // output_options_list_content
- S_output_entry = 179, // output_entry
- S_180_43 = 180, // $@43
- S_output_params_list = 181, // output_params_list
- S_output_params = 182, // output_params
- S_output = 183, // output
- S_184_44 = 184, // $@44
- S_flush = 185, // flush
- S_maxsize = 186, // maxsize
- S_maxver = 187, // maxver
- S_pattern = 188, // pattern
- S_189_45 = 189 // $@45
- };
- };
-
- /// (Internal) symbol kind.
- typedef symbol_kind::symbol_kind_type symbol_kind_type;
-
- /// The number of tokens.
- static const symbol_kind_type YYNTOKENS = symbol_kind::YYNTOKENS;
-
- /// A complete symbol.
- ///
- /// Expects its Base type to provide access to the symbol kind
- /// via kind ().
- ///
- /// Provide access to semantic value and location.
- template <typename Base>
- struct basic_symbol : Base
- {
- /// Alias to Base.
- typedef Base super_type;
-
- /// Default constructor.
- basic_symbol () YY_NOEXCEPT
- : value ()
- , location ()
- {}
-
-#if 201103L <= YY_CPLUSPLUS
- /// Move constructor.
- basic_symbol (basic_symbol&& that)
- : Base (std::move (that))
- , value ()
- , location (std::move (that.location))
- {
- switch (this->kind ())
- {
- case symbol_kind::S_value: // value
- case symbol_kind::S_map_value: // map_value
- case symbol_kind::S_socket_type_value: // socket_type_value
- case symbol_kind::S_auth_type_value: // auth_type_value
- value.move< ElementPtr > (std::move (that.value));
- break;
-
- case symbol_kind::S_BOOLEAN: // "boolean"
- value.move< bool > (std::move (that.value));
- break;
-
- case symbol_kind::S_FLOAT: // "floating point"
- value.move< double > (std::move (that.value));
- break;
-
- case symbol_kind::S_INTEGER: // "integer"
- value.move< int64_t > (std::move (that.value));
- break;
-
- case symbol_kind::S_STRING: // "constant string"
- value.move< std::string > (std::move (that.value));
- break;
-
- default:
- break;
- }
-
- }
-#endif
-
- /// Copy constructor.
- basic_symbol (const basic_symbol& that);
-
- /// Constructors for typed symbols.
-#if 201103L <= YY_CPLUSPLUS
- basic_symbol (typename Base::kind_type t, location_type&& l)
- : Base (t)
- , location (std::move (l))
- {}
-#else
- basic_symbol (typename Base::kind_type t, const location_type& l)
- : Base (t)
- , location (l)
- {}
-#endif
-
-#if 201103L <= YY_CPLUSPLUS
- basic_symbol (typename Base::kind_type t, ElementPtr&& v, location_type&& l)
- : Base (t)
- , value (std::move (v))
- , location (std::move (l))
- {}
-#else
- basic_symbol (typename Base::kind_type t, const ElementPtr& v, const location_type& l)
- : Base (t)
- , value (v)
- , location (l)
- {}
-#endif
-
-#if 201103L <= YY_CPLUSPLUS
- basic_symbol (typename Base::kind_type t, bool&& v, location_type&& l)
- : Base (t)
- , value (std::move (v))
- , location (std::move (l))
- {}
-#else
- basic_symbol (typename Base::kind_type t, const bool& v, const location_type& l)
- : Base (t)
- , value (v)
- , location (l)
- {}
-#endif
-
-#if 201103L <= YY_CPLUSPLUS
- basic_symbol (typename Base::kind_type t, double&& v, location_type&& l)
- : Base (t)
- , value (std::move (v))
- , location (std::move (l))
- {}
-#else
- basic_symbol (typename Base::kind_type t, const double& v, const location_type& l)
- : Base (t)
- , value (v)
- , location (l)
- {}
-#endif
-
-#if 201103L <= YY_CPLUSPLUS
- basic_symbol (typename Base::kind_type t, int64_t&& v, location_type&& l)
- : Base (t)
- , value (std::move (v))
- , location (std::move (l))
- {}
-#else
- basic_symbol (typename Base::kind_type t, const int64_t& v, const location_type& l)
- : Base (t)
- , value (v)
- , location (l)
- {}
-#endif
-
-#if 201103L <= YY_CPLUSPLUS
- basic_symbol (typename Base::kind_type t, std::string&& v, location_type&& l)
- : Base (t)
- , value (std::move (v))
- , location (std::move (l))
- {}
-#else
- basic_symbol (typename Base::kind_type t, const std::string& v, const location_type& l)
- : Base (t)
- , value (v)
- , location (l)
- {}
-#endif
-
- /// Destroy the symbol.
- ~basic_symbol ()
- {
- clear ();
- }
-
-
-
- /// Destroy contents, and record that is empty.
- void clear () YY_NOEXCEPT
- {
- // User destructor.
- symbol_kind_type yykind = this->kind ();
- basic_symbol<Base>& yysym = *this;
- (void) yysym;
- switch (yykind)
- {
- default:
- break;
- }
-
- // Value type destructor.
-switch (yykind)
- {
- case symbol_kind::S_value: // value
- case symbol_kind::S_map_value: // map_value
- case symbol_kind::S_socket_type_value: // socket_type_value
- case symbol_kind::S_auth_type_value: // auth_type_value
- value.template destroy< ElementPtr > ();
- break;
-
- case symbol_kind::S_BOOLEAN: // "boolean"
- value.template destroy< bool > ();
- break;
-
- case symbol_kind::S_FLOAT: // "floating point"
- value.template destroy< double > ();
- break;
-
- case symbol_kind::S_INTEGER: // "integer"
- value.template destroy< int64_t > ();
- break;
-
- case symbol_kind::S_STRING: // "constant string"
- value.template destroy< std::string > ();
- break;
-
- default:
- break;
- }
-
- Base::clear ();
- }
-
- /// The user-facing name of this symbol.
- std::string name () const YY_NOEXCEPT
- {
- return AgentParser::symbol_name (this->kind ());
- }
-
- /// Backward compatibility (Bison 3.6).
- symbol_kind_type type_get () const YY_NOEXCEPT;
-
- /// Whether empty.
- bool empty () const YY_NOEXCEPT;
-
- /// Destructive move, \a s is emptied into this.
- void move (basic_symbol& s);
-
- /// The semantic value.
- value_type value;
-
- /// The location.
- location_type location;
-
- private:
-#if YY_CPLUSPLUS < 201103L
- /// Assignment operator.
- basic_symbol& operator= (const basic_symbol& that);
-#endif
- };
-
- /// Type access provider for token (enum) based symbols.
- struct by_kind
- {
- /// The symbol kind as needed by the constructor.
- typedef token_kind_type kind_type;
-
- /// Default constructor.
- by_kind () YY_NOEXCEPT;
-
-#if 201103L <= YY_CPLUSPLUS
- /// Move constructor.
- by_kind (by_kind&& that) YY_NOEXCEPT;
-#endif
-
- /// Copy constructor.
- by_kind (const by_kind& that) YY_NOEXCEPT;
-
- /// Constructor from (external) token numbers.
- by_kind (kind_type t) YY_NOEXCEPT;
-
-
-
- /// Record that this symbol is empty.
- void clear () YY_NOEXCEPT;
-
- /// Steal the symbol kind from \a that.
- void move (by_kind& that);
-
- /// The (internal) type number (corresponding to \a type).
- /// \a empty when empty.
- symbol_kind_type kind () const YY_NOEXCEPT;
-
- /// Backward compatibility (Bison 3.6).
- symbol_kind_type type_get () const YY_NOEXCEPT;
-
- /// The symbol kind.
- /// \a S_YYEMPTY when empty.
- symbol_kind_type kind_;
- };
-
- /// Backward compatibility for a private implementation detail (Bison 3.6).
- typedef by_kind by_type;
-
- /// "External" symbols: returned by the scanner.
- struct symbol_type : basic_symbol<by_kind>
- {
- /// Superclass.
- typedef basic_symbol<by_kind> super_type;
-
- /// Empty symbol.
- symbol_type () YY_NOEXCEPT {}
-
- /// Constructor for valueless symbols, and symbols from each type.
-#if 201103L <= YY_CPLUSPLUS
- symbol_type (int tok, location_type l)
- : super_type (token_kind_type (tok), std::move (l))
-#else
- symbol_type (int tok, const location_type& l)
- : super_type (token_kind_type (tok), l)
-#endif
- {
-#if !defined _MSC_VER || defined __clang__
- AGENT__ASSERT (tok == token::TOKEN_END
- || (token::TOKEN_AGENT_error <= tok && tok <= token::TOKEN_START_SUB_AGENT));
-#endif
- }
-#if 201103L <= YY_CPLUSPLUS
- symbol_type (int tok, bool v, location_type l)
- : super_type (token_kind_type (tok), std::move (v), std::move (l))
-#else
- symbol_type (int tok, const bool& v, const location_type& l)
- : super_type (token_kind_type (tok), v, l)
-#endif
- {
-#if !defined _MSC_VER || defined __clang__
- AGENT__ASSERT (tok == token::TOKEN_BOOLEAN);
-#endif
- }
-#if 201103L <= YY_CPLUSPLUS
- symbol_type (int tok, double v, location_type l)
- : super_type (token_kind_type (tok), std::move (v), std::move (l))
-#else
- symbol_type (int tok, const double& v, const location_type& l)
- : super_type (token_kind_type (tok), v, l)
-#endif
- {
-#if !defined _MSC_VER || defined __clang__
- AGENT__ASSERT (tok == token::TOKEN_FLOAT);
-#endif
- }
-#if 201103L <= YY_CPLUSPLUS
- symbol_type (int tok, int64_t v, location_type l)
- : super_type (token_kind_type (tok), std::move (v), std::move (l))
-#else
- symbol_type (int tok, const int64_t& v, const location_type& l)
- : super_type (token_kind_type (tok), v, l)
-#endif
- {
-#if !defined _MSC_VER || defined __clang__
- AGENT__ASSERT (tok == token::TOKEN_INTEGER);
-#endif
- }
-#if 201103L <= YY_CPLUSPLUS
- symbol_type (int tok, std::string v, location_type l)
- : super_type (token_kind_type (tok), std::move (v), std::move (l))
-#else
- symbol_type (int tok, const std::string& v, const location_type& l)
- : super_type (token_kind_type (tok), v, l)
-#endif
- {
-#if !defined _MSC_VER || defined __clang__
- AGENT__ASSERT (tok == token::TOKEN_STRING);
-#endif
- }
- };
-
- /// Build a parser object.
- AgentParser (isc::agent::ParserContext& ctx_yyarg);
- virtual ~AgentParser ();
-
-#if 201103L <= YY_CPLUSPLUS
- /// Non copyable.
- AgentParser (const AgentParser&) = delete;
- /// Non copyable.
- AgentParser& operator= (const AgentParser&) = delete;
-#endif
-
- /// Parse. An alias for parse ().
- /// \returns 0 iff parsing succeeded.
- int operator() ();
-
- /// Parse.
- /// \returns 0 iff parsing succeeded.
- virtual int parse ();
-
-#if AGENT_DEBUG
- /// The current debugging stream.
- std::ostream& debug_stream () const YY_ATTRIBUTE_PURE;
- /// Set the current debugging stream.
- void set_debug_stream (std::ostream &);
-
- /// Type for debugging levels.
- typedef int debug_level_type;
- /// The current debugging level.
- debug_level_type debug_level () const YY_ATTRIBUTE_PURE;
- /// Set the current debugging level.
- void set_debug_level (debug_level_type l);
-#endif
-
- /// Report a syntax error.
- /// \param loc where the syntax error is found.
- /// \param msg a description of the syntax error.
- virtual void error (const location_type& loc, const std::string& msg);
-
- /// Report a syntax error.
- void error (const syntax_error& err);
-
- /// The user-facing name of the symbol whose (internal) number is
- /// YYSYMBOL. No bounds checking.
- static std::string symbol_name (symbol_kind_type yysymbol);
-
- // Implementation of make_symbol for each token kind.
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_END (location_type l)
- {
- return symbol_type (token::TOKEN_END, std::move (l));
- }
-#else
- static
- symbol_type
- make_END (const location_type& l)
- {
- return symbol_type (token::TOKEN_END, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_AGENT_error (location_type l)
- {
- return symbol_type (token::TOKEN_AGENT_error, std::move (l));
- }
-#else
- static
- symbol_type
- make_AGENT_error (const location_type& l)
- {
- return symbol_type (token::TOKEN_AGENT_error, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_AGENT_UNDEF (location_type l)
- {
- return symbol_type (token::TOKEN_AGENT_UNDEF, std::move (l));
- }
-#else
- static
- symbol_type
- make_AGENT_UNDEF (const location_type& l)
- {
- return symbol_type (token::TOKEN_AGENT_UNDEF, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_COMMA (location_type l)
- {
- return symbol_type (token::TOKEN_COMMA, std::move (l));
- }
-#else
- static
- symbol_type
- make_COMMA (const location_type& l)
- {
- return symbol_type (token::TOKEN_COMMA, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_COLON (location_type l)
- {
- return symbol_type (token::TOKEN_COLON, std::move (l));
- }
-#else
- static
- symbol_type
- make_COLON (const location_type& l)
- {
- return symbol_type (token::TOKEN_COLON, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_LSQUARE_BRACKET (location_type l)
- {
- return symbol_type (token::TOKEN_LSQUARE_BRACKET, std::move (l));
- }
-#else
- static
- symbol_type
- make_LSQUARE_BRACKET (const location_type& l)
- {
- return symbol_type (token::TOKEN_LSQUARE_BRACKET, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_RSQUARE_BRACKET (location_type l)
- {
- return symbol_type (token::TOKEN_RSQUARE_BRACKET, std::move (l));
- }
-#else
- static
- symbol_type
- make_RSQUARE_BRACKET (const location_type& l)
- {
- return symbol_type (token::TOKEN_RSQUARE_BRACKET, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_LCURLY_BRACKET (location_type l)
- {
- return symbol_type (token::TOKEN_LCURLY_BRACKET, std::move (l));
- }
-#else
- static
- symbol_type
- make_LCURLY_BRACKET (const location_type& l)
- {
- return symbol_type (token::TOKEN_LCURLY_BRACKET, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_RCURLY_BRACKET (location_type l)
- {
- return symbol_type (token::TOKEN_RCURLY_BRACKET, std::move (l));
- }
-#else
- static
- symbol_type
- make_RCURLY_BRACKET (const location_type& l)
- {
- return symbol_type (token::TOKEN_RCURLY_BRACKET, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_NULL_TYPE (location_type l)
- {
- return symbol_type (token::TOKEN_NULL_TYPE, std::move (l));
- }
-#else
- static
- symbol_type
- make_NULL_TYPE (const location_type& l)
- {
- return symbol_type (token::TOKEN_NULL_TYPE, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_CONTROL_AGENT (location_type l)
- {
- return symbol_type (token::TOKEN_CONTROL_AGENT, std::move (l));
- }
-#else
- static
- symbol_type
- make_CONTROL_AGENT (const location_type& l)
- {
- return symbol_type (token::TOKEN_CONTROL_AGENT, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_HTTP_HOST (location_type l)
- {
- return symbol_type (token::TOKEN_HTTP_HOST, std::move (l));
- }
-#else
- static
- symbol_type
- make_HTTP_HOST (const location_type& l)
- {
- return symbol_type (token::TOKEN_HTTP_HOST, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_HTTP_PORT (location_type l)
- {
- return symbol_type (token::TOKEN_HTTP_PORT, std::move (l));
- }
-#else
- static
- symbol_type
- make_HTTP_PORT (const location_type& l)
- {
- return symbol_type (token::TOKEN_HTTP_PORT, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_HTTP_HEADERS (location_type l)
- {
- return symbol_type (token::TOKEN_HTTP_HEADERS, std::move (l));
- }
-#else
- static
- symbol_type
- make_HTTP_HEADERS (const location_type& l)
- {
- return symbol_type (token::TOKEN_HTTP_HEADERS, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_USER_CONTEXT (location_type l)
- {
- return symbol_type (token::TOKEN_USER_CONTEXT, std::move (l));
- }
-#else
- static
- symbol_type
- make_USER_CONTEXT (const location_type& l)
- {
- return symbol_type (token::TOKEN_USER_CONTEXT, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_COMMENT (location_type l)
- {
- return symbol_type (token::TOKEN_COMMENT, std::move (l));
- }
-#else
- static
- symbol_type
- make_COMMENT (const location_type& l)
- {
- return symbol_type (token::TOKEN_COMMENT, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_NAME (location_type l)
- {
- return symbol_type (token::TOKEN_NAME, std::move (l));
- }
-#else
- static
- symbol_type
- make_NAME (const location_type& l)
- {
- return symbol_type (token::TOKEN_NAME, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_VALUE (location_type l)
- {
- return symbol_type (token::TOKEN_VALUE, std::move (l));
- }
-#else
- static
- symbol_type
- make_VALUE (const location_type& l)
- {
- return symbol_type (token::TOKEN_VALUE, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_AUTHENTICATION (location_type l)
- {
- return symbol_type (token::TOKEN_AUTHENTICATION, std::move (l));
- }
-#else
- static
- symbol_type
- make_AUTHENTICATION (const location_type& l)
- {
- return symbol_type (token::TOKEN_AUTHENTICATION, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_TYPE (location_type l)
- {
- return symbol_type (token::TOKEN_TYPE, std::move (l));
- }
-#else
- static
- symbol_type
- make_TYPE (const location_type& l)
- {
- return symbol_type (token::TOKEN_TYPE, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_BASIC (location_type l)
- {
- return symbol_type (token::TOKEN_BASIC, std::move (l));
- }
-#else
- static
- symbol_type
- make_BASIC (const location_type& l)
- {
- return symbol_type (token::TOKEN_BASIC, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_REALM (location_type l)
- {
- return symbol_type (token::TOKEN_REALM, std::move (l));
- }
-#else
- static
- symbol_type
- make_REALM (const location_type& l)
- {
- return symbol_type (token::TOKEN_REALM, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_DIRECTORY (location_type l)
- {
- return symbol_type (token::TOKEN_DIRECTORY, std::move (l));
- }
-#else
- static
- symbol_type
- make_DIRECTORY (const location_type& l)
- {
- return symbol_type (token::TOKEN_DIRECTORY, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_CLIENTS (location_type l)
- {
- return symbol_type (token::TOKEN_CLIENTS, std::move (l));
- }
-#else
- static
- symbol_type
- make_CLIENTS (const location_type& l)
- {
- return symbol_type (token::TOKEN_CLIENTS, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_USER (location_type l)
- {
- return symbol_type (token::TOKEN_USER, std::move (l));
- }
-#else
- static
- symbol_type
- make_USER (const location_type& l)
- {
- return symbol_type (token::TOKEN_USER, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_USER_FILE (location_type l)
- {
- return symbol_type (token::TOKEN_USER_FILE, std::move (l));
- }
-#else
- static
- symbol_type
- make_USER_FILE (const location_type& l)
- {
- return symbol_type (token::TOKEN_USER_FILE, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_PASSWORD (location_type l)
- {
- return symbol_type (token::TOKEN_PASSWORD, std::move (l));
- }
-#else
- static
- symbol_type
- make_PASSWORD (const location_type& l)
- {
- return symbol_type (token::TOKEN_PASSWORD, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_PASSWORD_FILE (location_type l)
- {
- return symbol_type (token::TOKEN_PASSWORD_FILE, std::move (l));
- }
-#else
- static
- symbol_type
- make_PASSWORD_FILE (const location_type& l)
- {
- return symbol_type (token::TOKEN_PASSWORD_FILE, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_TRUST_ANCHOR (location_type l)
- {
- return symbol_type (token::TOKEN_TRUST_ANCHOR, std::move (l));
- }
-#else
- static
- symbol_type
- make_TRUST_ANCHOR (const location_type& l)
- {
- return symbol_type (token::TOKEN_TRUST_ANCHOR, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_CERT_FILE (location_type l)
- {
- return symbol_type (token::TOKEN_CERT_FILE, std::move (l));
- }
-#else
- static
- symbol_type
- make_CERT_FILE (const location_type& l)
- {
- return symbol_type (token::TOKEN_CERT_FILE, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_KEY_FILE (location_type l)
- {
- return symbol_type (token::TOKEN_KEY_FILE, std::move (l));
- }
-#else
- static
- symbol_type
- make_KEY_FILE (const location_type& l)
- {
- return symbol_type (token::TOKEN_KEY_FILE, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_CERT_REQUIRED (location_type l)
- {
- return symbol_type (token::TOKEN_CERT_REQUIRED, std::move (l));
- }
-#else
- static
- symbol_type
- make_CERT_REQUIRED (const location_type& l)
- {
- return symbol_type (token::TOKEN_CERT_REQUIRED, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_CONTROL_SOCKETS (location_type l)
- {
- return symbol_type (token::TOKEN_CONTROL_SOCKETS, std::move (l));
- }
-#else
- static
- symbol_type
- make_CONTROL_SOCKETS (const location_type& l)
- {
- return symbol_type (token::TOKEN_CONTROL_SOCKETS, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_DHCP4_SERVER (location_type l)
- {
- return symbol_type (token::TOKEN_DHCP4_SERVER, std::move (l));
- }
-#else
- static
- symbol_type
- make_DHCP4_SERVER (const location_type& l)
- {
- return symbol_type (token::TOKEN_DHCP4_SERVER, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_DHCP6_SERVER (location_type l)
- {
- return symbol_type (token::TOKEN_DHCP6_SERVER, std::move (l));
- }
-#else
- static
- symbol_type
- make_DHCP6_SERVER (const location_type& l)
- {
- return symbol_type (token::TOKEN_DHCP6_SERVER, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_D2_SERVER (location_type l)
- {
- return symbol_type (token::TOKEN_D2_SERVER, std::move (l));
- }
-#else
- static
- symbol_type
- make_D2_SERVER (const location_type& l)
- {
- return symbol_type (token::TOKEN_D2_SERVER, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_SOCKET_NAME (location_type l)
- {
- return symbol_type (token::TOKEN_SOCKET_NAME, std::move (l));
- }
-#else
- static
- symbol_type
- make_SOCKET_NAME (const location_type& l)
- {
- return symbol_type (token::TOKEN_SOCKET_NAME, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_SOCKET_TYPE (location_type l)
- {
- return symbol_type (token::TOKEN_SOCKET_TYPE, std::move (l));
- }
-#else
- static
- symbol_type
- make_SOCKET_TYPE (const location_type& l)
- {
- return symbol_type (token::TOKEN_SOCKET_TYPE, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_UNIX (location_type l)
- {
- return symbol_type (token::TOKEN_UNIX, std::move (l));
- }
-#else
- static
- symbol_type
- make_UNIX (const location_type& l)
- {
- return symbol_type (token::TOKEN_UNIX, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_HOOKS_LIBRARIES (location_type l)
- {
- return symbol_type (token::TOKEN_HOOKS_LIBRARIES, std::move (l));
- }
-#else
- static
- symbol_type
- make_HOOKS_LIBRARIES (const location_type& l)
- {
- return symbol_type (token::TOKEN_HOOKS_LIBRARIES, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_LIBRARY (location_type l)
- {
- return symbol_type (token::TOKEN_LIBRARY, std::move (l));
- }
-#else
- static
- symbol_type
- make_LIBRARY (const location_type& l)
- {
- return symbol_type (token::TOKEN_LIBRARY, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_PARAMETERS (location_type l)
- {
- return symbol_type (token::TOKEN_PARAMETERS, std::move (l));
- }
-#else
- static
- symbol_type
- make_PARAMETERS (const location_type& l)
- {
- return symbol_type (token::TOKEN_PARAMETERS, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_LOGGERS (location_type l)
- {
- return symbol_type (token::TOKEN_LOGGERS, std::move (l));
- }
-#else
- static
- symbol_type
- make_LOGGERS (const location_type& l)
- {
- return symbol_type (token::TOKEN_LOGGERS, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_OUTPUT_OPTIONS (location_type l)
- {
- return symbol_type (token::TOKEN_OUTPUT_OPTIONS, std::move (l));
- }
-#else
- static
- symbol_type
- make_OUTPUT_OPTIONS (const location_type& l)
- {
- return symbol_type (token::TOKEN_OUTPUT_OPTIONS, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_OUTPUT (location_type l)
- {
- return symbol_type (token::TOKEN_OUTPUT, std::move (l));
- }
-#else
- static
- symbol_type
- make_OUTPUT (const location_type& l)
- {
- return symbol_type (token::TOKEN_OUTPUT, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_DEBUGLEVEL (location_type l)
- {
- return symbol_type (token::TOKEN_DEBUGLEVEL, std::move (l));
- }
-#else
- static
- symbol_type
- make_DEBUGLEVEL (const location_type& l)
- {
- return symbol_type (token::TOKEN_DEBUGLEVEL, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_SEVERITY (location_type l)
- {
- return symbol_type (token::TOKEN_SEVERITY, std::move (l));
- }
-#else
- static
- symbol_type
- make_SEVERITY (const location_type& l)
- {
- return symbol_type (token::TOKEN_SEVERITY, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_FLUSH (location_type l)
- {
- return symbol_type (token::TOKEN_FLUSH, std::move (l));
- }
-#else
- static
- symbol_type
- make_FLUSH (const location_type& l)
- {
- return symbol_type (token::TOKEN_FLUSH, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_MAXSIZE (location_type l)
- {
- return symbol_type (token::TOKEN_MAXSIZE, std::move (l));
- }
-#else
- static
- symbol_type
- make_MAXSIZE (const location_type& l)
- {
- return symbol_type (token::TOKEN_MAXSIZE, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_MAXVER (location_type l)
- {
- return symbol_type (token::TOKEN_MAXVER, std::move (l));
- }
-#else
- static
- symbol_type
- make_MAXVER (const location_type& l)
- {
- return symbol_type (token::TOKEN_MAXVER, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_PATTERN (location_type l)
- {
- return symbol_type (token::TOKEN_PATTERN, std::move (l));
- }
-#else
- static
- symbol_type
- make_PATTERN (const location_type& l)
- {
- return symbol_type (token::TOKEN_PATTERN, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_START_JSON (location_type l)
- {
- return symbol_type (token::TOKEN_START_JSON, std::move (l));
- }
-#else
- static
- symbol_type
- make_START_JSON (const location_type& l)
- {
- return symbol_type (token::TOKEN_START_JSON, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_START_AGENT (location_type l)
- {
- return symbol_type (token::TOKEN_START_AGENT, std::move (l));
- }
-#else
- static
- symbol_type
- make_START_AGENT (const location_type& l)
- {
- return symbol_type (token::TOKEN_START_AGENT, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_START_SUB_AGENT (location_type l)
- {
- return symbol_type (token::TOKEN_START_SUB_AGENT, std::move (l));
- }
-#else
- static
- symbol_type
- make_START_SUB_AGENT (const location_type& l)
- {
- return symbol_type (token::TOKEN_START_SUB_AGENT, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_STRING (std::string v, location_type l)
- {
- return symbol_type (token::TOKEN_STRING, std::move (v), std::move (l));
- }
-#else
- static
- symbol_type
- make_STRING (const std::string& v, const location_type& l)
- {
- return symbol_type (token::TOKEN_STRING, v, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_INTEGER (int64_t v, location_type l)
- {
- return symbol_type (token::TOKEN_INTEGER, std::move (v), std::move (l));
- }
-#else
- static
- symbol_type
- make_INTEGER (const int64_t& v, const location_type& l)
- {
- return symbol_type (token::TOKEN_INTEGER, v, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_FLOAT (double v, location_type l)
- {
- return symbol_type (token::TOKEN_FLOAT, std::move (v), std::move (l));
- }
-#else
- static
- symbol_type
- make_FLOAT (const double& v, const location_type& l)
- {
- return symbol_type (token::TOKEN_FLOAT, v, l);
- }
-#endif
-#if 201103L <= YY_CPLUSPLUS
- static
- symbol_type
- make_BOOLEAN (bool v, location_type l)
- {
- return symbol_type (token::TOKEN_BOOLEAN, std::move (v), std::move (l));
- }
-#else
- static
- symbol_type
- make_BOOLEAN (const bool& v, const location_type& l)
- {
- return symbol_type (token::TOKEN_BOOLEAN, v, l);
- }
-#endif
-
-
- class context
- {
- public:
- context (const AgentParser& yyparser, const symbol_type& yyla);
- const symbol_type& lookahead () const YY_NOEXCEPT { return yyla_; }
- symbol_kind_type token () const YY_NOEXCEPT { return yyla_.kind (); }
- const location_type& location () const YY_NOEXCEPT { return yyla_.location; }
-
- /// Put in YYARG at most YYARGN of the expected tokens, and return the
- /// number of tokens stored in YYARG. If YYARG is null, return the
- /// number of expected tokens (guaranteed to be less than YYNTOKENS).
- int expected_tokens (symbol_kind_type yyarg[], int yyargn) const;
-
- private:
- const AgentParser& yyparser_;
- const symbol_type& yyla_;
- };
-
- private:
-#if YY_CPLUSPLUS < 201103L
- /// Non copyable.
- AgentParser (const AgentParser&);
- /// Non copyable.
- AgentParser& operator= (const AgentParser&);
-#endif
-
-
- /// Stored state numbers (used for stacks).
- typedef short state_type;
-
- /// The arguments of the error message.
- int yy_syntax_error_arguments_ (const context& yyctx,
- symbol_kind_type yyarg[], int yyargn) const;
-
- /// Generate an error message.
- /// \param yyctx the context in which the error occurred.
- virtual std::string yysyntax_error_ (const context& yyctx) const;
- /// Compute post-reduction state.
- /// \param yystate the current state
- /// \param yysym the nonterminal to push on the stack
- static state_type yy_lr_goto_state_ (state_type yystate, int yysym);
-
- /// Whether the given \c yypact_ value indicates a defaulted state.
- /// \param yyvalue the value to check
- static bool yy_pact_value_is_default_ (int yyvalue) YY_NOEXCEPT;
-
- /// Whether the given \c yytable_ value indicates a syntax error.
- /// \param yyvalue the value to check
- static bool yy_table_value_is_error_ (int yyvalue) YY_NOEXCEPT;
-
- static const short yypact_ninf_;
- static const signed char yytable_ninf_;
-
- /// Convert a scanner token kind \a t to a symbol kind.
- /// In theory \a t should be a token_kind_type, but character literals
- /// are valid, yet not members of the token_kind_type enum.
- static symbol_kind_type yytranslate_ (int t) YY_NOEXCEPT;
-
- /// Convert the symbol name \a n to a form suitable for a diagnostic.
- static std::string yytnamerr_ (const char *yystr);
-
- /// For a symbol, its name in clear.
- static const char* const yytname_[];
-
-
- // Tables.
- // YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
- // STATE-NUM.
- static const short yypact_[];
-
- // YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
- // Performed when YYTABLE does not specify something else to do. Zero
- // means the default is an error.
- static const unsigned char yydefact_[];
-
- // YYPGOTO[NTERM-NUM].
- static const short yypgoto_[];
-
- // YYDEFGOTO[NTERM-NUM].
- static const short yydefgoto_[];
-
- // YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If
- // positive, shift that token. If negative, reduce the rule whose
- // number is the opposite. If YYTABLE_NINF, syntax error.
- static const short yytable_[];
-
- static const short yycheck_[];
-
- // YYSTOS[STATE-NUM] -- The symbol kind of the accessing symbol of
- // state STATE-NUM.
- static const unsigned char yystos_[];
-
- // YYR1[RULE-NUM] -- Symbol kind of the left-hand side of rule RULE-NUM.
- static const unsigned char yyr1_[];
-
- // YYR2[RULE-NUM] -- Number of symbols on the right-hand side of rule RULE-NUM.
- static const signed char yyr2_[];
-
-
-#if AGENT_DEBUG
- // YYRLINE[YYN] -- Source line where rule number YYN was defined.
- static const short yyrline_[];
- /// Report on the debug stream that the rule \a r is going to be reduced.
- virtual void yy_reduce_print_ (int r) const;
- /// Print the state stack on the debug stream.
- virtual void yy_stack_print_ () const;
-
- /// Debugging level.
- int yydebug_;
- /// Debug stream.
- std::ostream* yycdebug_;
-
- /// \brief Display a symbol kind, value and location.
- /// \param yyo The output stream.
- /// \param yysym The symbol.
- template <typename Base>
- void yy_print_ (std::ostream& yyo, const basic_symbol<Base>& yysym) const;
-#endif
-
- /// \brief Reclaim the memory associated to a symbol.
- /// \param yymsg Why this token is reclaimed.
- /// If null, print nothing.
- /// \param yysym The symbol.
- template <typename Base>
- void yy_destroy_ (const char* yymsg, basic_symbol<Base>& yysym) const;
-
- private:
- /// Type access provider for state based symbols.
- struct by_state
- {
- /// Default constructor.
- by_state () YY_NOEXCEPT;
-
- /// The symbol kind as needed by the constructor.
- typedef state_type kind_type;
-
- /// Constructor.
- by_state (kind_type s) YY_NOEXCEPT;
-
- /// Copy constructor.
- by_state (const by_state& that) YY_NOEXCEPT;
-
- /// Record that this symbol is empty.
- void clear () YY_NOEXCEPT;
-
- /// Steal the symbol kind from \a that.
- void move (by_state& that);
-
- /// The symbol kind (corresponding to \a state).
- /// \a symbol_kind::S_YYEMPTY when empty.
- symbol_kind_type kind () const YY_NOEXCEPT;
-
- /// The state number used to denote an empty symbol.
- /// We use the initial state, as it does not have a value.
- enum { empty_state = 0 };
-
- /// The state.
- /// \a empty when empty.
- state_type state;
- };
-
- /// "Internal" symbol: element of the stack.
- struct stack_symbol_type : basic_symbol<by_state>
- {
- /// Superclass.
- typedef basic_symbol<by_state> super_type;
- /// Construct an empty symbol.
- stack_symbol_type ();
- /// Move or copy construction.
- stack_symbol_type (YY_RVREF (stack_symbol_type) that);
- /// Steal the contents from \a sym to build this.
- stack_symbol_type (state_type s, YY_MOVE_REF (symbol_type) sym);
-#if YY_CPLUSPLUS < 201103L
- /// Assignment, needed by push_back by some old implementations.
- /// Moves the contents of that.
- stack_symbol_type& operator= (stack_symbol_type& that);
-
- /// Assignment, needed by push_back by other implementations.
- /// Needed by some other old implementations.
- stack_symbol_type& operator= (const stack_symbol_type& that);
-#endif
- };
-
- /// A stack with random access from its top.
- template <typename T, typename S = std::vector<T> >
- class stack
- {
- public:
- // Hide our reversed order.
- typedef typename S::iterator iterator;
- typedef typename S::const_iterator const_iterator;
- typedef typename S::size_type size_type;
- typedef typename std::ptrdiff_t index_type;
-
- stack (size_type n = 200) YY_NOEXCEPT
- : seq_ (n)
- {}
-
-#if 201103L <= YY_CPLUSPLUS
- /// Non copyable.
- stack (const stack&) = delete;
- /// Non copyable.
- stack& operator= (const stack&) = delete;
-#endif
-
- /// Random access.
- ///
- /// Index 0 returns the topmost element.
- const T&
- operator[] (index_type i) const
- {
- return seq_[size_type (size () - 1 - i)];
- }
-
- /// Random access.
- ///
- /// Index 0 returns the topmost element.
- T&
- operator[] (index_type i)
- {
- return seq_[size_type (size () - 1 - i)];
- }
-
- /// Steal the contents of \a t.
- ///
- /// Close to move-semantics.
- void
- push (YY_MOVE_REF (T) t)
- {
- seq_.push_back (T ());
- operator[] (0).move (t);
- }
-
- /// Pop elements from the stack.
- void
- pop (std::ptrdiff_t n = 1) YY_NOEXCEPT
- {
- for (; 0 < n; --n)
- seq_.pop_back ();
- }
-
- /// Pop all elements from the stack.
- void
- clear () YY_NOEXCEPT
- {
- seq_.clear ();
- }
-
- /// Number of elements on the stack.
- index_type
- size () const YY_NOEXCEPT
- {
- return index_type (seq_.size ());
- }
-
- /// Iterator on top of the stack (going downwards).
- const_iterator
- begin () const YY_NOEXCEPT
- {
- return seq_.begin ();
- }
-
- /// Bottom of the stack.
- const_iterator
- end () const YY_NOEXCEPT
- {
- return seq_.end ();
- }
-
- /// Present a slice of the top of a stack.
- class slice
- {
- public:
- slice (const stack& stack, index_type range) YY_NOEXCEPT
- : stack_ (stack)
- , range_ (range)
- {}
-
- const T&
- operator[] (index_type i) const
- {
- return stack_[range_ - i];
- }
-
- private:
- const stack& stack_;
- index_type range_;
- };
-
- private:
-#if YY_CPLUSPLUS < 201103L
- /// Non copyable.
- stack (const stack&);
- /// Non copyable.
- stack& operator= (const stack&);
-#endif
- /// The wrapped container.
- S seq_;
- };
-
-
- /// Stack type.
- typedef stack<stack_symbol_type> stack_type;
-
- /// The stack.
- stack_type yystack_;
-
- /// Push a new state on the stack.
- /// \param m a debug message to display
- /// if null, no trace is output.
- /// \param sym the symbol
- /// \warning the contents of \a s.value is stolen.
- void yypush_ (const char* m, YY_MOVE_REF (stack_symbol_type) sym);
-
- /// Push a new look ahead token on the state on the stack.
- /// \param m a debug message to display
- /// if null, no trace is output.
- /// \param s the state
- /// \param sym the symbol (for its value and location).
- /// \warning the contents of \a sym.value is stolen.
- void yypush_ (const char* m, state_type s, YY_MOVE_REF (symbol_type) sym);
-
- /// Pop \a n symbols from the stack.
- void yypop_ (int n = 1) YY_NOEXCEPT;
-
- /// Constants.
- enum
- {
- yylast_ = 279, ///< Last index in yytable_.
- yynnts_ = 132, ///< Number of nonterminal symbols.
- yyfinal_ = 8 ///< Termination state number.
- };
-
-
- // User arguments.
- isc::agent::ParserContext& ctx;
-
- };
-
- inline
- AgentParser::symbol_kind_type
- AgentParser::yytranslate_ (int t) YY_NOEXCEPT
- {
- // YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to
- // TOKEN-NUM as returned by yylex.
- static
- const signed char
- translate_table[] =
- {
- 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 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
- };
- // Last valid token kind.
- const int code_max = 312;
-
- if (t <= 0)
- return symbol_kind::S_YYEOF;
- else if (t <= code_max)
- return static_cast <symbol_kind_type> (translate_table[t]);
- else
- return symbol_kind::S_YYUNDEF;
- }
-
- // basic_symbol.
- template <typename Base>
- AgentParser::basic_symbol<Base>::basic_symbol (const basic_symbol& that)
- : Base (that)
- , value ()
- , location (that.location)
- {
- switch (this->kind ())
- {
- case symbol_kind::S_value: // value
- case symbol_kind::S_map_value: // map_value
- case symbol_kind::S_socket_type_value: // socket_type_value
- case symbol_kind::S_auth_type_value: // auth_type_value
- value.copy< ElementPtr > (YY_MOVE (that.value));
- break;
-
- case symbol_kind::S_BOOLEAN: // "boolean"
- value.copy< bool > (YY_MOVE (that.value));
- break;
-
- case symbol_kind::S_FLOAT: // "floating point"
- value.copy< double > (YY_MOVE (that.value));
- break;
-
- case symbol_kind::S_INTEGER: // "integer"
- value.copy< int64_t > (YY_MOVE (that.value));
- break;
-
- case symbol_kind::S_STRING: // "constant string"
- value.copy< std::string > (YY_MOVE (that.value));
- break;
-
- default:
- break;
- }
-
- }
-
-
-
-
- template <typename Base>
- AgentParser::symbol_kind_type
- AgentParser::basic_symbol<Base>::type_get () const YY_NOEXCEPT
- {
- return this->kind ();
- }
-
-
- template <typename Base>
- bool
- AgentParser::basic_symbol<Base>::empty () const YY_NOEXCEPT
- {
- return this->kind () == symbol_kind::S_YYEMPTY;
- }
-
- template <typename Base>
- void
- AgentParser::basic_symbol<Base>::move (basic_symbol& s)
- {
- super_type::move (s);
- switch (this->kind ())
- {
- case symbol_kind::S_value: // value
- case symbol_kind::S_map_value: // map_value
- case symbol_kind::S_socket_type_value: // socket_type_value
- case symbol_kind::S_auth_type_value: // auth_type_value
- value.move< ElementPtr > (YY_MOVE (s.value));
- break;
-
- case symbol_kind::S_BOOLEAN: // "boolean"
- value.move< bool > (YY_MOVE (s.value));
- break;
-
- case symbol_kind::S_FLOAT: // "floating point"
- value.move< double > (YY_MOVE (s.value));
- break;
-
- case symbol_kind::S_INTEGER: // "integer"
- value.move< int64_t > (YY_MOVE (s.value));
- break;
-
- case symbol_kind::S_STRING: // "constant string"
- value.move< std::string > (YY_MOVE (s.value));
- break;
-
- default:
- break;
- }
-
- location = YY_MOVE (s.location);
- }
-
- // by_kind.
- inline
- AgentParser::by_kind::by_kind () YY_NOEXCEPT
- : kind_ (symbol_kind::S_YYEMPTY)
- {}
-
-#if 201103L <= YY_CPLUSPLUS
- inline
- AgentParser::by_kind::by_kind (by_kind&& that) YY_NOEXCEPT
- : kind_ (that.kind_)
- {
- that.clear ();
- }
-#endif
-
- inline
- AgentParser::by_kind::by_kind (const by_kind& that) YY_NOEXCEPT
- : kind_ (that.kind_)
- {}
-
- inline
- AgentParser::by_kind::by_kind (token_kind_type t) YY_NOEXCEPT
- : kind_ (yytranslate_ (t))
- {}
-
-
-
- inline
- void
- AgentParser::by_kind::clear () YY_NOEXCEPT
- {
- kind_ = symbol_kind::S_YYEMPTY;
- }
-
- inline
- void
- AgentParser::by_kind::move (by_kind& that)
- {
- kind_ = that.kind_;
- that.clear ();
- }
-
- inline
- AgentParser::symbol_kind_type
- AgentParser::by_kind::kind () const YY_NOEXCEPT
- {
- return kind_;
- }
-
-
- inline
- AgentParser::symbol_kind_type
- AgentParser::by_kind::type_get () const YY_NOEXCEPT
- {
- return this->kind ();
- }
-
-
-#line 14 "agent_parser.yy"
-} } // isc::agent
-#line 2574 "agent_parser.h"
-
-
-
-
-#endif // !YY_AGENT_AGENT_PARSER_H_INCLUDED
+++ /dev/null
-/* Copyright (C) 2017-2024 Internet Systems Consortium, Inc. ("ISC")
-
- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-%skeleton "lalr1.cc" /* -*- C++ -*- */
-%require "3.3.0"
-%defines
-%define api.parser.class {AgentParser}
-%define api.prefix {agent_}
-%define api.token.constructor
-%define api.value.type variant
-%define api.namespace {isc::agent}
-%define parse.assert
-%code requires
-{
-#include <string>
-#include <cc/data.h>
-#include <boost/lexical_cast.hpp>
-#include <agent/parser_context_decl.h>
-
-using namespace isc::agent;
-using namespace isc::data;
-using namespace std;
-}
-// The parsing context.
-%param { isc::agent::ParserContext& ctx }
-%locations
-%define parse.trace
-%define parse.error verbose
-%code
-{
-#include <agent/parser_context.h>
-
-// Avoid warnings with the error counter.
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
-#endif
-}
-
-
-%define api.token.prefix {TOKEN_}
-// Tokens in an order which makes sense and related to the intended use.
-// Actual regexps for tokens are defined in agent_lexer.ll.
-%token
- END 0 "end of file"
- COMMA ","
- COLON ":"
- LSQUARE_BRACKET "["
- RSQUARE_BRACKET "]"
- LCURLY_BRACKET "{"
- RCURLY_BRACKET "}"
- NULL_TYPE "null"
-
- CONTROL_AGENT "Control-agent"
- HTTP_HOST "http-host"
- HTTP_PORT "http-port"
- HTTP_HEADERS "http-headers"
-
- USER_CONTEXT "user-context"
- COMMENT "comment"
-
- NAME "name"
- VALUE "value"
-
- AUTHENTICATION "authentication"
- TYPE "type"
- BASIC "basic"
- REALM "realm"
- DIRECTORY "directory"
- CLIENTS "clients"
- USER "user"
- USER_FILE "user-file"
- PASSWORD "password"
- PASSWORD_FILE "password-file"
-
- TRUST_ANCHOR "trust-anchor"
- CERT_FILE "cert-file"
- KEY_FILE "key-file"
- CERT_REQUIRED "cert-required"
-
- CONTROL_SOCKETS "control-sockets"
- DHCP4_SERVER "dhcp4"
- DHCP6_SERVER "dhcp6"
- D2_SERVER "d2"
- SOCKET_NAME "socket-name"
- SOCKET_TYPE "socket-type"
- UNIX "unix"
-
- HOOKS_LIBRARIES "hooks-libraries"
- LIBRARY "library"
- PARAMETERS "parameters"
-
- LOGGERS "loggers"
- OUTPUT_OPTIONS "output-options"
- OUTPUT "output"
- DEBUGLEVEL "debuglevel"
- SEVERITY "severity"
- FLUSH "flush"
- MAXSIZE "maxsize"
- MAXVER "maxver"
- PATTERN "pattern"
-
- // Not real tokens, just a way to signal what the parser is expected to
- // parse. This define the starting point. It either can be full grammar
- // (START_AGENT), part of the grammar related to control-agent (START_SUB_AGENT)
- // or can be any valid JSON (START_JSON)
- START_JSON
- START_AGENT
- START_SUB_AGENT
-;
-
-%token <std::string> STRING "constant string"
-%token <int64_t> INTEGER "integer"
-%token <double> FLOAT "floating point"
-%token <bool> BOOLEAN "boolean"
-
-%type <ElementPtr> value
-%type <ElementPtr> map_value
-%type <ElementPtr> socket_type_value
-%type <ElementPtr> auth_type_value
-
-%printer { yyoutput << $$; } <*>;
-
-%%
-
-// The whole grammar starts with a map, because the config file
-// consists of only Control-Agent entry in one big { }.
-%start start;
-
-// The starting token can be one of those listed below. Note these are
-// "fake" tokens. They're produced by the lexer before any input text
-// is parsed.
-start: START_JSON { ctx.ctx_ = ctx.NO_KEYWORDS; } json
- | START_AGENT { ctx.ctx_ = ctx.CONFIG; } agent_syntax_map
- | START_SUB_AGENT { ctx.ctx_ = ctx.AGENT; } sub_agent
- ;
-
-// This rule defines a "shortcut". Instead of specifying the whole structure
-// expected by full grammar, we can tell the parser to start from content of
-// the Control-agent. This is very useful for unit-testing, so we don't need
-// to repeat the outer map and "Control-agent" map. We can simply provide
-// the contents of that map.
-sub_agent: LCURLY_BRACKET {
- // Parse the Control-agent map
- ElementPtr m(new MapElement(ctx.loc2pos(@1)));
- ctx.stack_.push_back(m);
-} global_params RCURLY_BRACKET {
- // parsing completed
-};
-
-// --- generic JSON parser -----------------------------------------------------
-
-// json expression can be a value. What value means is defined below.
-json: value {
- // Push back the JSON value on the stack
- ctx.stack_.push_back($1);
-};
-
-// Rules for value. This can be one of the primary types allowed in JSON.
-value: INTEGER { $$ = ElementPtr(new IntElement($1, ctx.loc2pos(@1))); }
- | FLOAT { $$ = ElementPtr(new DoubleElement($1, ctx.loc2pos(@1))); }
- | BOOLEAN { $$ = ElementPtr(new BoolElement($1, ctx.loc2pos(@1))); }
- | STRING { $$ = ElementPtr(new StringElement($1, ctx.loc2pos(@1))); }
- | NULL_TYPE { $$ = ElementPtr(new NullElement(ctx.loc2pos(@1))); }
- | map { $$ = ctx.stack_.back(); ctx.stack_.pop_back(); }
- | list_generic { $$ = ctx.stack_.back(); ctx.stack_.pop_back(); }
- ;
-
-// Rule for map. It will start with {, have some content and will end with }.
-map: LCURLY_BRACKET {
- // This code is executed when we're about to start parsing
- // the content of the map
- ElementPtr m(new MapElement(ctx.loc2pos(@1)));
- ctx.stack_.push_back(m);
-} map_content RCURLY_BRACKET {
- // map parsing completed. If we ever want to do any wrap up
- // (maybe some sanity checking), this would be the best place
- // for it.
-};
-
-map_value: map { $$ = ctx.stack_.back(); ctx.stack_.pop_back(); };
-
-// Rule for map content. In some cases it is allowed to have an empty map,
-// so we should say that explicitly. In most cases, though, there will
-// be some actual content inside. That's defined by not_empty_map
-map_content: %empty // empty map
- | not_empty_map
- ;
-
-// Rule for content of the map. It can have one of two formats:
-// 1) string: value
-// 2) non_empty_map , string: value
-// The first case covers a single entry, while the second case
-// covers all longer lists recursively.
-not_empty_map: STRING COLON value {
- // map containing a single entry
- ctx.unique($1, ctx.loc2pos(@1));
- ctx.stack_.back()->set($1, $3);
- }
- | not_empty_map COMMA STRING COLON value {
- // map consisting of a shorter map followed by
- // comma and string:value
- ctx.unique($3, ctx.loc2pos(@3));
- ctx.stack_.back()->set($3, $5);
- }
- | not_empty_map COMMA {
- ctx.warnAboutExtraCommas(@2);
- }
- ;
-
-list_generic: LSQUARE_BRACKET {
- ElementPtr l(new ListElement(ctx.loc2pos(@1)));
- ctx.stack_.push_back(l);
-} list_content RSQUARE_BRACKET {
-};
-
-list_content: %empty // Empty list
- | not_empty_list
- ;
-
-not_empty_list: value {
- // List consisting of a single element.
- ctx.stack_.back()->add($1);
- }
- | not_empty_list COMMA value {
- // List ending with , and a value.
- ctx.stack_.back()->add($3);
- }
- | not_empty_list COMMA {
- ctx.warnAboutExtraCommas(@2);
- }
- ;
-
-// --- generic JSON parser ends here -------------------------------------------
-
-// --- syntax checking parser starts here --------------------------------------
-
-// Unknown keyword in a map. This clever rule can be added to any map
-// if you want to have a nice expression printed when unknown (mistyped?)
-// parameter is found.
-unknown_map_entry: STRING COLON {
- const std::string& where = ctx.contextName();
- const std::string& keyword = $1;
- error(@1,
- "got unexpected keyword \"" + keyword + "\" in " + where + " map.");
-};
-
-// This defines the top-level { } that holds only Control-agent object.
-agent_syntax_map: LCURLY_BRACKET {
- // This code is executed when we're about to start parsing
- // the content of the map
- ElementPtr m(new MapElement(ctx.loc2pos(@1)));
- ctx.stack_.push_back(m);
-} global_object RCURLY_BRACKET {
- // map parsing completed. If we ever want to do any wrap up
- // (maybe some sanity checking), this would be the best place
- // for it.
-};
-
-// This represents the single top level entry, e.g. Control-agent.
-global_object: CONTROL_AGENT {
- // Let's create a MapElement that will represent it, add it to the
- // top level map (that's already on the stack) and put the new map
- // on the stack as well, so child elements will be able to add
- // themselves to it.
- ctx.unique("Control-agent", ctx.loc2pos(@1));
- ElementPtr m(new MapElement(ctx.loc2pos(@1)));
- ctx.stack_.back()->set("Control-agent", m);
- ctx.stack_.push_back(m);
- ctx.enter(ctx.AGENT);
-} COLON LCURLY_BRACKET global_params RCURLY_BRACKET {
- // Ok, we're done with parsing control-agent. Let's take the map
- // off the stack.
- ctx.stack_.pop_back();
- ctx.leave();
-}
- | global_object_comma
- ;
-
-global_object_comma: global_object COMMA {
- ctx.warnAboutExtraCommas(@2);
-};
-
-global_params: global_param
- | global_params COMMA global_param
- | global_params COMMA {
- ctx.warnAboutExtraCommas(@2);
- }
- ;
-
-// These are the parameters that are allowed in the top-level for
-// Dhcp6.
-global_param: http_host
- | http_port
- | http_headers
- | trust_anchor
- | cert_file
- | key_file
- | cert_required
- | authentication
- | control_sockets
- | hooks_libraries
- | loggers
- | user_context
- | comment
- | unknown_map_entry
- ;
-
-http_host: HTTP_HOST {
- ctx.unique("http-host", ctx.loc2pos(@1));
- ctx.enter(ctx.NO_KEYWORDS);
-} COLON STRING {
- ElementPtr host(new StringElement($4, ctx.loc2pos(@4)));
- ctx.stack_.back()->set("http-host", host);
- ctx.leave();
-};
-
-http_port: HTTP_PORT COLON INTEGER {
- ctx.unique("http-port", ctx.loc2pos(@1));
- ElementPtr prf(new IntElement($3, ctx.loc2pos(@3)));
- ctx.stack_.back()->set("http-port", prf);
-};
-
-trust_anchor: TRUST_ANCHOR {
- ctx.unique("trust-anchor", ctx.loc2pos(@1));
- ctx.enter(ctx.NO_KEYWORDS);
-} COLON STRING {
- ElementPtr ca(new StringElement($4, ctx.loc2pos(@4)));
- ctx.stack_.back()->set("trust-anchor", ca);
- ctx.leave();
-};
-
-cert_file: CERT_FILE {
- ctx.unique("cert-file", ctx.loc2pos(@1));
- ctx.enter(ctx.NO_KEYWORDS);
-} COLON STRING {
- ElementPtr cert(new StringElement($4, ctx.loc2pos(@4)));
- ctx.stack_.back()->set("cert-file", cert);
- ctx.leave();
-};
-
-key_file: KEY_FILE {
- ctx.unique("key-file", ctx.loc2pos(@1));
- ctx.enter(ctx.NO_KEYWORDS);
-} COLON STRING {
- ElementPtr key(new StringElement($4, ctx.loc2pos(@4)));
- ctx.stack_.back()->set("key-file", key);
- ctx.leave();
-};
-
-cert_required: CERT_REQUIRED COLON BOOLEAN {
- ctx.unique("cert-required", ctx.loc2pos(@1));
- ElementPtr req(new BoolElement($3, ctx.loc2pos(@3)));
- ctx.stack_.back()->set("cert-required", req);
-};
-
-user_context: USER_CONTEXT {
- ctx.enter(ctx.NO_KEYWORDS);
-} COLON map_value {
- ElementPtr parent = ctx.stack_.back();
- ElementPtr user_context = $4;
- ConstElementPtr old = parent->get("user-context");
-
- // Handle already existing user context
- if (old) {
- // Check if it was a comment or a duplicate
- if ((old->size() != 1) || !old->contains("comment")) {
- std::stringstream msg;
- msg << "duplicate user-context entries (previous at "
- << old->getPosition().str() << ")";
- error(@1, msg.str());
- }
- // Merge the comment
- user_context->set("comment", old->get("comment"));
- }
-
- // Set the user context
- parent->set("user-context", user_context);
- ctx.leave();
-};
-
-comment: COMMENT {
- ctx.enter(ctx.NO_KEYWORDS);
-} COLON STRING {
- ElementPtr parent = ctx.stack_.back();
- ElementPtr user_context(new MapElement(ctx.loc2pos(@1)));
- ElementPtr comment(new StringElement($4, ctx.loc2pos(@4)));
- user_context->set("comment", comment);
-
- // Handle already existing user context
- ConstElementPtr old = parent->get("user-context");
- if (old) {
- // Check for duplicate comment
- if (old->contains("comment")) {
- std::stringstream msg;
- msg << "duplicate user-context/comment entries (previous at "
- << old->getPosition().str() << ")";
- error(@1, msg.str());
- }
- // Merge the user context in the comment
- merge(user_context, old);
- }
-
- // Set the user context
- parent->set("user-context", user_context);
- ctx.leave();
-};
-
-http_headers: HTTP_HEADERS {
- ctx.unique("http-headers", ctx.loc2pos(@1));
- ElementPtr l(new ListElement(ctx.loc2pos(@1)));
- ctx.stack_.back()->set("http-headers", l);
- ctx.stack_.push_back(l);
- ctx.enter(ctx.HTTP_HEADERS);
-} COLON LSQUARE_BRACKET http_header_list RSQUARE_BRACKET {
- ctx.stack_.pop_back();
- ctx.leave();
-};
-
-http_header_list: %empty
- | not_empty_http_header_list
- ;
-
-not_empty_http_header_list: http_header
- | not_empty_http_header_list COMMA http_header
- | not_empty_http_header_list COMMA {
- ctx.warnAboutExtraCommas(@2);
- }
- ;
-
-http_header: LCURLY_BRACKET {
- ElementPtr m(new MapElement(ctx.loc2pos(@1)));
- ctx.stack_.back()->add(m);
- ctx.stack_.push_back(m);
-} http_header_params RCURLY_BRACKET {
- ctx.stack_.pop_back();
-};
-
-http_header_params: http_header_param
- | http_header_params COMMA http_header_param
- | http_header_params COMMA {
- ctx.warnAboutExtraCommas(@2);
- }
- ;
-
-http_header_param: name
- | header_value
- | user_context
- | comment
- | unknown_map_entry
- ;
-
-name: NAME {
- ctx.unique("name", ctx.loc2pos(@1));
- ctx.enter(ctx.NO_KEYWORDS);
-} COLON STRING {
- ElementPtr name(new StringElement($4, ctx.loc2pos(@4)));
- ctx.stack_.back()->set("name", name);
- ctx.leave();
-};
-
-header_value: VALUE {
- ctx.unique("value", ctx.loc2pos(@1));
- ctx.enter(ctx.NO_KEYWORDS);
-} COLON STRING {
- ElementPtr value(new StringElement($4, ctx.loc2pos(@4)));
- ctx.stack_.back()->set("value", value);
- ctx.leave();
-};
-
-// --- hooks-libraries ---------------------------------------------------------
-hooks_libraries: HOOKS_LIBRARIES {
- ctx.unique("hooks-libraries", ctx.loc2pos(@1));
- ElementPtr l(new ListElement(ctx.loc2pos(@1)));
- ctx.stack_.back()->set("hooks-libraries", l);
- ctx.stack_.push_back(l);
- ctx.enter(ctx.HOOKS_LIBRARIES);
-} COLON LSQUARE_BRACKET hooks_libraries_list RSQUARE_BRACKET {
- ctx.stack_.pop_back();
- ctx.leave();
-};
-
-hooks_libraries_list: %empty
- | not_empty_hooks_libraries_list
- ;
-
-not_empty_hooks_libraries_list: hooks_library
- | not_empty_hooks_libraries_list COMMA hooks_library
- | not_empty_hooks_libraries_list COMMA {
- ctx.warnAboutExtraCommas(@2);
- }
- ;
-
-hooks_library: LCURLY_BRACKET {
- ElementPtr m(new MapElement(ctx.loc2pos(@1)));
- ctx.stack_.back()->add(m);
- ctx.stack_.push_back(m);
-} hooks_params RCURLY_BRACKET {
- ctx.stack_.pop_back();
-};
-
-hooks_params: hooks_param
- | hooks_params COMMA hooks_param
- | hooks_params COMMA {
- ctx.warnAboutExtraCommas(@2);
- }
- | unknown_map_entry
- ;
-
-hooks_param: library
- | parameters
- ;
-
-library: LIBRARY {
- ctx.unique("library", ctx.loc2pos(@1));
- ctx.enter(ctx.NO_KEYWORDS);
-} COLON STRING {
- ElementPtr lib(new StringElement($4, ctx.loc2pos(@4)));
- ctx.stack_.back()->set("library", lib);
- ctx.leave();
-};
-
-parameters: PARAMETERS {
- ctx.unique("parameters", ctx.loc2pos(@1));
- ctx.enter(ctx.NO_KEYWORDS);
-} COLON map_value {
- ctx.stack_.back()->set("parameters", $4);
- ctx.leave();
-};
-
-// --- hooks-libraries end here ------------------------------------------------
-
-// --- control-sockets starts here ---------------------------------------------
-control_sockets: CONTROL_SOCKETS COLON LCURLY_BRACKET {
- ctx.unique("control-sockets", ctx.loc2pos(@1));
- ElementPtr m(new MapElement(ctx.loc2pos(@1)));
- ctx.stack_.back()->set("control-sockets", m);
- ctx.stack_.push_back(m);
- ctx.enter(ctx.CONTROL_SOCKETS);
-} control_sockets_params RCURLY_BRACKET {
- ctx.stack_.pop_back();
- ctx.leave();
-};
-
-// This defines what kind of control-sockets parameters we allow.
-// Note that empty map is not allowed here, because at least one control socket
-// is required.
-control_sockets_params: control_socket
- | control_sockets_params COMMA control_socket
- | control_sockets_params COMMA {
- ctx.warnAboutExtraCommas(@2);
- }
- ;
-
-// We currently support three types of sockets: DHCPv4, DHCPv6 and D2
-// (even though D2 socket support is not yet implemented).
-control_socket: dhcp4_server_socket
- | dhcp6_server_socket
- | d2_server_socket
- | unknown_map_entry
- ;
-
-// That's an entry for dhcp4 socket.
-dhcp4_server_socket: DHCP4_SERVER {
- ctx.unique("dhcp4", ctx.loc2pos(@1));
- ElementPtr m(new MapElement(ctx.loc2pos(@1)));
- ctx.stack_.back()->set("dhcp4", m);
- ctx.stack_.push_back(m);
- ctx.enter(ctx.SERVER);
-} COLON LCURLY_BRACKET control_socket_params RCURLY_BRACKET {
- ctx.stack_.pop_back();
- ctx.leave();
-};
-
-// That's an entry for dhcp6 socket.
-dhcp6_server_socket: DHCP6_SERVER {
- ctx.unique("dhcp6", ctx.loc2pos(@1));
- ElementPtr m(new MapElement(ctx.loc2pos(@1)));
- ctx.stack_.back()->set("dhcp6", m);
- ctx.stack_.push_back(m);
- ctx.enter(ctx.SERVER);
-} COLON LCURLY_BRACKET control_socket_params RCURLY_BRACKET {
- ctx.stack_.pop_back();
- ctx.leave();
-};
-
-// That's an entry for d2 socket.
-d2_server_socket: D2_SERVER {
- ctx.unique("d2", ctx.loc2pos(@1));
- ElementPtr m(new MapElement(ctx.loc2pos(@1)));
- ctx.stack_.back()->set("d2", m);
- ctx.stack_.push_back(m);
- ctx.enter(ctx.SERVER);
-} COLON LCURLY_BRACKET control_socket_params RCURLY_BRACKET {
- ctx.stack_.pop_back();
- ctx.leave();
-};
-
-// Socket parameters consist of one or more parameters.
-control_socket_params: control_socket_param
- | control_socket_params COMMA control_socket_param
- | control_socket_params COMMA {
- ctx.warnAboutExtraCommas(@2);
- }
- ;
-
-// We currently support two socket parameters: type and name.
-control_socket_param: socket_name
- | socket_type
- | user_context
- | comment
- | unknown_map_entry
- ;
-
-// This rule defines socket-name parameter.
-socket_name: SOCKET_NAME {
- ctx.unique("socket-name", ctx.loc2pos(@1));
- ctx.enter(ctx.NO_KEYWORDS);
-} COLON STRING {
- ElementPtr name(new StringElement($4, ctx.loc2pos(@4)));
- ctx.stack_.back()->set("socket-name", name);
- ctx.leave();
-};
-
-// This rule specifies socket type.
-socket_type: SOCKET_TYPE {
- ctx.unique("socket-type", ctx.loc2pos(@1));
- ctx.enter(ctx.SOCKET_TYPE);
-} COLON socket_type_value {
- ctx.stack_.back()->set("socket-type", $4);
- ctx.leave();
-};
-
-// We currently allow only unix domain sockets
-socket_type_value : UNIX { $$ = ElementPtr(new StringElement("unix", ctx.loc2pos(@1))); }
- ;
-
-// --- control-sockets end here ------------------------------------------------
-
-// --- authentication starts here -----------------------------------------------------
-
-authentication: AUTHENTICATION {
- ctx.unique("authentication", ctx.loc2pos(@1));
- ElementPtr m(new MapElement(ctx.loc2pos(@1)));
- ctx.stack_.back()->set("authentication", m);
- ctx.stack_.push_back(m);
- ctx.enter(ctx.AUTHENTICATION);
-} COLON LCURLY_BRACKET auth_params RCURLY_BRACKET {
- // The type parameter is required
- ctx.require("type", ctx.loc2pos(@4), ctx.loc2pos(@6));
- ctx.stack_.pop_back();
- ctx.leave();
-};
-
-auth_params: auth_param
- | auth_params COMMA auth_param
- | auth_params COMMA {
- ctx.warnAboutExtraCommas(@2);
- }
- ;
-
-auth_param: auth_type
- | realm
- | directory
- | clients
- | comment
- | user_context
- | unknown_map_entry
- ;
-
-auth_type: TYPE {
- ctx.unique("type", ctx.loc2pos(@1));
- ctx.enter(ctx.AUTH_TYPE);
-} COLON auth_type_value {
- ctx.stack_.back()->set("type", $4);
- ctx.leave();
-};
-
-auth_type_value: BASIC { $$ = ElementPtr(new StringElement("basic", ctx.loc2pos(@1))); }
- ;
-
-realm: REALM {
- ctx.unique("realm", ctx.loc2pos(@1));
- ctx.enter(ctx.NO_KEYWORDS);
-} COLON STRING {
- ElementPtr realm(new StringElement($4, ctx.loc2pos(@4)));
- ctx.stack_.back()->set("realm", realm);
- ctx.leave();
-};
-
-directory: DIRECTORY {
- ctx.unique("directory", ctx.loc2pos(@1));
- ctx.enter(ctx.NO_KEYWORDS);
-} COLON STRING {
- ElementPtr directory(new StringElement($4, ctx.loc2pos(@4)));
- ctx.stack_.back()->set("directory", directory);
- ctx.leave();
-};
-
-clients: CLIENTS {
- ctx.unique("clients", ctx.loc2pos(@1));
- ElementPtr l(new ListElement(ctx.loc2pos(@1)));
- ctx.stack_.back()->set("clients", l);
- ctx.stack_.push_back(l);
- ctx.enter(ctx.CLIENTS);
-} COLON LSQUARE_BRACKET clients_list RSQUARE_BRACKET {
- ctx.stack_.pop_back();
- ctx.leave();
-};
-
-clients_list: %empty
- | not_empty_clients_list
- ;
-
-not_empty_clients_list: basic_auth
- | not_empty_clients_list COMMA basic_auth
- | not_empty_clients_list COMMA {
- ctx.warnAboutExtraCommas(@2);
- }
- ;
-
-basic_auth: LCURLY_BRACKET {
- ElementPtr m(new MapElement(ctx.loc2pos(@1)));
- ctx.stack_.back()->add(m);
- ctx.stack_.push_back(m);
-} clients_params RCURLY_BRACKET {
- ctx.stack_.pop_back();
-};
-
-clients_params: clients_param
- | clients_params COMMA clients_param
- | clients_params COMMA {
- ctx.warnAboutExtraCommas(@2);
- }
- ;
-
-clients_param: user
- | user_file
- | password
- | password_file
- | user_context
- | comment
- | unknown_map_entry
- ;
-
-user: USER {
- ctx.unique("user", ctx.loc2pos(@1));
- ctx.enter(ctx.NO_KEYWORDS);
-} COLON STRING {
- ElementPtr user(new StringElement($4, ctx.loc2pos(@4)));
- ctx.stack_.back()->set("user", user);
- ctx.leave();
-};
-
-user_file: USER_FILE {
- ctx.unique("user-file", ctx.loc2pos(@1));
- ctx.enter(ctx.NO_KEYWORDS);
-} COLON STRING {
- ElementPtr user(new StringElement($4, ctx.loc2pos(@4)));
- ctx.stack_.back()->set("user-file", user);
- ctx.leave();
-};
-
-password: PASSWORD {
- ctx.unique("password", ctx.loc2pos(@1));
- ctx.enter(ctx.NO_KEYWORDS);
-} COLON STRING {
- ElementPtr password(new StringElement($4, ctx.loc2pos(@4)));
- ctx.stack_.back()->set("password", password);
- ctx.leave();
-};
-
-password_file: PASSWORD_FILE {
- ctx.unique("password-file", ctx.loc2pos(@1));
- ctx.enter(ctx.NO_KEYWORDS);
-} COLON STRING {
- ElementPtr password(new StringElement($4, ctx.loc2pos(@4)));
- ctx.stack_.back()->set("password-file", password);
- ctx.leave();
-};
-
-// --- authentication end here -----------------------------------------------------
-
-// --- Loggers starts here -----------------------------------------------------
-
-loggers: LOGGERS {
- ctx.unique("loggers", ctx.loc2pos(@1));
- ElementPtr l(new ListElement(ctx.loc2pos(@1)));
- ctx.stack_.back()->set("loggers", l);
- ctx.stack_.push_back(l);
- ctx.enter(ctx.LOGGERS);
-} COLON LSQUARE_BRACKET loggers_entries RSQUARE_BRACKET {
- ctx.stack_.pop_back();
- ctx.leave();
-};
-
-// These are the parameters allowed in loggers: either one logger
-// entry or multiple entries separate by commas.
-loggers_entries: logger_entry
- | loggers_entries COMMA logger_entry
- | loggers_entries COMMA {
- ctx.warnAboutExtraCommas(@2);
- }
- ;
-
-// This defines a single entry defined in loggers.
-logger_entry: LCURLY_BRACKET {
- ElementPtr l(new MapElement(ctx.loc2pos(@1)));
- ctx.stack_.back()->add(l);
- ctx.stack_.push_back(l);
-} logger_params RCURLY_BRACKET {
- ctx.stack_.pop_back();
-};
-
-logger_params: logger_param
- | logger_params COMMA logger_param
- | logger_params COMMA {
- ctx.warnAboutExtraCommas(@2);
- }
- ;
-
-logger_param: name
- | output_options_list
- | debuglevel
- | severity
- | user_context
- | comment
- | unknown_map_entry
- ;
-
-debuglevel: DEBUGLEVEL COLON INTEGER {
- ctx.unique("debuglevel", ctx.loc2pos(@1));
- ElementPtr dl(new IntElement($3, ctx.loc2pos(@3)));
- ctx.stack_.back()->set("debuglevel", dl);
-};
-
-severity: SEVERITY {
- ctx.unique("severity", ctx.loc2pos(@1));
- ctx.enter(ctx.NO_KEYWORDS);
-} COLON STRING {
- ElementPtr sev(new StringElement($4, ctx.loc2pos(@4)));
- ctx.stack_.back()->set("severity", sev);
- ctx.leave();
-};
-
-output_options_list: OUTPUT_OPTIONS {
- ctx.unique("output-options", ctx.loc2pos(@1));
- ElementPtr l(new ListElement(ctx.loc2pos(@1)));
- ctx.stack_.back()->set("output-options", l);
- ctx.stack_.push_back(l);
- ctx.enter(ctx.OUTPUT_OPTIONS);
-} COLON LSQUARE_BRACKET output_options_list_content RSQUARE_BRACKET {
- ctx.stack_.pop_back();
- ctx.leave();
-};
-
-output_options_list_content: output_entry
- | output_options_list_content COMMA output_entry
- | output_options_list_content COMMA {
- ctx.warnAboutExtraCommas(@2);
- }
- ;
-
-output_entry: LCURLY_BRACKET {
- ElementPtr m(new MapElement(ctx.loc2pos(@1)));
- ctx.stack_.back()->add(m);
- ctx.stack_.push_back(m);
-} output_params_list RCURLY_BRACKET {
- ctx.stack_.pop_back();
-};
-
-output_params_list: output_params
- | output_params_list COMMA output_params
- | output_params_list COMMA {
- ctx.warnAboutExtraCommas(@2);
- }
- ;
-
-output_params: output
- | flush
- | maxsize
- | maxver
- | pattern
- ;
-
-output: OUTPUT {
- ctx.unique("output", ctx.loc2pos(@1));
- ctx.enter(ctx.NO_KEYWORDS);
-} COLON STRING {
- ElementPtr sev(new StringElement($4, ctx.loc2pos(@4)));
- ctx.stack_.back()->set("output", sev);
- ctx.leave();
-};
-
-flush: FLUSH COLON BOOLEAN {
- ctx.unique("flush", ctx.loc2pos(@1));
- ElementPtr flush(new BoolElement($3, ctx.loc2pos(@3)));
- ctx.stack_.back()->set("flush", flush);
-}
-
-maxsize: MAXSIZE COLON INTEGER {
- ctx.unique("maxsize", ctx.loc2pos(@1));
- ElementPtr maxsize(new IntElement($3, ctx.loc2pos(@3)));
- ctx.stack_.back()->set("maxsize", maxsize);
-}
-
-maxver: MAXVER COLON INTEGER {
- ctx.unique("maxver", ctx.loc2pos(@1));
- ElementPtr maxver(new IntElement($3, ctx.loc2pos(@3)));
- ctx.stack_.back()->set("maxver", maxver);
-}
-
-pattern: PATTERN {
- ctx.unique("pattern", ctx.loc2pos(@1));
- ctx.enter(ctx.NO_KEYWORDS);
-} COLON STRING {
- ElementPtr sev(new StringElement($4, ctx.loc2pos(@4)));
- ctx.stack_.back()->set("pattern", sev);
- ctx.leave();
-};
-
-%%
-
-void
-isc::agent::AgentParser::error(const location_type& loc,
- const std::string& what)
-{
- ctx.error(loc, what);
-}
+++ /dev/null
-// Copyright (C) 2016-2025 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#include <config.h>
-
-#include <agent/ca_cfg_mgr.h>
-#include <agent/ca_log.h>
-#include <agent/simple_parser.h>
-#include <cc/simple_parser.h>
-#include <cc/command_interpreter.h>
-#include <http/basic_auth_config.h>
-#include <exceptions/exceptions.h>
-
-using namespace isc::config;
-using namespace isc::dhcp;
-using namespace isc::process;
-using namespace isc::data;
-
-namespace isc {
-namespace agent {
-
-CtrlAgentCfgContext::CtrlAgentCfgContext()
- : http_host_(""), http_port_(0), http_headers_(),
- trust_anchor_(""), cert_file_(""), key_file_(""), cert_required_(true) {
-}
-
-CtrlAgentCfgContext::CtrlAgentCfgContext(const CtrlAgentCfgContext& orig)
- : ConfigBase(), ctrl_sockets_(orig.ctrl_sockets_),
- http_host_(orig.http_host_), http_port_(orig.http_port_),
- http_headers_(orig.http_headers_),
- trust_anchor_(orig.trust_anchor_), cert_file_(orig.cert_file_),
- key_file_(orig.key_file_), cert_required_(orig.cert_required_),
- hooks_config_(orig.hooks_config_), auth_config_(orig.auth_config_) {
-}
-
-CtrlAgentCfgMgr::CtrlAgentCfgMgr()
- : DCfgMgrBase(ConfigPtr(new CtrlAgentCfgContext())) {
-}
-
-CtrlAgentCfgMgr::~CtrlAgentCfgMgr() {
-}
-
-std::string
-CtrlAgentCfgMgr::getConfigSummary(const uint32_t /*selection*/) {
-
- CtrlAgentCfgContextPtr ctx = getCtrlAgentCfgContext();
-
- // First print the http stuff.
- std::ostringstream s;
- s << "listening on " << ctx->getHttpHost() << ", port "
- << ctx->getHttpPort();
-
- // When TLS is setup print its config.
- if (!ctx->getTrustAnchor().empty()) {
- s << ", trust anchor " << ctx->getTrustAnchor()
- << ", cert file " << ctx->getCertFile()
- << ", key file " << ctx->getKeyFile();
- if (ctx->getCertRequired()) {
- s << ", client certs are required";
- } else {
- s << ", client certs are optional";
- }
- }
- s << ", control sockets: ";
-
- // Then print the control-sockets
- s << ctx->getControlSocketInfoSummary();
-
- // Add something if authentication is required.
- const isc::http::HttpAuthConfigPtr& auth = ctx->getAuthConfig();
- if (auth && !auth->empty()) {
- s << ", requires basic HTTP authentication";
- }
-
- // Finally, print the hook libraries names
- const isc::hooks::HookLibsCollection libs = ctx->getHooksConfig().get();
- s << ", " << libs.size() << " lib(s):";
- for (auto const& lib : libs) {
- s << lib.cfgname_ << " ";
- }
-
- return (s.str());
-}
-
-ConfigPtr
-CtrlAgentCfgMgr::createNewContext() {
- return (ConfigPtr(new CtrlAgentCfgContext()));
-}
-
-ConstElementPtr
-CtrlAgentCfgMgr::parse(ConstElementPtr config_set, bool check_only) {
- // Do a sanity check first.
- if (!config_set) {
- isc_throw(DhcpConfigError, "Mandatory config parameter not provided");
- }
-
- CtrlAgentCfgContextPtr ctx = getCtrlAgentCfgContext();
-
- // Set the defaults
- ElementPtr cfg = boost::const_pointer_cast<Element>(config_set);
- AgentSimpleParser::setAllDefaults(cfg);
-
- // And parse the configuration.
- ConstElementPtr answer;
- std::string excuse;
- try {
- // Do the actual parsing
- AgentSimpleParser parser;
- parser.checkTlsSetup(cfg);
- parser.parse(ctx, cfg, check_only);
- } catch (const isc::Exception& ex) {
- excuse = ex.what();
- answer = createAnswer(CONTROL_RESULT_ERROR, excuse);
- } catch (...) {
- excuse = "undefined configuration parsing error";
- answer = createAnswer(CONTROL_RESULT_ERROR, excuse);
- }
-
- // At this stage the answer was created only in case of exception.
- if (answer) {
- if (check_only) {
- LOG_ERROR(agent_logger, CTRL_AGENT_CONFIG_CHECK_FAIL).arg(excuse);
- } else {
- LOG_ERROR(agent_logger, CTRL_AGENT_CONFIG_FAIL).arg(excuse);
- }
- return (answer);
- }
-
- if (check_only) {
- answer = createAnswer(CONTROL_RESULT_SUCCESS,
- "Configuration check successful");
- } else {
- answer = createAnswer(CONTROL_RESULT_SUCCESS,
- "Configuration applied successfully.");
- }
-
- return (answer);
-}
-
-std::list<std::list<std::string>>
-CtrlAgentCfgMgr::jsonPathsToRedact() const {
- static std::list<std::list<std::string>> const list({
- {"authentication", "clients", "[]"},
- {"hooks-libraries", "[]", "parameters", "*"},
- });
- return list;
-}
-
-data::ConstElementPtr
-CtrlAgentCfgContext::getControlSocketInfo(const std::string& service) const {
- auto si = ctrl_sockets_.find(service);
- return ((si != ctrl_sockets_.end()) ? si->second : ConstElementPtr());
-}
-
-void
-CtrlAgentCfgContext::setControlSocketInfo(const ConstElementPtr& control_socket,
- const std::string& service) {
- ctrl_sockets_[service] = control_socket;
-}
-
-std::string
-CtrlAgentCfgContext::getControlSocketInfoSummary() const {
- std::ostringstream s;
- for (auto const& si : ctrl_sockets_) {
- if (s.tellp() != 0) {
- s << " ";
- }
- s << si.first;
- }
-
- if (s.tellp() == 0) {
- s << "none";
- }
-
- return (s.str());
-}
-
-ElementPtr
-CtrlAgentCfgContext::toElement() const {
- ElementPtr ca = ConfigBase::toElement();
- // Set user-context
- contextToElement(ca);
- // Set http-host
- ca->set("http-host", Element::create(http_host_));
- // Set http-port
- ca->set("http-port", Element::create(static_cast<int64_t>(http_port_)));
- // Set http-headers
- if (!http_headers_.empty()) {
- ca->set("http-headers", CfgHttpHeaderstoElement(http_headers_));
- }
- // Set TLS setup when enabled
- if (!trust_anchor_.empty()) {
- ca->set("trust-anchor", Element::create(trust_anchor_));
- ca->set("cert-file", Element::create(cert_file_));
- ca->set("key-file", Element::create(key_file_));
- ca->set("cert-required", Element::create(cert_required_));
- }
- // Set authentication
- if (auth_config_) {
- ca->set("authentication", auth_config_->toElement());
- }
- ca->set("hooks-libraries", hooks_config_.toElement());
- // Set control-sockets
- ElementPtr control_sockets = Element::createMap();
- for (auto const& si : ctrl_sockets_) {
- // Remove validated_path.
- auto mutable_socket_info = boost::const_pointer_cast<Element>(
- UserContext::toElement(si.second));
- mutable_socket_info->remove("validated-socket-name");
- control_sockets->set(si.first, mutable_socket_info);
- }
-
- ca->set("control-sockets", control_sockets);
- // Set Control-agent
- ElementPtr result = Element::createMap();
- result->set("Control-agent", ca);
-
- return (result);
-}
-
-} // namespace isc::agent
-} // namespace isc
+++ /dev/null
-// Copyright (C) 2016-2024 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#ifndef CTRL_AGENT_CFG_MGR_H
-#define CTRL_AGENT_CFG_MGR_H
-
-#include <cc/data.h>
-#include <hooks/hooks_config.h>
-#include <http/auth_config.h>
-#include <http/cfg_http_header.h>
-#include <process/d_cfg_mgr.h>
-#include <boost/pointer_cast.hpp>
-#include <map>
-#include <string>
-
-namespace isc {
-namespace agent {
-
-class CtrlAgentCfgContext;
-/// @brief Pointer to a configuration context.
-typedef boost::shared_ptr<CtrlAgentCfgContext> CtrlAgentCfgContextPtr;
-
-/// @brief Control Agent Configuration Context.
-///
-/// Implement the storage container for configuration context.
-/// It provides a single enclosure for the storage of configuration parameters
-/// and any other Control Agent specific information that needs to be accessible
-/// during configuration parsing as well as to the application as a whole.
-/// It is derived from the context base class, ConfigBase.
-class CtrlAgentCfgContext : public process::ConfigBase {
-public:
-
- /// @brief Default constructor
- CtrlAgentCfgContext();
-
- /// @brief Creates a clone of this context object.
- ///
- /// Note this method does not do deep copy the information about control sockets.
- /// That data is stored as ConstElementPtr (a shared pointer) to the actual data.
- ///
- /// @return A pointer to the new clone.
- virtual process::ConfigPtr clone() {
- return (process::ConfigPtr(new CtrlAgentCfgContext(*this)));
- }
-
- /// @brief Returns information about control socket
- ///
- /// This method returns Element tree structure that describes the control
- /// socket (or null pointer if the socket is not defined for a particular
- /// server type). This information is expected to be compatible with
- /// data passed to @ref isc::config::UnixCommandMgr::openCommandSocket.
- ///
- /// @param service server being controlled
- /// @return pointer to the Element that holds control-socket map (or NULL)
- isc::data::ConstElementPtr
- getControlSocketInfo(const std::string& service) const;
-
- /// @brief Sets information about the control socket
- ///
- /// This method stores Element tree structure that describes the control
- /// socket. This information is expected to be compatible with
- /// data passed to @ref isc::config::UnixCommandMgr::openCommandSocket.
- ///
- /// @param control_socket Element that holds control-socket map
- /// @param service server being controlled
- void setControlSocketInfo(const isc::data::ConstElementPtr& control_socket,
- const std::string& service);
-
- /// @brief Returns socket configuration summary in a textual format.
- std::string getControlSocketInfoSummary() const;
-
- /// @brief Sets http-host parameter
- ///
- /// @param host Hostname or IP address where the agent's HTTP service
- /// will be available.
- void setHttpHost(const std::string& host) {
- http_host_ = host;
- }
-
- /// @brief Returns http-host parameter
- ///
- /// @return Hostname or IP address where the agent's HTTP service is
- /// available.
- std::string getHttpHost() const {
- return (http_host_);
- }
-
- /// @brief Sets http port
- ///
- /// @param port sets the TCP port the HTTP server will listen on
- void setHttpPort(const uint16_t port) {
- http_port_ = port;
- }
-
- /// @brief Returns the TCP post the HTTP server will listen on
- uint16_t getHttpPort() const {
- return (http_port_);
- }
-
- /// @brief Sets http-headers parameter
- ///
- /// @param headers Collection of config HTTP headers.
- void setHttpHeaders(const isc::http::CfgHttpHeaders& headers) {
- http_headers_ = headers;
- }
-
- /// @brief Returns http-headers parameter
- ///
- /// @return Collection of config HTTP headers.
- const isc::http::CfgHttpHeaders& getHttpHeaders() const {
- return (http_headers_);
- }
-
- /// @brief Sets HTTP authentication configuration.
- ///
- /// @note Only the basic HTTP authentication is supported.
- ///
- /// @param auth_config HTTP authentication configuration.
- void setAuthConfig(const isc::http::HttpAuthConfigPtr& auth_config) {
- auth_config_ = auth_config;
- }
-
- /// @brief Returns HTTP authentication configuration
- ///
- /// @note Only the basic HTTP authentication is supported.
- ///
- /// @return HTTP authentication configuration.
- const isc::http::HttpAuthConfigPtr& getAuthConfig() const {
- return (auth_config_);
- }
-
- /// @brief Sets trust-anchor parameter
- ///
- /// @param ca Trust anchor aka Certificate Authority (can be a file name
- /// or a directory path).
- void setTrustAnchor(const std::string& ca) {
- trust_anchor_ = ca;
- }
-
- /// @brief Returns trust-anchor parameter
- ///
- /// @return Trust anchor aka Certificate Authority
- std::string getTrustAnchor() const {
- return (trust_anchor_);
- }
-
- /// @brief Sets cert-file parameter
- ///
- /// @param cert Server certificate file name
- void setCertFile(const std::string& cert) {
- cert_file_ = cert;
- }
-
- /// @brief Returns cert-file parameter
- ///
- /// @return Server certificate file name
- std::string getCertFile() const {
- return (cert_file_);
- }
-
- /// @brief Sets key-file parameter
- ///
- /// @param key Server private key file name
- void setKeyFile(const std::string& key) {
- key_file_ = key;
- }
-
- /// @brief Returns key-file parameter
- ///
- /// @return Server private key file name
- std::string getKeyFile() const {
- return (key_file_);
- }
-
- /// @brief Sets cert-required parameter
- ///
- /// @param required Client certificates are required when true
- /// (the default) or optional when false
- void setCertRequired(bool required) {
- cert_required_ = required;
- }
-
- /// @brief Returns cert-required parameter
- ///
- /// @return True when client certificates are required, false when they
- /// are optional, the default is to require them (true).
- bool getCertRequired() const {
- return (cert_required_);
- }
-
- /// @brief Returns non-const reference to configured hooks libraries.
- ///
- /// @return non-const reference to configured hooks libraries.
- isc::hooks::HooksConfig& getHooksConfig() {
- return (hooks_config_);
- }
-
- /// @brief Returns const reference to configured hooks libraries.
- ///
- /// @return const reference to configured hooks libraries.
- const isc::hooks::HooksConfig& getHooksConfig() const {
- return (hooks_config_);
- }
-
- /// @brief Unparse a configuration object
- ///
- /// Returns an element which must parse into the same object, i.e.
- /// @code
- /// for all valid config C parse(parse(C)->toElement()) == parse(C)
- /// @endcode
- ///
- /// @return a pointer to a configuration which can be parsed into
- /// the initial configuration object
- virtual isc::data::ElementPtr toElement() const;
-
-private:
-
- /// @brief Private copy constructor
- ///
- /// It is private to forbid anyone outside of this class to make copies.
- /// The only legal way to copy a context is to call @ref clone().
- ///
- /// @param orig the original context to copy from
- CtrlAgentCfgContext(const CtrlAgentCfgContext& orig);
-
- /// @brief Private assignment operator to avoid potential for slicing.
- ///
- /// @param rhs Context to be assigned.
- CtrlAgentCfgContext& operator=(const CtrlAgentCfgContext& rhs);
-
- /// Socket information will be stored here (for all supported servers)
- std::map<std::string, isc::data::ConstElementPtr> ctrl_sockets_;
-
- /// Hostname the CA should listen on.
- std::string http_host_;
-
- /// TCP port the CA should listen on.
- uint16_t http_port_;
-
- /// Config HTTP headers.
- isc::http::CfgHttpHeaders http_headers_;
-
- /// Trust anchor aka Certificate Authority (can be a file name or
- /// a directory path).
- std::string trust_anchor_;
-
- /// Server certificate file name.
- std::string cert_file_;
-
- /// Server private key file name.
- std::string key_file_;
-
- /// Client certificates requirement flag (default is true i.e. to
- /// require them).
- bool cert_required_;
-
- /// @brief Configured hooks libraries.
- isc::hooks::HooksConfig hooks_config_;
-
- /// @brief Configured basic HTTP authentification clients.
- isc::http::HttpAuthConfigPtr auth_config_;
-};
-
-/// @brief Ctrl Agent Configuration Manager.
-///
-/// Provides the mechanisms for managing the Control Agent application's
-/// configuration.
-class CtrlAgentCfgMgr : public process::DCfgMgrBase {
-public:
-
- /// @brief Constructor.
- CtrlAgentCfgMgr();
-
- /// @brief Destructor
- virtual ~CtrlAgentCfgMgr();
-
- /// @brief Convenience method that returns the Control Agent configuration
- /// context.
- ///
- /// @return returns a pointer to the configuration context.
- CtrlAgentCfgContextPtr getCtrlAgentCfgContext() {
- return (boost::dynamic_pointer_cast<CtrlAgentCfgContext>(getContext()));
- }
-
- /// @brief Returns configuration summary in the textual format.
- ///
- /// @param selection Bitfield which describes the parts of the configuration
- /// to be returned. This parameter is ignored for the Control Agent.
- ///
- /// @return Summary of the configuration in the textual format.
- virtual std::string getConfigSummary(const uint32_t selection) override;
-
-protected:
-
- /// @brief Parses configuration of the Control Agent.
- ///
- /// @param config Pointer to a configuration specified for the agent.
- /// @param check_only Boolean flag indicating if this method should
- /// only verify correctness of the provided configuration.
- /// @return Pointer to a result of configuration parsing.
- virtual isc::data::ConstElementPtr
- parse(isc::data::ConstElementPtr config, bool check_only) override;
-
- /// @brief Creates a new, blank CtrlAgentCfgContext context.
- ///
- ///
- /// This method is used at the beginning of configuration process to
- /// create a fresh, empty copy of a CtrlAgentCfgContext. This new context
- /// will be populated during the configuration process and will replace the
- /// existing context provided the configuration process completes without
- /// error.
- ///
- /// @return Returns a ConfigPtr to the new context instance.
- virtual process::ConfigPtr createNewContext() override;
-
- /// @brief Return a list of all paths that contain passwords or secrets.
- ///
- /// Used in @ref isc::process::DCfgMgrBase::redactConfig.
- ///
- /// @return the list of lists of sequential JSON map keys needed to reach
- /// the passwords and secrets.
- std::list<std::list<std::string>> jsonPathsToRedact() const final override;
-};
-
-/// @brief Defines a shared pointer to CtrlAgentCfgMgr.
-typedef boost::shared_ptr<CtrlAgentCfgMgr> CtrlAgentCfgMgrPtr;
-
-} // namespace isc::agent
-} // namespace isc
-
-#endif // CTRL_AGENT_CFG_MGR_H
+++ /dev/null
-// Copyright (C) 2017-2025 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#include <config.h>
-
-#include <agent/ca_cfg_mgr.h>
-#include <agent/ca_command_mgr.h>
-#include <agent/ca_controller.h>
-#include <agent/ca_log.h>
-#include <agent/ca_process.h>
-#include <asiolink/asio_wrapper.h>
-#include <asiolink/io_service.h>
-#include <asiolink/unix_domain_socket.h>
-#include <cc/command_interpreter.h>
-#include <cc/data.h>
-#include <cc/json_feed.h>
-#include <config/client_connection.h>
-#include <config/timeouts.h>
-#include <boost/pointer_cast.hpp>
-#include <iterator>
-#include <sstream>
-#include <string>
-#include <vector>
-
-using namespace isc::asiolink;
-using namespace isc::config;
-using namespace isc::data;
-using namespace isc::hooks;
-using namespace isc::process;
-
-namespace isc {
-namespace agent {
-
-CtrlAgentCommandMgr&
-CtrlAgentCommandMgr::instance() {
- static CtrlAgentCommandMgr command_mgr;
- return (command_mgr);
-}
-
-CtrlAgentCommandMgr::CtrlAgentCommandMgr()
- : HookedCommandMgr() {
-}
-
-isc::data::ConstElementPtr
-CtrlAgentCommandMgr::processCommand(const isc::data::ConstElementPtr& cmd) {
- ConstElementPtr answer = HookedCommandMgr::processCommand(cmd);
-
- // Responses from the Kea Control Agent must be always wrapped
- // in a list because in general they contain responses from
- // multiple daemons.
- if (answer->getType() == Element::list) {
- return (answer);
- }
- ElementPtr answer_list = Element::createList();
- answer_list->add(boost::const_pointer_cast<Element>(answer));
-
- return (answer_list);
-}
-
-ConstElementPtr
-CtrlAgentCommandMgr::handleCommand(const std::string& cmd_name,
- const isc::data::ConstElementPtr& params,
- const isc::data::ConstElementPtr& original_cmd) {
-
- ConstElementPtr raddr_ptr = original_cmd->get("remote-address");
- if (raddr_ptr && (raddr_ptr->getType() == Element::string)) {
- remote_addr_ = raddr_ptr->stringValue();
- } else {
- remote_addr_ = "(unknown)";
- }
- LOG_INFO(agent_logger, CTRL_AGENT_COMMAND_RECEIVED)
- .arg(cmd_name)
- .arg(remote_addr_);
-
- ConstElementPtr services = Element::createList();
-
- // Retrieve 'service' parameter to determine if we should forward the
- // command or handle it on our own.
- if (original_cmd && original_cmd->contains("service")) {
- services = original_cmd->get("service");
- // If 'service' value is not a list, this is a fatal error. We don't want
- // to try processing commands that don't adhere to the required format.
- if (services->getType() != Element::list) {
- return (createAnswer(CONTROL_RESULT_ERROR, "service value must be a list"));
- }
- }
-
- // 'service' parameter hasn't been specified which indicates that the command
- // is intended to be processed by the CA. The following command will try to
- // process the command with hooks libraries (if available) or by one of the
- // CA's native handlers.
- if (services->empty()) {
-
- // It is frequent user error to not include the 'service' parameter in
- // the commands that should be forwarded to Kea servers. If the command
- // lacks this parameter the CA will try to process it and often fail
- // because it is not supported by the CA. In the future we may want to
- // make this parameter mandatory. For now, we're going to improve the
- // situation by clearly explaining to the controlling client that the
- // command is not supported by the CA, but it is possible that he may
- // achieve what he wants by providing the 'service' parameter.
-
- // Our interface is very restrictive so we walk around this by const
- // casting the returned pointer. It is certainly easier to do than
- // changing the whole data interface.
- ElementPtr answer = boost::const_pointer_cast<Element>
- (HookedCommandMgr::handleCommand(cmd_name, params, original_cmd));
-
- try {
- // Check what error code was returned by the handler.
- int rcode = 0;
- ConstElementPtr text = parseAnswer(rcode, answer);
-
- // There is a dedicated error code for unsupported command case.
- if (rcode == CONTROL_RESULT_COMMAND_UNSUPPORTED) {
-
- // Append the explanatory text to the text reported by the handler.
- // Smart, eh?
- std::ostringstream s;
- s << text->stringValue();
- s << " You did not include \"service\" parameter in the command,"
- " which indicates that Kea Control Agent should process this"
- " command rather than forward it to one or more Kea servers. If you"
- " aimed to send this command to one of the Kea servers you"
- " should include the \"service\" parameter in your request, e.g."
- " \"service\": [ \"dhcp4\" ] to forward the command to the DHCPv4"
- " server, or \"service\": [ \"dhcp4\", \"dhcp6\", \"d2\" ] to forward it to"
- " DHCPv4, DHCPv6 and D2 servers etc.";
-
- answer->set(CONTROL_TEXT, Element::create(s.str()));
- }
-
- } catch (...) {
- // Exceptions are not really possible assuming that the BaseCommandMgr
- // creates the response correctly.
- }
-
- return (answer);
- }
-
- ElementPtr answer_list = Element::createList();
-
- // Before the command is forwarded we check if there are any hooks libraries
- // which would process the command.
- if (HookedCommandMgr::delegateCommandToHookLibrary(cmd_name, params, original_cmd,
- answer_list)) {
- // The command has been processed by hooks library. Return the result.
- return (answer_list);
- }
-
- // We don't know whether the hooks libraries modified the value of the
- // answer list, so let's be safe and re-create the answer_list.
- answer_list = Element::createList();
-
- // For each value within 'service' we have to try forwarding the command.
- for (unsigned i = 0; i < services->size(); ++i) {
- if (original_cmd) {
- ConstElementPtr answer;
- try {
- LOG_DEBUG(agent_logger, isc::log::DBGLVL_COMMAND,
- CTRL_AGENT_COMMAND_FORWARD_BEGIN)
- .arg(cmd_name).arg(services->get(i)->stringValue());
-
- answer = forwardCommand(services->get(i)->stringValue(),
- cmd_name, original_cmd);
-
- } catch (const CommandForwardingError& ex) {
- LOG_DEBUG(agent_logger, isc::log::DBGLVL_COMMAND,
- CTRL_AGENT_COMMAND_FORWARD_FAILED)
- .arg(cmd_name).arg(ex.what());
- answer = createAnswer(CONTROL_RESULT_ERROR, ex.what());
- }
-
- answer_list->add(boost::const_pointer_cast<Element>(answer));
- }
- }
-
- return (answer_list);
-}
-
-ConstElementPtr
-CtrlAgentCommandMgr::forwardCommand(const std::string& service,
- const std::string& cmd_name,
- const isc::data::ConstElementPtr& command) {
- // Context will hold the server configuration.
- CtrlAgentCfgContextPtr ctx;
-
- // There is a hierarchy of the objects through which we need to pass to get
- // the configuration context. We may simplify this at some point but since
- // we're in the singleton we want to make sure that we're using most current
- // configuration.
- boost::shared_ptr<CtrlAgentController> controller =
- boost::dynamic_pointer_cast<CtrlAgentController>(CtrlAgentController::instance());
- if (controller) {
- CtrlAgentProcessPtr process = controller->getCtrlAgentProcess();
- if (process) {
- CtrlAgentCfgMgrPtr cfgmgr = process->getCtrlAgentCfgMgr();
- if (cfgmgr) {
- ctx = cfgmgr->getCtrlAgentCfgContext();
- }
- }
- }
-
- // This is highly unlikely but keep the checks just in case someone messes up
- // in the code.
- if (!ctx) {
- isc_throw(CommandForwardingError, "internal server error: unable to retrieve"
- " Control Agent configuration information");
- }
-
- // Now that we know what service it should be forwarded to, we should
- // find a matching forwarding socket. If this socket is not configured,
- // we have to communicate it to the client.
- ConstElementPtr socket_info = ctx->getControlSocketInfo(service);
- if (!socket_info) {
- isc_throw(CommandForwardingError, "forwarding socket is not configured"
- " for the server type " << service);
- }
-
- // If the configuration does its job properly the validated-socket-name
- // should be present.
- if (!socket_info->get("validated-socket-name")) {
- isc_throw(Unexpected, "validated-socket-name missing from "
- << " socket_info: " << socket_info->str()
- << " for the server type " << service);
- }
-
- auto socket_name = socket_info->get("validated-socket-name")->stringValue();
-
- // Forward command and receive reply.
- IOServicePtr io_service(new IOService());;
- ClientConnection conn(io_service);
- boost::system::error_code received_ec;
- ConstJSONFeedPtr received_feed;
- conn.start(ClientConnection::SocketPath(socket_name),
- ClientConnection::ControlCommand(command->toWire()),
- [&io_service, &received_ec, &received_feed]
- (const boost::system::error_code& ec, ConstJSONFeedPtr feed) {
- // Capture error code and parsed data.
- received_ec = ec;
- received_feed = feed;
- // Got the IO service so stop IO service. This causes to
- // stop IO service when all handlers have been invoked.
- io_service->stopWork();
- }, ClientConnection::Timeout(TIMEOUT_AGENT_FORWARD_COMMAND));
- io_service->run();
-
- if (received_ec) {
- isc_throw(CommandForwardingError, "unable to forward command to the "
- << service << " service: " << received_ec.message()
- << ". The server is likely to be offline");
- }
-
- // This shouldn't happen because the fact that there was no time out indicates
- // that the whole response has been read and it should be stored within the
- // feed. But, let's check to prevent assertions.
- if (!received_feed) {
- isc_throw(CommandForwardingError, "internal server error: empty response"
- " received from the unix domain socket");
- }
-
- ConstElementPtr answer;
- try {
- answer = received_feed->toElement();
-
- LOG_INFO(agent_logger, CTRL_AGENT_COMMAND_FORWARDED)
- .arg(cmd_name)
- .arg(service)
- .arg(remote_addr_);
-
- } catch (const std::exception& ex) {
- isc_throw(CommandForwardingError, "internal server error: unable to parse"
- " server's answer to the forwarded message: " << ex.what());
- }
-
- return (answer);
-}
-
-
-} // end of namespace isc::agent
-} // end of namespace isc
+++ /dev/null
-// Copyright (C) 2017-2024 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#ifndef CTRL_AGENT_COMMAND_MGR_H
-#define CTRL_AGENT_COMMAND_MGR_H
-
-#include <config/hooked_command_mgr.h>
-#include <exceptions/exceptions.h>
-#include <boost/noncopyable.hpp>
-#include <boost/shared_ptr.hpp>
-
-namespace isc {
-namespace agent {
-
-/// @brief Exception thrown when an error occurred during control command
-/// forwarding.
-class CommandForwardingError : public Exception {
-public:
- CommandForwardingError(const char* file, size_t line, const char* what) :
- isc::Exception(file, line, what) { }
-};
-
-/// @brief Command Manager for Control Agent.
-///
-/// This is an implementation of the Command Manager within Control Agent.
-/// In addition to the standard capabilities of the @ref HookedCommandMgr
-/// it is also intended to forward commands to the respective Kea servers
-/// when the command is not supported directly by the Control Agent.
-///
-/// The @ref CtrlAgentCommandMgr is implemented as a singleton. The commands
-/// are registered using @c CtrlAgentCommandMgr::instance().registerCommand().
-/// The @ref CtrlAgentResponseCreator uses the sole instance of the Command
-/// Manager to handle incoming commands.
-class CtrlAgentCommandMgr : public config::HookedCommandMgr,
- public boost::noncopyable {
-public:
-
- /// @brief Returns sole instance of the Command Manager.
- static CtrlAgentCommandMgr& instance();
-
- /// @brief Triggers command processing.
- ///
- /// This method overrides the @c BaseCommandMgr::processCommand to ensure
- /// that the response is always wrapped in a list. The base implementation
- /// returns a response map. Kea Control Agent forwards commands to multiple
- /// daemons behind it and thus it must return a list of responses from
- /// respective daemons. If an error occurs during command processing the
- /// error response must also be wrapped in a list because caller expects
- /// that CA always returns a list.
- ///
- /// This method is an entry point for dealing with a command. Internally
- /// it calls @c CtrlAgentCommandMgr::handleCommand.
- ///
- /// @param cmd Pointer to the data element representing command in JSON
- /// format.
- /// @return Pointer to the response.
- virtual isc::data::ConstElementPtr
- processCommand(const isc::data::ConstElementPtr& cmd);
-
- /// @brief Handles the command having a given name and arguments.
- ///
- /// This method extends the base implementation with the ability to forward
- /// commands to Kea servers.
- ///
- /// If the received command doesn't include 'service' parameter or this
- /// parameter is blank, the command is first handled by the attached hooks
- /// libraries, and if still unhandled, the Control Agent itself.
- ///
- /// If the non-blank 'service' parameter has been specified the hooks
- /// are executed. If the hooks process the command the result is returned
- /// to the controlling client. Otherwise, the command is forwarded to each
- /// Kea server listed in the 'service' parameter.
- ///
- /// @param cmd_name Command name.
- /// @param params Command arguments.
- /// @param original_cmd Original command being processed.
- ///
- /// @return Pointer to the const data element representing a list of
- /// responses to the command. If the command has been handled by the CA,
- /// this list includes one response.
- virtual isc::data::ConstElementPtr
- handleCommand(const std::string& cmd_name,
- const isc::data::ConstElementPtr& params,
- const isc::data::ConstElementPtr& original_cmd);
-
-private:
-
- /// @brief Tries to forward received control command to a specified server.
- ///
- /// @param service Contains name of the service where the command should be
- /// forwarded.
- /// @param cmd_name Command name.
- /// @param command Pointer to the object representing the forwarded command.
- ///
- /// @return Response to forwarded command.
- /// @throw CommandForwardingError when an error occurred during forwarding.
- isc::data::ConstElementPtr
- forwardCommand(const std::string& service, const std::string& cmd_name,
- const isc::data::ConstElementPtr& command);
-
- /// @brief Private constructor.
- ///
- /// The instance should be created using @ref CtrlAgentCommandMgr::instance,
- /// thus the constructor is private.
- CtrlAgentCommandMgr();
-
- /// @brief Remote address of HTTP endpoint.
- std::string remote_addr_;
-
-};
-
-} // end of namespace isc::agent
-} // end of namespace isc
-
-#endif
+++ /dev/null
-// Copyright (C) 2016-2023 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#include <config.h>
-
-#include <agent/ca_controller.h>
-#include <agent/ca_process.h>
-#include <agent/ca_command_mgr.h>
-#include <agent/parser_context.h>
-#include <process/cfgrpt/config_report.h>
-#include <functional>
-
-using namespace isc::process;
-namespace ph = std::placeholders;
-
-namespace isc {
-namespace agent {
-
-/// @brief Defines the application name, this is passed into base class
-/// it may be used to locate configuration data and appears in log statement.
-const char* CtrlAgentController::agent_app_name_ = "Control-agent";
-
-/// @brief Defines the executable name. This is passed into the base class
-const char* CtrlAgentController::agent_bin_name_ = "kea-ctrl-agent";
-
-DControllerBasePtr&
-CtrlAgentController::instance() {
- // If the instance hasn't been created yet, create it. Note this method
- // must use the base class singleton instance methods.
- if (!getController()) {
- DControllerBasePtr controller_ptr(new CtrlAgentController());
- setController(controller_ptr);
- }
-
- return (getController());
-}
-
-DProcessBase*
-CtrlAgentController::createProcess() {
- // Instantiate and return an instance of the D2 application process. Note
- // that the process is passed the controller's io_service.
- return (new CtrlAgentProcess(getAppName().c_str(), getIOService()));
-}
-
-isc::data::ConstElementPtr
-CtrlAgentController::parseFile(const std::string& name) {
- ParserContext parser;
- return (parser.parseFile(name, ParserContext::PARSER_AGENT));
-}
-
-void
-CtrlAgentController::registerCommands() {
- CtrlAgentCommandMgr::instance().registerCommand(BUILD_REPORT_COMMAND,
- std::bind(&DControllerBase::buildReportHandler, this, ph::_1, ph::_2));
-
- CtrlAgentCommandMgr::instance().registerCommand(CONFIG_GET_COMMAND,
- std::bind(&DControllerBase::configGetHandler, this, ph::_1, ph::_2));
-
- CtrlAgentCommandMgr::instance().registerCommand(CONFIG_HASH_GET_COMMAND,
- std::bind(&DControllerBase::configHashGetHandler, this, ph::_1, ph::_2));
-
- CtrlAgentCommandMgr::instance().registerCommand(CONFIG_RELOAD_COMMAND,
- std::bind(&DControllerBase::configReloadHandler, this, ph::_1, ph::_2));
-
- CtrlAgentCommandMgr::instance().registerCommand(CONFIG_SET_COMMAND,
- std::bind(&DControllerBase::configSetHandler, this, ph::_1, ph::_2));
-
- CtrlAgentCommandMgr::instance().registerCommand(CONFIG_TEST_COMMAND,
- std::bind(&DControllerBase::configTestHandler, this, ph::_1, ph::_2));
-
- CtrlAgentCommandMgr::instance().registerCommand(CONFIG_WRITE_COMMAND,
- std::bind(&DControllerBase::configWriteHandler, this, ph::_1, ph::_2));
-
- CtrlAgentCommandMgr::instance().registerCommand(SHUT_DOWN_COMMAND,
- std::bind(&DControllerBase::shutdownHandler, this, ph::_1, ph::_2));
-
- CtrlAgentCommandMgr::instance().registerCommand(STATUS_GET_COMMAND,
- std::bind(&DControllerBase::statusGetHandler, this, ph::_1, ph::_2));
-
- CtrlAgentCommandMgr::instance().registerCommand(VERSION_GET_COMMAND,
- std::bind(&DControllerBase::versionGetHandler, this, ph::_1, ph::_2));
-}
-
-void
-CtrlAgentController::deregisterCommands() {
- CtrlAgentCommandMgr::instance().deregisterCommand(BUILD_REPORT_COMMAND);
- CtrlAgentCommandMgr::instance().deregisterCommand(CONFIG_GET_COMMAND);
- CtrlAgentCommandMgr::instance().deregisterCommand(CONFIG_HASH_GET_COMMAND);
- CtrlAgentCommandMgr::instance().deregisterCommand(CONFIG_RELOAD_COMMAND);
- CtrlAgentCommandMgr::instance().deregisterCommand(CONFIG_SET_COMMAND);
- CtrlAgentCommandMgr::instance().deregisterCommand(CONFIG_TEST_COMMAND);
- CtrlAgentCommandMgr::instance().deregisterCommand(CONFIG_WRITE_COMMAND);
- CtrlAgentCommandMgr::instance().deregisterCommand(SHUT_DOWN_COMMAND);
- CtrlAgentCommandMgr::instance().deregisterCommand(STATUS_GET_COMMAND);
- CtrlAgentCommandMgr::instance().deregisterCommand(VERSION_GET_COMMAND);
-}
-
-CtrlAgentController::CtrlAgentController()
- : DControllerBase(agent_app_name_, agent_bin_name_) {
-}
-
-CtrlAgentController::~CtrlAgentController() {
-}
-
-CtrlAgentProcessPtr
-CtrlAgentController::getCtrlAgentProcess() {
- return (boost::dynamic_pointer_cast<CtrlAgentProcess>(getProcess()));
-}
-
-} // namespace isc::agent
-} // namespace isc
+++ /dev/null
-// Copyright (C) 2016-2017 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#ifndef CTRL_AGENT_CONTROLLER_H
-#define CTRL_AGENT_CONTROLLER_H
-
-#include <agent/ca_process.h>
-#include <process/d_controller.h>
-
-namespace isc {
-namespace agent {
-
-/// @brief Process Controller for Control Agent Process.
-///
-/// This class is the Control Agent specific derivation of the DControllerBase.
-/// It creates and manages an instance of the Control Agent application process,
-/// CtrlAgentProcess.
-class CtrlAgentController : public process::DControllerBase {
-public:
-
- /// @brief Static singleton instance method.
- ///
- /// This method returns the base class singleton instance member.
- /// It instantiates the singleton and sets the base class instance
- /// member upon first invocation.
- ///
- /// @return returns the pointer reference to the singleton instance.
- static process::DControllerBasePtr& instance();
-
- /// @brief Destructor
- virtual ~CtrlAgentController();
-
- /// @brief Returns pointer to an instance of the underlying process object.
- CtrlAgentProcessPtr getCtrlAgentProcess();
-
- /// @brief Defines the application name, this is passed into base class
- /// and appears in log statements.
- static const char* agent_app_name_;
-
- /// @brief Defines the executable name. This is passed into the base class
- /// by convention this should match the executable name.
- static const char* agent_bin_name_;
-
- /// @brief Parses the configuration file using Agent::ParserContext (bison)
- ///
- /// @param name name of the text file to be parsed
- /// @return Element tree structure representing parsed configuration
- isc::data::ConstElementPtr
- parseFile(const std::string& name);
-
- /// @brief Register commands.
- void registerCommands();
-
- /// @brief Deregister commands.
- void deregisterCommands();
-
-private:
-
- /// @brief Creates an instance of the Control Agent application
- /// process.
- ///
- /// This method is invoked during the process initialization step of
- /// the controller launch.
- ///
- /// @return returns a DProcessBase* to the application process created.
- /// Note the caller is responsible for destructing the process. This
- /// is handled by the base class, which wraps this pointer with a smart
- /// pointer.
- virtual process::DProcessBase* createProcess();
-
- /// @brief Constructor is declared private to maintain the integrity of
- /// the singleton instance.
- CtrlAgentController();
-};
-
-// @Defines a shared pointer to CtrlAgentController
-typedef boost::shared_ptr<CtrlAgentController> CtrlAgentControllerPtr;
-
-} // namespace isc::agent
-} // namespace isc
-
-#endif // CTRL_AGENT_CONTROLLER_H
+++ /dev/null
-// Copyright (C) 2016-2018 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#include <config.h>
-
-#include <agent/ca_log.h>
-
-namespace isc {
-namespace agent {
-
-isc::log::Logger agent_logger("ctrl-agent");
-
-} // namespace isc::agent
-} // namespace isc
+++ /dev/null
-// Copyright (C) 2016-2017 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#ifndef CTRL_AGENT_LOG_H
-#define CTRL_AGENT_LOG_H
-
-#include <log/logger_support.h>
-#include <log/macros.h>
-#include <agent/ca_messages.h>
-
-namespace isc {
-namespace agent {
-
-/// @brief Control Agent logger.
-extern isc::log::Logger agent_logger;
-
-} // namespace isc::agent
-} // namespace isc
-
-#endif
+++ /dev/null
-// File created from src/bin/agent/ca_messages.mes
-
-#include <cstddef>
-#include <log/message_types.h>
-#include <log/message_initializer.h>
-
-namespace isc {
-namespace agent {
-
-extern const isc::log::MessageID CTRL_AGENT_COMMAND_FORWARDED = "CTRL_AGENT_COMMAND_FORWARDED";
-extern const isc::log::MessageID CTRL_AGENT_COMMAND_FORWARD_BEGIN = "CTRL_AGENT_COMMAND_FORWARD_BEGIN";
-extern const isc::log::MessageID CTRL_AGENT_COMMAND_FORWARD_FAILED = "CTRL_AGENT_COMMAND_FORWARD_FAILED";
-extern const isc::log::MessageID CTRL_AGENT_COMMAND_RECEIVED = "CTRL_AGENT_COMMAND_RECEIVED";
-extern const isc::log::MessageID CTRL_AGENT_CONFIG_CHECK_FAIL = "CTRL_AGENT_CONFIG_CHECK_FAIL";
-extern const isc::log::MessageID CTRL_AGENT_CONFIG_FAIL = "CTRL_AGENT_CONFIG_FAIL";
-extern const isc::log::MessageID CTRL_AGENT_CONFIG_SYNTAX_WARNING = "CTRL_AGENT_CONFIG_SYNTAX_WARNING";
-extern const isc::log::MessageID CTRL_AGENT_FAILED = "CTRL_AGENT_FAILED";
-extern const isc::log::MessageID CTRL_AGENT_HTTPS_SERVICE_REUSE_FAILED = "CTRL_AGENT_HTTPS_SERVICE_REUSE_FAILED";
-extern const isc::log::MessageID CTRL_AGENT_HTTPS_SERVICE_STARTED = "CTRL_AGENT_HTTPS_SERVICE_STARTED";
-extern const isc::log::MessageID CTRL_AGENT_HTTPS_SERVICE_UPDATED = "CTRL_AGENT_HTTPS_SERVICE_UPDATED";
-extern const isc::log::MessageID CTRL_AGENT_HTTP_SERVICE_REUSE_FAILED = "CTRL_AGENT_HTTP_SERVICE_REUSE_FAILED";
-extern const isc::log::MessageID CTRL_AGENT_HTTP_SERVICE_STARTED = "CTRL_AGENT_HTTP_SERVICE_STARTED";
-extern const isc::log::MessageID CTRL_AGENT_HTTP_SERVICE_UPDATED = "CTRL_AGENT_HTTP_SERVICE_UPDATED";
-extern const isc::log::MessageID CTRL_AGENT_IS_DEPRECATED = "CTRL_AGENT_IS_DEPRECATED";
-extern const isc::log::MessageID CTRL_AGENT_RUN_EXIT = "CTRL_AGENT_RUN_EXIT";
-extern const isc::log::MessageID CTRL_AGENT_SECURITY_CHECKS_DISABLED = "CTRL_AGENT_SECURITY_CHECKS_DISABLED";
-extern const isc::log::MessageID CTRL_AGENT_STARTED = "CTRL_AGENT_STARTED";
-
-} // namespace agent
-} // namespace isc
-
-namespace {
-
-const char* values[] = {
- "CTRL_AGENT_COMMAND_FORWARDED", "command %1 successfully forwarded to the service %2 from remote address %3",
- "CTRL_AGENT_COMMAND_FORWARD_BEGIN", "begin forwarding command %1 to service %2",
- "CTRL_AGENT_COMMAND_FORWARD_FAILED", "failed forwarding command %1: %2",
- "CTRL_AGENT_COMMAND_RECEIVED", "command %1 received from remote address %2",
- "CTRL_AGENT_CONFIG_CHECK_FAIL", "Control Agent configuration check failed: %1",
- "CTRL_AGENT_CONFIG_FAIL", "Control Agent configuration failed: %1",
- "CTRL_AGENT_CONFIG_SYNTAX_WARNING", "Control Agent configuration syntax warning: %1",
- "CTRL_AGENT_FAILED", "application experienced a fatal error: %1",
- "CTRL_AGENT_HTTPS_SERVICE_REUSE_FAILED", "failed to reuse HTTPS service bound to address: %1 port: %2",
- "CTRL_AGENT_HTTPS_SERVICE_STARTED", "HTTPS service bound to address: %1 port: %2",
- "CTRL_AGENT_HTTPS_SERVICE_UPDATED", "reused HTTPS service bound to address: %1 port: %2 and updated TLS settings",
- "CTRL_AGENT_HTTP_SERVICE_REUSE_FAILED", "failed to reuse HTTP service bound to address: %1 port: %2",
- "CTRL_AGENT_HTTP_SERVICE_STARTED", "HTTP service bound to address: %1 port: %2",
- "CTRL_AGENT_HTTP_SERVICE_UPDATED", "reused HTTP service bound to address: %1 port: %2",
- "CTRL_AGENT_IS_DEPRECATED", "Kea Control Agent is deprecated. Its function has been moved to Kea servers.",
- "CTRL_AGENT_RUN_EXIT", "application is exiting the event loop",
- "CTRL_AGENT_SECURITY_CHECKS_DISABLED", "Invoked with command line option -X, Security checks are disabled!!",
- "CTRL_AGENT_STARTED", "Kea Control Agent version %1 started",
- NULL
-};
-
-const isc::log::MessageInitializer initializer(values);
-
-} // Anonymous namespace
-
+++ /dev/null
-// File created from src/bin/agent/ca_messages.mes
-
-#ifndef CA_MESSAGES_H
-#define CA_MESSAGES_H
-
-#include <log/message_types.h>
-
-namespace isc {
-namespace agent {
-
-extern const isc::log::MessageID CTRL_AGENT_COMMAND_FORWARDED;
-extern const isc::log::MessageID CTRL_AGENT_COMMAND_FORWARD_BEGIN;
-extern const isc::log::MessageID CTRL_AGENT_COMMAND_FORWARD_FAILED;
-extern const isc::log::MessageID CTRL_AGENT_COMMAND_RECEIVED;
-extern const isc::log::MessageID CTRL_AGENT_CONFIG_CHECK_FAIL;
-extern const isc::log::MessageID CTRL_AGENT_CONFIG_FAIL;
-extern const isc::log::MessageID CTRL_AGENT_CONFIG_SYNTAX_WARNING;
-extern const isc::log::MessageID CTRL_AGENT_FAILED;
-extern const isc::log::MessageID CTRL_AGENT_HTTPS_SERVICE_REUSE_FAILED;
-extern const isc::log::MessageID CTRL_AGENT_HTTPS_SERVICE_STARTED;
-extern const isc::log::MessageID CTRL_AGENT_HTTPS_SERVICE_UPDATED;
-extern const isc::log::MessageID CTRL_AGENT_HTTP_SERVICE_REUSE_FAILED;
-extern const isc::log::MessageID CTRL_AGENT_HTTP_SERVICE_STARTED;
-extern const isc::log::MessageID CTRL_AGENT_HTTP_SERVICE_UPDATED;
-extern const isc::log::MessageID CTRL_AGENT_IS_DEPRECATED;
-extern const isc::log::MessageID CTRL_AGENT_RUN_EXIT;
-extern const isc::log::MessageID CTRL_AGENT_SECURITY_CHECKS_DISABLED;
-extern const isc::log::MessageID CTRL_AGENT_STARTED;
-
-} // namespace agent
-} // namespace isc
-
-#endif // CA_MESSAGES_H
+++ /dev/null
-# Copyright (C) 2016-2026 Internet Systems Consortium, Inc. ("ISC")
-#
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-$NAMESPACE isc::agent
-
-% CTRL_AGENT_COMMAND_FORWARDED command %1 successfully forwarded to the service %2 from remote address %3
-This informational message is issued when the CA successfully forwards
-the control message to the specified Kea service and receives a response.
-
-% CTRL_AGENT_COMMAND_FORWARD_BEGIN begin forwarding command %1 to service %2
-Logged at debug log level 10.
-This debug message is issued when the Control Agent starts forwarding a
-received command to one of the Kea servers.
-
-% CTRL_AGENT_COMMAND_FORWARD_FAILED failed forwarding command %1: %2
-Logged at debug log level 10.
-This debug message is issued when the Control Agent failed forwarding a
-received command to one of the Kea servers. The second argument provides
-the details of the error.
-
-% CTRL_AGENT_COMMAND_RECEIVED command %1 received from remote address %2
-This informational message is issued when the CA receives a control message,
-whether it is destined to the control agent itself, or to be forwarded on.
-
-% CTRL_AGENT_CONFIG_CHECK_FAIL Control Agent configuration check failed: %1
-This error message indicates that the CA had failed configuration
-check. Details are provided. Additional details may be available
-in earlier log entries, possibly on lower levels.
-
-% CTRL_AGENT_CONFIG_FAIL Control Agent configuration failed: %1
-This error message indicates that the CA had failed configuration
-attempt. Details are provided. Additional details may be available
-in earlier log entries, possibly on lower levels.
-
-% CTRL_AGENT_CONFIG_SYNTAX_WARNING Control Agent configuration syntax warning: %1
-This warning message indicates that the CA configuration had a minor syntax
-error. The error was displayed and the configuration parsing resumed.
-
-% CTRL_AGENT_FAILED application experienced a fatal error: %1
-This is a fatal error message issued when the Control Agent application
-encounters an unrecoverable error from within the event loop.
-
-% CTRL_AGENT_HTTPS_SERVICE_REUSE_FAILED failed to reuse HTTPS service bound to address: %1 port: %2
-This error message indicates that the server has failed to reuse existing
-HTTPS service on the specified address and port. The server cannot switch from
-HTTPS to HTTP sockets using the same address and port.
-
-% CTRL_AGENT_HTTPS_SERVICE_STARTED HTTPS service bound to address: %1 port: %2
-This informational message indicates that the server has started HTTPS service
-on the specified address and port. All control commands should be sent to this
-address and port over a TLS channel.
-
-% CTRL_AGENT_HTTPS_SERVICE_UPDATED reused HTTPS service bound to address: %1 port: %2 and updated TLS settings
-This informational message indicates that the server has reused existing
-HTTPS service on the specified address and port. Note that any change in
-the TLS setup has been applied.
-
-% CTRL_AGENT_HTTP_SERVICE_REUSE_FAILED failed to reuse HTTP service bound to address: %1 port: %2
-This error message indicates that the server has failed to reuse existing
-HTTP service on the specified address and port. The server cannot switch from
-HTTP to HTTPS sockets using the same address and port.
-
-% CTRL_AGENT_HTTP_SERVICE_STARTED HTTP service bound to address: %1 port: %2
-This informational message indicates that the server has started HTTP service
-on the specified address and port. All control commands should be sent to this
-address and port.
-
-% CTRL_AGENT_HTTP_SERVICE_UPDATED reused HTTP service bound to address: %1 port: %2
-This informational message indicates that the server has reused existing
-HTTP service on the specified address and port.
-
-% CTRL_AGENT_IS_DEPRECATED Kea Control Agent is deprecated. Its function has been moved to Kea servers.
-This warning message indicates that the Control Agent has been deprecated.
-All its functions have been moved to Kea servers.
-
-% CTRL_AGENT_RUN_EXIT application is exiting the event loop
-Logged at debug log level 0.
-This is a debug message issued when the Control Agent exits its
-event loop.
-
-% CTRL_AGENT_SECURITY_CHECKS_DISABLED Invoked with command line option -X, Security checks are disabled!!
-This warning is emitted when internal security checks normally
-performed by kea-ctrl-agent have been disabled via command line option '-X'.
-This means the server is not enforcing restrictions on resource
-paths or permissions. This mode of operation may expose your
-environment to security vulnerabilities and should only be used
-after consideration.
-
-% CTRL_AGENT_STARTED Kea Control Agent version %1 started
-This informational message indicates that the Control Agent has
-processed all configuration information and is ready to begin processing.
-The version is also printed.
+++ /dev/null
-// Copyright (C) 2016-2026 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#include <config.h>
-#include <asiolink/asio_wrapper.h>
-#include <asiolink/io_service_mgr.h>
-#include <agent/ca_process.h>
-#include <agent/ca_controller.h>
-#include <agent/ca_response_creator_factory.h>
-#include <agent/ca_log.h>
-#include <asiolink/io_address.h>
-#include <asiolink/io_error.h>
-#include <cc/command_interpreter.h>
-#include <config/timeouts.h>
-#include <util/filesystem.h>
-#include <boost/pointer_cast.hpp>
-
-using namespace isc::asiolink;
-using namespace isc::config;
-using namespace isc::data;
-using namespace isc::http;
-using namespace isc::process;
-using namespace isc::util::file;
-
-namespace isc {
-namespace agent {
-
-CtrlAgentProcess::CtrlAgentProcess(const char* name,
- const asiolink::IOServicePtr& io_service)
- : DProcessBase(name, io_service, DCfgMgrBasePtr(new CtrlAgentCfgMgr())) {
-}
-
-CtrlAgentProcess::~CtrlAgentProcess() {
-}
-
-void
-CtrlAgentProcess::init() {
-}
-
-void
-CtrlAgentProcess::run() {
- LOG_INFO(agent_logger, CTRL_AGENT_STARTED).arg(VERSION);
-
- LOG_WARN(agent_logger, CTRL_AGENT_IS_DEPRECATED);
-
- if (!PathChecker::shouldEnforceSecurity()) {
- LOG_WARN(agent_logger, CTRL_AGENT_SECURITY_CHECKS_DISABLED);
- }
-
- try {
- // Register commands.
- CtrlAgentControllerPtr controller =
- boost::dynamic_pointer_cast<CtrlAgentController>(
- CtrlAgentController::instance());
- controller->registerCommands();
-
- // Let's process incoming data or expiring timers in a loop until
- // shutdown condition is detected.
- while (!shouldShutdown()) {
- runIO();
- }
- // Done so removing all listeners.
- closeCommandSockets();
- stopIOService();
- } catch (const std::exception& ex) {
- LOG_FATAL(agent_logger, CTRL_AGENT_FAILED).arg(ex.what());
- try {
- stopIOService();
- } catch (...) {
- // Ignore double errors
- }
- isc_throw(DProcessBaseError,
- "Process run method failed: " << ex.what());
- }
-
- try {
- // Deregister commands.
- CtrlAgentControllerPtr controller =
- boost::dynamic_pointer_cast<CtrlAgentController>(
- CtrlAgentController::instance());
- controller->deregisterCommands();
- } catch (const std::exception&) {
- // What to do? Simply ignore...
- }
-
- LOG_DEBUG(agent_logger, isc::log::DBGLVL_START_SHUT, CTRL_AGENT_RUN_EXIT);
-}
-
-size_t
-CtrlAgentProcess::runIO() {
- // Handle events registered by hooks using external IOService objects.
- IOServiceMgr::instance().pollIOServices();
- size_t cnt = getIOService()->poll();
- if (!cnt) {
- cnt = getIOService()->runOne();
- }
- return (cnt);
-}
-
-isc::data::ConstElementPtr
-CtrlAgentProcess::shutdown(isc::data::ConstElementPtr /*args*/) {
- setShutdownFlag(true);
- return (isc::config::createAnswer(CONTROL_RESULT_SUCCESS,
- "Control Agent is shutting down"));
-}
-
-isc::data::ConstElementPtr
-CtrlAgentProcess::configure(isc::data::ConstElementPtr config_set,
- bool check_only) {
- // System reconfiguration often poses an interesting issue whereby the
- // configuration parsing is successful, but an attempt to use a new
- // configuration is not. This will leave us in the inconsistent state
- // when the configuration is in fact only partially applied and the
- // system's ability to operate is impaired. The use of C++ lambda is
- // a way to resolve this problem by injecting the code to the
- // simpleParseConfig which performs an attempt to open new instance
- // of the listener (if required). The lambda code will throw an
- // exception if it fails and cause the simpleParseConfig to rollback
- // configuration changes and report an error.
- ConstElementPtr answer = getCfgMgr()->simpleParseConfig(config_set,
- check_only,
- [this]() {
- ConfigPtr base_ctx = getCfgMgr()->getContext();
- CtrlAgentCfgContextPtr
- ctx = boost::dynamic_pointer_cast<CtrlAgentCfgContext>(base_ctx);
-
- if (!ctx) {
- isc_throw(Unexpected, "Internal logic error: bad context type");
- }
-
- /// @todo: If the parameter is a hostname, we need to resolve it.
- IOAddress server_address("::");
- try {
- server_address = IOAddress(ctx->getHttpHost());
-
- } catch (const IOError& e) {
- isc_throw(BadValue, "Failed to convert " << ctx->getHttpHost()
- << " to IP address:" << e.what());
- }
-
- uint16_t server_port = ctx->getHttpPort();
-
- // Search for the specific connection and reuse the existing one if found.
- auto it = sockets_.find(std::make_pair(server_address, server_port));
- if (it != sockets_.end()) {
- auto listener = it->second->listener_;
- if (listener) {
- // Reconfig keeping the same address and port.
- if (listener->getTlsContext()) {
- if (ctx->getTrustAnchor().empty()) {
- // Can not switch from HTTPS to HTTP
- LOG_ERROR(agent_logger, CTRL_AGENT_HTTPS_SERVICE_REUSE_FAILED)
- .arg(server_address.toText())
- .arg(server_port);
- isc_throw(BadValue,
- "Can not switch from HTTPS to HTTP sockets using the same address and port.");
- } else {
- // Apply TLS settings each time.
- TlsContextPtr tls_context;
- TlsContext::configure(tls_context,
- TlsRole::SERVER,
- ctx->getTrustAnchor(),
- ctx->getCertFile(),
- ctx->getKeyFile(),
- ctx->getCertRequired());
- // Overwrite the authentication setup and the http headers in the response creator config.
- it->second->config_->setAuthConfig(ctx->getAuthConfig());
- it->second->config_->setHttpHeaders(ctx->getHttpHeaders());
- listener->setTlsContext(tls_context);
- LOG_INFO(agent_logger, CTRL_AGENT_HTTPS_SERVICE_UPDATED)
- .arg(server_address.toText())
- .arg(server_port);
- }
- } else {
- if (!ctx->getTrustAnchor().empty()) {
- // Can not switch from HTTP to HTTPS
- LOG_ERROR(agent_logger, CTRL_AGENT_HTTP_SERVICE_REUSE_FAILED)
- .arg(server_address.toText())
- .arg(server_port);
- isc_throw(BadValue,
- "Can not switch from HTTP to HTTPS sockets using the same address and port.");
- } else {
- // Overwrite the authentication setup and the http headers in the response creator config.
- it->second->config_->setAuthConfig(ctx->getAuthConfig());
- it->second->config_->setHttpHeaders(ctx->getHttpHeaders());
- LOG_INFO(agent_logger, CTRL_AGENT_HTTP_SERVICE_UPDATED)
- .arg(server_address.toText())
- .arg(server_port);
- }
- }
- }
- // If the connection can be reused, mark it as usable.
- it->second->usable_ = true;
- } else {
-
- // Connection not found so it needs to be created.
- // When TLS is enabled configure it.
- bool use_https = false;
- TlsContextPtr tls_context;
- if (!ctx->getCertFile().empty()) {
- TlsContext::configure(tls_context,
- TlsRole::SERVER,
- ctx->getTrustAnchor(),
- ctx->getCertFile(),
- ctx->getKeyFile(),
- ctx->getCertRequired());
- use_https = true;
- }
-
- // Create response creator factory first. It will be used to
- // generate response creators. Each response creator will be
- // used to generate answer to specific request.
- HttpResponseCreatorFactoryPtr rcf(new CtrlAgentResponseCreatorFactory());
-
- // Create HTTP listener. It will open up a TCP socket and be
- // prepared to accept incoming connection.
- HttpListenerPtr http_listener
- (new HttpListener(getIOService(),
- server_address,
- server_port,
- tls_context,
- rcf,
- HttpListener::RequestTimeout(TIMEOUT_AGENT_RECEIVE_COMMAND),
- HttpListener::IdleTimeout(TIMEOUT_AGENT_IDLE_CONNECTION_TIMEOUT)));
-
- // Instruct the HTTP listener to actually open socket, install
- // callback and start listening.
- http_listener->start();
-
- HttpSocketInfoPtr socket_info(new HttpSocketInfo());
- socket_info->config_ = ctx;
- socket_info->listener_ = http_listener;
-
- sockets_[std::make_pair(server_address, server_port)] = socket_info;
-
- // Ok, seems we're good to go.
- if (use_https) {
- LOG_INFO(agent_logger, CTRL_AGENT_HTTPS_SERVICE_STARTED)
- .arg(server_address.toText())
- .arg(server_port);
- } else {
- LOG_INFO(agent_logger, CTRL_AGENT_HTTP_SERVICE_STARTED)
- .arg(server_address.toText())
- .arg(server_port);
- }
- }
-
- auto copy = sockets_;
- for (auto const& data : copy) {
- if (data.second->usable_) {
- // If the connection can be used (just created) or reused, keep it
- // in the list and clear the flag. It will be marked again on next
- // configuration event if needed.
- data.second->usable_ = false;
- } else {
- // If the connection can not be reused, stop it and remove it from the list.
- data.second->listener_->stop();
- auto it2 = sockets_.find(std::make_pair(data.second->config_->getHttpHost(),
- data.second->config_->getHttpPort()));
- if (it2 != sockets_.end()) {
- sockets_.erase(it2);
- }
- }
- }
- });
-
- int rcode = 0;
- config::parseAnswer(rcode, answer);
-
- /// Let postponed hook initializations run.
- try {
- // Handle events registered by hooks using external IOService objects.
- IOServiceMgr::instance().pollIOServices();
- } catch (const std::exception& ex) {
- if (rcode == CONTROL_RESULT_FATAL_ERROR) {
- return (answer);
- }
- std::ostringstream err;
- err << "Error initializing hooks: "
- << ex.what();
- return (isc::config::createAnswer(CONTROL_RESULT_ERROR, err.str()));
- }
-
- return (answer);
-}
-
-void
-CtrlAgentProcess::closeCommandSockets() {
- for (auto const& data : sockets_) {
- data.second->listener_->stop();
- }
- sockets_.clear();
- // We have stopped listeners but there may be some pending handlers
- // related to these listeners. Need to invoke these handlers.
- try {
- getIOService()->poll();
- } catch (...) {
- }
-}
-
-CtrlAgentCfgMgrPtr
-CtrlAgentProcess::getCtrlAgentCfgMgr() {
- return (boost::dynamic_pointer_cast<CtrlAgentCfgMgr>(getCfgMgr()));
-}
-
-ConstHttpListenerPtr
-CtrlAgentProcess::getHttpListener(HttpSocketInfoPtr info) const {
- // Return the most recent listener or null.
- if (info) {
- auto it = sockets_.find(std::make_pair(info->config_->getHttpHost(), info->config_->getHttpPort()));
- if (it != sockets_.end()) {
- return (it->second->listener_);
- }
- } else if (sockets_.size()) {
- return (sockets_.begin()->second->listener_);
- }
- return (ConstHttpListenerPtr());
-}
-
-bool
-CtrlAgentProcess::isListening() const {
- // If there are is a listener, we're listening.
- return (static_cast<bool>(getHttpListener()));
-}
-
-} // namespace isc::agent
-} // namespace isc
+++ /dev/null
-// Copyright (C) 2016-2025 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#ifndef CTRL_AGENT_PROCESS_H
-#define CTRL_AGENT_PROCESS_H
-
-#include <agent/ca_cfg_mgr.h>
-#include <http/listener.h>
-#include <process/d_process.h>
-#include <vector>
-
-namespace isc {
-namespace agent {
-
-/// @brief Structure used to store HTTP/HTTPS connection data.
-/// (configuration, listener, etc.)
-struct HttpSocketInfo {
- /// @brief Flag which indicates if socket can be reused.
- bool usable_;
-
- /// @brief Pointer to the socket config.
- CtrlAgentCfgContextPtr config_;
-
- /// @brief Pointer to HTTP/HTTPS listener.
- isc::http::HttpListenerPtr listener_;
-
- /// @brief Constructor.
- HttpSocketInfo() : usable_(true) {
- }
-
- /// @brief Destructor.
- ~HttpSocketInfo() = default;
-};
-
-/// @brief Pointer to a HttpSocketInfo object.
-typedef boost::shared_ptr<HttpSocketInfo> HttpSocketInfoPtr;
-
-/// @brief Kea Control Agent Application Process
-///
-/// CtrlAgentProcess provides top level application logic for the Control
-/// Agent, a process managing Kea servers.
-///
-/// The Control Agent receives JSON control commands over HTTP and forwards
-/// the JSON commands to the respective Kea servers. The JSON command
-/// includes a name of the server to which the command pertains. After
-/// receiving a response from the Kea server it is sent back over HTTP
-/// to the control API client.
-///
-/// Some commands are handled by the Control Agent process itself, rather than
-/// forwarded to the Kea servers. An example of such command is the one that
-/// instructs the agent to start a specific service.
-class CtrlAgentProcess : public process::DProcessBase {
-public:
- /// @brief Constructor
- ///
- /// @param name name is a text label for the process. Generally used
- /// in log statements, but otherwise arbitrary.
- /// @param io_service is the io_service used by the caller for
- /// asynchronous event handling.
- CtrlAgentProcess(const char* name, const asiolink::IOServicePtr& io_service);
-
- /// @brief Destructor
- virtual ~CtrlAgentProcess();
-
- /// @brief Initialize the Control Agent process.
- ///
- /// This is invoked by the controller after command line arguments but
- /// prior to configuration reception. The base class provides this method
- /// as a place to perform any derivation-specific initialization steps
- /// that are inappropriate for the constructor but necessary prior to
- /// launch.
- virtual void init();
-
- /// @brief Implements the process's event loop.
- ///
- /// @throw DProcessBaseError if an operational error is encountered.
- virtual void run();
-
- /// @brief Initiates the process's shutdown process.
- ///
- /// This is last step in the shutdown event callback chain, that is
- /// intended to notify the process it is to begin its shutdown process.
- ///
- /// @param args an Element set of shutdown arguments (if any) that are
- /// supported by the process derivation.
- ///
- /// @return an Element that contains the results of argument processing,
- /// consisting of an integer status value (0 means successful,
- /// non-zero means failure), and a string explanation of the outcome.
- ///
- /// @throw DProcessBaseError if an operational error is encountered.
- virtual isc::data::ConstElementPtr
- shutdown(isc::data::ConstElementPtr args);
-
- /// @brief Processes the given configuration.
- ///
- /// This method may be called multiple times during the process lifetime.
- /// Certainly once during process startup, and possibly later if the user
- /// alters configuration. This method must not throw, it should catch any
- /// processing errors and return a success or failure answer as described
- /// below.
- ///
- /// A usual problem related to the system reconfiguration is how to preserve
- /// configuration integrity in case of errors. In this case, when the
- /// HTTP listener's configuration is modified there is a need to close all
- /// existing connections and gracefully shutdown the listener's instance.
- /// This, however, makes it possible that the control agent looses
- /// connectivity if opening a new listener is unsuccessful. In fact, this
- /// is quite possible scenario when the user is setting up the listener to
- /// use a restricted port range or non-existing IP address. In this case,
- /// the configuration parser will not signal the problem because IP address
- /// and/or port are syntactically correct.
- ///
- /// This method deals with this problem by opening a new listener aside of
- /// the currently running listener (if the new listener settings are
- /// different than current settings). Both instances are held until the
- /// CtrlAgentProcess::garbageCollectListeners is invoked, which
- /// removes any listeners which are no longer used.
- ///
- /// @param config_set a new configuration (JSON) for the process
- /// @param check_only true if configuration is to be verified only, not applied
- /// @return an Element that contains the results of configuration composed
- /// of an integer status value (0 means successful, non-zero means failure),
- /// and a string explanation of the outcome.
- virtual isc::data::ConstElementPtr
- configure(isc::data::ConstElementPtr config_set,
- bool check_only = false);
-
- /// @brief Returns a pointer to the configuration manager.
- CtrlAgentCfgMgrPtr getCtrlAgentCfgMgr();
-
- /// @brief Returns a const pointer to the HTTP listener.
- ///
- /// @param info Configuration information for the http control socket.
- ///
- /// @return Const pointer to the currently used listener or null pointer if
- /// there is no listener.
- isc::http::ConstHttpListenerPtr getHttpListener(HttpSocketInfoPtr info = HttpSocketInfoPtr()) const;
-
- /// @brief Checks if the process is listening to the HTTP requests.
- ///
- /// @return true if the process is listening.
- bool isListening() const;
-
- /// @brief Close http control sockets.
- void closeCommandSockets();
-
-private:
-
- /// @brief Polls all ready handlers and then runs one handler if none
- /// handlers have been executed as a result of polling.
- ///
- /// @return Number of executed handlers.
- size_t runIO();
-
- /// @brief The HTTP/HTTPS socket data (configuration, listener, etc.).
- std::map<std::pair<isc::asiolink::IOAddress, uint16_t>, HttpSocketInfoPtr> sockets_;
-};
-
-/// @brief Defines a shared pointer to CtrlAgentProcess.
-typedef boost::shared_ptr<CtrlAgentProcess> CtrlAgentProcessPtr;
-
-} // namespace isc::agent
-} // namespace isc
-
-#endif // CTRL_AGENT_PROCESS_H
+++ /dev/null
-// Copyright (C) 2017-2024 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#include <config.h>
-
-#include <agent/ca_cfg_mgr.h>
-#include <agent/ca_command_mgr.h>
-#include <agent/ca_controller.h>
-#include <agent/ca_process.h>
-#include <agent/ca_response_creator.h>
-#include <cc/data.h>
-#include <hooks/callout_handle.h>
-#include <hooks/hooks_log.h>
-#include <hooks/hooks_manager.h>
-#include <http/post_request_json.h>
-#include <http/response_json.h>
-#include <boost/pointer_cast.hpp>
-#include <iostream>
-
-using namespace isc::data;
-using namespace isc::hooks;
-using namespace isc::http;
-
-namespace {
-
-/// Structure that holds registered hook indexes.
-struct CtrlAgentHooks {
- int hook_index_http_auth_; ///< index of "http_auth" hook point.
- int hook_index_http_response_; ///< index of "http_response" hook point.
-
- /// Constructor that registers hook points.
- CtrlAgentHooks() {
- hook_index_http_auth_ = HooksManager::registerHook("http_auth");
- hook_index_http_response_ = HooksManager::registerHook("http_response");
- }
-};
-
-} // end of anonymous namespace.
-
-// Declare a Hooks object. As this is outside any function or method, it
-// will be instantiated (and the constructor run) when the module is loaded.
-// As a result, the hook indexes will be defined before any method in this
-// module is called.
-CtrlAgentHooks Hooks;
-
-namespace isc {
-namespace agent {
-
-HttpRequestPtr
-CtrlAgentResponseCreator::createNewHttpRequest() const {
- return (HttpRequestPtr(new PostHttpRequestJson()));
-}
-
-HttpResponsePtr
-CtrlAgentResponseCreator::
-createStockHttpResponse(const HttpRequestPtr& request,
- const HttpStatusCode& status_code) const {
- HttpResponsePtr response = createStockHttpResponseInternal(request, status_code);
- response->finalize();
- return (response);
-}
-
-namespace {
-
-/// Getting the config context.
-CtrlAgentCfgContextPtr getCtrlAgentCfgContext() {
- // There is a hierarchy of the objects through which we need to pass to get
- // the configuration context. We may simplify this at some point but since
- // we're in the singleton we want to make sure that we're using most current
- // configuration.
- CtrlAgentCfgContextPtr ctx;
- boost::shared_ptr<CtrlAgentController> controller =
- boost::dynamic_pointer_cast<CtrlAgentController>(CtrlAgentController::instance());
- if (controller) {
- CtrlAgentProcessPtr process = controller->getCtrlAgentProcess();
- if (process) {
- CtrlAgentCfgMgrPtr cfgmgr = process->getCtrlAgentCfgMgr();
- if (cfgmgr) {
- ctx = cfgmgr->getCtrlAgentCfgContext();
- }
- }
- }
- return (ctx);
-}
-
-} // end of anonymous namespace.
-
-HttpResponsePtr
-CtrlAgentResponseCreator::
-createStockHttpResponseInternal(const HttpRequestPtr& request,
- const HttpStatusCode& status_code) const {
- // The request hasn't been finalized so the request object
- // doesn't contain any information about the HTTP version number
- // used. But, the context should have this data (assuming the
- // HTTP version is parsed ok).
- HttpVersion http_version(request->context()->http_version_major_,
- request->context()->http_version_minor_);
- // We only accept HTTP version 1.0 or 1.1. If other version number is found
- // we fall back to HTTP/1.0.
- if ((http_version < HttpVersion(1, 0)) || (HttpVersion(1, 1) < http_version)) {
- http_version.major_ = 1;
- http_version.minor_ = 0;
- }
- // This will generate the response holding JSON content.
- HttpResponsePtr response(new HttpResponseJson(http_version, status_code));
- CtrlAgentCfgContextPtr ctx = getCtrlAgentCfgContext();
- if (ctx) {
- copyHttpHeaders(ctx->getHttpHeaders(), *response);
- }
- return (response);
-}
-
-HttpResponsePtr
-CtrlAgentResponseCreator::
-createDynamicHttpResponse(HttpRequestPtr request) {
- // Extra headers.
- CfgHttpHeaders headers;
-
- // First check authentication.
- HttpResponseJsonPtr http_response;
-
- // Context will hold the server configuration.
- CtrlAgentCfgContextPtr ctx = getCtrlAgentCfgContext();
- if (ctx) {
- headers = ctx->getHttpHeaders();
- const HttpAuthConfigPtr& auth = ctx->getAuthConfig();
- if (auth) {
- // Check authentication.
- http_response = auth->checkAuth(*this, request);
- }
- }
-
- // Pass extra headers to the hook.
- bool auth_failed = false;
- if (http_response) {
- auth_failed = true;
- copyHttpHeaders(headers, *http_response);
- }
-
- // Callout point for "http_auth".
- bool reset_handle = false;
- if (HooksManager::calloutsPresent(Hooks.hook_index_http_auth_)) {
- // Get callout handle.
- CalloutHandlePtr callout_handle = request->getCalloutHandle();
- ScopedCalloutHandleState callout_handle_state(callout_handle);
-
- // Pass arguments.
- callout_handle->setArgument("request", request);
- callout_handle->setArgument("response", http_response);
-
- // Call callouts.
- HooksManager::callCallouts(Hooks.hook_index_http_auth_,
- *callout_handle);
- callout_handle->getArgument("request", request);
- callout_handle->getArgument("response", http_response);
-
- // Status other than continue means 'please reset the handle'.
- if (callout_handle->getStatus() != CalloutHandle::NEXT_STEP_CONTINUE) {
- reset_handle = true;
- }
- }
-
- // The basic HTTP authentication check or a callout failed and
- // left a response.
- if (http_response) {
- // Avoid to copy extra headers twice even this should not be required.
- if (!auth_failed && !headers.empty()) {
- copyHttpHeaders(headers, *http_response);
- if (http_response->isFinalized()) {
- // Argh! The response was already finalized.
- http_response->reset();
- http_response->finalize();
- }
- }
- return (http_response);
- }
-
- // Reset the handle when a hook asks for.
- if (reset_handle) {
- request->resetCalloutHandle();
- }
-
- // The request is always non-null, because this is verified by the
- // createHttpResponse method. Let's try to convert it to the
- // PostHttpRequestJson type as this is the type generated by the
- // createNewHttpRequest. If the conversion result is null it means that
- // the caller did not use createNewHttpRequest method to create this
- // instance. This is considered an error in the server logic.
- PostHttpRequestJsonPtr request_json =
- boost::dynamic_pointer_cast<PostHttpRequestJson>(request);
- if (!request_json) {
- // Notify the client that we have a problem with our server.
- return (createStockHttpResponse(request, HttpStatusCode::INTERNAL_SERVER_ERROR));
- }
-
- // We have already checked that the request is finalized so the call
- // to getBodyAsJson must not trigger an exception.
- ConstElementPtr command = request_json->getBodyAsJson();
-
- // Process command doesn't generate exceptions but can possibly return
- // null response, if the handler is not implemented properly. This is
- // again an internal server issue.
- ConstElementPtr response = CtrlAgentCommandMgr::instance().processCommand(command);
- if (!response) {
- // Notify the client that we have a problem with our server.
- return (createStockHttpResponse(request, HttpStatusCode::INTERNAL_SERVER_ERROR));
- }
- // The response is ok, so let's create new HTTP response with the status OK.
- http_response = boost::dynamic_pointer_cast<
- HttpResponseJson>(createStockHttpResponseInternal(request, HttpStatusCode::OK));
- http_response->setBodyAsJson(response);
- http_response->finalize();
-
- // Callout point for "http_response".
- if (HooksManager::calloutsPresent(Hooks.hook_index_http_response_)) {
- // Get callout handle.
- CalloutHandlePtr callout_handle = request->getCalloutHandle();
- ScopedCalloutHandleState callout_handle_state(callout_handle);
-
- // Pass arguments.
- callout_handle->setArgument("request", request);
- callout_handle->setArgument("response", http_response);
-
- // Call callouts.
- HooksManager::callCallouts(Hooks.hook_index_http_response_,
- *callout_handle);
- callout_handle->getArgument("response", http_response);
-
- // Ignore status as the HTTP response is used instead.
- }
-
- return (http_response);
-}
-
-} // end of namespace isc::agent
-} // end of namespace isc
+++ /dev/null
-// Copyright (C) 2017-2021 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#ifndef CTRL_AGENT_RESPONSE_CREATOR_H
-#define CTRL_AGENT_RESPONSE_CREATOR_H
-
-#include <agent/ca_command_mgr.h>
-#include <http/response_creator.h>
-#include <boost/shared_ptr.hpp>
-
-namespace isc {
-namespace agent {
-
-class CtrlAgentResponseCreator;
-
-/// @brief Pointer to the @ref CtrlAgentResponseCreator.
-typedef boost::shared_ptr<CtrlAgentResponseCreator> CtrlAgentResponseCreatorPtr;
-
-/// @brief Concrete implementation of the HTTP response creator used
-/// by the Control Agent.
-///
-/// See the documentation of the @ref isc::http::HttpResponseCreator for
-/// the basic information how HTTP response creators are utilized by
-/// the libkea-http library to generate HTTP responses.
-///
-/// This creator expects that received requests are encapsulated in the
-/// @ref isc::http::PostHttpRequestJson objects. The generated responses
-/// are encapsulated in the HttpResponseJson objects.
-///
-/// This class uses @ref CtrlAgentCommandMgr singleton to process commands
-/// conveyed in the HTTP body. The JSON responses returned by the manager
-/// are placed in the body of the generated HTTP responses.
-class CtrlAgentResponseCreator : public http::HttpResponseCreator {
-public:
-
- /// @brief Create a new request.
- ///
- /// This method creates a bare instance of the @ref
- /// isc::http::PostHttpRequestJson.
- ///
- /// @return Pointer to the new instance of the @ref
- /// isc::http::PostHttpRequestJson.
- virtual http::HttpRequestPtr createNewHttpRequest() const;
-
- /// @brief Creates stock HTTP response.
- ///
- /// @param request Pointer to an object representing HTTP request.
- /// @param status_code Status code of the response.
- /// @return Pointer to an @ref isc::http::HttpResponseJson object
- /// representing stock HTTP response.
- virtual http::HttpResponsePtr
- createStockHttpResponse(const http::HttpRequestPtr& request,
- const http::HttpStatusCode& status_code) const;
-
-private:
-
- /// @brief Creates unfinalized stock HTTP response.
- ///
- /// The unfinalized response is the response that can't be sent over the
- /// wire until @c finalize() is called, which commits the contents of the
- /// message body.
- ///
- /// @param request Pointer to an object representing HTTP request.
- /// @param status_code Status code of the response.
- /// @return Pointer to an @ref isc::http::HttpResponseJson object
- /// representing stock HTTP response.
- http::HttpResponsePtr
- createStockHttpResponseInternal(const http::HttpRequestPtr& request,
- const http::HttpStatusCode& status_code) const;
-
- /// @brief Creates implementation specific HTTP response.
- ///
- /// @param request Pointer to an object representing HTTP request.
- /// @return Pointer to an object representing HTTP response.
- virtual http::HttpResponsePtr
- createDynamicHttpResponse(http::HttpRequestPtr request);
-};
-
-} // end of namespace isc::agent
-} // end of namespace isc
-
-#endif
+++ /dev/null
-// Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#ifndef CTRL_AGENT_RESPONSE_CREATOR_FACTORY_H
-#define CTRL_AGENT_RESPONSE_CREATOR_FACTORY_H
-
-#include <agent/ca_response_creator.h>
-#include <http/response_creator_factory.h>
-
-namespace isc {
-namespace agent {
-
-/// @brief HTTP response creator factory for Control Agent.
-///
-/// See the documentation of the @ref isc::http::HttpResponseCreatorFactory
-/// for the details how the response factory object is used by the
-/// @ref isc::http::HttpListener.
-///
-/// This class always returns the same instance of the
-/// @ref CtrlAgentResponseCreator which @ref isc::http::HttpListener and
-/// @ref isc::http::HttpConnection classes use to generate HTTP response
-/// messages which comply with the formats required by the Control Agent.
-class CtrlAgentResponseCreatorFactory : public http::HttpResponseCreatorFactory {
-public:
-
- /// @brief Constructor.
- ///
- /// Creates sole instance of the @ref CtrlAgentResponseCreator object
- /// returned by the @ref CtrlAgentResponseCreatorFactory::create.
- CtrlAgentResponseCreatorFactory()
- : sole_creator_(new CtrlAgentResponseCreator()) {
- }
-
- /// @brief Returns an instance of the @ref CtrlAgentResponseCreator which
- /// is used by HTTP server to generate responses to commands.
- ///
- /// @return Pointer to the @ref CtrlAgentResponseCreator object.
- virtual http::HttpResponseCreatorPtr create() const {
- return (sole_creator_);
- }
-
-private:
-
- /// @brief Instance of the @ref CtrlAgentResponseCreator returned.
- http::HttpResponseCreatorPtr sole_creator_;
-
-};
-
-} // end of namespace isc::agent
-} // end of namespace isc
-
-#endif
+++ /dev/null
-// A Bison parser, made by GNU Bison 3.8.2.
-
-// Locations for Bison parsers in C++
-
-// Copyright (C) 2002-2015, 2018-2021 Free Software Foundation, Inc.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <https://www.gnu.org/licenses/>.
-
-// As a special exception, you may create a larger work that contains
-// part or all of the Bison parser skeleton and distribute that work
-// under terms of your choice, so long as that work isn't itself a
-// parser generator using the skeleton or a modified version thereof
-// as a parser skeleton. Alternatively, if you modify or redistribute
-// the parser skeleton itself, you may (at your option) remove this
-// special exception, which will cause the skeleton and the resulting
-// Bison output files to be licensed under the GNU General Public
-// License without this special exception.
-
-// This special exception was added by the Free Software Foundation in
-// version 2.2 of Bison.
-
-/**
- ** \file location.hh
- ** Define the isc::agent::location class.
- */
-
-#ifndef YY_AGENT_LOCATION_HH_INCLUDED
-# define YY_AGENT_LOCATION_HH_INCLUDED
-
-# include <iostream>
-# include <string>
-
-# ifndef YY_NULLPTR
-# if defined __cplusplus
-# if 201103L <= __cplusplus
-# define YY_NULLPTR nullptr
-# else
-# define YY_NULLPTR 0
-# endif
-# else
-# define YY_NULLPTR ((void*)0)
-# endif
-# endif
-
-#line 14 "agent_parser.yy"
-namespace isc { namespace agent {
-#line 59 "location.hh"
-
- /// A point in a source file.
- class position
- {
- public:
- /// Type for file name.
- typedef const std::string filename_type;
- /// Type for line and column numbers.
- typedef int counter_type;
-
- /// Construct a position.
- explicit position (filename_type* f = YY_NULLPTR,
- counter_type l = 1,
- counter_type c = 1)
- : filename (f)
- , line (l)
- , column (c)
- {}
-
-
- /// Initialization.
- void initialize (filename_type* fn = YY_NULLPTR,
- counter_type l = 1,
- counter_type c = 1)
- {
- filename = fn;
- line = l;
- column = c;
- }
-
- /** \name Line and Column related manipulators
- ** \{ */
- /// (line related) Advance to the COUNT next lines.
- void lines (counter_type count = 1)
- {
- if (count)
- {
- column = 1;
- line = add_ (line, count, 1);
- }
- }
-
- /// (column related) Advance to the COUNT next columns.
- void columns (counter_type count = 1)
- {
- column = add_ (column, count, 1);
- }
- /** \} */
-
- /// File name to which this position refers.
- filename_type* filename;
- /// Current line number.
- counter_type line;
- /// Current column number.
- counter_type column;
-
- private:
- /// Compute max (min, lhs+rhs).
- static counter_type add_ (counter_type lhs, counter_type rhs, counter_type min)
- {
- return lhs + rhs < min ? min : lhs + rhs;
- }
- };
-
- /// Add \a width columns, in place.
- inline position&
- operator+= (position& res, position::counter_type width)
- {
- res.columns (width);
- return res;
- }
-
- /// Add \a width columns.
- inline position
- operator+ (position res, position::counter_type width)
- {
- return res += width;
- }
-
- /// Subtract \a width columns, in place.
- inline position&
- operator-= (position& res, position::counter_type width)
- {
- return res += -width;
- }
-
- /// Subtract \a width columns.
- inline position
- operator- (position res, position::counter_type width)
- {
- return res -= width;
- }
-
- /** \brief Intercept output stream redirection.
- ** \param ostr the destination output stream
- ** \param pos a reference to the position to redirect
- */
- template <typename YYChar>
- std::basic_ostream<YYChar>&
- operator<< (std::basic_ostream<YYChar>& ostr, const position& pos)
- {
- if (pos.filename)
- ostr << *pos.filename << ':';
- return ostr << pos.line << '.' << pos.column;
- }
-
- /// Two points in a source file.
- class location
- {
- public:
- /// Type for file name.
- typedef position::filename_type filename_type;
- /// Type for line and column numbers.
- typedef position::counter_type counter_type;
-
- /// Construct a location from \a b to \a e.
- location (const position& b, const position& e)
- : begin (b)
- , end (e)
- {}
-
- /// Construct a 0-width location in \a p.
- explicit location (const position& p = position ())
- : begin (p)
- , end (p)
- {}
-
- /// Construct a 0-width location in \a f, \a l, \a c.
- explicit location (filename_type* f,
- counter_type l = 1,
- counter_type c = 1)
- : begin (f, l, c)
- , end (f, l, c)
- {}
-
-
- /// Initialization.
- void initialize (filename_type* f = YY_NULLPTR,
- counter_type l = 1,
- counter_type c = 1)
- {
- begin.initialize (f, l, c);
- end = begin;
- }
-
- /** \name Line and Column related manipulators
- ** \{ */
- public:
- /// Reset initial location to final location.
- void step ()
- {
- begin = end;
- }
-
- /// Extend the current location to the COUNT next columns.
- void columns (counter_type count = 1)
- {
- end += count;
- }
-
- /// Extend the current location to the COUNT next lines.
- void lines (counter_type count = 1)
- {
- end.lines (count);
- }
- /** \} */
-
-
- public:
- /// Beginning of the located region.
- position begin;
- /// End of the located region.
- position end;
- };
-
- /// Join two locations, in place.
- inline location&
- operator+= (location& res, const location& end)
- {
- res.end = end.end;
- return res;
- }
-
- /// Join two locations.
- inline location
- operator+ (location res, const location& end)
- {
- return res += end;
- }
-
- /// Add \a width columns to the end position, in place.
- inline location&
- operator+= (location& res, location::counter_type width)
- {
- res.columns (width);
- return res;
- }
-
- /// Add \a width columns to the end position.
- inline location
- operator+ (location res, location::counter_type width)
- {
- return res += width;
- }
-
- /// Subtract \a width columns to the end position, in place.
- inline location&
- operator-= (location& res, location::counter_type width)
- {
- return res += -width;
- }
-
- /// Subtract \a width columns to the end position.
- inline location
- operator- (location res, location::counter_type width)
- {
- return res -= width;
- }
-
- /** \brief Intercept output stream redirection.
- ** \param ostr the destination output stream
- ** \param loc a reference to the location to redirect
- **
- ** Avoid duplicate information.
- */
- template <typename YYChar>
- std::basic_ostream<YYChar>&
- operator<< (std::basic_ostream<YYChar>& ostr, const location& loc)
- {
- location::counter_type end_col
- = 0 < loc.end.column ? loc.end.column - 1 : 0;
- ostr << loc.begin;
- if (loc.end.filename
- && (!loc.begin.filename
- || *loc.begin.filename != *loc.end.filename))
- ostr << '-' << loc.end.filename << ':' << loc.end.line << '.' << end_col;
- else if (loc.begin.line < loc.end.line)
- ostr << '-' << loc.end.line << '.' << end_col;
- else if (loc.begin.column < end_col)
- ostr << '-' << end_col;
- return ostr;
- }
-
-#line 14 "agent_parser.yy"
-} } // isc::agent
-#line 305 "location.hh"
-
-#endif // !YY_AGENT_LOCATION_HH_INCLUDED
+++ /dev/null
-// Copyright (C) 2016-2025 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#include <config.h>
-#include <agent/ca_controller.h>
-#include <exceptions/exceptions.h>
-#include <util/filesystem.h>
-#include <cstdlib>
-#include <iostream>
-
-using namespace isc::agent;
-using namespace isc::process;
-
-int main(int argc, char* argv[]) {
- isc::util::file::setUmask();
-
- int ret = EXIT_SUCCESS;
-
- // Launch the controller passing in command line arguments.
- // Exit program with the controller's return code.
- try {
- // Instantiate/fetch the application controller singleton.
- DControllerBasePtr& controller = CtrlAgentController::instance();
-
- // 'false' value disables test mode.
- ret = controller->launch(argc, argv, false);
- } catch (const VersionMessage& ex) {
- std::string msg(ex.what());
- if (!msg.empty()) {
- std::cout << msg << std::endl;
- }
- } catch (const InvalidUsage& ex) {
- std::string msg(ex.what());
- if (!msg.empty()) {
- std::cerr << msg << std::endl;
- }
- ret = EXIT_FAILURE;
- } catch (const std::exception& ex) {
- std::cerr << "Service failed: " << ex.what() << std::endl;
- ret = EXIT_FAILURE;
- } catch (...) {
- std::cerr << "Service failed" << std::endl;
- ret = EXIT_FAILURE;
- }
-
- CtrlAgentController::instance().reset();
-
- return (ret);
-}
+++ /dev/null
-agent_lib = static_library(
- 'agent',
- 'agent_lexer.cc',
- 'agent_parser.cc',
- 'ca_cfg_mgr.cc',
- 'ca_command_mgr.cc',
- 'ca_controller.cc',
- 'ca_log.cc',
- 'ca_messages.cc',
- 'ca_process.cc',
- 'ca_response_creator.cc',
- 'parser_context.cc',
- 'simple_parser.cc',
- dependencies: [CRYPTO_DEP],
- include_directories: [include_directories('.')] + INCLUDES,
-)
-executable(
- 'kea-ctrl-agent',
- 'main.cc',
- dependencies: [CRYPTO_DEP],
- include_directories: [include_directories('.')] + INCLUDES,
- install: true,
- install_dir: SBINDIR,
- install_rpath: INSTALL_RPATH,
- build_rpath: BUILD_RPATH,
- link_with: [agent_lib] + LIBS_BUILT_SO_FAR,
-)
-subdir('tests')
-
-current_source_dir = meson.current_source_dir()
-if KEA_MSG_COMPILER.found()
- target_gen_messages = run_target(
- 'src-bin-agent-ca_messages',
- command: [
- CD_AND_RUN,
- TOP_SOURCE_DIR,
- KEA_MSG_COMPILER,
- 'src/bin/agent/ca_messages.mes',
- ],
- )
- TARGETS_GEN_MESSAGES += [target_gen_messages]
-endif
-
-if FLEX.found() and BISON.found()
- target_parser = run_target(
- 'src-bin-agent-parser',
- command: [
- CD_AND_RUN,
- current_source_dir,
- BISON,
- '-Wno-yacc',
- '--defines=agent_parser.h',
- '--report=all',
- '--report-file=agent_parser.report',
- '-o',
- 'agent_parser.cc',
- 'agent_parser.yy',
- ],
- )
- target_lexer = run_target(
- 'src-bin-agent-lexer',
- command: [
- CD_AND_RUN,
- current_source_dir,
- FLEX,
- '--prefix',
- 'agent_',
- '-o',
- 'agent_lexer.cc',
- 'agent_lexer.ll',
- ],
- )
- TARGETS_GEN_PARSER += [target_parser, target_lexer]
-endif
+++ /dev/null
-// Copyright (C) 2017-2024 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#include <config.h>
-
-#include <agent/parser_context.h>
-#include <agent/agent_parser.h>
-#include <agent/ca_log.h>
-#include <exceptions/exceptions.h>
-#include <cc/dhcp_config_error.h>
-#include <cc/data.h>
-#include <fstream>
-#include <sstream>
-#include <limits>
-
-namespace isc {
-namespace agent {
-
-ParserContext::ParserContext()
- : sfile_(0), ctx_(NO_KEYWORDS), trace_scanning_(false), trace_parsing_(false)
-{
-}
-
-ParserContext::~ParserContext()
-{
-}
-
-isc::data::ElementPtr
-ParserContext::parseString(const std::string& str, ParserType parser_type)
-{
- scanStringBegin(str, parser_type);
- return (parseCommon());
-}
-
-isc::data::ElementPtr
-ParserContext::parseFile(const std::string& filename, ParserType parser_type) {
- FILE* f = fopen(filename.c_str(), "r");
- if (!f) {
- isc_throw(ParseError, "Unable to open file " << filename);
- }
- scanFileBegin(f, filename, parser_type);
- return (parseCommon());
-}
-
-isc::data::ElementPtr
-ParserContext::parseCommon() {
- isc::agent::AgentParser parser(*this);
- // Uncomment this to get detailed parser logs.
- // trace_parsing_ = true;
- parser.set_debug_level(trace_parsing_);
- try {
- int res = parser.parse();
- if (res != 0) {
- isc_throw(ParseError, "Parser abort");
- }
- scanEnd();
- } catch (...) {
- scanEnd();
- throw;
- }
- if (stack_.size() == 1) {
- return (stack_[0]);
- } else {
- isc_throw(ParseError, "Expected exactly one terminal Element, found "
- << stack_.size());
- }
-}
-
-void
-ParserContext::error(const isc::agent::location& loc,
- const std::string& what,
- size_t pos)
-{
- if (pos == 0) {
- isc_throw(ParseError, loc << ": " << what);
- } else {
- isc_throw(ParseError, loc << " (near " << pos << "): " << what);
- }
-}
-
-void
-ParserContext::error(const std::string& what)
-{
- isc_throw(ParseError, what);
-}
-
-void
-ParserContext::fatal(const std::string& what)
-{
- isc_throw(ParseError, what);
-}
-
-isc::data::Element::Position
-ParserContext::loc2pos(isc::agent::location& loc)
-{
- const std::string& file = *loc.begin.filename;
- const uint32_t line = loc.begin.line;
- const uint32_t pos = loc.begin.column;
- return (isc::data::Element::Position(file, line, pos));
-}
-
-void
-ParserContext::require(const std::string& name,
- isc::data::Element::Position open_loc,
- isc::data::Element::Position close_loc)
-{
- ConstElementPtr value = stack_.back()->get(name);
- if (!value) {
- isc_throw(ParseError,
- "missing parameter '" << name << "' ("
- << stack_.back()->getPosition() << ") ["
- << contextName() << " map between "
- << open_loc << " and " << close_loc << "]");
- }
-}
-
-void
-ParserContext::unique(const std::string& name,
- isc::data::Element::Position loc)
-{
- ConstElementPtr value = stack_.back()->get(name);
- if (value) {
- if (ctx_ != NO_KEYWORDS) {
- isc_throw(ParseError, loc << ": duplicate " << name
- << " entries in " << contextName()
- << " map (previous at " << value->getPosition() << ")");
- } else {
- isc_throw(ParseError, loc << ": duplicate " << name
- << " entries in JSON"
- << " map (previous at " << value->getPosition() << ")");
- }
- }
-}
-
-void
-ParserContext::enter(const LexerContext& ctx)
-{
- cstack_.push_back(ctx_);
- ctx_ = ctx;
-}
-
-void
-ParserContext::leave()
-{
- if (cstack_.empty()) {
- fatal("unbalanced syntactic context");
- }
- ctx_ = cstack_.back();
- cstack_.pop_back();
-}
-
-const std::string
-ParserContext::contextName()
-{
- switch (ctx_) {
- case NO_KEYWORDS:
- return ("__no keywords__");
- case CONFIG:
- return ("toplevel");
- case AGENT:
- return ("Control-agent");
- case HTTP_HEADERS:
- return ("http-headers");
- case AUTHENTICATION:
- return ("authentication");
- case AUTH_TYPE:
- return ("auth-type");
- case CLIENTS:
- return ("clients");
- case CONTROL_SOCKETS:
- return ("control-sockets");
- case SERVER:
- return ("xxx-server");
- case SOCKET_TYPE:
- return ("socket-type");
- case HOOKS_LIBRARIES:
- return ("hooks-libraries");
- case LOGGERS:
- return ("loggers");
- case OUTPUT_OPTIONS:
- return ("output-options");
- default:
- return ("__unknown__");
- }
-}
-
-void
-ParserContext::warning(const isc::agent::location& loc,
- const std::string& what) {
- std::ostringstream msg;
- msg << loc << ": " << what;
- LOG_WARN(agent_logger, CTRL_AGENT_CONFIG_SYNTAX_WARNING)
- .arg(msg.str());
-}
-
-void
-ParserContext::warnAboutExtraCommas(const isc::agent::location& loc) {
- warning(loc, "Extraneous comma. A piece of configuration may have been omitted.");
-}
-
-} // end of isc::eval namespace
-} // end of isc namespace
+++ /dev/null
-// Copyright (C) 2017-2024 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#ifndef PARSER_CONTEXT_H
-#define PARSER_CONTEXT_H
-#include <string>
-#include <map>
-#include <vector>
-#include <agent/agent_parser.h>
-#include <agent/parser_context_decl.h>
-#include <exceptions/exceptions.h>
-
-// Tell Flex the lexer's prototype ...
-#define YY_DECL isc::agent::AgentParser::symbol_type agent_lex (ParserContext& driver)
-
-// ... and declare it for the parser's sake.
-YY_DECL;
-
-namespace isc {
-namespace agent {
-
-/// @brief Parser context is a wrapper around flex/bison instances dedicated to
-/// Control-agent config file parser.
-///
-/// It follows the same principle as other components. The primary interface
-/// are @ref parseString and @ref parseFile methods. All other methods are
-/// public for testing purposes only. This interface allows parsing the
-/// whole configuration with syntactic checking (which is by far the most
-/// frequent use), but it also allows parsing input as generic JSON or
-/// parse only content of the Control-agent object, which is a subset
-/// of full grammar (this will be very useful for unit-tests to not duplicate
-/// unnecessary parts of the config file).
-class ParserContext
-{
-public:
-
- /// @brief Defines currently supported scopes
- ///
- /// AgentParser is able to parse several types of scope. Usually,
- /// when it parses a config file, it expects the data to have a map
- /// with Control-agent in it and all the parameters within that map.
- /// However, sometimes the parser is expected to parse only a subset
- /// of that information.
- typedef enum {
- /// This parser will parse the content as generic JSON.
- PARSER_JSON,
-
- /// This parser will expect the content as Control-agent config wrapped
- /// in a map (that's the regular config file)
- PARSER_AGENT,
-
- /// This parser will expect only the content of Control-agent.
- PARSER_SUB_AGENT
- } ParserType;
-
- /// @brief Default constructor.
- ParserContext();
-
- /// @brief destructor
- virtual ~ParserContext();
-
- /// @brief JSON elements being parsed.
- std::vector<isc::data::ElementPtr> stack_;
-
- /// @brief Method called before scanning starts on a string.
- ///
- /// @param str string to be parsed
- /// @param type specifies expected content
- void scanStringBegin(const std::string& str, ParserType type);
-
- /// @brief Method called before scanning starts on a file.
- ///
- /// @param f stdio FILE pointer
- /// @param filename file to be parsed
- /// @param type specifies expected content
- void scanFileBegin(FILE* f, const std::string& filename, ParserType type);
-
- /// @brief Method called after the last tokens are scanned.
- void scanEnd();
-
- /// @brief Divert input to an include file.
- ///
- /// @param filename file to be included
- void includeFile(const std::string& filename);
-
- /// @brief Run the parser on the string specified.
- ///
- /// This method parses specified string. Depending on the value of
- /// parser_type, parser may either check only that the input is valid
- /// JSON, or may do more specific syntax checking. See @ref ParserType
- /// for supported syntax checkers.
- ///
- /// @param str string to be parsed
- /// @param parser_type specifies expected content (usually AGENT or generic JSON)
- /// @return Element structure representing parsed text.
- isc::data::ElementPtr parseString(const std::string& str,
- ParserType parser_type);
-
- /// @brief Run the parser on the file specified.
- ///
- /// This method parses specified file. Depending on the value of
- /// parser_type, parser may either check only that the input is valid
- /// JSON, or may do more specific syntax checking. See @ref ParserType
- /// for supported syntax checkers.
- ///
- /// @param filename file to be parsed
- /// @param parser_type specifies expected content (usually PARSER_AGENT or
- /// PARSER_JSON)
- /// @return Element structure representing parsed text.
- isc::data::ElementPtr parseFile(const std::string& filename,
- ParserType parser_type);
-
- /// @brief Error handler
- ///
- /// @note The optional position for an error in a string begins by 1
- /// so the caller should add 1 to the position of the C++ string.
- ///
- /// @param loc location within the parsed file where the problem was experienced.
- /// @param what string explaining the nature of the error.
- /// @param pos optional position for in string errors.
- /// @throw ParseError
- void error(const isc::agent::location& loc,
- const std::string& what,
- size_t pos = 0);
-
- /// @brief Error handler
- ///
- /// This is a simplified error reporting tool for possible future
- /// cases when the AgentParser is not able to handle the packet.
- ///
- /// @param what string explaining the nature of the error.
- /// @throw ParseError
- void error(const std::string& what);
-
- /// @brief Fatal error handler
- ///
- /// This is for should not happen but fatal errors.
- /// Used by YY_FATAL_ERROR macro so required to be static.
- ///
- /// @param what string explaining the nature of the error.
- /// @throw ParseError
- static void fatal(const std::string& what);
-
- /// @brief Converts bison's position to one understandable by isc::data::Element
- ///
- /// Convert a bison location into an element position
- /// (take the begin, the end is lost)
- ///
- /// @param loc location in bison format
- /// @return Position in format accepted by Element
- isc::data::Element::Position loc2pos(isc::agent::location& loc);
-
- /// @brief Check if a required parameter is present
- ///
- /// Check if a required parameter is present in the map at the top
- /// of the stack and raise an error when it is not.
- ///
- /// @param name name of the parameter to check
- /// @param open_loc location of the opening curly bracket
- /// @param close_loc location of the closing curly bracket
- /// @throw ParseError
- void require(const std::string& name,
- isc::data::Element::Position open_loc,
- isc::data::Element::Position close_loc);
-
- /// @brief Check if a parameter is already present
- ///
- /// Check if a parameter is already present in the map at the top
- /// of the stack and raise an error when it is.
- ///
- /// @param name name of the parameter to check
- /// @param loc location of the current parameter
- /// @throw ParseError
- void unique(const std::string& name,
- isc::data::Element::Position loc);
-
- /// @brief Warning handler
- ///
- /// @param loc location within the parsed file where the problem was experienced
- /// @param what string explaining the nature of the error
- ///
- /// @throw ParseError
- void warning(const isc::agent::location& loc, const std::string& what);
-
- /// @brief Warning for extra commas
- ///
- /// @param loc location within the parsed file of the extra comma
- ///
- /// @throw ParseError
- void warnAboutExtraCommas(const isc::agent::location& loc);
-
- /// @brief Defines syntactic contexts for lexical tie-ins
- typedef enum {
- ///< This one is used in pure JSON mode.
- NO_KEYWORDS,
-
- ///< Used while parsing top level (that contains Control-agent)
- CONFIG,
-
- ///< Used while parsing content of Agent.
- AGENT,
-
- ///< Used while parsing HTTP headers.
- HTTP_HEADERS,
-
- ///< Used while parsing Control-agent/Authentication.
- AUTHENTICATION,
-
- ///< Used while parsing Control-agent/Authentication/type.
- AUTH_TYPE,
-
- ///< Used while parsing Control-agent/Authentication/clients.
- CLIENTS,
-
- ///< Used while parsing Control-agent/control-sockets.
- CONTROL_SOCKETS,
-
- ///< Used while parsing Control-agent/control-socket/*-server.
- SERVER,
-
- ///< Used while parsing Control-agent/control-socket/*-server/socket-type.
- SOCKET_TYPE,
-
- ///< Used while parsing Control-agent/hooks-libraries.
- HOOKS_LIBRARIES,
-
- ///< Used while parsing Control-agent/loggers structures.
- LOGGERS,
-
- ///< Used while parsing Control-agent/loggers/output-options structures.
- OUTPUT_OPTIONS
- } LexerContext;
-
- /// @brief File name
- std::string file_;
-
- /// @brief File name stack
- std::vector<std::string> files_;
-
- /// @brief Location of the current token
- ///
- /// The lexer will keep updating it. This variable will be useful
- /// for logging errors.
- isc::agent::location loc_;
-
- /// @brief Location stack
- std::vector<isc::agent::location> locs_;
-
- /// @brief Lexer state stack
- std::vector<struct yy_buffer_state*> states_;
-
- /// @brief sFile (aka FILE)
- FILE* sfile_;
-
- /// @brief sFile (aka FILE) stack
- ///
- /// This is a stack of files. Typically there's only one file (the
- /// one being currently parsed), but there may be more if one
- /// file includes another.
- std::vector<FILE*> sfiles_;
-
- /// @brief Current syntactic context
- LexerContext ctx_;
-
- /// @brief Enter a new syntactic context
- ///
- /// Entering a new syntactic context is useful in several ways.
- /// First, it allows the parser to avoid conflicts. Second, it
- /// allows the lexer to return different tokens depending on
- /// context (e.g. if "renew-timer" string is detected, the lexer
- /// will return STRING token if in JSON mode or RENEW_TIMER if
- /// in DHCP6 mode. Finally, the syntactic context allows the
- /// error message to be more descriptive if the input string
- /// does not parse properly. Control Agent parser uses simplified
- /// contexts: either it recognizes keywords (value set to KEYWORDS)
- /// or not (value set to NO_KEYWORDS).
- ///
- /// Make sure to call @ref leave() once the parsing of your
- /// context is complete.
- ///
- /// @param ctx the syntactic context to enter into
- void enter(const LexerContext& ctx);
-
- /// @brief Leave a syntactic context
- ///
- /// @ref enter() must be called before (when entering a new scope
- /// or context). Once you complete the parsing, this method
- /// should be called.
- ///
- /// @throw isc::Unexpected if unbalanced (more leave() than enter() calls)
- void leave();
-
- /// @brief Get the syntactic context name
- ///
- /// @return printable name of the context.
- const std::string contextName();
-
- private:
- /// @brief Flag determining scanner debugging.
- bool trace_scanning_;
-
- /// @brief Flag determining parser debugging.
- bool trace_parsing_;
-
- /// @brief Syntactic context stack
- std::vector<LexerContext> cstack_;
-
- /// @brief Common part of parseXXX
- ///
- /// @return Element structure representing parsed text.
- isc::data::ElementPtr parseCommon();
-};
-
-} // end of isc::eval namespace
-} // end of isc namespace
-
-#endif
+++ /dev/null
-// Copyright (C) 2017-2024 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#ifndef AGENT_CONTEXT_DECL_H
-#define AGENT_CONTEXT_DECL_H
-
-/// @file agent/parser_context_decl.h Forward declaration of the ParserContext class
-
-namespace isc {
-namespace agent {
-
-class ParserContext;
-
-} // end of isc::dhcp namespace
-} // end of isc namespace
-
-#endif
+++ /dev/null
-// Copyright (C) 2017-2026 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#include <config.h>
-
-#include <agent/simple_parser.h>
-#include <asiolink/io_service_mgr.h>
-#include <cc/data.h>
-#include <cc/dhcp_config_error.h>
-#include <config/unix_command_config.h>
-#include <hooks/hooks_manager.h>
-#include <hooks/hooks_parser.h>
-#include <http/basic_auth_config.h>
-
-using namespace isc::data;
-using namespace isc::dhcp;
-using namespace isc::asiolink;
-using namespace isc::config;
-
-namespace isc {
-namespace agent {
-/// @brief This sets of arrays define the default values in various scopes
-/// of the Control Agent Configuration.
-///
-/// Each of those is documented in @file agent/simple_parser.cc. This
-/// is different than most other comments in Kea code. The reason
-/// for placing those in .cc rather than .h file is that it
-/// is expected to be one centralized place to look at for
-/// the default values. This is expected to be looked at also by
-/// people who are not skilled in C or C++, so they may be
-/// confused with the differences between declaration and definition.
-/// As such, there's one file to look at that hopefully is readable
-/// without any C or C++ skills.
-///
-/// @{
-
-/// @brief This table defines default values for global options.
-///
-/// These are global Control Agent parameters.
-const SimpleDefaults AgentSimpleParser::AGENT_DEFAULTS = {
- { "http-host", Element::string, "127.0.0.1" },
- { "http-port", Element::integer, "8000" },
- { "trust-anchor", Element::string, "" },
- { "cert-file", Element::string, "" },
- { "key-file", Element::string, "" },
- { "cert-required", Element::boolean, "true" }
-};
-
-/// @brief This table defines default values for authentication.
-const SimpleDefaults AgentSimpleParser::AUTH_DEFAULTS = {
- { "type", Element::string, "basic" },
- { "realm", Element::string, "kea-control-agent" },
- { "directory", Element::string, "" }
-};
-
-/// @brief This table defines default values for control sockets.
-///
-const SimpleDefaults AgentSimpleParser::SOCKET_DEFAULTS = {
- { "socket-type", Element::string, "unix" }
-};
-
-/// @}
-
-/// ---------------------------------------------------------------------------
-/// --- end of default values -------------------------------------------------
-/// ---------------------------------------------------------------------------
-
-size_t AgentSimpleParser::setAllDefaults(const isc::data::ElementPtr& global) {
- size_t cnt = 0;
-
- // Set global defaults first.
- cnt = setDefaults(global, AGENT_DEFAULTS);
-
- // After set the defaults for authentication if it exists.
- ConstElementPtr authentication = global->get("authentication");
- if (authentication) {
- ElementPtr auth = boost::const_pointer_cast<Element>(authentication);
- if (auth) {
- cnt += SimpleParser::setDefaults(auth, AUTH_DEFAULTS);
- }
- }
-
- // Now set the defaults for control-sockets, if any.
- ConstElementPtr sockets = global->get("control-sockets");
- if (sockets) {
- ElementPtr d2 = boost::const_pointer_cast<Element>(sockets->get("d2"));
- if (d2) {
- cnt += SimpleParser::setDefaults(d2, SOCKET_DEFAULTS);
- }
-
- ElementPtr d4 = boost::const_pointer_cast<Element>(sockets->get("dhcp4"));
- if (d4) {
- cnt += SimpleParser::setDefaults(d4, SOCKET_DEFAULTS);
- }
-
- ElementPtr d6 = boost::const_pointer_cast<Element>(sockets->get("dhcp6"));
- if (d6) {
- cnt += SimpleParser::setDefaults(d6, SOCKET_DEFAULTS);
- }
- }
-
- return (cnt);
-}
-
-void
-AgentSimpleParser::checkTlsSetup(const isc::data::ConstElementPtr& config) {
- ConstElementPtr ca = config->get("trust-anchor");
- ConstElementPtr cert = config->get("cert-file");
- ConstElementPtr key = config->get("key-file");
- bool have_ca = (ca && !ca->stringValue().empty());
- bool have_cert = (cert && !cert->stringValue().empty());
- bool have_key = (key && !key->stringValue().empty());
- if (!have_ca && !have_cert && !have_key) {
- // No TLS parameter so TLS is not used.
- return;
- }
- // TLS is used: all 3 parameters are required.
- if (!have_ca) {
- isc_throw(ConfigError, "trust-anchor parameter is missing or empty:"
- " all or none of TLS parameters must be set");
- }
- if (!have_cert) {
- isc_throw(ConfigError, "cert-file parameter is missing or empty:"
- " all or none of TLS parameters must be set");
- }
- if (!have_key) {
- isc_throw(ConfigError, "key-file parameter is missing or empty:"
- " all or none of TLS parameters must be set");
- }
-}
-
-void
-AgentSimpleParser::parse(const CtrlAgentCfgContextPtr& ctx,
- const isc::data::ConstElementPtr& config,
- bool check_only) {
-
- // Let's get the HTTP parameters first.
- ctx->setHttpHost(SimpleParser::getString(config, "http-host"));
- ctx->setHttpPort(SimpleParser::getIntType<uint16_t>(config, "http-port"));
-
- // TLS parameter are second.
- ctx->setTrustAnchor(SimpleParser::getString(config, "trust-anchor"));
- ctx->setCertFile(SimpleParser::getString(config, "cert-file"));
- ctx->setKeyFile(SimpleParser::getString(config, "key-file"));
- ctx->setCertRequired(SimpleParser::getBoolean(config, "cert-required"));
-
- // Control sockets are third.
- ConstElementPtr ctrl_sockets = config->get("control-sockets");
- if (ctrl_sockets) {
- auto const& sockets_map = ctrl_sockets->mapValue();
- for (auto const& cs : sockets_map) {
- if (!cs.second->get("socket-name")) {
- isc_throw(DhcpConfigError, "missing parameter 'socket-name' from '" << cs.first
- << "' service map (" << cs.second->getPosition() << ")");
- }
- // Add a validated socket name so we can suppress it in
- // toElement() but don't have to revalidate it every time we
- // want to use it.
- auto mutable_socket_info = boost::const_pointer_cast<Element>(cs.second);
- std::string socket_name = mutable_socket_info->get("socket-name")->stringValue();
- auto validated_name = UnixCommandConfig::validatePath(socket_name);
- mutable_socket_info->set("validated-socket-name", Element::create(validated_name));
- ctx->setControlSocketInfo(mutable_socket_info, cs.first);
- }
- }
-
- // Basic HTTP authentications are fourth.
- ConstElementPtr auth_config = config->get("authentication");
- if (auth_config) {
- using namespace isc::http;
- BasicHttpAuthConfigPtr auth(new BasicHttpAuthConfig());
- auth->parse(auth_config);
- ctx->setAuthConfig(auth);
- }
-
- // HTTP headers are fifth.
- ConstElementPtr headers_config = config->get("http-headers");
- if (headers_config) {
- using namespace isc::http;
- ctx->setHttpHeaders(parseCfgHttpHeaders(headers_config));
- }
-
- // User context can be done at anytime.
- ConstElementPtr user_context = config->get("user-context");
- if (user_context) {
- ctx->setContext(user_context);
- }
-
- // Finally, let's get the hook libs!
- using namespace isc::hooks;
- HooksConfig& libraries = ctx->getHooksConfig();
- ConstElementPtr hooks = config->get("hooks-libraries");
- if (hooks) {
- HooksLibrariesParser hooks_parser;
- hooks_parser.parse(libraries, hooks);
- libraries.verifyLibraries(hooks->getPosition(), false);
- }
-
- if (!check_only) {
- // This occurs last as if it succeeds, there is no easy way
- // revert it. As a result, the failure to commit a subsequent
- // change causes problems when trying to roll back.
- HooksManager::prepareUnloadLibraries();
- static_cast<void>(HooksManager::unloadLibraries());
- IOServiceMgr::instance().clearIOServices();
- libraries.loadLibraries(false);
- }
-}
-
-}
-}
+++ /dev/null
-// Copyright (C) 2017-2021 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#ifndef AGENT_SIMPLE_PARSER_H
-#define AGENT_SIMPLE_PARSER_H
-
-#include <cc/simple_parser.h>
-#include <agent/ca_cfg_mgr.h>
-
-namespace isc {
-namespace agent {
-
-/// @brief SimpleParser specialized for Control Agent
-///
-/// This class is a @ref isc::data::SimpleParser dedicated to Control Agent.
-/// In particular, it contains all the default values for the whole
-/// agent and for the socket defaults.
-///
-/// For the actual values, see @file agent/simple_parser.cc
-class AgentSimpleParser : public isc::data::SimpleParser {
-public:
- /// @brief Sets all defaults for Control Agent configuration
- ///
- /// This method sets global, option data and option definitions defaults.
- ///
- /// @param global scope to be filled in with defaults.
- /// @return number of default values added
- static size_t setAllDefaults(const isc::data::ElementPtr& global);
-
- /// @brief Check TLS setup consistency i.e. all or none.
- ///
- /// @param config - Element tree structure that holds configuration.
- /// @throw ConfigError when the configuration is not consistent.
- void checkTlsSetup(const isc::data::ConstElementPtr& config);
-
- /// @brief Parses the control agent configuration
- ///
- /// @param ctx - parsed information will be stored here
- /// @param config - Element tree structure that holds configuration
- /// @param check_only - if true the configuration is verified only, not applied
- ///
- /// @throw ConfigError if any issues are encountered.
- void parse(const CtrlAgentCfgContextPtr& ctx,
- const isc::data::ConstElementPtr& config,
- bool check_only);
-
- // see simple_parser.cc for comments for those parameters
- static const isc::data::SimpleDefaults AGENT_DEFAULTS;
- static const isc::data::SimpleDefaults AUTH_DEFAULTS;
- static const isc::data::SimpleDefaults SOCKET_DEFAULTS;
-};
-
-}
-}
-#endif
+++ /dev/null
-// Copyright (C) 2020-2024 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-/// @file
-/// @brief Basic HTTP Authentication callout library
-
-#include <config.h>
-
-#include <cc/command_interpreter.h>
-#include <cc/data.h>
-#include <exceptions/exceptions.h>
-#include <hooks/hooks.h>
-#include <http/basic_auth_config.h>
-#include <http/post_request_json.h>
-#include <http/response_creator.h>
-#include <boost/shared_ptr.hpp>
-#include <boost/pointer_cast.hpp>
-
-using namespace isc::data;
-using namespace isc::hooks;
-using namespace isc::http;
-using namespace isc;
-using namespace std;
-
-namespace {
-
-/// @brief Response creator.
-class ResponseCreator : public HttpResponseCreator {
-public:
- /// @brief Create a new request.
- /// @return Pointer to the new instance of the @ref
- /// isc::http::PostHttpRequestJson.
- virtual HttpRequestPtr
- createNewHttpRequest() const;
-
- /// @brief Create stock HTTP response.
- ///
- /// @param request Pointer to an object representing HTTP request.
- /// @param status_code Status code of the response.
- /// @return Pointer to an @ref isc::http::HttpResponseJson object
- /// representing stock HTTP response.
- virtual HttpResponsePtr
- createStockHttpResponse(const HttpRequestPtr& request,
- const HttpStatusCode& status_code) const;
-
- /// @brief Creates implementation specific HTTP response.
- ///
- /// @param request Pointer to an object representing HTTP request.
- /// @return Pointer to an object representing HTTP response.
- virtual HttpResponsePtr
- createDynamicHttpResponse(HttpRequestPtr request);
-};
-
-HttpRequestPtr
-ResponseCreator::createNewHttpRequest() const {
- return (HttpRequestPtr(new PostHttpRequestJson()));
-}
-
-HttpResponsePtr
-ResponseCreator::createStockHttpResponse(const HttpRequestPtr& /*request*/,
- const HttpStatusCode& status_code) const {
- HttpVersion http_version(1, 1);
- HttpResponsePtr response(new HttpResponseJson(http_version, status_code));
- response->finalize();
- return (response);
-}
-
-HttpResponsePtr
-ResponseCreator::createDynamicHttpResponse(HttpRequestPtr /*request*/) {
- isc_throw(NotImplemented, "createDynamicHttpResponse should not be called");
-}
-
-/// @brief The type of shared pointers to response creators.
-typedef boost::shared_ptr<ResponseCreator> ResponseCreatorPtr;
-
-/// @brief Implementation.
-class Impl {
-public:
-
- /// @brief Constructor.
- Impl();
-
- /// @brief Destructor.
- ~Impl();
-
- /// @brief Configure.
- ///
- /// @param config element pointer to client list.
- void configure(ConstElementPtr config);
-
- /// @brief Basic HTTP authentication configuration.
- BasicHttpAuthConfigPtr config_;
-
- /// @brief Response creator.
- ResponseCreatorPtr creator_;
-};
-
-Impl::Impl()
- : config_(new BasicHttpAuthConfig()), creator_(new ResponseCreator()) {
-}
-
-Impl::~Impl() {
-}
-
-void
-Impl::configure(ConstElementPtr config) {
- config_->parse(config);
-}
-
-/// @brief The type of shared pointers to implementations.
-typedef boost::shared_ptr<Impl> ImplPtr;
-
-/// @brief The implementation.
-ImplPtr impl;
-
-extern "C" {
-
-// Framework functions.
-
-/// @brief returns Kea hooks version.
-int
-version() {
- return (KEA_HOOKS_VERSION);
-}
-
-/// @brief This function is called when the library is loaded.
-///
-/// @param handle library handle.
-/// @return 0 when initialization is successful, 1 otherwise.
-int
-load(LibraryHandle& handle) {
-#ifdef USE_STATIC_LINK
- hooksStaticLinkInit();
-#endif
- try {
- impl.reset(new Impl());
- ConstElementPtr config = handle.getParameter("config");
- impl->configure(config);
- } catch (const std::exception& ex) {
- std::cerr << "load error: " << ex.what() << std::endl;
- return (1);
- }
-
- return (0);
-}
-
-/// @brief This function is called when the library is unloaded.
-///
-/// @return always 0.
-int
-unload() {
- impl.reset();
- return (0);
-}
-
-// Callout functions.
-
-/// @brief This callout is called at the "http_auth" hook.
-///
-/// @param handle CalloutHandle.
-/// @return 0 upon success, non-zero otherwise.
-int
-http_auth(CalloutHandle& handle) {
- // Sanity.
- if (!impl) {
- std::cerr << "no implementation" << std::endl;
- return (0);
- }
-
- // Get the parameters.
- HttpRequestPtr request;
- HttpResponseJsonPtr response;
- handle.getArgument("request", request);
- handle.getArgument("response", response);
-
- if (response) {
- std::cerr << "response already set" << std::endl;
- return (0);
- }
- if (!request) {
- std::cerr << "no request" << std::endl;
- return (0);
- }
- PostHttpRequestJsonPtr request_json =
- boost::dynamic_pointer_cast<PostHttpRequestJson>(request);
- if (!request_json) {
- std::cerr << "no json post request" << std::endl;
- return (0);
- }
- ConstElementPtr command = request_json->getBodyAsJson();
- if (!command) {
- std::cerr << "no command" << std::endl;
- return (0);
- }
- if (command->getType() != Element::map) {
- std::cerr << "command is not a map" << std::endl;
- return (0);
- }
-
- // Modify request.
- int extra = 0;
- ConstElementPtr extra_elem = command->get("extra");
- ElementPtr mutable_command = boost::const_pointer_cast<Element>(command);
- if (extra_elem) {
- if (extra_elem->getType() == Element::integer) {
- extra = extra_elem->intValue();
- }
- mutable_command->remove("extra");
- request_json->setBodyAsJson(command);
- }
- handle.setContext("extra", extra);
-
- // Perform authentication.
- response = impl->config_->checkAuth(*impl->creator_, request);
-
- // Set parameters.
- handle.setArgument("request", request);
- handle.setArgument("response", response);
- return (0);
-}
-
-/// @brief This callout is called at the "http_response" hook.
-///
-/// @param handle CalloutHandle.
-/// @return 0 upon success, non-zero otherwise.
-int
-http_response(CalloutHandle& handle) {
- // Sanity.
- if (!impl) {
- std::cerr << "no implementation" << std::endl;
- return (0);
- }
-
- // Get the parameters.
- HttpRequestPtr request;
- HttpResponseJsonPtr response;
- handle.getArgument("request", request);
- handle.getArgument("response", response);
-
- if (!request) {
- std::cerr << "no request" << std::endl;
- return (0);
- }
- if (!response) {
- std::cerr << "no response" << std::endl;
- return (0);
- }
-
- // Modify response.
- ConstElementPtr body = response->getBodyAsJson();
- if (!body) {
- std::cerr << "no body" << std::endl;
- return (0);
- }
- if (body->getType() != Element::list) {
- std::cerr << "body is not a list" << std::endl;
- return (0);
- }
- if (body->size() < 1) {
- std::cerr << "body is empty" << std::endl;
- return (0);
- }
- ConstElementPtr answer = body->get(0);
- if (!answer || (answer->getType() != Element::map)) {
- std::cerr << "answer is not map" << std::endl;
- return (0);
- }
- ElementPtr mutable_answer = boost::const_pointer_cast<Element>(answer);
- try {
- int extra = 0;
- handle.getContext("extra", extra);
- mutable_answer->set("got", Element::create(extra));
- } catch (const NoSuchCalloutContext&) {
- std::cerr << "can't find 'extra' context\n";
- } catch (...) {
- std::cerr << "getContext('extra') failed\n";
- }
- response->setBodyAsJson(body);
-
- // Set parameters.
- handle.setArgument("response", response);
- return (0);
-}
-
-}
-}
+++ /dev/null
-// Copyright (C) 2016-2025 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#include <config.h>
-#include <agent/ca_cfg_mgr.h>
-#include <agent/parser_context.h>
-#include <config/unix_command_config.h>
-#include <exceptions/exceptions.h>
-#include <process/testutils/d_test_stubs.h>
-#include <process/d_cfg_mgr.h>
-#include <http/basic_auth_config.h>
-#include <agent/tests/test_callout_libraries.h>
-#include <agent/tests/test_data_files_config.h>
-#include <hooks/hooks_parser.h>
-#include <util/filesystem.h>
-#include <boost/pointer_cast.hpp>
-#include <boost/scoped_ptr.hpp>
-#include <gtest/gtest.h>
-
-using namespace isc::agent;
-using namespace isc::data;
-using namespace isc::hooks;
-using namespace isc::http;
-using namespace isc::process;
-using namespace isc::config;
-using namespace isc::util;
-
-namespace {
-
-/// @brief Almost regular agent CfgMgr with internal parse method exposed.
-class NakedAgentCfgMgr : public CtrlAgentCfgMgr {
-public:
- using CtrlAgentCfgMgr::parse;
-};
-
-// Tests construction of CtrlAgentCfgMgr class.
-TEST(CtrlAgentCfgMgr, construction) {
- boost::scoped_ptr<CtrlAgentCfgMgr> cfg_mgr;
-
- // Verify that configuration manager constructions without error.
- ASSERT_NO_THROW(cfg_mgr.reset(new CtrlAgentCfgMgr()));
-
- // Verify that the context can be retrieved and is not null.
- CtrlAgentCfgContextPtr context;
- ASSERT_NO_THROW(context = cfg_mgr->getCtrlAgentCfgContext());
- EXPECT_TRUE(context);
-
- // Verify that the manager can be destructed without error.
- EXPECT_NO_THROW(cfg_mgr.reset());
-}
-
-// Tests if getContext can be retrieved.
-TEST(CtrlAgentCfgMgr, getContext) {
- CtrlAgentCfgMgr cfg_mgr;
-
- CtrlAgentCfgContextPtr ctx;
- ASSERT_NO_THROW(ctx = cfg_mgr.getCtrlAgentCfgContext());
- ASSERT_TRUE(ctx);
-}
-
-// Tests if context can store and retrieve HTTP parameters
-TEST(CtrlAgentCfgMgr, contextHttpParams) {
- CtrlAgentCfgContext ctx;
-
- // Check http parameters
- ctx.setHttpPort(12345);
- EXPECT_EQ(12345, ctx.getHttpPort());
-
- ctx.setHttpHost("alnitak");
- EXPECT_EQ("alnitak", ctx.getHttpHost());
-}
-
-// Tests if context can store and retrieve TLS parameters.
-TEST(CtrlAgentCfgMgr, contextTlsParams) {
- CtrlAgentCfgContext ctx;
-
- // Check TLS parameters
- ctx.setTrustAnchor("my-ca");
- EXPECT_EQ("my-ca", ctx.getTrustAnchor());
-
- ctx.setCertFile("my-cert");
- EXPECT_EQ("my-cert", ctx.getCertFile());
-
- ctx.setKeyFile("my-key");
- EXPECT_EQ("my-key", ctx.getKeyFile());
-
- EXPECT_TRUE(ctx.getCertRequired());
- ctx.setCertRequired(false);
- EXPECT_FALSE(ctx.getCertRequired());
-}
-
-// Tests if context can store and retrieve control socket information.
-TEST(CtrlAgentCfgMgr, contextSocketInfo) {
-
- CtrlAgentCfgContext ctx;
-
- // Check control socket parameters
- // By default, there are no control sockets stored.
- EXPECT_FALSE(ctx.getControlSocketInfo("d2"));
- EXPECT_FALSE(ctx.getControlSocketInfo("dhcp4"));
- EXPECT_FALSE(ctx.getControlSocketInfo("dhcp6"));
-
- ConstElementPtr socket1 = Element::fromJSON("{ \"socket-type\": \"unix\",\n"
- " \"socket-name\": \"socket1\" }");
- ConstElementPtr socket2 = Element::fromJSON("{ \"socket-type\": \"unix\",\n"
- " \"socket-name\": \"socket2\" }");
- ConstElementPtr socket3 = Element::fromJSON("{ \"socket-type\": \"unix\",\n"
- " \"socket-name\": \"socket3\" }");
- // Ok, now set the control socket for D2
- EXPECT_NO_THROW(ctx.setControlSocketInfo(socket1, "d2"));
-
- // Now check the values returned
- EXPECT_EQ(socket1, ctx.getControlSocketInfo("d2"));
- EXPECT_FALSE(ctx.getControlSocketInfo("dhcp4"));
- EXPECT_FALSE(ctx.getControlSocketInfo("dhcp6"));
-
- // Now set the v6 socket and sanity check again
- EXPECT_NO_THROW(ctx.setControlSocketInfo(socket2, "dhcp6"));
-
- // Should be possible to retrieve two sockets.
- EXPECT_EQ(socket1, ctx.getControlSocketInfo("d2"));
- EXPECT_EQ(socket2, ctx.getControlSocketInfo("dhcp6"));
- EXPECT_FALSE(ctx.getControlSocketInfo("dhcp4"));
-
- // Finally, set the third control socket.
- EXPECT_NO_THROW(ctx.setControlSocketInfo(socket3, "dhcp4"));
- EXPECT_EQ(socket1, ctx.getControlSocketInfo("d2"));
- EXPECT_EQ(socket2, ctx.getControlSocketInfo("dhcp6"));
- EXPECT_EQ(socket3, ctx.getControlSocketInfo("dhcp4"));
-}
-
-// Tests if copied context retains all parameters.
-TEST(CtrlAgentCfgMgr, contextSocketInfoCopy) {
-
- CtrlAgentCfgContext ctx;
-
- ConstElementPtr socket1 = Element::fromJSON("{ \"socket-type\": \"unix\",\n"
- " \"socket-name\": \"socket1\" }");
- ConstElementPtr socket2 = Element::fromJSON("{ \"socket-type\": \"unix\",\n"
- " \"socket-name\": \"socket2\" }");
- ConstElementPtr socket3 = Element::fromJSON("{ \"socket-type\": \"unix\",\n"
- " \"socket-name\": \"socket3\" }");
- // Ok, now set the control sockets
- EXPECT_NO_THROW(ctx.setControlSocketInfo(socket1, "d2"));
- EXPECT_NO_THROW(ctx.setControlSocketInfo(socket2, "dhcp4"));
- EXPECT_NO_THROW(ctx.setControlSocketInfo(socket3, "dhcp6"));
-
- EXPECT_NO_THROW(ctx.setHttpPort(12345));
- EXPECT_NO_THROW(ctx.setHttpHost("bellatrix"));
-
- HooksConfig& libs = ctx.getHooksConfig();
- string exp_name("testlib1.so");
- ConstElementPtr exp_param(new StringElement("myparam"));
- libs.add(exp_name, exp_param);
-
- BasicHttpAuthConfigPtr auth(new BasicHttpAuthConfig());
- auth->setRealm("foobar");
- auth->add("foo", "", "bar", "");
- EXPECT_NO_THROW(ctx.setAuthConfig(auth));
-
- // Make a copy.
- ConfigPtr copy_base(ctx.clone());
- CtrlAgentCfgContextPtr copy = boost::dynamic_pointer_cast<CtrlAgentCfgContext>(copy_base);
- ASSERT_TRUE(copy);
-
- // Now check the values returned
- EXPECT_EQ(12345, copy->getHttpPort());
- EXPECT_EQ("bellatrix", copy->getHttpHost());
-
- // Check socket info
- ASSERT_TRUE(copy->getControlSocketInfo("d2"));
- ASSERT_TRUE(copy->getControlSocketInfo("dhcp4"));
- ASSERT_TRUE(copy->getControlSocketInfo("dhcp6"));
- EXPECT_EQ(socket1->str(), copy->getControlSocketInfo("d2")->str());
- EXPECT_EQ(socket2->str(), copy->getControlSocketInfo("dhcp4")->str());
- EXPECT_EQ(socket3->str(), copy->getControlSocketInfo("dhcp6")->str());
-
- // Check hook libs
- const HookLibsCollection& libs2 = copy->getHooksConfig().get();
- ASSERT_EQ(1, libs2.size());
- EXPECT_EQ(exp_name, libs2[0].libname_);
- ASSERT_TRUE(libs2[0].parameters_);
- EXPECT_EQ(exp_param->str(), libs2[0].parameters_->str());
-
- // Check authentication
- const HttpAuthConfigPtr& auth2 = copy->getAuthConfig();
- ASSERT_TRUE(auth2);
- EXPECT_EQ(auth->toElement()->str(), auth2->toElement()->str());
-}
-
-
-// Tests if the context can store and retrieve hook libs information.
-TEST(CtrlAgentCfgMgr, contextHookParams) {
- CtrlAgentCfgContext ctx;
-
- // By default there should be no hooks.
- HooksConfig& libs = ctx.getHooksConfig();
- EXPECT_TRUE(libs.get().empty());
-
- libs.add("libone.so", ConstElementPtr());
- libs.add("libtwo.so", Element::fromJSON("{\"foo\": true}"));
- libs.add("libthree.so", Element::fromJSON("{\"bar\": 42}"));
-
- const HooksConfig& stored_libs = ctx.getHooksConfig();
- EXPECT_EQ(3, stored_libs.get().size());
-
- // @todo add a == operator to HooksConfig
- EXPECT_EQ(libs.get(), stored_libs.get());
-}
-
-// Test if the context can store and retrieve basic HTTP authentication
-// configuration.
-TEST(CtrlAgentCfgMgr, contextAuthConfig) {
- CtrlAgentCfgContext ctx;
-
- // By default there should be no authentication.
- EXPECT_FALSE(ctx.getAuthConfig());
- BasicHttpAuthConfigPtr auth(new BasicHttpAuthConfig());
- EXPECT_NO_THROW(ctx.setAuthConfig(auth));
-
- auth->setRealm("foobar");
- auth->add("foo", "", "bar", "");
- auth->add("test", "", "123\xa3", "");
-
- const HttpAuthConfigPtr& stored_auth = ctx.getAuthConfig();
- ASSERT_TRUE(stored_auth);
- EXPECT_FALSE(stored_auth->empty());
- EXPECT_EQ(auth->toElement()->str(), stored_auth->toElement()->str());
-}
-
-// Test if the context can store and retrieve basic HTTP authentication
-// configuration using files.
-TEST(CtrlAgentCfgMgr, contextAuthConfigFile) {
- CtrlAgentCfgContext ctx;
-
- // By default there should be no authentication.
- EXPECT_FALSE(ctx.getAuthConfig());
- BasicHttpAuthConfigPtr auth(new BasicHttpAuthConfig());
- EXPECT_NO_THROW(ctx.setAuthConfig(auth));
-
- auth->setRealm("foobar");
- auth->setDirectory("/tmp");
- auth->add("", "foo", "", "bar");
- auth->add("", "test", "", "pwd");
-
- const HttpAuthConfigPtr& stored_auth = ctx.getAuthConfig();
- ASSERT_TRUE(stored_auth);
- EXPECT_FALSE(stored_auth->empty());
- EXPECT_EQ(auth->toElement()->str(), stored_auth->toElement()->str());
-}
-
-/// Control Agent configurations used in tests.
-const char* AGENT_CONFIGS[] = {
-
- // configuration 0: empty (nothing specified)
- "{ }",
-
- // Configuration 1: http parameters only (no control sockets, not hooks)
- "{ \"http-host\": \"betelgeuse\",\n"
- " \"http-port\": 8001\n"
- "}",
-
- // Configuration 2: http and 1 socket
- "{\n"
- " \"http-host\": \"betelgeuse\",\n"
- " \"http-port\": 8001,\n"
- " \"control-sockets\": {\n"
- " \"dhcp4\": {\n"
- " \"socket-name\": \"socket-v4\"\n"
- " }\n"
- " }\n"
- "}",
-
- // Configuration 3: http and all 3 sockets
- "{\n"
- " \"http-host\": \"betelgeuse\",\n"
- " \"http-port\": 8001,\n"
- " \"control-sockets\": {\n"
- " \"dhcp4\": {\n"
- " \"socket-name\": \"socket-v4\"\n"
- " },\n"
- " \"dhcp6\": {\n"
- " \"socket-name\": \"socket-v6\"\n"
- " },\n"
- " \"d2\": {\n"
- " \"socket-name\": \"socket-d2\"\n"
- " }\n"
- " }\n"
- "}",
-
- // Configuration 4: http, 1 socket and hooks
- // CA is able to load hook libraries that augment its operation.
- // The primary functionality is the ability to add new commands.
- "{\n"
- " \"http-host\": \"betelgeuse\",\n"
- " \"http-port\": 8001,\n"
- " \"control-sockets\": {\n"
- " \"dhcp4\": {\n"
- " \"socket-name\": \"socket-v4\"\n"
- " }\n"
- " },\n"
- " \"hooks-libraries\": ["
- " {"
- " \"library\": \"%LIBRARY%\","
- " \"parameters\": {\n"
- " \"param1\": \"foo\"\n"
- " }\n"
- " }\n"
- " ]\n"
- "}",
-
- // Configuration 5: http and 1 socket (d2 only)
- "{\n"
- " \"http-host\": \"betelgeuse\",\n"
- " \"http-port\": 8001,\n"
- " \"control-sockets\": {\n"
- " \"d2\": {\n"
- " \"socket-name\": \"socket-d2\"\n"
- " }\n"
- " }\n"
- "}",
-
- // Configuration 6: http and 1 socket (dhcp6 only)
- "{\n"
- " \"http-host\": \"betelgeuse\",\n"
- " \"http-port\": 8001,\n"
- " \"control-sockets\": {\n"
- " \"dhcp6\": {\n"
- " \"socket-name\": \"socket-v6\"\n"
- " }\n"
- " }\n"
- "}",
-
- // Configuration 7: http, 1 socket and authentication
- "{\n"
- " \"http-host\": \"betelgeuse\",\n"
- " \"http-port\": 8001,\n"
- " \"authentication\": {\n"
- " \"type\": \"basic\",\n"
- " \"realm\": \"foobar\",\n"
- " \"clients\": ["
- " {"
- " \"user\": \"foo\",\n"
- " \"password\": \"bar\"\n"
- " },{\n"
- " \"user\": \"test\",\n"
- " \"password\": \"123\\u00a3\"\n"
- " }\n"
- " ]\n"
- " },\n"
- " \"control-sockets\": {\n"
- " \"dhcp4\": {\n"
- " \"socket-name\": \"socket-v4\"\n"
- " }\n"
- " }\n"
- "}",
-
- // Configuration 8: http and 2 sockets with user contexts and comments
- "{\n"
- " \"user-context\": { \"comment\": \"Indirect comment\" },\n"
- " \"http-host\": \"betelgeuse\",\n"
- " \"http-port\": 8001,\n"
- " \"http-headers\": [ {\n"
- " \"comment\": \"HSTS header\",\n"
- " \"name\": \"Strict-Transport-Security\",\n"
- " \"value\": \"max-age=31536000\"\n"
- " } ],\n"
- " \"authentication\": {\n"
- " \"comment\": \"basic HTTP authentication\",\n"
- " \"type\": \"basic\",\n"
- " \"realm\": \"foobar\",\n"
- " \"clients\": ["
- " {"
- " \"comment\": \"foo is authorized\",\n"
- " \"user\": \"foo\",\n"
- " \"password\": \"bar\"\n"
- " },{\n"
- " \"user\": \"test\",\n"
- " \"user-context\": { \"no password\": true }\n"
- " }\n"
- " ]\n"
- " },\n"
- " \"control-sockets\": {\n"
- " \"dhcp4\": {\n"
- " \"comment\": \"dhcp4 socket\",\n"
- " \"socket-name\": \"socket-v4\"\n"
- " },\n"
- " \"dhcp6\": {\n"
- " \"socket-name\": \"socket-v6\",\n"
- " \"user-context\": { \"version\": 1 }\n"
- " }\n"
- " }\n"
- "}",
-
- // Configuration 9: https aka http over TLS
- "{\n"
- " \"http-host\": \"betelgeuse\",\n"
- " \"http-port\": 8001,\n"
- " \"trust-anchor\": \"my-ca\",\n"
- " \"cert-file\": \"my-cert\",\n"
- " \"key-file\": \"my-key\",\n"
- " \"cert-required\": false\n"
- "}",
-
- // Configuration 10: http, 1 socket and authentication using files
- "{\n"
- " \"http-host\": \"betelgeuse\",\n"
- " \"http-port\": 8001,\n"
- " \"authentication\": {\n"
- " \"type\": \"basic\",\n"
- " \"realm\": \"foobar\",\n"
- " \"directory\": \"" CA_TEST_DATA_DIR "\",\n"
- " \"clients\": ["
- " {"
- " \"user-file\": \"hiddenu\",\n"
- " \"password-file\": \"hiddenp\"\n"
- " },{\n"
- " \"password-file\": \"hiddens\"\n"
- " }\n"
- " ]\n"
- " },\n"
- " \"control-sockets\": {\n"
- " \"dhcp4\": {\n"
- " \"socket-name\": \"socket-v4\"\n"
- " }\n"
- " }\n"
- "}"
-};
-
-/// @brief Class used for testing CfgMgr
-class AgentParserTest : public isc::process::ConfigParseTest {
-public:
- virtual void SetUp() {
- resetHooksPath();
- setSocketTestPath();
- file::PathChecker::enableEnforcement(false);
- }
-
- virtual void TearDown() {
- resetHooksPath();
- resetSocketPath();
- file::PathChecker::enableEnforcement(true);
- }
-
- /// @brief Sets the Hooks path from which hooks can be loaded.
- /// @param explicit_path path to use as the hooks path.
- void setHooksTestPath(const std::string explicit_path = "") {
- HooksLibrariesParser::getHooksPath(true,
- (!explicit_path.empty() ?
- explicit_path : CA_HOOKS_TEST_PATH));
- }
-
- /// @brief Resets the hooks path to DEFAULT_HOOKS_PATH.
- void resetHooksPath() {
- HooksLibrariesParser::getHooksPath(true);
- }
-
- /// @brief Sets the path in which the socket can be created.
- /// @param explicit_path path to use as the socket path.
- void setSocketTestPath(const std::string explicit_path = "") {
- auto path = UnixCommandConfig::getSocketPath(true, (!explicit_path.empty() ?
- explicit_path : TEST_DATA_BUILDDIR));
- UnixCommandConfig::setSocketPathPerms(file::getPermissions(path));
- }
-
- /// @brief Resets the socket path to the default.
- void resetSocketPath() {
- UnixCommandConfig::getSocketPath(true);
- UnixCommandConfig::setSocketPathPerms();
- }
-
- /// @brief Tries to load input text as a configuration
- ///
- /// @param config text containing input configuration
- /// @param expected_answer expected result of configuration (0 = success)
- void configParse(const char* config, int expected_answer) {
- isc::agent::ParserContext parser;
- ConstElementPtr json = parser.parseString(config, ParserContext::PARSER_SUB_AGENT);
-
- EXPECT_NO_THROW(answer_ = cfg_mgr_.parse(json, false));
- EXPECT_TRUE(checkAnswer(expected_answer));
- }
-
- /// @brief Replaces %LIBRARY% with specified library name
- ///
- /// @param config input config text (should contain "%LIBRARY%" string)
- /// @param lib_name %LIBRARY% will be replaced with that name
- /// @return configuration text with library name replaced
- std::string pathReplacer(const char* config, const char* lib_name) {
- string txt(config);
- txt.replace(txt.find("%LIBRARY%"), strlen("%LIBRARY%"), string(lib_name));
- return (txt);
- }
-
- /// @brief Make expected contents of socket info with socket path added.
- ///
- /// @param name name of the socket
- /// @return expected string
- std::string makeSocketStr(const std::string& name) {
- std::ostringstream os;
- os << "{ \"socket-name\": \""
- << name << "\", \"socket-type\": \"unix\","
- << " \"validated-socket-name\": \""
- << UnixCommandConfig::getSocketPath() << "/" << name
- << "\" }";
- return (os.str());
- }
-
- /// Configuration Manager (used in tests)
- NakedAgentCfgMgr cfg_mgr_;
-};
-
-// This test verifies if an empty config is handled properly. In practice such
-// a config makes little sense, but perhaps it's ok for a default deployment.
-// Sadly, our bison parser requires at last one parameter to be present.
-// Until we determine whether we want the empty config to be allowed or not,
-// this test remains disabled.
-TEST_F(AgentParserTest, DISABLED_configParseEmpty) {
- configParse(AGENT_CONFIGS[0], 0);
-}
-
-// This test checks if a config with only HTTP parameters is parsed properly.
-TEST_F(AgentParserTest, configParseHttpOnly) {
- configParse(AGENT_CONFIGS[1], 0);
-
- CtrlAgentCfgContextPtr ctx = cfg_mgr_.getCtrlAgentCfgContext();
- ASSERT_TRUE(ctx);
- EXPECT_EQ("betelgeuse", ctx->getHttpHost());
- EXPECT_EQ(8001, ctx->getHttpPort());
-}
-
-// Tests if a single socket can be configured. BTW this test also checks
-// if default value for socket-type is specified (the config doesn't have it,
-// so the default value should be filed in).
-TEST_F(AgentParserTest, configParseSocketDhcp4) {
- configParse(AGENT_CONFIGS[2], 0);
-
- CtrlAgentCfgContextPtr ctx = cfg_mgr_.getCtrlAgentCfgContext();
- ASSERT_TRUE(ctx);
- ConstElementPtr socket = ctx->getControlSocketInfo("dhcp4");
- ASSERT_TRUE(socket);
- EXPECT_EQ(makeSocketStr("socket-v4"), socket->str());
- EXPECT_FALSE(ctx->getControlSocketInfo("dhcp6"));
- EXPECT_FALSE(ctx->getControlSocketInfo("d2"));
-}
-
-// Tests if a single socket can be configured. BTW this test also checks
-// if default value for socket-type is specified (the config doesn't have it,
-// so the default value should be filed in).
-TEST_F(AgentParserTest, configParseSocketD2) {
- configParse(AGENT_CONFIGS[5], 0);
-
- CtrlAgentCfgContextPtr ctx = cfg_mgr_.getCtrlAgentCfgContext();
- ASSERT_TRUE(ctx);
- ConstElementPtr socket = ctx->getControlSocketInfo("d2");
- ASSERT_TRUE(socket);
- EXPECT_EQ(makeSocketStr("socket-d2"), socket->str());
- EXPECT_FALSE(ctx->getControlSocketInfo("dhcp4"));
- EXPECT_FALSE(ctx->getControlSocketInfo("dhcp6"));
-}
-
-// Tests if a single socket can be configured. BTW this test also checks
-// if default value for socket-type is specified (the config doesn't have it,
-// so the default value should be filed in).
-TEST_F(AgentParserTest, configParseSocketDhcp6) {
- configParse(AGENT_CONFIGS[6], 0);
-
- CtrlAgentCfgContextPtr ctx = cfg_mgr_.getCtrlAgentCfgContext();
- ASSERT_TRUE(ctx);
- ConstElementPtr socket = ctx->getControlSocketInfo("dhcp6");
- ASSERT_TRUE(socket);
- EXPECT_EQ(makeSocketStr("socket-v6"), socket->str());
- EXPECT_FALSE(ctx->getControlSocketInfo("dhcp4"));
- EXPECT_FALSE(ctx->getControlSocketInfo("d2"));
-}
-
-// This tests if all 3 sockets can be configured and makes sure the parser
-// doesn't confuse them.
-TEST_F(AgentParserTest, configParse3Sockets) {
- configParse(AGENT_CONFIGS[3], 0);
- CtrlAgentCfgContextPtr ctx = cfg_mgr_.getCtrlAgentCfgContext();
- ASSERT_TRUE(ctx);
- ConstElementPtr socket2 = ctx->getControlSocketInfo("d2");
- ConstElementPtr socket4 = ctx->getControlSocketInfo("dhcp4");
- ConstElementPtr socket6 = ctx->getControlSocketInfo("dhcp6");
- ASSERT_TRUE(socket2);
- EXPECT_EQ(makeSocketStr("socket-d2"), socket2->str());
- ASSERT_TRUE(socket4);
- EXPECT_EQ(makeSocketStr("socket-v4"), socket4->str());
- ASSERT_TRUE(socket6);
- EXPECT_EQ(makeSocketStr("socket-v6"), socket6->str());
-}
-
-// This test checks that the config file with hook library specified can be
-// loaded. This one is a bit tricky, because the parser sanity checks the lib
-// name. In particular, it checks if such a library exists. Therefore we
-// can't use AGENT_CONFIGS[4] as is, but need to run it through path replacer.
-TEST_F(AgentParserTest, configParseHooks) {
- setHooksTestPath();
-
- // Create the configuration with proper lib path.
- std::string cfg = pathReplacer(AGENT_CONFIGS[4], CALLOUT_LIBRARY);
- // The configuration should be successful.
- configParse(cfg.c_str(), 0);
-
- // The context now should have the library specified.
- CtrlAgentCfgContextPtr ctx = cfg_mgr_.getCtrlAgentCfgContext();
- const HookLibsCollection libs = ctx->getHooksConfig().get();
- ASSERT_EQ(1, libs.size());
- EXPECT_EQ(string(CALLOUT_LIBRARY), libs[0].libname_);
- ASSERT_TRUE(libs[0].parameters_);
- EXPECT_EQ("{ \"param1\": \"foo\" }", libs[0].parameters_->str());
-}
-
-// This test checks that the config file with basic HTTP authentication can be
-// loaded.
-TEST_F(AgentParserTest, configParseAuth) {
- configParse(AGENT_CONFIGS[7], 0);
- CtrlAgentCfgContextPtr ctx = cfg_mgr_.getCtrlAgentCfgContext();
- const HttpAuthConfigPtr& auth = ctx->getAuthConfig();
- ASSERT_TRUE(auth);
- const BasicHttpAuthConfigPtr& basic_auth =
- boost::dynamic_pointer_cast<BasicHttpAuthConfig>(auth);
- ASSERT_TRUE(basic_auth);
-
- // Check realm
- EXPECT_EQ("foobar", basic_auth->getRealm());
-
- // Check credentials
- auto credentials = basic_auth->getCredentialMap();
- EXPECT_EQ(2, credentials.size());
- std::string user;
- EXPECT_NO_THROW(user = credentials.at("Zm9vOmJhcg=="));
- EXPECT_EQ("foo", user);
- EXPECT_NO_THROW(user = credentials.at("dGVzdDoxMjPCow=="));
- EXPECT_EQ("test", user);
-
- // Check clients.
- BasicHttpAuthConfig expected;
- expected.setRealm("foobar");
- expected.add("foo", "", "bar", "");
- expected.add("test", "", "123\xa3", "");
- EXPECT_EQ(expected.toElement()->str(), basic_auth->toElement()->str());
-}
-
-// This test checks comments.
-TEST_F(AgentParserTest, comments) {
- configParse(AGENT_CONFIGS[8], 0);
- CtrlAgentCfgContextPtr agent_ctx = cfg_mgr_.getCtrlAgentCfgContext();
- ASSERT_TRUE(agent_ctx);
-
- // Check global user context.
- ConstElementPtr ctx = agent_ctx->getContext();
- ASSERT_TRUE(ctx);
- ASSERT_EQ(1, ctx->size());
- ASSERT_TRUE(ctx->get("comment"));
- EXPECT_EQ("\"Indirect comment\"", ctx->get("comment")->str());
-
- // There is a DHCP4 control socket.
- ConstElementPtr socket4 = agent_ctx->getControlSocketInfo("dhcp4");
- ASSERT_TRUE(socket4);
-
- // Check DHCP4 control socket user context.
- ConstElementPtr ctx4 = socket4->get("user-context");
- ASSERT_TRUE(ctx4);
- ASSERT_EQ(1, ctx4->size());
- ASSERT_TRUE(ctx4->get("comment"));
- EXPECT_EQ("\"dhcp4 socket\"", ctx4->get("comment")->str());
-
- // There is a DHCP6 control socket.
- ConstElementPtr socket6 = agent_ctx->getControlSocketInfo("dhcp6");
- ASSERT_TRUE(socket6);
-
- // Check DHCP6 control socket user context.
- ConstElementPtr ctx6 = socket6->get("user-context");
- ASSERT_TRUE(ctx6);
- ASSERT_EQ(1, ctx6->size());
- ASSERT_TRUE(ctx6->get("version"));
- EXPECT_EQ("1", ctx6->get("version")->str());
-
- // Check HTTP header comment.
- const CfgHttpHeaders& headers = agent_ctx->getHttpHeaders();
- ASSERT_EQ(1, headers.size());
- ConstElementPtr ctx7 = headers[0].getContext();
- ASSERT_TRUE(ctx7);
- ASSERT_EQ(1, ctx7->size());
- ASSERT_TRUE(ctx7->get("comment"));
- EXPECT_EQ("\"HSTS header\"", ctx7->get("comment")->str());
-
- // Check authentication comment.
- const HttpAuthConfigPtr& auth = agent_ctx->getAuthConfig();
- ASSERT_TRUE(auth);
- ConstElementPtr ctx8 = auth->getContext();
- ASSERT_TRUE(ctx8);
- ASSERT_EQ(1, ctx8->size());
- ASSERT_TRUE(ctx8->get("comment"));
- EXPECT_EQ("\"basic HTTP authentication\"", ctx8->get("comment")->str());
-
- // Check basic HTTP authentication client comment.
- const BasicHttpAuthConfigPtr& basic_auth =
- boost::dynamic_pointer_cast<BasicHttpAuthConfig>(auth);
- ASSERT_TRUE(basic_auth);
- auto clients = basic_auth->getClientList();
- ASSERT_EQ(2, clients.size());
- ConstElementPtr ctx9 = clients.front().getContext();
- ASSERT_TRUE(ctx9);
- ASSERT_EQ(1, ctx9->size());
- ASSERT_TRUE(ctx9->get("comment"));
- EXPECT_EQ("\"foo is authorized\"", ctx9->get("comment")->str());
-
- // Check basic HTTP authentication client user context.
- ConstElementPtr ctx10 = clients.back().getContext();
- ASSERT_TRUE(ctx10);
- ASSERT_EQ(1, ctx10->size());
- ASSERT_TRUE(ctx10->get("no password"));
- EXPECT_EQ("true", ctx10->get("no password")->str());
-}
-
-// This test checks if a config with TLS parameters is parsed properly.
-TEST_F(AgentParserTest, configParseTls) {
- configParse(AGENT_CONFIGS[9], 0);
-
- CtrlAgentCfgContextPtr ctx = cfg_mgr_.getCtrlAgentCfgContext();
- ASSERT_TRUE(ctx);
- EXPECT_EQ("my-ca", ctx->getTrustAnchor());
- EXPECT_EQ("my-cert", ctx->getCertFile());
- EXPECT_EQ("my-key", ctx->getKeyFile());
- EXPECT_FALSE(ctx->getCertRequired());
-}
-
-// This test checks that the config file with basic HTTP authentication
-// using files can be loaded.
-TEST_F(AgentParserTest, configParseAuthFile) {
- configParse(AGENT_CONFIGS[10], 0);
- CtrlAgentCfgContextPtr ctx = cfg_mgr_.getCtrlAgentCfgContext();
- const HttpAuthConfigPtr& auth = ctx->getAuthConfig();
- ASSERT_TRUE(auth);
- const BasicHttpAuthConfigPtr& basic_auth =
- boost::dynamic_pointer_cast<BasicHttpAuthConfig>(auth);
- ASSERT_TRUE(basic_auth);
-
- // Check realm
- EXPECT_EQ("foobar", basic_auth->getRealm());
-
- // Check directory
- EXPECT_EQ(std::string(CA_TEST_DATA_DIR), basic_auth->getDirectory());
-
- // Check credentials
- auto credentials = basic_auth->getCredentialMap();
- EXPECT_EQ(2, credentials.size());
- std::string user;
- EXPECT_NO_THROW(user = credentials.at("a2VhdGVzdDpLZWFUZXN0"));
- EXPECT_EQ("keatest", user);
- EXPECT_NO_THROW(user = credentials.at("a2VhOnRlc3Q="));
- EXPECT_EQ("kea", user);
-
- // Check clients.
- BasicHttpAuthConfig expected;
- expected.setRealm("foobar");
- expected.setDirectory(std::string(CA_TEST_DATA_DIR));
- expected.add("", "hiddenu", "", "hiddenp");
- expected.add("", "", "", "hiddens", true);
- EXPECT_EQ(expected.toElement()->str(), basic_auth->toElement()->str());
-}
-
-} // end of anonymous namespace
+++ /dev/null
-// Copyright (C) 2017-2025 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#include <config.h>
-
-#include <agent/ca_cfg_mgr.h>
-#include <agent/ca_command_mgr.h>
-#include <agent/ca_controller.h>
-#include <agent/ca_process.h>
-#include <asiolink/asio_wrapper.h>
-#include <asiolink/interval_timer.h>
-#include <asiolink/io_service.h>
-#include <asiolink/testutils/test_server_unix_socket.h>
-#include <cc/command_interpreter.h>
-#include <cc/data.h>
-#include <config/testutils/socket_path.h>
-#include <config/unix_command_config.h>
-#include <process/testutils/d_test_stubs.h>
-#include <testutils/gtest_utils.h>
-#include <util/filesystem.h>
-
-#include <cstdlib>
-#include <functional>
-#include <thread>
-#include <vector>
-
-#include <boost/pointer_cast.hpp>
-
-#include <gtest/gtest.h>
-
-using namespace isc::agent;
-using namespace isc::asiolink;
-using namespace isc::asiolink::test;
-using namespace isc::config::test;
-using namespace isc::data;
-using namespace isc::process;
-using namespace isc::config;
-using namespace isc::util;
-
-namespace {
-
-/// @brief Test timeout in ms.
-const long TEST_TIMEOUT = 10000;
-
-/// @brief Test fixture class for @ref CtrlAgentCommandMgr.
-///
-/// @todo Add tests for various commands, including the cases when the
-/// commands are forwarded to other servers via unix sockets.
-/// Meanwhile, this is just a placeholder for the tests.
-class CtrlAgentCommandMgrTest : public DControllerTest {
-public:
- /// @brief Constructor.
- ///
- /// Deregisters all commands except 'list-commands'.
- CtrlAgentCommandMgrTest()
- : DControllerTest(CtrlAgentController::instance),
- mgr_(CtrlAgentCommandMgr::instance()),
- skipped_(false) {
- mgr_.deregisterAll();
- setSocketTestPath();
- SocketPath::removeUnixSocketFile();
- initProcess();
- }
-
- /// @brief Destructor.
- ///
- /// Deregisters all commands except 'list-commands'.
- virtual ~CtrlAgentCommandMgrTest() {
- mgr_.deregisterAll();
- SocketPath::removeUnixSocketFile();
- resetSocketPath();
- }
-
- /// @brief Verifies received answer
- ///
- /// @todo Add better checks for failure cases and for
- /// verification of the response parameters.
- ///
- /// @param answer answer to be verified
- /// @param expected_code0 code expected to be returned in first result within
- /// the answer.
- /// @param expected_code1 code expected to be returned in second result within
- /// the answer.
- /// @param expected_code2 code expected to be returned in third result within
- /// the answer.
- void checkAnswer(const ConstElementPtr& answer, const int expected_code0 = 0,
- const int expected_code1 = -1, const int expected_code2 = -1) {
- std::vector<int> expected_codes;
- if (expected_code0 >= 0) {
- expected_codes.push_back(expected_code0);
- }
-
- if (expected_code1 >= 0) {
- expected_codes.push_back(expected_code1);
- }
-
- if (expected_code2 >= 0) {
- expected_codes.push_back(expected_code2);
- }
-
- int status_code;
- // There may be multiple answers returned within a list.
- std::vector<ElementPtr> answer_list = answer->listValue();
-
- ASSERT_EQ(expected_codes.size(), answer_list.size());
- size_t count = 0;
- // Check all answers.
- for (auto const& ans : answer_list) {
- ConstElementPtr text;
- ASSERT_NO_THROW(text = isc::config::parseAnswer(status_code, ans));
- EXPECT_EQ(expected_codes[count], status_code)
- << "answer contains text: " << text->stringValue();
- count++;
- }
- }
-
- /// @brief Sets the path in which the socket can be created.
- /// @param explicit_path path to use as the socket path.
- void setSocketTestPath(const std::string explicit_path = "") {
- auto path = UnixCommandConfig::getSocketPath(true, (!explicit_path.empty() ?
- explicit_path : TEST_DATA_BUILDDIR));
- UnixCommandConfig::setSocketPathPerms(file::getPermissions(path));
- }
-
- /// @brief Resets the socket path to the default.
- void resetSocketPath() {
- UnixCommandConfig::getSocketPath(true);
- UnixCommandConfig::setSocketPathPerms();
- }
-
- /// @brief Returns pointer to CtrlAgentProcess instance.
- CtrlAgentProcessPtr getCtrlAgentProcess() {
- return (boost::dynamic_pointer_cast<CtrlAgentProcess>(getProcess()));
- }
-
- /// @brief Returns pointer to CtrlAgentCfgMgr instance for a process.
- CtrlAgentCfgMgrPtr getCtrlAgentCfgMgr() {
- CtrlAgentCfgMgrPtr p;
- if (getCtrlAgentProcess()) {
- p = getCtrlAgentProcess()->getCtrlAgentCfgMgr();
- }
- return (p);
- }
-
- /// @brief Returns a pointer to the configuration context.
- CtrlAgentCfgContextPtr getCtrlAgentCfgContext() {
- CtrlAgentCfgContextPtr p;
- if (getCtrlAgentCfgMgr()) {
- p = getCtrlAgentCfgMgr()->getCtrlAgentCfgContext();
- }
- return (p);
- }
-
- /// @brief Adds configuration of the control socket.
- ///
- /// @param service Service for which socket configuration is to be added.
- void
- configureControlSocket(const std::string& service) {
- CtrlAgentCfgContextPtr ctx = getCtrlAgentCfgContext();
- ASSERT_TRUE(ctx);
-
- ElementPtr control_socket = Element::createMap();
- std::string const socket_path(SocketPath::unixSocketFilePath());
- control_socket->set("validated-socket-name", Element::create(socket_path));
- ctx->setControlSocketInfo(control_socket, service);
-
- bool const too_long(SocketPath::isTooLong(socket_path));
- if (too_long) {
- skipped_ = true;
- SKIP_IF("Socket name too long.");
- }
- }
-
- /// @brief Create and bind server side socket.
- ///
- /// @param response Stub response to be sent from the server socket to the
- /// client.
- /// @param use_thread Indicates if the IO service will be ran in thread.
- void bindServerSocket(const std::string& response,
- const bool use_thread = false) {
- server_socket_.reset(new TestServerUnixSocket(getIOService(),
- SocketPath::unixSocketFilePath(),
- response));
- server_socket_->startTimer(TEST_TIMEOUT);
- server_socket_->bindServerSocket(use_thread);
- }
-
- /// @brief Creates command with no arguments.
- ///
- /// @param command_name Command name.
- /// @param service Service value to be added to the command. This value is
- /// specified as a list of comma separated values, e.g. "dhcp4, dhcp6".
- ///
- /// @return Pointer to the instance of the created command.
- ConstElementPtr createCommand(const std::string& command_name,
- const std::string& service) {
- ElementPtr command = Element::createMap();
- command->set("command", Element::create(command_name));
-
- // Only add the 'service' parameter if non-empty.
- if (!service.empty()) {
- std::string s = boost::replace_all_copy(service, ",", "\",\"");
- s = std::string("[ \"") + s + std::string("\" ]");
- command->set("service", Element::fromJSON(s));
- }
-
- command->set("arguments", Element::createMap());
-
- return (command);
- }
-
- /// @brief Test forwarding the command.
- ///
- /// @param server_type Server for which the client socket should be
- /// configured.
- /// @param service Service to be included in the command.
- /// @param expected_result0 Expected first result in response from the server.
- /// @param expected_result1 Expected second result in response from the server.
- /// @param expected_result2 Expected third result in response from the server.
- /// server socket after which the IO service should be stopped.
- /// @param expected_responses Number of responses after which the test finishes.
- /// @param server_response Stub response to be sent by the server.
- void testForward(const std::string& configured_service,
- const std::string& service,
- const int expected_result0,
- const int expected_result1 = -1,
- const int expected_result2 = -1,
- const size_t expected_responses = 1,
- const std::string& server_response = "{ \"result\": 0 }") {
- // Configure client side socket.
- configureControlSocket(configured_service);
- SKIP_IF(skipped_);
- // Create server side socket.
- bindServerSocket(server_response, true);
-
- // The client side communication is synchronous. To be able to respond
- // to this we need to run the server side socket at the same time as the
- // client. Running IO service in a thread guarantees that the server
- //responds as soon as it receives the control command.
- std::thread th(std::bind(&IOService::run, getIOService().get()));
-
-
- // Wait for the IO service in thread to actually run.
- server_socket_->waitForRunning();
-
- ConstElementPtr command = createCommand("foo", service);
- ConstElementPtr answer = mgr_.processCommand(command);
-
- // Stop IO service immediately and let the thread die.
- getIOService()->stop();
-
- // Wait for the thread to finish.
- th.join();
-
- // Cancel all asynchronous operations on the server.
- server_socket_->stopServer();
-
- // We have some cancelled operations for which we need to invoke the
- // handlers with the operation_aborted error code.
- getIOService()->stopAndPoll(false);
-
- EXPECT_EQ(expected_responses, server_socket_->getResponseNum());
- checkAnswer(answer, expected_result0, expected_result1, expected_result2);
- }
-
- /// @brief a convenience reference to control agent command manager
- CtrlAgentCommandMgr& mgr_;
-
- /// @brief Pointer to the test server unix socket.
- TestServerUnixSocketPtr server_socket_;
-
- /// @brief Whether the current test was skipped.
- bool skipped_;
-};
-
-/// Just a basic test checking that non-existent command is handled
-/// properly.
-TEST_F(CtrlAgentCommandMgrTest, bogus) {
- ConstElementPtr answer;
- EXPECT_NO_THROW(answer = mgr_.processCommand(createCommand("fish-and-chips-please", "")));
- checkAnswer(answer, isc::config::CONTROL_RESULT_COMMAND_UNSUPPORTED);
-};
-
-// Test verifying that parameter other than command, arguments and service is
-// rejected and that the correct error is returned.
-TEST_F(CtrlAgentCommandMgrTest, extraParameter) {
- ElementPtr command = Element::createMap();
- command->set("command", Element::create("list-commands"));
- command->set("arguments", Element::createMap());
- command->set("extra-arg", Element::createMap());
-
- ConstElementPtr answer;
- EXPECT_NO_THROW(answer = mgr_.processCommand(command));
- checkAnswer(answer, isc::config::CONTROL_RESULT_ERROR);
-}
-
-/// Just a basic test checking that 'list-commands' is supported.
-TEST_F(CtrlAgentCommandMgrTest, listCommands) {
- ConstElementPtr answer;
- EXPECT_NO_THROW(answer = mgr_.processCommand(createCommand("list-commands", "")));
-
- checkAnswer(answer, isc::config::CONTROL_RESULT_SUCCESS);
-};
-
-/// Check that control command is successfully forwarded to the DHCPv4 server.
-TEST_F(CtrlAgentCommandMgrTest, forwardToDHCPv4Server) {
- testForward("dhcp4", "dhcp4", isc::config::CONTROL_RESULT_SUCCESS);
-}
-
-/// Check that control command is successfully forwarded to the DHCPv6 server.
-TEST_F(CtrlAgentCommandMgrTest, forwardToDHCPv6Server) {
- testForward("dhcp6", "dhcp6", isc::config::CONTROL_RESULT_SUCCESS);
-}
-
-/// Check that control command is successfully forwarded to the D2 server.
-TEST_F(CtrlAgentCommandMgrTest, forwardToD2Server) {
- testForward("d2", "d2", isc::config::CONTROL_RESULT_SUCCESS);
-}
-
-/// Check that the same command is forwarded to multiple servers.
-TEST_F(CtrlAgentCommandMgrTest, forwardToBothDHCPServers) {
- configureControlSocket("dhcp6");
- SKIP_IF(skipped_);
-
- testForward("dhcp4", "dhcp4,dhcp6", isc::config::CONTROL_RESULT_SUCCESS,
- isc::config::CONTROL_RESULT_SUCCESS, -1, 2);
-}
-
-/// Check that the same command is forwarded to all servers.
-TEST_F(CtrlAgentCommandMgrTest, forwardToAllServers) {
- configureControlSocket("dhcp6");
- configureControlSocket("d2");
- SKIP_IF(skipped_);
-
- testForward("dhcp4", "dhcp4,dhcp6,d2", isc::config::CONTROL_RESULT_SUCCESS,
- isc::config::CONTROL_RESULT_SUCCESS,
- isc::config::CONTROL_RESULT_SUCCESS, 3);
-}
-
-/// Check that the command may forwarded to the second server even if
-/// forwarding to a first server fails.
-TEST_F(CtrlAgentCommandMgrTest, failForwardToServer) {
- testForward("dhcp6", "dhcp4,dhcp6",
- isc::config::CONTROL_RESULT_ERROR,
- isc::config::CONTROL_RESULT_SUCCESS);
-}
-
-/// Check that control command is not forwarded if the service is not specified.
-TEST_F(CtrlAgentCommandMgrTest, noService) {
- testForward("dhcp6", "",
- isc::config::CONTROL_RESULT_COMMAND_UNSUPPORTED,
- -1, -1, 0);
-}
-
-/// Check that error is returned to the client when the server to which the
-/// command was forwarded sent an invalid message.
-TEST_F(CtrlAgentCommandMgrTest, invalidAnswer) {
- testForward("dhcp6", "dhcp6",
- isc::config::CONTROL_RESULT_ERROR, -1, -1, 1,
- "{ \"result\": }");
-}
-
-/// Check that connection is dropped if it takes too long. The test checks
-/// client's behavior when partial JSON is returned. Client will be waiting
-/// for the '}' and will timeout because it is never received.
-/// @todo Currently this test is disabled because we don't have configurable
-/// timeout value. It is hardcoded to 5 sec, which is too long for the
-/// unit test to run.
-TEST_F(CtrlAgentCommandMgrTest, DISABLED_connectionTimeout) {
- testForward("dhcp6", "dhcp6",
- isc::config::CONTROL_RESULT_ERROR, -1, -1, 1,
- "{ \"result\": 0");
-}
-
-/// Check that error is returned to the client if the forwarding socket is
-/// not configured for the given service.
-TEST_F(CtrlAgentCommandMgrTest, noClientSocket) {
- ConstElementPtr command = createCommand("foo", "dhcp4");
- ConstElementPtr answer = mgr_.handleCommand("foo", ConstElementPtr(),
- command);
-
- checkAnswer(answer, isc::config::CONTROL_RESULT_ERROR);
-}
-
-/// Check that error is returned to the client if the remote server to
-/// which the control command is to be forwarded is not available.
-TEST_F(CtrlAgentCommandMgrTest, noServerSocket) {
- configureControlSocket("dhcp6");
- SKIP_IF(skipped_);
-
- ConstElementPtr command = createCommand("foo", "dhcp6");
- ConstElementPtr answer = mgr_.handleCommand("foo", ConstElementPtr(),
- command);
-
- checkAnswer(answer, isc::config::CONTROL_RESULT_ERROR);
-}
-
-// Check that list-commands command is forwarded when the service
-// value is specified.
-TEST_F(CtrlAgentCommandMgrTest, forwardListCommands) {
- // Configure client side socket.
- configureControlSocket("dhcp4");
- SKIP_IF(skipped_);
- // Create server side socket.
- bindServerSocket("{ \"result\" : 3 }", true);
-
- // The client side communication is synchronous. To be able to respond
- // to this we need to run the server side socket at the same time.
- // Running IO service in a thread guarantees that the server responds
- // as soon as it receives the control command.
- std::thread th(std::bind(&IOService::run, getIOService().get()));
-
- // Wait for the IO service in thread to actually run.
- server_socket_->waitForRunning();
-
- ConstElementPtr command = createCommand("list-commands", "dhcp4");
- ConstElementPtr answer = mgr_.handleCommand("list-commands", ConstElementPtr(),
- command);
-
- // Stop IO service immediately and let the thread die.
- getIOService()->stop();
-
- // Wait for the thread to finish.
- th.join();
-
- // Cancel all asynchronous operations on the server.
- server_socket_->stopServer();
-
- // We have some cancelled operations for which we need to invoke the
- // handlers with the operation_aborted error code.
- getIOService()->stopAndPoll(false);
-
- // Answer of 3 is specific to the stub response we send when the
- // command is forwarded. So having this value returned means that
- // the command was forwarded as expected.
- checkAnswer(answer, 3);
-}
-
-}
+++ /dev/null
-// Copyright (C) 2016-2026 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#include <config.h>
-
-#include <asiolink/testutils/timed_signal.h>
-#include <agent/ca_controller.h>
-#include <agent/ca_process.h>
-#include <agent/ca_command_mgr.h>
-#include <cc/data.h>
-#include <cc/command_interpreter.h>
-#include <config/unix_command_config.h>
-#include <process/testutils/d_test_stubs.h>
-#include <util/filesystem.h>
-#include <testutils/gtest_utils.h>
-
-#include <boost/pointer_cast.hpp>
-
-#include <sstream>
-
-#include <unistd.h>
-
-using namespace isc::asiolink;
-using namespace isc::asiolink::test;
-using namespace isc::agent;
-using namespace isc::data;
-using namespace isc::http;
-using namespace isc::process;
-using namespace isc::config;
-using namespace isc::util;
-using namespace boost::posix_time;
-using namespace std;
-
-namespace {
-
-/// @brief Valid Control Agent Config used in tests.
-const char* valid_agent_config =
- "{"
- " \"http-host\": \"127.0.0.1\","
- " \"http-port\": 8081,"
- " \"control-sockets\": {"
- " \"dhcp4\": {"
- " \"socket-type\": \"unix\","
- " \"socket-name\": \"first_socket4\""
- " },"
- " \"dhcp6\": {"
- " \"socket-type\": \"unix\","
- " \"socket-name\": \"first_socket6\""
- " }"
- " }"
- "}";
-
-/// @brief test fixture class for testing CtrlAgentController class.
-///
-/// This class derives from DControllerTest and wraps CtrlAgentController. Much
-/// of the underlying functionality is in the DControllerBase class which
-/// has extensive set of unit tests that are independent from the Control
-/// Agent.
-class CtrlAgentControllerTest : public DControllerTest {
-public:
-
- /// @brief Constructor.
- CtrlAgentControllerTest()
- : DControllerTest(CtrlAgentController::instance) {
- setSocketTestPath();
- }
-
- /// @brief Destructor.
- virtual ~CtrlAgentControllerTest() {
- resetSocketPath();
- }
-
- /// @brief Returns pointer to CtrlAgentProcess instance.
- CtrlAgentProcessPtr getCtrlAgentProcess() {
- return (boost::dynamic_pointer_cast<CtrlAgentProcess>(getProcess()));
- }
-
- /// @brief Returns pointer to CtrlAgentCfgMgr instance for a process.
- CtrlAgentCfgMgrPtr getCtrlAgentCfgMgr() {
- CtrlAgentCfgMgrPtr p;
- if (getCtrlAgentProcess()) {
- p = getCtrlAgentProcess()->getCtrlAgentCfgMgr();
- }
- return (p);
- }
-
- /// @brief Returns a pointer to the configuration context.
- CtrlAgentCfgContextPtr getCtrlAgentCfgContext() {
- CtrlAgentCfgContextPtr p;
- if (getCtrlAgentCfgMgr()) {
- p = getCtrlAgentCfgMgr()->getCtrlAgentCfgContext();
- }
- return (p);
- }
-
- /// @brief Sets the path in which the socket can be created.
- /// @param explicit_path path to use as the socket path.
- void setSocketTestPath(const std::string explicit_path = "") {
- auto path = UnixCommandConfig::getSocketPath(true, (!explicit_path.empty() ?
- explicit_path : TEST_DATA_BUILDDIR));
- UnixCommandConfig::setSocketPathPerms(file::getPermissions(path));
- }
-
- /// @brief Resets the socket path to the default.
- void resetSocketPath() {
- UnixCommandConfig::getSocketPath(true);
- UnixCommandConfig::setSocketPathPerms();
- }
-
- /// @brief Tests that socket info structure contains 'unix' socket-type
- /// value and the expected socket-name.
- ///
- /// @param service Service type.
- /// @param exp_socket_name Expected socket name.
- void testUnixSocketInfo(const std::string& service,
- const std::string& exp_socket_name) {
- CtrlAgentCfgContextPtr ctx = getCtrlAgentCfgContext();
- ASSERT_TRUE(ctx);
-
- ConstElementPtr sock_info = ctx->getControlSocketInfo(service);
- ASSERT_TRUE(sock_info);
- ASSERT_TRUE(sock_info->contains("socket-type"));
- EXPECT_EQ("unix", sock_info->get("socket-type")->stringValue());
- ASSERT_TRUE(sock_info->contains("socket-name"));
- EXPECT_EQ(exp_socket_name, sock_info->get("socket-name")->stringValue());
- }
-
- /// @brief Compares the status in the given parse result to a given value.
- ///
- /// @param answer Element set containing an integer response and string
- /// comment.
- /// @param exp_status is an integer against which to compare the status.
- /// @param exp_txt is expected text (not checked if "")
- ///
- void checkAnswer(isc::data::ConstElementPtr answer,
- int exp_status,
- string exp_txt = "") {
- int rcode = 0;
- isc::data::ConstElementPtr comment;
- comment = isc::config::parseAnswer(rcode, answer);
-
- if (rcode != exp_status) {
- ADD_FAILURE() << "Expected status code " << exp_status
- << " but received " << rcode << ", comment: "
- << (comment ? comment->str() : "(none)");
- }
-
- // Ok, parseAnswer interface is weird. If there are no arguments,
- // it returns content of text. But if there is an argument,
- // it returns the argument and it's not possible to retrieve
- // "text" (i.e. comment).
- if (comment->getType() != Element::string) {
- comment = answer->get("text");
- }
-
- if (!exp_txt.empty()) {
- EXPECT_EQ(exp_txt, comment->stringValue());
- }
- }
-
- /// @brief Checks whether specified command is registered
- ///
- /// @param name name of the command to be checked
- /// @param expect_true true - must be registered, false - must not be
- void checkCommandRegistered(const std::string& name, bool expect_true = true) {
-
- // First get the list of registered commands
- ConstElementPtr lst = Element::fromJSON("{ \"command\": \"list-commands\" }");
- ConstElementPtr rsp = CtrlAgentCommandMgr::instance().processCommand(lst);
-
- // The response must be an array with at least one element
- ASSERT_TRUE(rsp);
- ASSERT_EQ(Element::list, rsp->getType());
- ASSERT_LE(1, rsp->size());
- ConstElementPtr args = rsp->get(0)->get("arguments");
- ASSERT_TRUE(args);
-
- string args_txt = args->str();
-
- if (expect_true) {
- EXPECT_TRUE(args_txt.find(name) != string::npos);
- } else {
- EXPECT_TRUE(args_txt.find(name) == string::npos);
- }
- }
-
-};
-
-// Basic Controller instantiation testing.
-// Verifies that the controller singleton gets created and that the
-// basic derivation from the base class is intact.
-TEST_F(CtrlAgentControllerTest, basicInstanceTesting) {
- // Verify the singleton instance can be fetched and that
- // it has the correct type.
- DControllerBasePtr& controller = DControllerTest::getController();
- ASSERT_TRUE(controller);
- ASSERT_NO_THROW(boost::dynamic_pointer_cast<CtrlAgentController>(controller));
-
- // Verify that controller's app name is correct.
- EXPECT_TRUE(checkAppName(CtrlAgentController::agent_app_name_));
-
- // Verify that controller's bin name is correct.
- EXPECT_TRUE(checkBinName(CtrlAgentController::agent_bin_name_));
-
- // Verify that controller's IOService exists.
- EXPECT_TRUE(checkIOService());
-
- // Verify that the Process does NOT exist.
- EXPECT_FALSE(checkProcess());
-}
-
-// Tests basic command line processing.
-// Verifies that:
-// 1. Standard command line options are supported.
-// 2. Invalid options are detected.
-TEST_F(CtrlAgentControllerTest, commandLineArgs) {
- char* argv[] = { const_cast<char*>("progName"),
- const_cast<char*>("-c"),
- const_cast<char*>(DControllerTest::CFG_TEST_FILE),
- const_cast<char*>("-d") };
- int argc = 4;
-
- // Verify that verbose flag is false initially.
- EXPECT_TRUE(checkVerbose(false));
-
- // Verify that standard options can be parsed without error.
- EXPECT_NO_THROW_LOG(parseArgs(argc, argv));
-
- // Verify that verbose flag is true.
- EXPECT_TRUE(checkVerbose(true));
-
- // Verify configuration file name is correct.
- EXPECT_TRUE(checkConfigFileName(DControllerTest::CFG_TEST_FILE));
-
- // Verify that an unknown option is detected.
- char* argv2[] = { const_cast<char*>("progName"),
- const_cast<char*>("-x") };
- argc = 2;
- EXPECT_THROW_MSG(parseArgs(argc, argv2), InvalidUsage, "unsupported option: -x");
-}
-
-// Tests application process creation and initialization.
-// Verifies that the process can be successfully created and initialized.
-TEST_F(CtrlAgentControllerTest, initProcessTesting) {
- ASSERT_NO_THROW(initProcess());
- EXPECT_TRUE(checkProcess());
-}
-
-// Tests launch and normal shutdown (stand alone mode).
-// This creates an interval timer to generate a normal shutdown and then
-// launches with a valid, stand-alone command line and no simulated errors.
-TEST_F(CtrlAgentControllerTest, launchNormalShutdown) {
- // Write valid_agent_config and then run launch() for 1000 ms.
- time_duration elapsed_time;
- runWithConfig(valid_agent_config, 1000, elapsed_time);
-
- // Give a generous margin to accommodate slower test environs.
- EXPECT_TRUE(elapsed_time.total_milliseconds() >= 800 &&
- elapsed_time.total_milliseconds() <= 1300);
-}
-
-// Tests that the SIGINT triggers a normal shutdown.
-TEST_F(CtrlAgentControllerTest, sigintShutdown) {
- // Setup to raise SIGHUP in 1 ms.
- TimedSignal sighup(getIOService(), SIGINT, 1);
-
- // Write valid_agent_config and then run launch() for a maximum
- // of 1000 ms.
- time_duration elapsed_time;
- runWithConfig(valid_agent_config, 1000, elapsed_time);
-
- // Signaled shutdown should make our elapsed time much smaller than
- // the maximum run time. Give generous margin to accommodate slow
- // test environs.
- EXPECT_TRUE(elapsed_time.total_milliseconds() < 300);
-}
-
-// Tests that the SIGTERM triggers a normal shutdown.
-TEST_F(CtrlAgentControllerTest, sigtermShutdown) {
- // Setup to raise SIGTERM in 1 ms.
- TimedSignal sighup(getIOService(), SIGTERM, 1);
-
- // Write valid_agent_config and then run launch() for a maximum of 1 s.
- time_duration elapsed_time;
- runWithConfig(valid_agent_config, 1000, elapsed_time);
-
- // Signaled shutdown should make our elapsed time much smaller than
- // the maximum run time. Give generous margin to accommodate slow
- // test environs.
- EXPECT_TRUE(elapsed_time.total_milliseconds() < 300);
-}
-
-// Tests that the sockets settings are updated upon successful reconfiguration.
-TEST_F(CtrlAgentControllerTest, successfulConfigUpdate) {
- // This configuration should be used to override the initial configuration.
- const char* second_config =
- "{"
- " \"http-host\": \"127.0.0.1\","
- " \"http-port\": 8080,"
- " \"control-sockets\": {"
- " \"dhcp4\": {"
- " \"socket-type\": \"unix\","
- " \"socket-name\": \"second_socket4\""
- " },"
- " \"dhcp6\": {"
- " \"socket-type\": \"unix\","
- " \"socket-name\": \"second_socket6\""
- " }"
- " }"
- "}";
-
- // This check callback is called before the shutdown.
- auto check_callback = [&] {
- CtrlAgentProcessPtr process = getCtrlAgentProcess();
- ASSERT_TRUE(process);
-
- // Check that the HTTP listener still exists after reconfiguration.
- ConstHttpListenerPtr listener = process->getHttpListener();
- ASSERT_TRUE(listener);
- EXPECT_TRUE(process->isListening());
-
- // The listener should have been reconfigured to use new address and port.
- EXPECT_EQ("127.0.0.1", listener->getLocalAddress().toText());
- EXPECT_EQ(8080, listener->getLocalPort());
- };
-
- // Schedule reconfiguration.
- scheduleTimedWrite(second_config, 100);
- // Schedule SIGHUP signal to trigger reconfiguration.
- TimedSignal sighup(getIOService(), SIGHUP, 200);
-
- // Start the server.
- time_duration elapsed_time;
- runWithConfig(valid_agent_config, 500,
- static_cast<const TestCallback&>(check_callback),
- elapsed_time);
-
- CtrlAgentCfgContextPtr ctx = getCtrlAgentCfgContext();
- ASSERT_TRUE(ctx);
-
- // The server should now hold the new listener configuration.
- EXPECT_EQ("127.0.0.1", ctx->getHttpHost());
- EXPECT_EQ(8080, ctx->getHttpPort());
-
- // The forwarding configuration should have been updated too.
- testUnixSocketInfo("dhcp4", "second_socket4");
- testUnixSocketInfo("dhcp6", "second_socket6");
-
- // After the shutdown the HTTP listener no longer exists.
- CtrlAgentProcessPtr process = getCtrlAgentProcess();
- ASSERT_TRUE(process);
- ConstHttpListenerPtr listener = process->getHttpListener();
- ASSERT_FALSE(listener);
- EXPECT_FALSE(process->isListening());
-}
-
-// Tests that the server continues to use an old configuration when the listener
-// reconfiguration is unsuccessful.
-TEST_F(CtrlAgentControllerTest, unsuccessfulConfigUpdate) {
- // This is invalid configuration. We're using restricted port number and
- // IP address of 1.1.1.1.
- const char* second_config =
- "{"
- " \"http-host\": \"1.1.1.1\","
- " \"http-port\": 1,"
- " \"control-sockets\": {"
- " \"dhcp4\": {"
- " \"socket-type\": \"unix\","
- " \"socket-name\": \"second_socket4\""
- " },"
- " \"dhcp6\": {"
- " \"socket-type\": \"unix\","
- " \"socket-name\": \"second_socket6\""
- " }"
- " }"
- "}";
-
- // This check callback is called before the shutdown.
- auto check_callback = [&] {
- CtrlAgentProcessPtr process = getCtrlAgentProcess();
- ASSERT_TRUE(process);
-
- // We should still be using an original listener.
- ConstHttpListenerPtr listener = process->getHttpListener();
- ASSERT_TRUE(listener);
- EXPECT_TRUE(process->isListening());
-
- EXPECT_EQ("127.0.0.1", listener->getLocalAddress().toText());
- EXPECT_EQ(8081, listener->getLocalPort());
- };
-
- // Schedule reconfiguration.
- scheduleTimedWrite(second_config, 100);
- // Schedule SIGHUP signal to trigger reconfiguration.
- TimedSignal sighup(getIOService(), SIGHUP, 200);
-
- // Start the server.
- time_duration elapsed_time;
- runWithConfig(valid_agent_config, 500,
- static_cast<const TestCallback&>(check_callback),
- elapsed_time);
-
- CtrlAgentCfgContextPtr ctx = getCtrlAgentCfgContext();
- ASSERT_TRUE(ctx);
-
- // The reconfiguration should have been unsuccessful, and the server should
- // still use the original configuration.
- EXPECT_EQ("127.0.0.1", ctx->getHttpHost());
- EXPECT_EQ(8081, ctx->getHttpPort());
-
- // Same for forwarding.
- testUnixSocketInfo("dhcp4", "first_socket4");
- testUnixSocketInfo("dhcp6", "first_socket6");
-
- // After the shutdown the HTTP listener no longer exists.
- CtrlAgentProcessPtr process = getCtrlAgentProcess();
- ASSERT_TRUE(process);
- ConstHttpListenerPtr listener = process->getHttpListener();
- ASSERT_FALSE(listener);
- EXPECT_FALSE(process->isListening());
-}
-
-// Tests that the server continues to use an old configuration when the listener
-// reconfiguration is unsuccessful because of incomplete socket data.
-TEST_F(CtrlAgentControllerTest, unsuccessfulIncompleteConfigUpdate) {
- // This is invalid configuration.
- const char* second_config =
- "{"
- " \"http-host\": \"127.0.0.1\","
- " \"http-port\": 8081,"
- " \"control-sockets\": {"
- " \"dhcp4\": {"
- " \"socket-type\": \"unix\""
- " },"
- " \"dhcp6\": {"
- " \"socket-type\": \"unix\""
- " }"
- " }"
- "}";
-
- // This check callback is called before the shutdown.
- auto check_callback = [&] {
- CtrlAgentProcessPtr process = getCtrlAgentProcess();
- ASSERT_TRUE(process);
-
- // We should still be using an original listener.
- ConstHttpListenerPtr listener = process->getHttpListener();
- ASSERT_TRUE(listener);
- EXPECT_TRUE(process->isListening());
-
- EXPECT_EQ("127.0.0.1", listener->getLocalAddress().toText());
- EXPECT_EQ(8081, listener->getLocalPort());
- };
-
- // Schedule reconfiguration.
- scheduleTimedWrite(second_config, 100);
- // Schedule SIGHUP signal to trigger reconfiguration.
- TimedSignal sighup(getIOService(), SIGHUP, 200);
-
- // Start the server.
- time_duration elapsed_time;
- runWithConfig(valid_agent_config, 500,
- static_cast<const TestCallback&>(check_callback),
- elapsed_time);
-
- CtrlAgentCfgContextPtr ctx = getCtrlAgentCfgContext();
- ASSERT_TRUE(ctx);
-
- // The reconfiguration should have been unsuccessful, and the server should
- // still use the original configuration.
- EXPECT_EQ("127.0.0.1", ctx->getHttpHost());
- EXPECT_EQ(8081, ctx->getHttpPort());
-
- // Same for forwarding.
- testUnixSocketInfo("dhcp4", "first_socket4");
- testUnixSocketInfo("dhcp6", "first_socket6");
-
- // After the shutdown the HTTP listener no longer exists.
- CtrlAgentProcessPtr process = getCtrlAgentProcess();
- ASSERT_TRUE(process);
- ConstHttpListenerPtr listener = process->getHttpListener();
- ASSERT_FALSE(listener);
- EXPECT_FALSE(process->isListening());
-}
-
-// Tests that it is possible to update the configuration in such a way that the
-// listener configuration remains the same. The server should continue using the
-// listener instance it has been using prior to the reconfiguration.
-TEST_F(CtrlAgentControllerTest, noListenerChangeHttp) {
- // This configuration should be used to override the initial configuration.
- const char* second_config =
- "{"
- " \"http-host\": \"127.0.0.1\","
- " \"http-port\": 8081,"
- " \"control-sockets\": {"
- " \"dhcp4\": {"
- " \"socket-type\": \"unix\","
- " \"socket-name\": \"second_socket4\""
- " },"
- " \"dhcp6\": {"
- " \"socket-type\": \"unix\","
- " \"socket-name\": \"second_socket6\""
- " }"
- " }"
- "}";
-
- // Pointer used to store the listener instance. It is set after 50 ms the
- // process has started (using a timer) and it's value is checked on server
- // shutdown using the callback.
- const HttpListener* listener_ptr = 0;
-
- // This check callback is called before the shutdown.
- auto check_callback = [&] {
- CtrlAgentProcessPtr process = getCtrlAgentProcess();
- ASSERT_TRUE(process);
-
- // Check that the HTTP listener still exists after reconfiguration.
- ConstHttpListenerPtr listener = process->getHttpListener();
- ASSERT_TRUE(listener);
- ASSERT_EQ(listener_ptr, listener.get());
- ASSERT_FALSE(listener->getTlsContext());
- EXPECT_TRUE(process->isListening());
-
- EXPECT_EQ("127.0.0.1", listener->getLocalAddress().toText());
- EXPECT_EQ(8081, listener->getLocalPort());
- };
-
- // Schedule reconfiguration.
- scheduleTimedWrite(second_config, 100);
- // Schedule SIGHUP signal to trigger reconfiguration.
- TimedSignal sighup(getIOService(), SIGHUP, 200);
-
- IntervalTimer timer(getIOService());
- timer.setup([&] {
- CtrlAgentProcessPtr process = getCtrlAgentProcess();
- ASSERT_TRUE(process);
- ConstHttpListenerPtr listener = process->getHttpListener();
- ASSERT_TRUE(listener);
- listener_ptr = listener.get();
- ASSERT_FALSE(listener->getTlsContext());
- }, 50, IntervalTimer::ONE_SHOT);
-
- // Start the server.
- time_duration elapsed_time;
- runWithConfig(valid_agent_config, 500,
- static_cast<const TestCallback&>(check_callback),
- elapsed_time);
-
- CtrlAgentCfgContextPtr ctx = getCtrlAgentCfgContext();
- ASSERT_TRUE(ctx);
-
- // The server should use a correct listener configuration.
- EXPECT_EQ("127.0.0.1", ctx->getHttpHost());
- EXPECT_EQ(8081, ctx->getHttpPort());
-
- // The forwarding configuration should have been updated.
- testUnixSocketInfo("dhcp4", "second_socket4");
- testUnixSocketInfo("dhcp6", "second_socket6");
-
- CtrlAgentProcessPtr process = getCtrlAgentProcess();
- ASSERT_TRUE(process);
- ConstHttpListenerPtr listener = process->getHttpListener();
- ASSERT_FALSE(listener);
- EXPECT_FALSE(process->isListening());
-}
-
-// Tests that it is possible to update the configuration in such a way that the
-// listener configuration remains the same. The server should continue using the
-// listener instance it has been using prior to the reconfiguration.
-TEST_F(CtrlAgentControllerTest, noListenerChangeHttps) {
- // This configuration should be used to override the initial configuration.
- string ca_dir(string(TEST_CA_DIR));
- ostringstream agent_st;
- agent_st << "{"
- << " \"http-host\": \"127.0.0.1\","
- << " \"http-port\": 8081,"
- << " \"trust-anchor\": \"" << ca_dir << "/kea-ca.crt\", \n"
- << " \"cert-file\": \"" << ca_dir << "/kea-server.crt\", \n"
- << " \"key-file\": \"" << ca_dir << "/kea-server.key\", \n"
- << " \"control-sockets\": {"
- << " \"dhcp4\": {"
- << " \"socket-type\": \"unix\","
- << " \"socket-name\": \"first_socket4\""
- << " },"
- << " \"dhcp6\": {"
- << " \"socket-type\": \"unix\","
- << " \"socket-name\": \"first_socket6\""
- << " }"
- << " }"
- << "}";
-
- ostringstream second_config_st;
- second_config_st << "{"
- << " \"http-host\": \"127.0.0.1\","
- << " \"http-port\": 8081,"
- << " \"trust-anchor\": \"" << ca_dir << "/kea-ca.crt\", \n"
- << " \"cert-file\": \"" << ca_dir << "/kea-server.crt\", \n"
- << " \"key-file\": \"" << ca_dir << "/kea-server.key\", \n"
- << " \"control-sockets\": {"
- << " \"dhcp4\": {"
- << " \"socket-type\": \"unix\","
- << " \"socket-name\": \"second_socket4\""
- << " },"
- << " \"dhcp6\": {"
- << " \"socket-type\": \"unix\","
- << " \"socket-name\": \"second_socket6\""
- << " }"
- << " }"
- << "}";
-
- // Pointer used to store the listener instance. It is set after 50 ms the
- // process has started (using a timer) and it's value is checked on server
- // shutdown using the callback.
- const HttpListener* listener_ptr = 0;
- TlsContext* context = 0;
-
- // This check callback is called before the shutdown.
- auto check_callback = [&] {
- CtrlAgentProcessPtr process = getCtrlAgentProcess();
- ASSERT_TRUE(process);
-
- // Check that the HTTP listener still exists after reconfiguration.
- ConstHttpListenerPtr listener = process->getHttpListener();
- ASSERT_TRUE(listener);
- ASSERT_EQ(listener_ptr, listener.get());
- ASSERT_TRUE(listener->getTlsContext());
- // The TLS settings have been applied
- ASSERT_NE(context, listener->getTlsContext().get());
- EXPECT_TRUE(process->isListening());
-
- EXPECT_EQ("127.0.0.1", listener->getLocalAddress().toText());
- EXPECT_EQ(8081, listener->getLocalPort());
- };
-
- // Schedule reconfiguration.
- scheduleTimedWrite(second_config_st.str(), 100);
- // Schedule SIGHUP signal to trigger reconfiguration.
- TimedSignal sighup(getIOService(), SIGHUP, 200);
-
- IntervalTimer timer(getIOService());
- timer.setup([&] {
- CtrlAgentProcessPtr process = getCtrlAgentProcess();
- ASSERT_TRUE(process);
- ConstHttpListenerPtr listener = process->getHttpListener();
- ASSERT_TRUE(listener);
- listener_ptr = listener.get();
- ASSERT_TRUE(listener->getTlsContext());
- context = listener->getTlsContext().get();
- }, 50, IntervalTimer::ONE_SHOT);
-
- // Start the server.
- time_duration elapsed_time;
- runWithConfig(agent_st.str(), 500,
- static_cast<const TestCallback&>(check_callback),
- elapsed_time);
-
- CtrlAgentCfgContextPtr ctx = getCtrlAgentCfgContext();
- ASSERT_TRUE(ctx);
-
- // The server should use a correct listener configuration.
- EXPECT_EQ("127.0.0.1", ctx->getHttpHost());
- EXPECT_EQ(8081, ctx->getHttpPort());
-
- // The forwarding configuration should have been updated.
- testUnixSocketInfo("dhcp4", "second_socket4");
- testUnixSocketInfo("dhcp6", "second_socket6");
-
- CtrlAgentProcessPtr process = getCtrlAgentProcess();
- ASSERT_TRUE(process);
- ConstHttpListenerPtr listener = process->getHttpListener();
- ASSERT_FALSE(listener);
- EXPECT_FALSE(process->isListening());
-}
-
-// Verify that the reload will issue an error
-TEST_F(CtrlAgentControllerTest, handleHttpToHttpsSwitch) {
- string ca_dir(string(TEST_CA_DIR));
-
- // This configuration should be used to override the initial configuration.
- ostringstream second_config_st;
- second_config_st << "{"
- << " \"http-host\": \"127.0.0.1\","
- << " \"http-port\": 8081,"
- << " \"trust-anchor\": \"" << ca_dir << "/kea-ca.crt\", \n"
- << " \"cert-file\": \"" << ca_dir << "/kea-server.crt\", \n"
- << " \"key-file\": \"" << ca_dir << "/kea-server.key\", \n"
- << " \"control-sockets\": {"
- << " \"dhcp4\": {"
- << " \"socket-type\": \"unix\","
- << " \"socket-name\": \"second_socket4\""
- << " },"
- << " \"dhcp6\": {"
- << " \"socket-type\": \"unix\","
- << " \"socket-name\": \"second_socket6\""
- << " }"
- << " }"
- << "}";
-
- // Pointer used to store the listener instance. It is set after 50 ms the
- // process has started (using a timer) and it's value is checked on server
- // shutdown using the callback.
- const HttpListener* listener_ptr = 0;
-
- // This check callback is called before the shutdown.
- auto check_callback = [&] {
- CtrlAgentProcessPtr process = getCtrlAgentProcess();
- ASSERT_TRUE(process);
-
- // Check that the HTTP listener still exists after reconfiguration.
- ConstHttpListenerPtr listener = process->getHttpListener();
- ASSERT_TRUE(listener);
- ASSERT_EQ(listener_ptr, listener.get());
- ASSERT_FALSE(listener->getTlsContext());
- EXPECT_TRUE(process->isListening());
-
- EXPECT_EQ("127.0.0.1", listener->getLocalAddress().toText());
- EXPECT_EQ(8081, listener->getLocalPort());
- };
-
- // Schedule reconfiguration.
- scheduleTimedWrite(second_config_st.str(), 100);
- // Schedule SIGHUP signal to trigger reconfiguration.
- TimedSignal sighup(getIOService(), SIGHUP, 200);
-
- IntervalTimer timer(getIOService());
- timer.setup([&] {
- CtrlAgentProcessPtr process = getCtrlAgentProcess();
- ASSERT_TRUE(process);
- ConstHttpListenerPtr listener = process->getHttpListener();
- ASSERT_TRUE(listener);
- listener_ptr = listener.get();
- ASSERT_FALSE(listener->getTlsContext());
- }, 50, IntervalTimer::ONE_SHOT);
-
- // Start the server.
- time_duration elapsed_time;
- runWithConfig(valid_agent_config, 500,
- static_cast<const TestCallback&>(check_callback),
- elapsed_time);
-
- CtrlAgentCfgContextPtr ctx = getCtrlAgentCfgContext();
- ASSERT_TRUE(ctx);
-
- // The server should use a correct listener configuration.
- EXPECT_EQ("127.0.0.1", ctx->getHttpHost());
- EXPECT_EQ(8081, ctx->getHttpPort());
-
- // The forwarding configuration should have not been updated.
- testUnixSocketInfo("dhcp4", "first_socket4");
- testUnixSocketInfo("dhcp6", "first_socket6");
-
- CtrlAgentProcessPtr process = getCtrlAgentProcess();
- ASSERT_TRUE(process);
- ConstHttpListenerPtr listener = process->getHttpListener();
- ASSERT_FALSE(listener);
- EXPECT_FALSE(process->isListening());
-}
-
-// Verify that the reload will issue an error
-TEST_F(CtrlAgentControllerTest, handleHttpsToHttpSwitch) {
- string ca_dir(string(TEST_CA_DIR));
- ostringstream agent_st;
- agent_st << "{"
- << " \"http-host\": \"127.0.0.1\","
- << " \"http-port\": 8081,"
- << " \"trust-anchor\": \"" << ca_dir << "/kea-ca.crt\", \n"
- << " \"cert-file\": \"" << ca_dir << "/kea-server.crt\", \n"
- << " \"key-file\": \"" << ca_dir << "/kea-server.key\", \n"
- << " \"control-sockets\": {"
- << " \"dhcp4\": {"
- << " \"socket-type\": \"unix\","
- << " \"socket-name\": \"first_socket4\""
- << " },"
- << " \"dhcp6\": {"
- << " \"socket-type\": \"unix\","
- << " \"socket-name\": \"first_socket6\""
- << " }"
- << " }"
- << "}";
-
- // This configuration should be used to override the initial configuration.
- ostringstream second_config_st;
- second_config_st << "{"
- << " \"http-host\": \"127.0.0.1\","
- << " \"http-port\": 8081,"
- << " \"control-sockets\": {"
- << " \"dhcp4\": {"
- << " \"socket-type\": \"unix\","
- << " \"socket-name\": \"second_socket4\""
- << " },"
- << " \"dhcp6\": {"
- << " \"socket-type\": \"unix\","
- << " \"socket-name\": \"second_socket6\""
- << " }"
- << " }"
- << "}";
-
- // Pointer used to store the listener instance. It is set after 50 ms the
- // process has started (using a timer) and it's value is checked on server
- // shutdown using the callback.
- const HttpListener* listener_ptr = 0;
- TlsContext* context = 0;
-
- // This check callback is called before the shutdown.
- auto check_callback = [&] {
- CtrlAgentProcessPtr process = getCtrlAgentProcess();
- ASSERT_TRUE(process);
-
- // Check that the HTTP listener still exists after reconfiguration.
- ConstHttpListenerPtr listener = process->getHttpListener();
- ASSERT_TRUE(listener);
- ASSERT_EQ(listener_ptr, listener.get());
- ASSERT_TRUE(listener->getTlsContext());
- // The TLS settings have not changed
- ASSERT_EQ(context, listener->getTlsContext().get());
- EXPECT_TRUE(process->isListening());
-
- EXPECT_EQ("127.0.0.1", listener->getLocalAddress().toText());
- EXPECT_EQ(8081, listener->getLocalPort());
- };
-
- // Schedule reconfiguration.
- scheduleTimedWrite(second_config_st.str(), 100);
- // Schedule SIGHUP signal to trigger reconfiguration.
- TimedSignal sighup(getIOService(), SIGHUP, 200);
-
- IntervalTimer timer(getIOService());
- timer.setup([&] {
- CtrlAgentProcessPtr process = getCtrlAgentProcess();
- ASSERT_TRUE(process);
- ConstHttpListenerPtr listener = process->getHttpListener();
- ASSERT_TRUE(listener);
- listener_ptr = listener.get();
- ASSERT_TRUE(listener->getTlsContext());
- context = listener->getTlsContext().get();
- }, 50, IntervalTimer::ONE_SHOT);
-
- // Start the server.
- time_duration elapsed_time;
- runWithConfig(agent_st.str(), 500,
- static_cast<const TestCallback&>(check_callback),
- elapsed_time);
-
- CtrlAgentCfgContextPtr ctx = getCtrlAgentCfgContext();
- ASSERT_TRUE(ctx);
-
- // The server should use a correct listener configuration.
- EXPECT_EQ("127.0.0.1", ctx->getHttpHost());
- EXPECT_EQ(8081, ctx->getHttpPort());
-
- // The forwarding configuration should have not been updated.
- testUnixSocketInfo("dhcp4", "first_socket4");
- testUnixSocketInfo("dhcp6", "first_socket6");
-
- CtrlAgentProcessPtr process = getCtrlAgentProcess();
- ASSERT_TRUE(process);
- ConstHttpListenerPtr listener = process->getHttpListener();
- ASSERT_FALSE(listener);
- EXPECT_FALSE(process->isListening());
-}
-
-// Tests that registerCommands actually registers anything.
-TEST_F(CtrlAgentControllerTest, registeredCommands) {
- ASSERT_NO_THROW(initProcess());
- EXPECT_TRUE(checkProcess());
-
- // The framework available makes it very difficult to test the actual
- // code as CtrlAgentController is not initialized the same way it is
- // in production code. In particular, the way CtrlAgentController
- // is initialized in tests does not call registerCommands().
- // This is a crude workaround for this problem. Proper solution should
- // be developed sooner rather than later.
- const DControllerBasePtr& base = getController();
- const CtrlAgentControllerPtr& ctrl =
- boost::dynamic_pointer_cast<CtrlAgentController>(base);
- ASSERT_TRUE(ctrl);
- ctrl->registerCommands();
-
- // Check that the following command are really available.
- checkCommandRegistered("build-report");
- checkCommandRegistered("config-get");
- checkCommandRegistered("config-hash-get");
- checkCommandRegistered("config-reload");
- checkCommandRegistered("config-set");
- checkCommandRegistered("config-test");
- checkCommandRegistered("config-write");
- checkCommandRegistered("list-commands");
- checkCommandRegistered("shutdown");
- checkCommandRegistered("status-get");
- checkCommandRegistered("version-get");
-
- ctrl->deregisterCommands();
-}
-
-// Tests that config-write really writes a config file that contains
-// Control-agent configuration and not some other random nonsense.
-TEST_F(CtrlAgentControllerTest, configWrite) {
- ASSERT_NO_THROW(initProcess());
- EXPECT_TRUE(checkProcess());
-
- // The framework available makes it very difficult to test the actual
- // code as CtrlAgentController is not initialized the same way it is
- // in production code. In particular, the way CtrlAgentController
- // is initialized in tests does not call registerCommands().
- // This is a crude workaround for this problem. Proper solution should
- // be developed sooner rather than later.
- const DControllerBasePtr& base = getController();
- const CtrlAgentControllerPtr& ctrl
- = boost::dynamic_pointer_cast<CtrlAgentController>(base);
- ASSERT_TRUE(ctrl);
- // Now clean up after ourselves.
- ctrl->registerCommands();
-
- // Add a config file.
- ctrl->setConfigFile(string(TEST_DATA_BUILDDIR) + string("/config.json"));
-
- // First, build the command:
- string file = string(TEST_DATA_BUILDDIR) + string("/config-write.json");
- string cmd_txt = "{ \"command\": \"config-write\" }";
- ConstElementPtr cmd = Element::fromJSON(cmd_txt);
- ConstElementPtr params = Element::fromJSON("{\"filename\": \"" + file + "\" }");
- CtrlAgentCommandMgr& mgr_ = CtrlAgentCommandMgr::instance();
-
- // Send the command
- ConstElementPtr answer = mgr_.handleCommand("config-write", params, cmd);
-
- // Check that the command was successful
- checkAnswer(answer, isc::config::CONTROL_RESULT_SUCCESS);
-
- // Now check that the file is there.
- ifstream f(file.c_str());
- ASSERT_TRUE(f.good());
-
- // Now that's some rough check that the config written really contains
- // something that looks like Control-agent configuration.
- ConstElementPtr from_file = Element::fromJSONFile(file, true);
- ASSERT_TRUE(from_file);
- ConstElementPtr ca = from_file->get("Control-agent");
- ASSERT_TRUE(ca);
- EXPECT_TRUE(ca->get("control-sockets"));
- EXPECT_TRUE(ca->get("hooks-libraries"));
- EXPECT_TRUE(ca->get("http-host"));
- EXPECT_TRUE(ca->get("http-port"));
-
- // Remove the file.
- ::remove(file.c_str());
-
- // Now clean up after ourselves.
- ctrl->deregisterCommands();
-}
-
-// Tests that config-write fails with a bad path.
-TEST_F(CtrlAgentControllerTest, badConfigWrite) {
- ASSERT_NO_THROW(initProcess());
- EXPECT_TRUE(checkProcess());
-
- // The framework available makes it very difficult to test the actual
- // code as CtrlAgentController is not initialized the same way it is
- // in production code. In particular, the way CtrlAgentController
- // is initialized in tests does not call registerCommands().
- // This is a crude workaround for this problem. Proper solution should
- // be developed sooner rather than later.
- const DControllerBasePtr& base = getController();
- const CtrlAgentControllerPtr& ctrl
- = boost::dynamic_pointer_cast<CtrlAgentController>(base);
- ASSERT_TRUE(ctrl);
- // Now clean up after ourselves.
- ctrl->registerCommands();
-
- // Add a config file.
- ctrl->setConfigFile(string(TEST_DATA_BUILDDIR) + string("/config.json"));
-
- // First, build the command:
- string file("/tmp/config-write.json");
- string cmd_txt = "{ \"command\": \"config-write\" }";
- ConstElementPtr cmd = Element::fromJSON(cmd_txt);
- ConstElementPtr params = Element::fromJSON("{\"filename\": \"" + file + "\" }");
- CtrlAgentCommandMgr& mgr_ = CtrlAgentCommandMgr::instance();
-
- // Send the command
- ConstElementPtr answer = mgr_.handleCommand("config-write", params, cmd);
-
- // Check that the command failed.
- string expected = "not allowed to write config into ";
- expected += file;
- expected += ": file ";
- expected += file;
- expected += " must be in the same directory as the config file (";
- expected += string(TEST_DATA_BUILDDIR) + string("/config.json");
- expected += ")";
- checkAnswer(answer, isc::config::CONTROL_RESULT_ERROR, expected);
-
- // Remove the file.
- ::remove(file.c_str());
-
- // Now clean up after ourselves.
- ctrl->deregisterCommands();
-}
-
-// Tests if config-reload attempts to reload a file and reports that the
-// file is missing.
-TEST_F(CtrlAgentControllerTest, configReloadMissingFile) {
- ASSERT_NO_THROW(initProcess());
- EXPECT_TRUE(checkProcess());
-
- // The framework available makes it very difficult to test the actual
- // code as CtrlAgentController is not initialized the same way it is
- // in production code. In particular, the way CtrlAgentController
- // is initialized in tests does not call registerCommands().
- // This is a crude workaround for this problem. Proper solution should
- // be developed sooner rather than later.
- const DControllerBasePtr& base = getController();
- const CtrlAgentControllerPtr& ctrl
- = boost::dynamic_pointer_cast<CtrlAgentController>(base);
- ASSERT_TRUE(ctrl);
- // Now clean up after ourselves.
- ctrl->registerCommands();
-
- // This is normally set to whatever value is passed to -c when the server is
- // started, but we're not starting it that way, so need to set it by hand.
- getController()->setConfigFile("does-not-exist.json");
-
- // Build and execute the command.
- string cmd_txt = "{ \"command\": \"config-reload\" }";
- ConstElementPtr cmd = Element::fromJSON(cmd_txt);
- ConstElementPtr params;
- ConstElementPtr answer;
- answer = CtrlAgentCommandMgr::instance().handleCommand("config-reload",
- params, cmd);
-
- // Verify the reload was rejected.
- string expected = "{ \"result\": 1, \"text\": "
- "\"Configuration parsing failed: "
- "Unable to open file does-not-exist.json\" }";
- EXPECT_EQ(expected, answer->str());
-
- // Now clean up after ourselves.
- ctrl->deregisterCommands();
-}
-
-// Tests if config-reload attempts to reload a file and reports that the
-// file is not a valid JSON.
-TEST_F(CtrlAgentControllerTest, configReloadBrokenFile) {
- ASSERT_NO_THROW(initProcess());
- EXPECT_TRUE(checkProcess());
-
- // The framework available makes it very difficult to test the actual
- // code as CtrlAgentController is not initialized the same way it is
- // in production code. In particular, the way CtrlAgentController
- // is initialized in tests does not call registerCommands().
- // This is a crude workaround for this problem. Proper solution should
- // be developed sooner rather than later.
- const DControllerBasePtr& base = getController();
- const CtrlAgentControllerPtr& ctrl
- = boost::dynamic_pointer_cast<CtrlAgentController>(base);
- ASSERT_TRUE(ctrl);
- // Now clean up after ourselves.
- ctrl->registerCommands();
-
- // This is normally set to whatever value is passed to -c when the server is
- // started, but we're not starting it that way, so need to set it by hand.
- getController()->setConfigFile("testbad.json");
-
- // Although Kea is smart, its AI routines are not smart enough to handle
- // this one... at least not yet.
- ofstream f("testbad.json", ios::trunc);
- f << "bla bla bla...";
- f.close();
-
- // Build and execute the command.
- string cmd_txt = "{ \"command\": \"config-reload\" }";
- ConstElementPtr cmd = Element::fromJSON(cmd_txt);
- ConstElementPtr params;
- ConstElementPtr answer;
- answer = CtrlAgentCommandMgr::instance().handleCommand("config-reload",
- params, cmd);
-
- // Verify the reload was rejected.
- string expected = "{ \"result\": 1, \"text\": "
- "\"Configuration parsing failed: "
- "testbad.json:1.1: Invalid character: b\" }";
- EXPECT_EQ(expected, answer->str());
-
- // Remove the file.
- ::remove("testbad.json");
-
- // Now clean up after ourselves.
- ctrl->deregisterCommands();
-}
-
-// Tests if config-reload attempts to reload a file and reports that the
-// file is missing.
-TEST_F(CtrlAgentControllerTest, configReloadFileValid) {
- ASSERT_NO_THROW(initProcess());
- EXPECT_TRUE(checkProcess());
-
- // The framework available makes it very difficult to test the actual
- // code as CtrlAgentController is not initialized the same way it is
- // in production code. In particular, the way CtrlAgentController
- // is initialized in tests does not call registerCommands().
- // This is a crude workaround for this problem. Proper solution should
- // be developed sooner rather than later.
- const DControllerBasePtr& base = getController();
- const CtrlAgentControllerPtr& ctrl
- = boost::dynamic_pointer_cast<CtrlAgentController>(base);
- ASSERT_TRUE(ctrl);
- // Now clean up after ourselves.
- ctrl->registerCommands();
-
- // This is normally set to whatever value is passed to -c when the server is
- // started, but we're not starting it that way, so need to set it by hand.
- getController()->setConfigFile("testvalid.json");
-
- // Ok, enough fooling around. Let's create a valid config.
- ofstream f("testvalid.json", ios::trunc);
- f << "{ \"Control-agent\": "
- << string(valid_agent_config)
- << " }" << endl;
- f.close();
-
- // Build and execute the command.
- string cmd_txt = "{ \"command\": \"config-reload\" }";
- ConstElementPtr cmd = Element::fromJSON(cmd_txt);
- ConstElementPtr params;
- ConstElementPtr answer;
- answer = CtrlAgentCommandMgr::instance().handleCommand("config-reload",
- params, cmd);
-
- // Verify the reload was successful.
- string expected = "{ \"result\": 0, \"text\": "
- "\"Configuration applied successfully.\" }";
- EXPECT_EQ(expected, answer->str());
-
- // Check that the config was indeed applied?
-
- // Remove the file.
- ::remove("testvalid.json");
-
- // Now clean up after ourselves.
- ctrl->deregisterCommands();
-}
-
-// Tests that status-get returns expected info (pid, uptime and reload).
-TEST_F(CtrlAgentControllerTest, statusGet) {
- // Start the server.
- time_duration elapsed_time;
- runWithConfig(valid_agent_config, 500, elapsed_time);
-
- const DControllerBasePtr& ctrl = getController();
- ConstElementPtr response;
- ASSERT_NO_THROW(response = ctrl->statusGetHandler("status-get", ConstElementPtr()));
- ASSERT_TRUE(response);
- ASSERT_EQ(Element::map, response->getType());
- EXPECT_EQ(2, response->size());
- ConstElementPtr result = response->get("result");
- ASSERT_TRUE(result);
- ASSERT_EQ(Element::integer, result->getType());
- EXPECT_EQ(0, result->intValue());
- ConstElementPtr arguments = response->get("arguments");
- ASSERT_EQ(Element::map, arguments->getType());
-
- // The returned pid should be the pid of our process.
- auto found_pid = arguments->get("pid");
- ASSERT_TRUE(found_pid);
- EXPECT_EQ(static_cast<int64_t>(getpid()), found_pid->intValue());
-
- // It is hard to check the actual uptime (and reload) as it is based
- // on current time. Let's just make sure it is within a reasonable
- // range.
- auto found_uptime = arguments->get("uptime");
- ASSERT_TRUE(found_uptime);
- EXPECT_LE(found_uptime->intValue(), 5);
- EXPECT_GE(found_uptime->intValue(), 0);
-
- auto found_reload = arguments->get("reload");
- ASSERT_TRUE(found_reload);
- EXPECT_LE(found_reload->intValue(), 5);
- EXPECT_GE(found_reload->intValue(), 0);
-}
-
-TEST_F(CtrlAgentControllerTest, shutdown) {
- ASSERT_NO_THROW(initProcess());
- EXPECT_TRUE(checkProcess());
-
- // The framework available makes it very difficult to test the actual
- // code as CtrlAgentController is not initialized the same way it is
- // in production code. In particular, the way CtrlAgentController
- // is initialized in tests does not call registerCommands().
- // This is a crude workaround for this problem. Proper solution should
- // be developed sooner rather than later.
- const DControllerBasePtr& base = getController();
- const CtrlAgentControllerPtr& ctrl
- = boost::dynamic_pointer_cast<CtrlAgentController>(base);
- ASSERT_TRUE(ctrl);
- // Now clean up after ourselves.
- ctrl->registerCommands();
-
- // This is normally set to whatever value is passed to -c when the server is
- // started, but we're not starting it that way, so need to set it by hand.
- getController()->setConfigFile("testvalid.json");
-
- // Ok, enough fooling around. Let's create a valid config.
- ofstream f("testvalid.json", ios::trunc);
- f << "{ \"Control-agent\": "
- << string(valid_agent_config)
- << " }" << endl;
- f.close();
-
- // Build and execute the command.
-
- ConstElementPtr cmd = Element::fromJSON("{ \"command\": \"shutdown\"}");
- ConstElementPtr params;
- ConstElementPtr answer;
- answer = CtrlAgentCommandMgr::instance().handleCommand("shutdown",
- params, cmd);
-
- // Verify the reload was successful.
- string expected = "{ \"result\": 0, \"text\": "
- "\"Control Agent is shutting down\" }";
-
- EXPECT_EQ(expected, answer->str());
-
- int exit_value = ctrl->getExitValue();
- EXPECT_EQ(0, exit_value);
-
- // Remove the file.
- ::remove("testvalid.json");
-
- // Now clean up after ourselves.
- ctrl->deregisterCommands();
-}
-
-TEST_F(CtrlAgentControllerTest, shutdownExitValue) {
- ASSERT_NO_THROW(initProcess());
- EXPECT_TRUE(checkProcess());
-
- // The framework available makes it very difficult to test the actual
- // code as CtrlAgentController is not initialized the same way it is
- // in production code. In particular, the way CtrlAgentController
- // is initialized in tests does not call registerCommands().
- // This is a crude workaround for this problem. Proper solution should
- // be developed sooner rather than later.
- const DControllerBasePtr& base = getController();
- const CtrlAgentControllerPtr& ctrl
- = boost::dynamic_pointer_cast<CtrlAgentController>(base);
- ASSERT_TRUE(ctrl);
- // Now clean up after ourselves.
- ctrl->registerCommands();
-
- // This is normally set to whatever value is passed to -c when the server is
- // started, but we're not starting it that way, so need to set it by hand.
- getController()->setConfigFile("testvalid.json");
-
- // Ok, enough fooling around. Let's create a valid config.
- ofstream f("testvalid.json", ios::trunc);
- f << "{ \"Control-agent\": "
- << string(valid_agent_config)
- << " }" << endl;
- f.close();
-
- // Build and execute the command.
-
- ConstElementPtr cmd = Element::fromJSON("{ \"command\": \"shutdown\"}");
- ConstElementPtr params = Element::fromJSON("{ \"exit-value\": 77 }");
- ConstElementPtr answer;
- answer = CtrlAgentCommandMgr::instance().handleCommand("shutdown",
- params, cmd);
-
- // Verify the reload was successful.
- string expected = "{ \"result\": 0, \"text\": "
- "\"Control Agent is shutting down\" }";
-
- EXPECT_EQ(expected, answer->str());
-
- int exit_value = ctrl->getExitValue();
- EXPECT_EQ(77, exit_value);
-
- // Remove the file.
- ::remove("testvalid.json");
-
- // Now clean up after ourselves.
- ctrl->deregisterCommands();
-}
-
-}
+++ /dev/null
-#!/bin/sh
-
-# Copyright (C) 2016-2025 Internet Systems Consortium, Inc. ("ISC")
-#
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-# Exit with error if commands exit with non-zero and if undefined variables are
-# used.
-set -eu
-
-# Include common test library.
-# shellcheck source=src/lib/testutils/dhcp_test_lib.sh.in
-. "@abs_top_builddir@/src/lib/testutils/dhcp_test_lib.sh"
-
-# Path to the temporary configuration file.
-CFG_FILE="@abs_top_builddir@/src/bin/agent/tests/test_config.json"
-# Path to the Control Agent log file.
-LOG_FILE="@abs_top_builddir@/src/bin/agent/tests/test.log"
-# Set env KEA_HOOKS_PATH to override DEFAULT_HOOKS_PATH
-export KEA_HOOKS_PATH="@abs_top_builddir@/src/bin/agent/tests"
-
-# Set env KEA_LOG_FILE_DIR to override default log path
-export KEA_LOG_FILE_DIR="@abs_top_builddir@/src/bin/agent/tests"
-
-# Control Agent configuration to be stored in the configuration file.
-CONFIG="{
- \"Control-agent\":
- {
- \"http-host\": \"127.0.0.1\",
- \"loggers\": [
- {
- \"name\": \"kea-ctrl-agent\",
- \"output-options\": [
- {
- \"output\": \"$LOG_FILE\"
- }
- ],
- \"severity\": \"DEBUG\"
- }
- ]
- }
-}"
-
-# Invalid configuration (syntax error) to check that Kea can check syntax.
-CONFIG_BAD_SYNTAX="{
- \"Control-agent\":
- {
- \"http-port\": BOGUS
- }
-}"
-
-# Invalid configuration (out of range port) to check that Kea can check syntax.
-CONFIG_BAD_VALUE="{
- \"Control-agent\":
- {
- \"http-port\": 80000
- }
-}"
-
-# Configuration with a password.
-CONFIG_PWD="{
- \"Control-agent\":
- {
- \"http-host\": \"127.0.0.1\",
- \"authentication\":
- {
- \"clients\": [
- {
- \"password\": \"sensitive\",
- \"user\": \"superadmin\"
- }
- ],
- \"type\": \"basic\"
- }
- }
-}"
-
-bin="kea-ctrl-agent"
-bin_path="@abs_top_builddir@/src/bin/agent"
-
-# This test verifies that syntax checking works properly. This function
-# requires 3 parameters:
-# test_name
-# config - string with a content of the config (will be written to a file)
-# expected_code - expected exit code returned by kea (0 - success, 1 - failure)
-syntax_check_test() {
- local test_name="${1}"
- local config="${2}"
- local expected_code="${3}"
-
- # Log the start of the test and print test name.
- test_start "${test_name}"
- # Create correct configuration file.
- create_config "${config}"
- # Check it
- printf 'Running command %s.\n' "\"${bin_path}/${bin} -t ${CFG_FILE}\""
- run_command \
- "${bin_path}/${bin}" -t "${CFG_FILE}"
- if [ "${EXIT_CODE}" -ne "${expected_code}" ]; then
- printf 'ERROR: expected exit code %s, got %s\n' "${expected_code}" "${EXIT_CODE}"
- clean_exit 1
- fi
- test_finish 0
-}
-
-# This test verifies that Control Agent is shut down gracefully when it
-# receives a SIGINT or SIGTERM signal.
-shutdown_test() {
- test_name=${1} # Test name
- signum=${2} # Signal number
- # Log the start of the test and print test name.
- test_start "${test_name}"
- # Create new configuration file.
- create_config "${CONFIG}"
- # Instruct Control Agent to log to the specific file.
- set_logger
- # Start Control Agent.
- start_kea "${bin_path}/${bin}"
- # Wait up to 20s for Control Agent to start.
- wait_for_kea 20
- if [ "${_WAIT_FOR_KEA}" -eq 0 ]; then
- printf "ERROR: timeout waiting for Control Agent to start.\n"
- clean_exit 1
- fi
-
- # Check if it is still running. It could have terminated (e.g. as a result
- # of configuration failure).
- get_pid "${bin}"
- if [ "${_GET_PIDS_NUM}" -ne 1 ]; then
- printf "ERROR: expected one Control Agent process to be started. Found %d processes\
- started.\n" "${_GET_PIDS_NUM}"
- clean_exit 1
- fi
-
- # Check in the log file, how many times server has been configured.
- # It should be just once on startup.
- get_reconfigs
- if [ "${_GET_RECONFIGS}" -ne 1 ]; then
- printf 'ERROR: server been configured %s time(s), but exactly 1 was expected.\n' "${_GET_RECONFIGS}"
- clean_exit 1
- else
- printf "Server successfully configured.\n"
- fi
-
- # Send signal to Control Agent (SIGTERM, SIGINT etc.)
- send_signal "${signum}" "${bin}"
-
- # Now wait for process to log that it is exiting.
- wait_for_message 10 "DCTL_SHUTDOWN" 1
- if [ "${_WAIT_FOR_MESSAGE}" -eq 0 ]; then
- printf "ERROR: Control Agent did not log shutdown.\n"
- clean_exit 1
- fi
-
- # Make sure the server is down.
- wait_for_server_down 5 "${bin}"
- assert_eq 1 "${_WAIT_FOR_SERVER_DOWN}" \
- "Expected wait_for_server_down return %d, returned %d"
-
- test_finish 0
-}
-
-server_pid_file_test "${CONFIG}" DCTL_ALREADY_RUNNING
-shutdown_test "ctrl-agent.sigterm_test" 15
-shutdown_test "ctrl-agent.sigint_test" 2
-syntax_check_test "ctrl-agent.syntax_check_success" "${CONFIG}" 0
-syntax_check_test "ctrl-agent.syntax_check_bad_syntax" "${CONFIG_BAD_SYNTAX}" 1
-syntax_check_test "ctrl-agent.syntax_check_bad_values" "${CONFIG_BAD_VALUE}" 1
-password_redact_test "ctrl-agent.password_redact_test" "${CONFIG_PWD}" 0
+++ /dev/null
-// Copyright (C) 2016-2024 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#include <config.h>
-#include <agent/ca_cfg_mgr.h>
-#include <agent/ca_process.h>
-#include <asiolink/interval_timer.h>
-#include <asiolink/io_service.h>
-#include <process/testutils/d_test_stubs.h>
-#include <boost/date_time/posix_time/posix_time.hpp>
-#include <gtest/gtest.h>
-#include <functional>
-
-using namespace boost::posix_time;
-using namespace isc;
-using namespace isc::agent;
-using namespace isc::asiolink;
-using namespace isc::process;
-
-namespace {
-
-/// @brief CtrlAgentProcess test fixture class.
-class CtrlAgentProcessTest : public CtrlAgentProcess, public ::testing::Test {
-public:
- /// @brief Constructor
- CtrlAgentProcessTest() :
- CtrlAgentProcess("agent-test",
- IOServicePtr(new isc::asiolink::IOService())) {
- CtrlAgentCfgContextPtr ctx = getCtrlAgentCfgMgr()->getCtrlAgentCfgContext();
- ctx->setHttpHost("127.0.0.1");
- ctx->setHttpPort(8081);
- }
-
- /// @brief Destructor
- virtual ~CtrlAgentProcessTest() {
- }
-
- /// @brief Callback that will invoke shutdown method.
- void genShutdownCallback() {
- shutdown(isc::data::ConstElementPtr());
- }
-};
-
-// Test construction of the CtrlAgentProcess object.
-TEST(CtrlAgentProcess, construction) {
- // Verify that the constructor will fail if given an empty
- // io service.
- IOServicePtr lcl_io_service;
- EXPECT_THROW(CtrlAgentProcess("TestProcess", lcl_io_service),
- DProcessBaseError);
-
- // Verify that the constructor succeeds with a valid io_service
- lcl_io_service.reset(new IOService());
- ASSERT_NO_THROW(CtrlAgentProcess("TestProcess", lcl_io_service));
-
- // Verify tha the configuration is accessible after construction.
- CtrlAgentProcess agent_process("TestProcess", lcl_io_service);
- CtrlAgentCfgMgrPtr cfg_mgr = agent_process.getCtrlAgentCfgMgr();
- ASSERT_TRUE(cfg_mgr);
-}
-
-// Verifies that en external call to shutdown causes the run method to
-// exit gracefully.
-TEST_F(CtrlAgentProcessTest, shutdown) {
- // Use an asiolink IntervalTimer and callback to generate the
- // shutdown invocation. (Note IntervalTimer setup is in milliseconds).
- IntervalTimer timer(getIOService());
- timer.setup(std::bind(&CtrlAgentProcessTest::genShutdownCallback, this),
- 200);
-
- // Record start time, and invoke run().
- ptime start = microsec_clock::universal_time();
- EXPECT_NO_THROW(run());
-
- // Record stop time.
- ptime stop = microsec_clock::universal_time();
-
- // Verify that duration of the run invocation is the same as the
- // timer duration. This demonstrates that the shutdown was driven
- // by an io_service event and callback.
- time_duration elapsed = stop - start;
- EXPECT_TRUE(elapsed.total_milliseconds() >= 100 &&
- elapsed.total_milliseconds() <= 400);
-
- timer.cancel();
- getIOService()->stopAndPoll();
-}
-
-}
+++ /dev/null
-// Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#include <config.h>
-#include <agent/ca_response_creator.h>
-#include <agent/ca_response_creator_factory.h>
-#include <boost/pointer_cast.hpp>
-#include <gtest/gtest.h>
-
-using namespace isc::agent;
-
-namespace {
-
-// This test verifies that create() method always returns the same
-// instance of the CtrlAgentResponseCreator object.
-TEST(CtrlAgentResponseCreatorFactory, create) {
- CtrlAgentResponseCreatorFactory factory;
-
- // Invoke twice.
- CtrlAgentResponseCreatorPtr response1;
- CtrlAgentResponseCreatorPtr response2;
- ASSERT_NO_THROW(response1 = boost::dynamic_pointer_cast<
- CtrlAgentResponseCreator>(factory.create()));
- ASSERT_NO_THROW(response2 = boost::dynamic_pointer_cast<
- CtrlAgentResponseCreator>(factory.create()));
-
- // It must always return non-null object.
- ASSERT_TRUE(response1);
- ASSERT_TRUE(response2);
-
- // And it must always return the same object.
- EXPECT_TRUE(response1 == response2);
-
-}
-
-}
+++ /dev/null
-// Copyright (C) 2017-2025 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#include <config.h>
-#include <agent/ca_controller.h>
-#include <agent/ca_process.h>
-#include <agent/ca_command_mgr.h>
-#include <agent/ca_response_creator.h>
-#include <cc/command_interpreter.h>
-#include <cryptolink/crypto_rng.h>
-#include <hooks/hooks_manager.h>
-#include <http/basic_auth_config.h>
-#include <http/post_request.h>
-#include <http/post_request_json.h>
-#include <http/response_json.h>
-#include <util/filesystem.h>
-#include <process/testutils/d_test_stubs.h>
-#include <agent/tests/test_basic_auth_libraries.h>
-#include <gtest/gtest.h>
-#include <boost/pointer_cast.hpp>
-#include <functional>
-
-using namespace isc;
-using namespace isc::agent;
-using namespace isc::config;
-using namespace isc::data;
-using namespace isc::hooks;
-using namespace isc::http;
-using namespace isc::process;
-using namespace isc::util;
-namespace ph = std::placeholders;
-
-namespace {
-
-/// @brief Test fixture class for @ref CtrlAgentResponseCreator.
-class CtrlAgentResponseCreatorTest : public DControllerTest {
-public:
-
- /// @brief Constructor.
- ///
- /// Creates instance of the response creator and uses this instance to
- /// create "empty" request. It also removes registered commands from the
- /// command manager.
- CtrlAgentResponseCreatorTest()
- : DControllerTest(CtrlAgentController::instance),
- response_creator_(),
- request_(response_creator_.createNewHttpRequest()) {
- file::PathChecker::enableEnforcement(true);
- // Deregisters commands.
- CtrlAgentCommandMgr::instance().deregisterAll();
- CtrlAgentCommandMgr::instance().
- registerCommand("foo", std::bind(&CtrlAgentResponseCreatorTest::
- fooCommandHandler,
- this, ph::_1, ph::_2));
-
- // Make sure that the request has been initialized properly.
- if (!request_) {
- ADD_FAILURE() << "CtrlAgentResponseCreator::createNewHttpRequest"
- " returns NULL!";
- }
- HttpRequest::recordBasicAuth_ = true;
- // Initialize process and cfgmgr.
- try {
- initProcess();
- static_cast<void>(getCtrlAgentCfgContext());
- } catch (const std::exception& ex) {
- ADD_FAILURE() << "Initialization failed: " << ex.what();
- }
- }
-
- /// @brief Destructor.
- ///
- /// Removes registered commands from the command manager.
- virtual ~CtrlAgentResponseCreatorTest() {
- HttpRequest::recordBasicAuth_ = false;
- CtrlAgentCommandMgr::instance().deregisterAll();
- HooksManager::prepareUnloadLibraries();
- static_cast<void>(HooksManager::unloadLibraries());
- file::PathChecker::enableEnforcement(true);
- }
-
- /// @brief Fills request context with required data to create new request.
- ///
- /// @param request Request which context should be configured.
- void setBasicContext(const HttpRequestPtr& request) {
- request->context()->method_ = "POST";
- request->context()->http_version_major_ = 1;
- request->context()->http_version_minor_ = 1;
- request->context()->uri_ = "/foo";
-
- // Content-Type
- HttpHeaderContext content_type;
- content_type.name_ = "Content-Type";
- content_type.value_ = "application/json";
- request->context()->headers_.push_back(content_type);
-
- // Content-Length
- HttpHeaderContext content_length;
- content_length.name_ = "Content-Length";
- content_length.value_ = "0";
- request->context()->headers_.push_back(content_length);
- }
-
- /// @brief Test creation of stock response.
- ///
- /// @param status_code Status code to be included in the response.
- /// @param must_contain Text that must be present in the textual
- /// representation of the generated response.
- void testStockResponse(const HttpStatusCode& status_code,
- const std::string& must_contain) {
- HttpResponsePtr response;
- ASSERT_NO_THROW(
- response = response_creator_.createStockHttpResponse(request_,
- status_code)
- );
- ASSERT_TRUE(response);
- HttpResponseJsonPtr response_json = boost::dynamic_pointer_cast<
- HttpResponseJson>(response);
- ASSERT_TRUE(response_json);
- // Make sure the response contains the string specified as argument.
- EXPECT_TRUE(response_json->toString().find(must_contain) != std::string::npos);
-
- }
-
- /// @brief Handler for the 'foo' test command.
- ///
- /// @param command_name Command name, i.e. 'foo'.
- /// @param command_arguments Command arguments (empty).
- ///
- /// @return Returns response with a single string "bar".
- ConstElementPtr fooCommandHandler(const std::string& /*command_name*/,
- const ConstElementPtr& /*command_arguments*/) {
- ElementPtr arguments = Element::createList();
- arguments->add(Element::create("bar"));
- return (createAnswer(CONTROL_RESULT_SUCCESS, arguments));
- }
-
- /// @brief Returns a pointer to the configuration context.
- CtrlAgentCfgContextPtr getCtrlAgentCfgContext() {
- CtrlAgentProcessPtr process =
- boost::dynamic_pointer_cast<CtrlAgentProcess>(getProcess());
- if (!process) {
- isc_throw(Unexpected, "no process");
- }
- CtrlAgentCfgMgrPtr cfgmgr = process->getCtrlAgentCfgMgr();
- if (!cfgmgr) {
- isc_throw(Unexpected, "no cfgmgr");
- }
- CtrlAgentCfgContextPtr ctx = cfgmgr->getCtrlAgentCfgContext();
- if (!ctx) {
- isc_throw(Unexpected, "no context");
- }
- return (ctx);
- }
-
- /// @brief Convert header vector to header map.
- static std::map<std::string, std::string>
- headers2map(std::vector<HttpHeaderContext> headers) {
- std::map<std::string, std::string> result;
- for (const auto& header : headers) {
- result[header.name_] = header.value_;
- }
- return (result);
- }
-
- /// @brief Instance of the response creator.
- CtrlAgentResponseCreator response_creator_;
-
- /// @brief Instance of the "empty" request.
- ///
- /// The context belonging to this request may be modified by the unit
- /// tests to verify various scenarios of response creation.
- HttpRequestPtr request_;
-};
-
-// This test verifies that the created "empty" request has valid type.
-TEST_F(CtrlAgentResponseCreatorTest, createNewHttpRequest) {
- // The request must be of PostHttpRequestJson type.
- PostHttpRequestJsonPtr request_json = boost::dynamic_pointer_cast<
- PostHttpRequestJson>(request_);
- ASSERT_TRUE(request_json);
-}
-
-// Test that HTTP version of stock response is set to 1.0 if the request
-// context doesn't specify any version.
-TEST_F(CtrlAgentResponseCreatorTest, createStockHttpResponseNoVersion) {
- testStockResponse(HttpStatusCode::BAD_REQUEST, "HTTP/1.0 400 Bad Request");
-}
-
-// Test that HTTP version of stock response is set to 1.0 if the request
-// version is higher than 1.1.
-TEST_F(CtrlAgentResponseCreatorTest, createStockHttpResponseHighVersion) {
- request_->context()->http_version_major_ = 2;
- testStockResponse(HttpStatusCode::REQUEST_TIMEOUT,
- "HTTP/1.0 408 Request Timeout");
-}
-
-// Test that the server responds with version 1.1 if request version is 1.1.
-TEST_F(CtrlAgentResponseCreatorTest, createStockHttpResponseCorrectVersion) {
- request_->context()->http_version_major_ = 1;
- request_->context()->http_version_minor_ = 1;
- testStockResponse(HttpStatusCode::NO_CONTENT, "HTTP/1.1 204 No Content");
-}
-
-// Test that the server responds with extra headers for an error response.
-TEST_F(CtrlAgentResponseCreatorTest, createStockHttpResponseHeaders) {
- CtrlAgentCfgContextPtr ctx = getCtrlAgentCfgContext();
- ASSERT_TRUE(ctx);
- // Add a STS header.
- CfgHttpHeader hsts("Strict-Transport-Security", "max-age=31536000");
- CfgHttpHeaders headers;
- headers.push_back(hsts);
- // Add a random header.
- CfgHttpHeader foobar("Foo", "bar");
- headers.push_back(foobar);
- ctx->setHttpHeaders(headers);
- // Set request.
- request_->context()->http_version_major_ = 1;
- request_->context()->http_version_minor_ = 1;
- const HttpStatusCode& status_code = HttpStatusCode::NO_CONTENT;
- HttpResponsePtr response;
- response = response_creator_.createStockHttpResponse(request_, status_code);
- ASSERT_TRUE(response);
- // Check that the two extra headers are in the response.
- auto got = headers2map(response->context()->headers_);
- EXPECT_EQ("max-age=31536000", got["Strict-Transport-Security"]);
- EXPECT_EQ("bar", got["Foo"]);
-}
-
-// Test successful server response when the client specifies valid command.
-TEST_F(CtrlAgentResponseCreatorTest, createDynamicHttpResponse) {
- setBasicContext(request_);
-
- // Body: "foo" command has been registered in the test fixture constructor.
- request_->context()->body_ = "{ \"command\": \"foo\" }";
-
- // All requests must be finalized before they can be processed.
- ASSERT_NO_THROW(request_->finalize());
-
- // Create response from the request.
- HttpResponsePtr response;
- ASSERT_NO_THROW(response = response_creator_.createHttpResponse(request_));
- ASSERT_TRUE(response);
-
- // Response must be convertible to HttpResponseJsonPtr.
- HttpResponseJsonPtr response_json = boost::dynamic_pointer_cast<
- HttpResponseJson>(response);
- ASSERT_TRUE(response_json);
-
- // Response must be successful.
- EXPECT_TRUE(response_json->toString().find("HTTP/1.1 200 OK") !=
- std::string::npos);
- // Response must contain JSON body with "result" of 0.
- EXPECT_TRUE(response_json->toString().find("\"result\": 0") !=
- std::string::npos);
-}
-
-// Test that the server responds with extra headers for a command response.
-TEST_F(CtrlAgentResponseCreatorTest, createDynamicHttpResponseHeaders) {
- CtrlAgentCfgContextPtr ctx = getCtrlAgentCfgContext();
- ASSERT_TRUE(ctx);
- // Add a STS header.
- CfgHttpHeader hsts("Strict-Transport-Security", "max-age=31536000");
- CfgHttpHeaders headers;
- headers.push_back(hsts);
- // Add a random header.
- CfgHttpHeader foobar("Foo", "bar");
- headers.push_back(foobar);
- ctx->setHttpHeaders(headers);
-
- // From previous test.
- setBasicContext(request_);
-
- // Body: "foo" command has been registered in the test fixture constructor.
- request_->context()->body_ = "{ \"command\": \"foo\" }";
-
- // All requests must be finalized before they can be processed.
- ASSERT_NO_THROW(request_->finalize());
-
- // Create response from the request.
- HttpResponsePtr response;
- ASSERT_NO_THROW(response = response_creator_.createHttpResponse(request_));
- ASSERT_TRUE(response);
-
- // Check that the two extra headers are in the response.
- auto got = headers2map(response->context()->headers_);
- EXPECT_EQ("max-age=31536000", got["Strict-Transport-Security"]);
- EXPECT_EQ("bar", got["Foo"]);
-}
-
-// This test verifies that Internal Server Error is returned when invalid C++
-// request type is used. This is considered an error in the server logic.
-TEST_F(CtrlAgentResponseCreatorTest, createDynamicHttpResponseInvalidType) {
- PostHttpRequestPtr request(new PostHttpRequest());
- setBasicContext(request);
-
- // Body: "list-commands" is natively supported by the command manager.
- request->context()->body_ = "{ \"command\": \"list-commands\" }";
-
- // All requests must be finalized before they can be processed.
- ASSERT_NO_THROW(request->finalize());
-
- HttpResponsePtr response;
- ASSERT_NO_THROW(response = response_creator_.createHttpResponse(request));
- ASSERT_TRUE(response);
-
- // Response must be convertible to HttpResponseJsonPtr.
- HttpResponseJsonPtr response_json = boost::dynamic_pointer_cast<
- HttpResponseJson>(response);
- ASSERT_TRUE(response_json);
-
- // Response must contain Internal Server Error status code.
- EXPECT_TRUE(response_json->toString().find("HTTP/1.1 500 Internal Server Error") !=
- std::string::npos);
-}
-
-// This test verifies that Unauthorized is returned when authentication is
-// required but not provided by request.
-TEST_F(CtrlAgentResponseCreatorTest, noAuth) {
- setBasicContext(request_);
-
- // Body: "list-commands" is natively supported by the command manager.
- request_->context()->body_ = "{ \"command\": \"list-commands\" }";
-
- // All requests must be finalized before they can be processed.
- ASSERT_NO_THROW(request_->finalize());
-
- // Require authentication.
- CtrlAgentCfgContextPtr ctx = getCtrlAgentCfgContext();
- ASSERT_TRUE(ctx);
- BasicHttpAuthConfigPtr auth(new BasicHttpAuthConfig());
- ASSERT_NO_THROW(ctx->setAuthConfig(auth));
- auth->setRealm("ISC.ORG");
- auth->add("foo", "", "bar", "");
-
- HttpResponsePtr response;
- ASSERT_NO_THROW(response = response_creator_.createHttpResponse(request_));
- EXPECT_TRUE(request_->getBasicAuth().empty());
- ASSERT_TRUE(response);
-
- // Response must be convertible to HttpResponseJsonPtr.
- HttpResponseJsonPtr response_json = boost::dynamic_pointer_cast<
- HttpResponseJson>(response);
- ASSERT_TRUE(response_json);
-
- // Response must contain Unauthorized status code.
- std::string expected = "HTTP/1.1 401 Unauthorized";
- EXPECT_TRUE(response_json->toString().find(expected) != std::string::npos);
- // Reponse should contain WWW-Authenticate header with configured realm.
- expected = "WWW-Authenticate: Basic realm=\"ISC.ORG\"";
- EXPECT_TRUE(response_json->toString().find(expected) != std::string::npos);
-}
-
-// Test that the server responds with extra headers for no auth response.
-TEST_F(CtrlAgentResponseCreatorTest, noAuthHeader) {
- setBasicContext(request_);
-
- // Body: "list-commands" is natively supported by the command manager.
- request_->context()->body_ = "{ \"command\": \"list-commands\" }";
-
- // All requests must be finalized before they can be processed.
- ASSERT_NO_THROW(request_->finalize());
-
- // Require authentication.
- CtrlAgentCfgContextPtr ctx = getCtrlAgentCfgContext();
- ASSERT_TRUE(ctx);
- BasicHttpAuthConfigPtr auth(new BasicHttpAuthConfig());
- ASSERT_NO_THROW(ctx->setAuthConfig(auth));
- auth->setRealm("ISC.ORG");
- auth->add("foo", "", "bar", "");
-
- // Add a STS header.
- CfgHttpHeader hsts("Strict-Transport-Security", "max-age=31536000");
- CfgHttpHeaders headers;
- headers.push_back(hsts);
- // Add a random header.
- CfgHttpHeader foobar("Foo", "bar");
- headers.push_back(foobar);
- ctx->setHttpHeaders(headers);
-
- HttpResponsePtr response;
- ASSERT_NO_THROW(response = response_creator_.createHttpResponse(request_));
- EXPECT_TRUE(request_->getBasicAuth().empty());
- ASSERT_TRUE(response);
-
- // Check that the two extra headers are in the response.
- auto got = headers2map(response->context()->headers_);
- EXPECT_EQ("max-age=31536000", got["Strict-Transport-Security"]);
- EXPECT_EQ("bar", got["Foo"]);
-}
-
-// Test successful server response when the client is authenticated.
-TEST_F(CtrlAgentResponseCreatorTest, basicAuth) {
- setBasicContext(request_);
-
- // Body: "list-commands" is natively supported by the command manager.
- request_->context()->body_ = "{ \"command\": \"list-commands\" }";
-
- // Add basic HTTP authentication header.
- const BasicHttpAuth& basic_auth = BasicHttpAuth("foo", "bar");
- const BasicAuthHttpHeaderContext& basic_auth_header =
- BasicAuthHttpHeaderContext(basic_auth);
- request_->context()->headers_.push_back(basic_auth_header);
-
- // All requests must be finalized before they can be processed.
- ASSERT_NO_THROW(request_->finalize());
-
- // Require authentication.
- CtrlAgentCfgContextPtr ctx = getCtrlAgentCfgContext();
- ASSERT_TRUE(ctx);
- BasicHttpAuthConfigPtr auth(new BasicHttpAuthConfig());
- ASSERT_NO_THROW(ctx->setAuthConfig(auth));
- // In fact the realm is used only on errors... set it anyway.
- auth->setRealm("ISC.ORG");
- auth->add("foo", "", "bar", "");
-
- HttpResponsePtr response;
- ASSERT_NO_THROW(response = response_creator_.createHttpResponse(request_));
- EXPECT_EQ("foo", request_->getBasicAuth());
- ASSERT_TRUE(response);
-
- // Response must be convertible to HttpResponseJsonPtr.
- HttpResponseJsonPtr response_json = boost::dynamic_pointer_cast<
- HttpResponseJson>(response);
- ASSERT_TRUE(response_json);
-
- // Response must be successful.
- EXPECT_TRUE(response_json->toString().find("HTTP/1.1 200 OK") !=
- std::string::npos);
- // Response must contain JSON body with "result" of 0.
- EXPECT_TRUE(response_json->toString().find("\"result\": 0") !=
- std::string::npos);
-}
-
-// This test verifies that Unauthorized is returned when authentication is
-// required but not provided by request using the hook.
-TEST_F(CtrlAgentResponseCreatorTest, hookNoAuth) {
- setBasicContext(request_);
- file::PathChecker::enableEnforcement(false);
-
- // Body: "list-commands" is natively supported by the command manager.
- // We add a random value in the extra entry: see next unit test
- // for an explanation about how it is used.
- auto r32 = isc::cryptolink::random(4);
- ASSERT_EQ(4, r32.size());
- int extra = r32[0];
- extra = (extra << 8) | r32[1];
- extra = (extra << 8) | r32[2];
- extra = (extra << 8) | r32[3];
- request_->context()->body_ = "{ \"command\": \"list-commands\", ";
- request_->context()->body_ += "\"extra\": " + std::to_string(extra) + " }";
-
- // All requests must be finalized before they can be processed.
- ASSERT_NO_THROW(request_->finalize());
-
- // Setup hook.
- CtrlAgentCfgContextPtr ctx = getCtrlAgentCfgContext();
- ASSERT_TRUE(ctx);
- HooksConfig& hooks_cfg = ctx->getHooksConfig();
- std::string auth_cfg = "{ \"config\": {\n"
- "\"type\": \"basic\",\n"
- "\"realm\": \"ISC.ORG\",\n"
- "\"clients\": [{\n"
- " \"user\": \"foo\",\n"
- " \"password\": \"bar\"\n"
- " }]}}";
- ConstElementPtr auth_json;
- ASSERT_NO_THROW(auth_json = Element::fromJSON(auth_cfg));
- hooks_cfg.add(std::string(BASIC_AUTH_LIBRARY), auth_json);
- ASSERT_NO_THROW(hooks_cfg.loadLibraries(false));
-
- HttpResponsePtr response;
- ASSERT_NO_THROW(response = response_creator_.createHttpResponse(request_));
- EXPECT_TRUE(request_->getBasicAuth().empty());
- ASSERT_TRUE(response);
-
- // Request should have no extra.
- EXPECT_EQ("{ \"command\": \"list-commands\" }",
- request_->context()->body_);
-
- // Response must be convertible to HttpResponseJsonPtr.
- HttpResponseJsonPtr response_json = boost::dynamic_pointer_cast<
- HttpResponseJson>(response);
- ASSERT_TRUE(response_json);
-
- // Response must contain Unauthorized status code.
- std::string expected = "HTTP/1.1 401 Unauthorized";
- EXPECT_TRUE(response_json->toString().find(expected) != std::string::npos);
- // Reponse should contain WWW-Authenticate header with configured realm.
- expected = "WWW-Authenticate: Basic realm=\"ISC.ORG\"";
- EXPECT_TRUE(response_json->toString().find(expected) != std::string::npos);
-}
-
-// This test verifies that the server responds with extra headers for no
-// auth response provided by the hook.
-TEST_F(CtrlAgentResponseCreatorTest, hookNoAuthHeaders) {
- setBasicContext(request_);
- file::PathChecker::enableEnforcement(false);
-
- // Body: "list-commands" is natively supported by the command manager.
- // We add a random value in the extra entry: see next unit test
- // for an explanation about how it is used.
- auto r32 = isc::cryptolink::random(4);
- ASSERT_EQ(4, r32.size());
- int extra = r32[0];
- extra = (extra << 8) | r32[1];
- extra = (extra << 8) | r32[2];
- extra = (extra << 8) | r32[3];
- request_->context()->body_ = "{ \"command\": \"list-commands\", ";
- request_->context()->body_ += "\"extra\": " + std::to_string(extra) + " }";
-
- // All requests must be finalized before they can be processed.
- ASSERT_NO_THROW(request_->finalize());
-
- // Setup hook.
- CtrlAgentCfgContextPtr ctx = getCtrlAgentCfgContext();
- ASSERT_TRUE(ctx);
- HooksConfig& hooks_cfg = ctx->getHooksConfig();
- std::string auth_cfg = "{ \"config\": {\n"
- "\"type\": \"basic\",\n"
- "\"realm\": \"ISC.ORG\",\n"
- "\"clients\": [{\n"
- " \"user\": \"foo\",\n"
- " \"password\": \"bar\"\n"
- " }]}}";
- ConstElementPtr auth_json;
- ASSERT_NO_THROW(auth_json = Element::fromJSON(auth_cfg));
- hooks_cfg.add(std::string(BASIC_AUTH_LIBRARY), auth_json);
- ASSERT_NO_THROW(hooks_cfg.loadLibraries(false));
-
- // Add a STS header.
- CfgHttpHeader hsts("Strict-Transport-Security", "max-age=31536000");
- CfgHttpHeaders headers;
- headers.push_back(hsts);
- // Add a random header.
- CfgHttpHeader foobar("Foo", "bar");
- headers.push_back(foobar);
- ctx->setHttpHeaders(headers);
-
- HttpResponsePtr response;
- ASSERT_NO_THROW(response = response_creator_.createHttpResponse(request_));
- EXPECT_TRUE(request_->getBasicAuth().empty());
- ASSERT_TRUE(response);
-
- // Check that the two extra headers are in the response.
- auto got = headers2map(response->context()->headers_);
- EXPECT_EQ("max-age=31536000", got["Strict-Transport-Security"]);
- EXPECT_EQ("bar", got["Foo"]);
-}
-
-// Test successful server response when the client is authenticated.
-TEST_F(CtrlAgentResponseCreatorTest, hookBasicAuth) {
- setBasicContext(request_);
- file::PathChecker::enableEnforcement(false);
-
- // Body: "list-commands" is natively supported by the command manager.
- // We add a random value in the extra entry:
- // - this proves that the http_auth callout can get the request argument
- // - this proves that the http_auth callout can modify the request
- // argument before the request is executed (the extra entry
- // if still present would make the command to be rejected as malformed)
- // - this proves that a value can be communicate between the http_auth
- // and http_response callout points
- // - this proves that the http_response callout can get the
- // response argument
- // - this proves that the http_response callout can modify the
- // response argument
- auto r32 = isc::cryptolink::random(4);
- ASSERT_EQ(4, r32.size());
- int extra = r32[0];
- extra = (extra << 8) | r32[1];
- extra = (extra << 8) | r32[2];
- extra = (extra << 8) | r32[3];
- if (extra == 0) {
- extra = 1;
- }
- std::string extra_str = std::to_string(extra);
- request_->context()->body_ = "{ \"command\": \"list-commands\", ";
- request_->context()->body_ += "\"extra\": " + extra_str + " }";
-
- // Add basic HTTP authentication header.
- const BasicHttpAuth& basic_auth = BasicHttpAuth("foo", "bar");
- const BasicAuthHttpHeaderContext& basic_auth_header =
- BasicAuthHttpHeaderContext(basic_auth);
- request_->context()->headers_.push_back(basic_auth_header);
-
- // All requests must be finalized before they can be processed.
- ASSERT_NO_THROW(request_->finalize());
-
- // Setup hook.
- CtrlAgentCfgContextPtr ctx = getCtrlAgentCfgContext();
- ASSERT_TRUE(ctx);
- HooksConfig& hooks_cfg = ctx->getHooksConfig();
- std::string auth_cfg = "{ \"config\": {\n"
- "\"type\": \"basic\",\n"
- "\"realm\": \"ISC.ORG\",\n"
- "\"clients\": [{\n"
- " \"user\": \"foo\",\n"
- " \"password\": \"bar\"\n"
- " }]}}";
- ConstElementPtr auth_json;
- ASSERT_NO_THROW(auth_json = Element::fromJSON(auth_cfg));
- hooks_cfg.add(std::string(BASIC_AUTH_LIBRARY), auth_json);
- ASSERT_NO_THROW(hooks_cfg.loadLibraries(false));
-
- HttpResponsePtr response;
- ASSERT_NO_THROW(response = response_creator_.createHttpResponse(request_));
- EXPECT_EQ("foo", request_->getBasicAuth());
- ASSERT_TRUE(response);
-
- // Request should have no extra.
- EXPECT_EQ("{ \"command\": \"list-commands\" }",
- request_->context()->body_);
-
- // Response must be convertible to HttpResponseJsonPtr.
- HttpResponseJsonPtr response_json = boost::dynamic_pointer_cast<
- HttpResponseJson>(response);
- ASSERT_TRUE(response_json);
-
- // Response must be successful.
- EXPECT_TRUE(response_json->toString().find("HTTP/1.1 200 OK") !=
- std::string::npos);
- // Response must contain JSON body with "result" of 0.
- EXPECT_TRUE(response_json->toString().find("\"result\": 0") !=
- std::string::npos);
- // Response must contain JSON body with "comment": "got".
- std::string expected = "\"got\": " + extra_str + ", ";
- EXPECT_TRUE(response_json->toString().find(expected) !=
- std::string::npos);
-}
-
-}
+++ /dev/null
-// Copyright (C) 2016-2026 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#include <config.h>
-
-#include <cstdlib>
-
-#include <log/logger_support.h>
-#include <gtest/gtest.h>
-
-int
-main(int argc, char* argv[]) {
-
- ::testing::InitGoogleTest(&argc, argv);
-
- // See the documentation of the KEA_* environment variables in
- // the developer's guide for info on how to tweak logging
- isc::log::initLogger();
-
- // Override --localstatedir value for PID files
- setenv("KEA_PIDFILE_DIR", TEST_DATA_BUILDDIR, 1);
-
- int result = RUN_ALL_TESTS();
-
- return (result);
-}
+++ /dev/null
-// Copyright (C) 2017-2020 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-/// @file
-/// @brief Basic callout library
-///
-/// This is source of a test library for Control Agent.
-///
-/// - Only the "version" framework function is supplied.
-///
-/// - hookpt_one callout is supplied.
-
-#include <config.h>
-#include <hooks/hooks.h>
-
-using namespace isc::hooks;
-using namespace std;
-
-namespace {
-
-extern "C" {
-
-// Callouts. All return their result through the "result" argument.
-
-int
-context_create(CalloutHandle& handle) {
- handle.setContext("result", static_cast<int>(10));
- handle.setArgument("result", static_cast<int>(10));
- return (0);
-}
-
-// First callout adds the passed "integer" argument to the initialized context
-// value of 10. (Note that the value set by context_create is accessed through
-// context and not the argument, so checking that context is correctly passed
-// between callouts in the same library.)
-
-int
-hookpt_one(CalloutHandle& handle) {
- int data;
- handle.getArgument("integer", data);
-
- int result;
- handle.getArgument("result", result);
-
- result += data;
- handle.setArgument("result", result);
-
- return (0);
-}
-
-// Framework functions.
-
-int
-version() {
- return (KEA_HOOKS_VERSION);
-}
-
-// load() initializes the user library if the main image was statically linked.
-int
-load(isc::hooks::LibraryHandle&) {
-#ifdef USE_STATIC_LINK
- hooksStaticLinkInit();
-#endif
- return (0);
-}
-
-}
-}
-
+++ /dev/null
-// Copyright (C) 2017-2025 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#include <config.h>
-
-#include <cc/data.h>
-#include <cc/command_interpreter.h>
-#include <config/unix_command_config.h>
-#include <testutils/user_context_utils.h>
-#include <process/redact_config.h>
-#include <process/testutils/d_test_stubs.h>
-#include <agent/ca_cfg_mgr.h>
-#include <agent/parser_context.h>
-#include <hooks/hooks_parser.h>
-#include <util/filesystem.h>
-#include <boost/scoped_ptr.hpp>
-#include <gtest/gtest.h>
-
-#include <iostream>
-#include <fstream>
-#include <string>
-#include <sstream>
-
-#include "test_data_files_config.h"
-#include "test_callout_libraries.h"
-
-using namespace isc::agent;
-using namespace isc::config;
-using namespace isc::data;
-using namespace isc::process;
-using namespace isc::test;
-using namespace isc::hooks;
-using namespace isc::config;
-using namespace isc::util;
-
-namespace {
-
-/// @name How to generate the testdata/get_config.json file
-///
-/// Define GENERATE_ACTION and recompile. Run ca_unittests on
-/// CtrlAgentGetCfgTest redirecting the standard error to a temporary
-/// file, e.g. by
-/// @code
-/// ./ca_unittests --gtest_filter="CtrlAgentGetCfg*" > /dev/null 2> u
-/// @endcode
-///
-/// Update testdata/get_config.json using the temporary file content,
-/// (removing head comment and restoring hook library path),
-/// recompile without GENERATE_ACTION.
-
-/// @brief the generate action
-/// false means do nothing, true means unparse extracted configurations
-#ifdef GENERATE_ACTION
-const bool generate_action = true;
-#else
-const bool generate_action = false;
-#endif
-
-/// @brief Read a file into a string
-std::string
-readFile(const std::string& file_path) {
- std::ifstream ifs(file_path);
- if (!ifs.is_open()) {
- ADD_FAILURE() << "readFile cannot open " << file_path;
- isc_throw(isc::Unexpected, "readFile cannot open " << file_path);
- }
- std::string lines;
- std::string line;
- while (std::getline(ifs, line)) {
- lines += line + "\n";
- }
- ifs.close();
- return (lines);
-}
-
-/// @brief Runs parser in JSON mode
-ElementPtr
-parseJSON(const std::string& in, bool verbose = false) {
- try {
- ParserContext ctx;
- return (ctx.parseString(in, ParserContext::PARSER_JSON));
- } catch (const std::exception& ex) {
- if (verbose) {
- std::cout << "EXCEPTION: " << ex.what() << std::endl;
- }
- throw;
- }
-}
-
-/// @brief Runs parser in AGENT mode
-ElementPtr
-parseAGENT(const std::string& in, bool verbose = false) {
- try {
- ParserContext ctx;
- return (ctx.parseString(in, ParserContext::PARSER_AGENT));
- } catch (const std::exception& ex) {
- if (verbose) {
- std::cout << "EXCEPTION: " << ex.what() << std::endl;
- }
- throw;
- }
-}
-
-/// @brief Replace the library path
-void
-pathReplacer(ConstElementPtr ca_cfg) {
- ConstElementPtr hooks_libs = ca_cfg->get("hooks-libraries");
- if (!hooks_libs || hooks_libs->empty()) {
- return;
- }
- ElementPtr first_lib = hooks_libs->getNonConst(0);
- std::string lib_path(CALLOUT_LIBRARY);
- first_lib->set("library", Element::create(lib_path));
-}
-
-/// @brief Replace the credential directory
-void
-dirReplacer(ConstElementPtr ca_cfg) {
- ConstElementPtr auth = ca_cfg->get("authentication");
- if (!auth || auth->empty()) {
- return;
- }
- ElementPtr mutable_auth = boost::const_pointer_cast<Element>(auth);
- std::string dir_path(CA_TEST_DATA_DIR);
- mutable_auth->set("directory", Element::create(dir_path));
-}
-
-/// @brief Almost regular agent CfgMgr with internal parse method exposed.
-class NakedAgentCfgMgr : public CtrlAgentCfgMgr {
-public:
- using CtrlAgentCfgMgr::parse;
-};
-
-}
-
-/// Test fixture class
-class CtrlAgentGetCfgTest : public ConfigParseTest {
-public:
- CtrlAgentGetCfgTest()
- : rcode_(-1) {
- resetHooksPath();
- srv_.reset(new NakedAgentCfgMgr());
- // Create fresh context.
- resetConfiguration();
- setSocketTestPath();
- file::PathChecker::enableEnforcement(true);
- }
-
- ~CtrlAgentGetCfgTest() {
- resetConfiguration();
- resetHooksPath();
- resetSocketPath();
- file::PathChecker::enableEnforcement(true);
- }
-
- /// @brief Sets the Hooks path from which hooks can be loaded.
- /// @param explicit_path path to use as the hooks path.
- void setHooksTestPath(const std::string explicit_path = "") {
- HooksLibrariesParser::getHooksPath(true,
- (!explicit_path.empty() ?
- explicit_path : CA_HOOKS_TEST_PATH));
- }
-
- /// @brief Resets the hooks path to DEFAULT_HOOKS_PATH.
- void resetHooksPath() {
- HooksLibrariesParser::getHooksPath(true);
- }
-
- /// @brief Sets the path in which the socket can be created.
- /// @param explicit_path path to use as the socket path.
- void setSocketTestPath(const std::string explicit_path = "") {
- auto path = UnixCommandConfig::getSocketPath(true, (!explicit_path.empty() ?
- explicit_path : TEST_DATA_BUILDDIR));
- UnixCommandConfig::setSocketPathPerms(file::getPermissions(path));
- }
-
- /// @brief Resets the socket path to the default.
- void resetSocketPath() {
- UnixCommandConfig::getSocketPath(true);
- UnixCommandConfig::setSocketPathPerms();
- }
-
- /// @brief Parse and Execute configuration
- ///
- /// Parses a configuration and executes a configuration of the server.
- /// If the operation fails, the current test will register a failure.
- ///
- /// @param config Configuration to parse
- /// @param operation Operation being performed. In the case of an error,
- /// the error text will include the string "unable to <operation>.".
- ///
- /// @return true if the configuration succeeded, false if not.
- bool
- executeConfiguration(const std::string& config, const char* operation) {
- // try JSON parser
- ConstElementPtr json;
- try {
- json = parseJSON(config, true);
- } catch (const std::exception& ex) {
- ADD_FAILURE() << "invalid JSON for " << operation
- << " failed with " << ex.what()
- << " on\n" << config << "\n";
- return (false);
- }
-
- // try AGENT parser
- try {
- json = parseAGENT(config, true);
- } catch (...) {
- ADD_FAILURE() << "parsing failed for " << operation
- << " on\n" << prettyPrint(json) << "\n";
- return (false);
- }
-
- // get Control-agent element
- ConstElementPtr ca = json->get("Control-agent");
- if (!ca) {
- ADD_FAILURE() << "cannot get Control-agent for " << operation
- << " on\n" << prettyPrint(json) << "\n";
- return (false);
- }
-
- // update hooks-libraries
- pathReplacer(ca);
-
- // update authentication directory
- dirReplacer(ca);
-
- // redact passwords
- ca = redactConfig(ca, { "*" }, "-----");
-
- // try AGENT configure
- ConstElementPtr status;
- try {
- status = srv_->parse(ca, true);
- } catch (const std::exception& ex) {
- ADD_FAILURE() << "configure for " << operation
- << " failed with " << ex.what()
- << " on\n" << prettyPrint(json) << "\n";
- return (false);
- }
-
- // The status object must not be NULL
- if (!status) {
- ADD_FAILURE() << "configure for " << operation
- << " returned null on\n"
- << prettyPrint(json) << "\n";
- return (false);
- }
-
- // Returned value should be 0 (configuration success)
- comment_ = parseAnswer(rcode_, status);
- if (rcode_ != 0) {
- string reason = "";
- if (comment_) {
- reason = string(" (") + comment_->stringValue() + string(")");
- }
- ADD_FAILURE() << "configure for " << operation
- << " returned error code "
- << rcode_ << reason << " on\n"
- << prettyPrint(json) << "\n";
- return (false);
- }
- return (true);
- }
-
- /// @brief Reset configuration database.
- ///
- /// This function resets configuration data base by
- /// removing control sockets and hooks. Reset must
- /// be performed after each test to make sure that
- /// contents of the database do not affect result of
- /// subsequent tests.
- void resetConfiguration() {
- string config = "{ \"Control-agent\": {"
- " \"http-host\": \"\","
- " \"http-port\": 0 } }";
- EXPECT_TRUE(executeConfiguration(config, "reset config"));
- }
-
- boost::scoped_ptr<NakedAgentCfgMgr> srv_; ///< CA server under test
- int rcode_; ///< Return code from element parsing
- ConstElementPtr comment_; ///< Reason for parse fail
-};
-
-/// Test a configuration
-TEST_F(CtrlAgentGetCfgTest, simple) {
- setHooksTestPath();
- file::PathChecker::enableEnforcement(false);
-
- // get the simple configuration
- std::string simple_file = string(CFG_EXAMPLES) + "/" + "simple.json";
- std::string config;
- ASSERT_NO_THROW(config = readFile(simple_file));
-
- // get the expected configuration
- std::string expected_file =
- std::string(CA_TEST_DATA_DIR) + "/" + "get_config.json";
- std::string expected;
- ASSERT_NO_THROW(expected = readFile(expected_file));
-
- // execute the sample configuration
- ASSERT_TRUE(executeConfiguration(config, "simple config"));
-
- // unparse it
- CtrlAgentCfgContextPtr context = srv_->getCtrlAgentCfgContext();
- ConstElementPtr unparsed;
- ASSERT_NO_THROW(unparsed = context->toElement());
-
- // dump if wanted else check
- if (generate_action) {
- std::cerr << "// Generated Configuration (remove this line)\n";
- ASSERT_NO_THROW(expected = prettyPrint(unparsed));
- prettyPrint(unparsed, std::cerr, 0, 4);
- std::cerr << "\n";
- } else {
- // get the expected config using the agent syntax parser
- ElementPtr jsond;
- ASSERT_NO_THROW(jsond = parseAGENT(expected, true));
- // get the expected config using the generic JSON syntax parser
- ElementPtr jsonj;
- ASSERT_NO_THROW(jsonj = parseJSON(expected));
- // the generic JSON parser does not handle comments
- EXPECT_TRUE(isEquivalent(jsond, moveComments(jsonj)));
- // replace the paths by their actual values
- ConstElementPtr ca;
- ASSERT_NO_THROW(ca = jsonj->get("Control-agent"));
- ASSERT_TRUE(ca);
- pathReplacer(ca);
- dirReplacer(ca);
- // check that unparsed and updated expected values match
- EXPECT_TRUE(isEquivalent(unparsed, jsonj));
- // check on pretty prints too
- std::string current = prettyPrint(unparsed, 0, 4);
- std::string expected2 = prettyPrint(jsonj, 0, 4);
- EXPECT_EQ(expected2, current);
- if (expected2 != current) {
- expected = current + "\n";
- }
- }
-
- // execute the control agent configuration
- EXPECT_TRUE(executeConfiguration(expected, "unparsed config"));
-
- // is it a fixed point?
- CtrlAgentCfgContextPtr context2 = srv_->getCtrlAgentCfgContext();
- ConstElementPtr unparsed2;
- ASSERT_NO_THROW(unparsed2 = context2->toElement());
- ASSERT_TRUE(unparsed2);
- EXPECT_TRUE(isEquivalent(unparsed, unparsed2));
-}
+++ /dev/null
-if not TESTS_OPT.enabled()
- subdir_done()
-endif
-
-current_build_dir = meson.current_build_dir()
-kea_agent_tests_data = configuration_data()
-kea_agent_tests_data.set('abs_top_builddir', TOP_BUILD_DIR)
-kea_agent_tests_data.set('abs_top_srcdir', TOP_SOURCE_DIR)
-kea_agent_tests_data.set('abs_builddir', current_build_dir)
-ca_process_tests = configure_file(
- input: 'ca_process_tests.sh.in',
- output: 'ca_process_tests.sh',
- configuration: kea_agent_tests_data,
-)
-test(
- 'ca_process_tests.sh',
- ca_process_tests,
- workdir: current_build_dir,
- is_parallel: false,
- priority: -1,
- suite: 'shell-tests',
-)
-configure_file(
- input: 'test_basic_auth_libraries.h.in',
- output: 'test_basic_auth_libraries.h',
- configuration: kea_agent_tests_data,
-)
-configure_file(
- input: 'test_callout_libraries.h.in',
- output: 'test_callout_libraries.h',
- configuration: kea_agent_tests_data,
-)
-configure_file(
- input: 'test_data_files_config.h.in',
- output: 'test_data_files_config.h',
- configuration: kea_agent_tests_data,
-)
-
-callout = shared_library(
- 'callout',
- 'callout_library.cc',
- include_directories: [include_directories('.')] + INCLUDES,
- link_with: LIBS_BUILT_SO_FAR,
- build_rpath: '/nowhere',
- name_suffix: 'so',
-)
-basic_auth = shared_library(
- 'basicauth',
- 'basic_auth_library.cc',
- include_directories: [include_directories('.')] + INCLUDES,
- link_with: LIBS_BUILT_SO_FAR,
- build_rpath: '/nowhere',
- name_suffix: 'so',
-)
-
-current_source_dir = meson.current_source_dir()
-kea_agent_tests_libs = [
- kea_process_testutils_lib,
- kea_testutils_lib,
- kea_asiolink_testutils_lib,
-]
-kea_agent_tests = executable(
- 'kea-agent-tests',
- 'ca_cfg_mgr_unittests.cc',
- 'ca_command_mgr_unittests.cc',
- 'ca_controller_unittests.cc',
- 'ca_process_unittests.cc',
- 'ca_response_creator_factory_unittests.cc',
- 'ca_response_creator_unittests.cc',
- 'ca_unittests.cc',
- 'get_config_unittest.cc',
- 'parser_unittests.cc',
- cpp_args: [
- f'-DTEST_DATA_BUILDDIR="@current_build_dir@"',
- f'-DCFG_EXAMPLES="@TOP_SOURCE_DIR@/doc/examples/agent"',
- f'-DSYNTAX_FILE="@current_source_dir@/../agent_parser.yy"',
- f'-DTEST_CA_DIR="@TEST_CA_DIR@"',
- ],
- dependencies: [GTEST_DEP, CRYPTO_DEP],
- include_directories: [include_directories('.')] + INCLUDES,
- link_with: [agent_lib] + kea_agent_tests_libs + LIBS_BUILT_SO_FAR,
-)
-test(
- 'kea-agent-tests',
- kea_agent_tests,
- depends: [callout, basic_auth],
- protocol: 'gtest',
- is_parallel: false,
- priority: -1,
-)
+++ /dev/null
-// Copyright (C) 2017-2025 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#include <config.h>
-
-#include <agent/parser_context.h>
-#include <cc/data.h>
-#include <cc/dhcp_config_error.h>
-#include <testutils/io_utils.h>
-#include <testutils/log_utils.h>
-#include <testutils/test_to_element.h>
-#include <testutils/user_context_utils.h>
-
-#include <gtest/gtest.h>
-
-#include <fstream>
-#include <set>
-
-#include <boost/algorithm/string.hpp>
-
-using namespace isc::data;
-using namespace isc::test;
-using namespace std;
-
-namespace isc {
-namespace agent {
-namespace test {
-
-/// @brief compares two JSON trees
-///
-/// If differences are discovered, gtest failure is reported (using EXPECT_EQ)
-///
-/// @param a first to be compared
-/// @param b second to be compared
-void compareJSON(ConstElementPtr a, ConstElementPtr b) {
- expectEqWithDiff(a, b);
-}
-
-/// @brief Tests if the input string can be parsed with specific parser
-///
-/// The input text will be passed to bison parser of specified type.
-/// Then the same input text is passed to legacy JSON parser and outputs
-/// from both parsers are compared. The legacy comparison can be disabled,
-/// if the feature tested is not supported by the old parser (e.g.
-/// new comment styles)
-///
-/// @param txt text to be compared
-/// @param parser_type bison parser type to be instantiated
-/// @param compare whether to compare the output with legacy JSON parser
-void testParser(const std::string& txt, ParserContext::ParserType parser_type,
- bool compare = true) {
- SCOPED_TRACE("\n=== tested config ===\n" + txt + "=====================");
-
- ConstElementPtr test_json;
- ASSERT_NO_THROW({
- try {
- ParserContext ctx;
- test_json = ctx.parseString(txt, parser_type);
- } catch (const std::exception &e) {
- cout << "EXCEPTION: " << e.what() << endl;
- throw;
- }
-
- });
-
- if (!compare) {
- return;
- }
-
- // Now compare if both representations are the same.
- ElementPtr reference_json;
- ASSERT_NO_THROW(reference_json = Element::fromJSON(txt, true));
- compareJSON(reference_json, test_json);
-}
-
-TEST(ParserTest, mapInMap) {
- string txt = "{ \"xyzzy\": { \"foo\": 123, \"baz\": 456 } }";
- testParser(txt, ParserContext::PARSER_JSON);
-}
-
-TEST(ParserTest, listInList) {
- string txt = "[ [ \"Britain\", \"Wales\", \"Scotland\" ], "
- "[ \"Pomorze\", \"Wielkopolska\", \"Tatry\"] ]";
- testParser(txt, ParserContext::PARSER_JSON);
-}
-
-TEST(ParserTest, nestedMaps) {
- string txt = "{ \"europe\": { \"UK\": { \"London\": { \"street\": \"221B Baker\" }}}}";
- testParser(txt, ParserContext::PARSER_JSON);
-}
-
-TEST(ParserTest, nestedLists) {
- string txt = "[ \"half\", [ \"quarter\", [ \"eighth\", [ \"sixteenth\" ]]]]";
- testParser(txt, ParserContext::PARSER_JSON);
-}
-
-TEST(ParserTest, listsInMaps) {
- string txt = "{ \"constellations\": { \"orion\": [ \"rigel\", \"betelgeuse\" ], "
- "\"cygnus\": [ \"deneb\", \"albireo\"] } }";
- testParser(txt, ParserContext::PARSER_JSON);
-}
-
-TEST(ParserTest, mapsInLists) {
- string txt = "[ { \"body\": \"earth\", \"gravity\": 1.0 }, "
- "{ \"body\": \"mars\", \"gravity\": 0.376 } ]";
- testParser(txt, ParserContext::PARSER_JSON);
-}
-
-TEST(ParserTest, types) {
- string txt = "{ \"string\": \"foo\", "
- "\"integer\": 42, "
- "\"boolean\": true, "
- "\"map\": { \"foo\": \"bar\" }, "
- "\"list\": [ 1, 2, 3 ], "
- "\"null\": null }";
- testParser(txt, ParserContext::PARSER_JSON);
-}
-
-TEST(ParserTest, keywordJSON) {
- string txt = "{ \"name\": \"user\", "
- "\"type\": \"password\", "
- "\"user\": \"name\", "
- "\"password\": \"type\" }";
- testParser(txt, ParserContext::PARSER_JSON);
-}
-
-// This test checks if full config (with top level and Control-agent objects) can
-// be parsed with syntactic checking (and as pure JSON).
-TEST(ParserTest, keywordAgent) {
- string txt = "{ \"Control-agent\": {\n"
- " \"http-host\": \"localhost\",\n"
- " \"http-port\": 8000,\n"
- " \"control-sockets\": {"
- " \"dhcp4\": {"
- " \"socket-type\": \"unix\","
- " \"socket-name\": \"kea4-ctrl-socket\""
- " },"
- " \"dhcp6\": {"
- " \"socket-type\": \"unix\","
- " \"socket-name\": \"kea6-ctrl-socket\""
- " },"
- " \"d2\": {"
- " \"socket-type\": \"unix\","
- " \"socket-name\": \"kea-ddns-ctrl-socket\""
- " }"
- " },"
- " \"hooks-libraries\": ["
- " {"
- " \"library\": \"/opt/local/control-agent-commands.so\","
- " \"parameters\": {"
- " \"param1\": \"foo\""
- " }"
- " }"
- " ]"
- "} }";
- // This is a full config, so we'll parse it as full config (PARSER_AGENT)
- testParser(txt, ParserContext::PARSER_AGENT);
- testParser(txt, ParserContext::PARSER_JSON);
-}
-
-// This test checks if simplified config (without top level and Control-agent
-// objects) can be parsed with syntactic checking (and as pure JSON).
-TEST(ParserTest, keywordSubAgent) {
-
- // This is similar to previous test, but note the lack of outer
- // map and Control-agent.
- string txt = "{\n"
- " \"http-host\": \"localhost\",\n"
- " \"http-port\": 8000,\n"
- " \"control-sockets\": {"
- " \"dhcp4\": {"
- " \"socket-type\": \"unix\","
- " \"socket-name\": \"kea4-ctrl-socket\""
- " },"
- " \"dhcp6\": {"
- " \"socket-type\": \"unix\","
- " \"socket-name\": \"kea6-ctrl-socket\""
- " },"
- " \"d2\": {"
- " \"socket-type\": \"unix\","
- " \"socket-name\": \"kea-ddns-ctrl-socket\""
- " }"
- " },"
- " \"hooks-libraries\": ["
- " {"
- " \"library\": \"/opt/local/control-agent-commands.so\","
- " \"parameters\": {"
- " \"param1\": \"foo\""
- " }"
- " }"
- " ]"
- "}";
-
- // This is only a subset of full config, so we'll parse with PARSER_SUB_AGENT.
- testParser(txt, ParserContext::PARSER_SUB_AGENT);
- testParser(txt, ParserContext::PARSER_JSON);
-}
-
-// Tests if bash (#) comments are supported. That's the only comment type that
-// was supported by the old parser.
-TEST(ParserTest, bashComments) {
- string txt = "{ \"Control-agent\": {\n"
- " \"http-host\": \"localhost\",\n"
- " \"http-port\": 9000,\n"
- " \"control-sockets\": {\n"
- " \"d2\": {\n"
- "# this is a comment\n"
- " \"socket-type\": \"unix\", \n"
- "# This socket is mine. I can name it whatever\n"
- "# I like, ok?\n"
- " \"socket-name\": \"Hector\" \n"
- "} } } }";
- testParser(txt, ParserContext::PARSER_AGENT);
-}
-
-// Tests if C++ (//) comments can start anywhere, not just in the first line.
-TEST(ParserTest, cppComments) {
- string txt = "{ \"Control-agent\": {\n"
- " \"http-host\": \"localhost\",\n"
- " \"http-port\": 9001, // the level is over 9000!\n"
- " \"control-sockets\": {\n"
- " // Let's try talking to D2. Sadly, it never talks"
- " // to us back :( Maybe he doesn't like his name?\n"
- " \"d2\": {"
- " \"socket-type\": \"unix\", \n"
- " \"socket-name\": \"Hector\" \n"
- "} } } }";
- testParser(txt, ParserContext::PARSER_AGENT, false);
-}
-
-// Tests if bash (#) comments can start anywhere, not just in the first line.
-TEST(ParserTest, bashCommentsInline) {
- string txt= "{ \"Control-agent\": {\n"
- " \"http-host\": \"localhost\",\n"
- " \"http-port\": 9000,\n"
- " \"control-sockets\": {\n"
- " \"d2\": {"
- " \"socket-type\": \"unix\", # Maybe Hector is not really a \n"
- " \"socket-name\": \"Hector\" # Unix process?\n"
- "# Oh no! He's a windows one and just pretending!\n"
- "} } } }";
- testParser(txt, ParserContext::PARSER_AGENT, false);
-}
-
-// Tests if multi-line C style comments are handled correctly.
-TEST(ParserTest, multilineComments) {
- string txt = "{ \"Control-agent\": {\n"
- " \"http-host\": \"localhost\",\n"
- " \"http-port\": 9000,\n"
- " \"control-sockets\": {\n"
- " \"dhcp4\": {\n"
- " \"socket-type\": \"unix\"\n"
- " }\n"
- " /* Ok, forget about it. If Hector doesn't want to talk,\n"
- " we won't talk to him either. We now have quiet days. */\n"
- " /* \"d2\": {"
- " \"socket-type\": \"unix\",\n"
- " \"socket-name\": \"Hector\"\n"
- "}*/ } } }";
- testParser(txt, ParserContext::PARSER_AGENT, false);
-}
-
-// Tests if embedded comments are handled correctly.
-TEST(ParserTest, embbededComments) {
- string txt = "{ \"Control-agent\": {\n"
- " \"comment\": \"a comment\",\n"
- " \"http-host\": \"localhost\",\n"
- " \"http-port\": 9000,\n"
- " \"control-sockets\": {\n"
- " \"dhcp4\": {\n"
- " \"user-context\": { \"comment\": \"indirect\" },\n"
- " \"socket-type\": \"unix\"\n"
- " } },\n"
- " \"user-context\": { \"compatible\": true }\n"
- "} }";
- testParser(txt, ParserContext::PARSER_AGENT, false);
-}
-
-// Test that output_options is an alias of output-options.
-TEST(ParserTest, outputDashOptions) {
- string txt = "{ \"Control-agent\": {"
- " \"loggers\": [ { "
- " \"name\": \"kea-ctrl-agent\","
- " \"output_options\": [ { \"output\": \"stdout\" } ],"
- " \"severity\": \"INFO\" } ]"
- "} }";
- testParser(txt, ParserContext::PARSER_AGENT, false);
-}
-
-/// @brief Loads specified example config file
-///
-/// This test loads specified example file twice: first, using the legacy
-/// JSON file and then second time using bison parser. Two created Element
-/// trees are then compared. The input is decommented before it is passed
-/// to legacy parser (as legacy support for comments is very limited).
-///
-/// @param fname name of the file to be loaded
-void testFile(const std::string& fname) {
- ElementPtr json;
- ElementPtr reference_json;
- ConstElementPtr test_json;
-
- string decommented = decommentJSONfile(fname);
-
- cout << "Parsing file " << fname << "(" << decommented << ")" << endl;
-
- EXPECT_NO_THROW(json = Element::fromJSONFile(decommented, true));
- reference_json = moveComments(json);
-
- // remove the temporary file
- EXPECT_NO_THROW(::remove(decommented.c_str()));
-
- EXPECT_NO_THROW(
- try {
- ParserContext ctx;
- test_json = ctx.parseFile(fname, ParserContext::PARSER_AGENT);
- } catch (const std::exception &x) {
- cout << "EXCEPTION: " << x.what() << endl;
- throw;
- });
-
- ASSERT_TRUE(reference_json);
- ASSERT_TRUE(test_json);
-
- compareJSON(reference_json, test_json);
-}
-
-// This test loads all available existing files. Each config is loaded
-// twice: first with the existing Element::fromJSONFile() and then
-// the second time with AgentParser. Both JSON trees are then compared.
-// Hopefully the list of example configs will grow over time.
-TEST(ParserTest, file) {
- vector<string> configs;
- configs.push_back("comments.json");
- configs.push_back("https.json");
- configs.push_back("simple.json");
-
- for (unsigned i = 0; i < configs.size(); i++) {
- testFile(string(CFG_EXAMPLES) + "/" + configs[i]);
- }
-}
-
-/// @brief Tests error conditions in AgentParser
-///
-/// @param txt text to be parsed
-/// @param parser_type type of the parser to be used in the test
-/// @param msg expected content of the exception
-void testError(const std::string& txt,
- ParserContext::ParserType parser_type,
- const std::string& msg) {
- SCOPED_TRACE("\n=== tested config ===\n" + txt + "=====================");
-
- try {
- ParserContext ctx;
- ConstElementPtr parsed = ctx.parseString(txt, parser_type);
- FAIL() << "Expected ParseError but nothing was raised (expected: "
- << msg << ")";
- }
- catch (const ParseError& ex) {
- EXPECT_EQ(msg, ex.what());
- }
- catch (...) {
- FAIL() << "Expected ParseError but something else was raised";
- }
-}
-
-// Verify that error conditions are handled correctly.
-TEST(ParserTest, errors) {
- // no input
- testError("", ParserContext::PARSER_JSON,
- "<string>:1.1: syntax error, unexpected end of file");
- testError(" ", ParserContext::PARSER_JSON,
- "<string>:1.2: syntax error, unexpected end of file");
- testError("\n", ParserContext::PARSER_JSON,
- "<string>:2.1: syntax error, unexpected end of file");
- testError("\t", ParserContext::PARSER_JSON,
- "<string>:1.2: syntax error, unexpected end of file");
- testError("\r", ParserContext::PARSER_JSON,
- "<string>:1.2: syntax error, unexpected end of file");
-
- // comments
- testError("# nothing\n",
- ParserContext::PARSER_JSON,
- "<string>:2.1: syntax error, unexpected end of file");
- testError(" #\n",
- ParserContext::PARSER_JSON,
- "<string>:2.1: syntax error, unexpected end of file");
- testError("// nothing\n",
- ParserContext::PARSER_JSON,
- "<string>:2.1: syntax error, unexpected end of file");
- testError("/* nothing */\n",
- ParserContext::PARSER_JSON,
- "<string>:2.1: syntax error, unexpected end of file");
- testError("/* no\nthing */\n",
- ParserContext::PARSER_JSON,
- "<string>:3.1: syntax error, unexpected end of file");
- testError("/* no\nthing */\n\n",
- ParserContext::PARSER_JSON,
- "<string>:4.1: syntax error, unexpected end of file");
- testError("/* nothing\n",
- ParserContext::PARSER_JSON,
- "Comment not closed. (/* in line 1");
- testError("\n\n\n/* nothing\n",
- ParserContext::PARSER_JSON,
- "Comment not closed. (/* in line 4");
- testError("{ /* */*/ }\n",
- ParserContext::PARSER_JSON,
- "<string>:1.3-8: Invalid character: *");
- testError("{ /* // *// }\n",
- ParserContext::PARSER_JSON,
- "<string>:1.3-11: Invalid character: /");
- testError("{ /* // */// }\n",
- ParserContext::PARSER_JSON,
- "<string>:2.1: syntax error, unexpected end of file, "
- "expecting }");
-
- // includes
- testError("<?\n",
- ParserContext::PARSER_JSON,
- "Directive not closed.");
- testError("<?include\n",
- ParserContext::PARSER_JSON,
- "Directive not closed.");
- string file = string(CFG_EXAMPLES) + "/" + "simple.json";
- testError("<?include \"" + file + "\"\n",
- ParserContext::PARSER_JSON,
- "Directive not closed.");
- testError("<?include \"/foo/bar\" ?>/n",
- ParserContext::PARSER_JSON,
- "Can't open include file /foo/bar");
-
- // JSON keywords
- testError("{ \"foo\": True }",
- ParserContext::PARSER_JSON,
- "<string>:1.10-13: JSON true reserved keyword is lower case only");
- testError("{ \"foo\": False }",
- ParserContext::PARSER_JSON,
- "<string>:1.10-14: JSON false reserved keyword is lower case only");
- testError("{ \"foo\": NULL }",
- ParserContext::PARSER_JSON,
- "<string>:1.10-13: JSON null reserved keyword is lower case only");
- testError("{ \"foo\": Tru }",
- ParserContext::PARSER_JSON,
- "<string>:1.10: Invalid character: T");
- testError("{ \"foo\": nul }",
- ParserContext::PARSER_JSON,
- "<string>:1.10: Invalid character: n");
-
- // numbers
- testError("123",
- ParserContext::PARSER_AGENT,
- "<string>:1.1-3: syntax error, unexpected integer, "
- "expecting {");
- testError("-456",
- ParserContext::PARSER_AGENT,
- "<string>:1.1-4: syntax error, unexpected integer, "
- "expecting {");
- testError("-0001",
- ParserContext::PARSER_AGENT,
- "<string>:1.1-5: syntax error, unexpected integer, "
- "expecting {");
- testError("1234567890123456789012345678901234567890",
- ParserContext::PARSER_JSON,
- "<string>:1.1-40: Failed to convert "
- "1234567890123456789012345678901234567890"
- " to an integer.");
- testError("-3.14e+0",
- ParserContext::PARSER_AGENT,
- "<string>:1.1-8: syntax error, unexpected floating point, "
- "expecting {");
- testError("1e50000",
- ParserContext::PARSER_JSON,
- "<string>:1.1-7: Failed to convert 1e50000 "
- "to a floating point.");
-
- // strings
- testError("\"aabb\"",
- ParserContext::PARSER_AGENT,
- "<string>:1.1-6: syntax error, unexpected constant string, "
- "expecting {");
- testError("{ \"aabb\"err",
- ParserContext::PARSER_JSON,
- "<string>:1.9: Invalid character: e");
- testError("{ err\"aabb\"",
- ParserContext::PARSER_JSON,
- "<string>:1.3: Invalid character: e");
- testError("\"a\n\tb\"",
- ParserContext::PARSER_JSON,
- "<string>:1.1-6 (near 2): Invalid control in \"a\n\tb\"");
- testError("\"a\n\\u12\"",
- ParserContext::PARSER_JSON,
- "<string>:1.1-8 (near 2): Invalid control in \"a\n\\u12\"");
- testError("\"a\\n\\tb\"",
- ParserContext::PARSER_AGENT,
- "<string>:1.1-8: syntax error, unexpected constant string, "
- "expecting {");
- testError("\"a\\x01b\"",
- ParserContext::PARSER_JSON,
- "<string>:1.1-8 (near 3): Bad escape in \"a\\x01b\"");
- testError("\"a\\u0162\"",
- ParserContext::PARSER_JSON,
- "<string>:1.1-9 (near 4): Unsupported unicode escape "
- "in \"a\\u0162\"");
- testError("\"a\\u062z\"",
- ParserContext::PARSER_JSON,
- "<string>:1.1-9 (near 3): Bad escape in \"a\\u062z\"");
- testError("\"abc\\\"",
- ParserContext::PARSER_JSON,
- "<string>:1.1-6 (near 6): Overflow escape in \"abc\\\"");
- testError("\"a\\u006\"",
- ParserContext::PARSER_JSON,
- "<string>:1.1-8 (near 3): Overflow unicode escape "
- "in \"a\\u006\"");
- testError("\"\\u\"",
- ParserContext::PARSER_JSON,
- "<string>:1.1-4 (near 2): Overflow unicode escape in \"\\u\"");
- testError("\"\\u\x02\"",
- ParserContext::PARSER_JSON,
- "<string>:1.1-5 (near 2): Bad escape in \"\\u\x02\"");
- testError("\"\\u\\\"foo\"",
- ParserContext::PARSER_JSON,
- "<string>:1.1-5 (near 2): Bad escape in \"\\u\\\"...");
- testError("\"\x02\\u\"",
- ParserContext::PARSER_JSON,
- "<string>:1.1-5 (near 1): Invalid control in \"\x02\\u\"");
-
- // from data_unittest.c
- testError("\\a",
- ParserContext::PARSER_JSON,
- "<string>:1.1: Invalid character: \\");
- testError("\\",
- ParserContext::PARSER_JSON,
- "<string>:1.1: Invalid character: \\");
- testError("\\\"\\\"",
- ParserContext::PARSER_JSON,
- "<string>:1.1: Invalid character: \\");
-
- // want a map
- testError("[]\n",
- ParserContext::PARSER_AGENT,
- "<string>:1.1: syntax error, unexpected [, "
- "expecting {");
- testError("[]\n",
- ParserContext::PARSER_AGENT,
- "<string>:1.1: syntax error, unexpected [, "
- "expecting {");
- testError("{ 123 }\n",
- ParserContext::PARSER_JSON,
- "<string>:1.3-5: syntax error, unexpected integer, "
- "expecting }");
- testError("{ 123 }\n",
- ParserContext::PARSER_AGENT,
- "<string>:1.3-5: syntax error, unexpected integer, "
- "expecting Control-agent");
- testError("{ \"foo\" }\n",
- ParserContext::PARSER_JSON,
- "<string>:1.9: syntax error, unexpected }, "
- "expecting :");
- testError("{ \"foo\" }\n",
- ParserContext::PARSER_AGENT,
- "<string>:1.3-7: syntax error, unexpected constant string, "
- "expecting Control-agent");
- testError("{ \"foo\":null }\n",
- ParserContext::PARSER_AGENT,
- "<string>:1.3-7: syntax error, unexpected constant string, "
- "expecting Control-agent");
- testError("{ \"Logging\":null }\n",
- ParserContext::PARSER_AGENT,
- "<string>:1.3-11: syntax error, unexpected constant string, "
- "expecting Control-agent");
- testError("{ \"Control-agent\" }\n",
- ParserContext::PARSER_AGENT,
- "<string>:1.19: syntax error, unexpected }, "
- "expecting :");
- testError("{ \"Control-agent\":",
- ParserContext::PARSER_AGENT,
- "<string>:1.19: syntax error, unexpected end of file, "
- "expecting {");
- testError("{}{}\n",
- ParserContext::PARSER_JSON,
- "<string>:1.3: syntax error, unexpected {, "
- "expecting end of file");
-
- // duplicate in map
- testError("{ \"foo\": 1, \"foo\": true }\n",
- ParserContext::PARSER_JSON,
- "<string>:1:13: duplicate foo entries in "
- "JSON map (previous at <string>:1:10)");
-
- // bad commas
- testError("{ , }\n",
- ParserContext::PARSER_JSON,
- "<string>:1.3: syntax error, unexpected \",\", "
- "expecting }");
- testError("{ , \"foo\":true }\n",
- ParserContext::PARSER_JSON,
- "<string>:1.3: syntax error, unexpected \",\", "
- "expecting }");
-
- // bad type
- testError("{ \"Control-agent\":{\n"
- " \"http-port\":false }}\n",
- ParserContext::PARSER_AGENT,
- "<string>:2.15-19: syntax error, unexpected boolean, "
- "expecting integer");
-
- // unknown keyword
- testError("{ \"Control-agent\":{\n"
- " \"topping\": \"Mozzarella\" }}\n",
- ParserContext::PARSER_AGENT,
- "<string>:2.2-10: got unexpected keyword "
- "\"topping\" in Control-agent map.");
-
- // user context and embedded comments
- testError("{ \"Control-agent\":{\n"
- " \"comment\": true,\n"
- " \"http-port\": 9000 }}\n",
- ParserContext::PARSER_AGENT,
- "<string>:2.14-17: syntax error, unexpected boolean, "
- "expecting constant string");
-
- testError("{ \"Control-agent\":{\n"
- " \"user-context\": \"a comment\",\n"
- " \"http-port\": 9000 }}\n",
- ParserContext::PARSER_AGENT,
- "<string>:2.19-29: syntax error, unexpected constant string, "
- "expecting {");
-
- testError("{ \"Control-agent\":{\n"
- " \"comment\": \"a comment\",\n"
- " \"comment\": \"another one\",\n"
- " \"http-port\": 9000 }}\n",
- ParserContext::PARSER_AGENT,
- "<string>:3.3-11: duplicate user-context/comment entries "
- "(previous at <string>:2:3)");
-
- testError("{ \"Control-agent\":{\n"
- " \"user-context\": { \"version\": 1 },\n"
- " \"user-context\": { \"one\": \"only\" },\n"
- " \"http-port\": 9000 }}\n",
- ParserContext::PARSER_AGENT,
- "<string>:3.3-16: duplicate user-context entries "
- "(previous at <string>:2:19)");
-
- testError("{ \"Control-agent\":{\n"
- " \"user-context\": { \"comment\": \"indirect\" },\n"
- " \"comment\": \"a comment\",\n"
- " \"http-port\": 9000 }}\n",
- ParserContext::PARSER_AGENT,
- "<string>:3.3-11: duplicate user-context/comment entries "
- "(previous at <string>:2:19)");
-
- // duplicate Control-agent entries
- testError("{ \"Control-agent\":{\n"
- " \"comment\": \"first\" },\n"
- " \"Control-agent\":{\n"
- " \"comment\": \"second\" }}\n",
- ParserContext::PARSER_AGENT,
- "<string>:3.3-17: syntax error, unexpected Control-agent, expecting \",\" or }");
-
- // duplicate of not string entries
- testError("{ \"Control-agent\":{\n"
- " \"http-port\": 8000,\n"
- " \"http-port\": 8001 }}\n",
- ParserContext::PARSER_AGENT,
- "<string>:3:2: duplicate http-port entries in "
- "Control-agent map (previous at <string>:2:15)");
-
- // duplicate of string entries
- testError("{ \"Control-agent\":{\n"
- " \"http-host\": \"127.0.0.1\",\n"
- " \"http-host\": \"::1\" }}\n",
- ParserContext::PARSER_AGENT,
- "<string>:3:2: duplicate http-host entries in "
- "Control-agent map (previous at <string>:2:15)");
-}
-
-// Check unicode escapes
-TEST(ParserTest, unicodeEscapes) {
- ConstElementPtr result;
- string json;
-
- // check we can reread output
- for (char c = -128; c < 127; ++c) {
- string ins(" ");
- ins[1] = c;
- ConstElementPtr e(new StringElement(ins));
- json = e->str();
- ASSERT_NO_THROW(
- try {
- ParserContext ctx;
- result = ctx.parseString(json, ParserContext::PARSER_JSON);
- } catch (const std::exception &x) {
- cout << "EXCEPTION: " << x.what() << endl;
- throw;
- });
- ASSERT_EQ(Element::string, result->getType());
- EXPECT_EQ(ins, result->stringValue());
- }
-}
-
-// This test checks that all representations of a slash is recognized properly.
-TEST(ParserTest, unicodeSlash) {
- // check the 4 possible encodings of solidus '/'
- ConstElementPtr result;
- string json = "\"/\\/\\u002f\\u002F\"";
- ASSERT_NO_THROW(
- try {
- ParserContext ctx;
- result = ctx.parseString(json, ParserContext::PARSER_JSON);
- } catch (const std::exception &x) {
- cout << "EXCEPTION: " << x.what() << endl;
- throw;
- });
- ASSERT_EQ(Element::string, result->getType());
- EXPECT_EQ("////", result->stringValue());
-}
-
-/// @brief Load a file into a JSON element.
-///
-/// @param fname The name of the file to load.
-/// @param list The JSON element list to add the parsing result to.
-void loadFile(const string& fname, ElementPtr list) {
- ParserContext ctx;
- ElementPtr json;
- EXPECT_NO_THROW(json = ctx.parseFile(fname, ParserContext::PARSER_AGENT));
- ASSERT_TRUE(json);
- list->add(json);
-}
-
-// This test checks that all map entries are in the sample file.
-TEST(ParserTest, mapEntries) {
- // Type of keyword set.
- typedef set<string> KeywordSet;
-
- // Get keywords from the syntax file (agent_parser.yy).
- ifstream syntax_file(SYNTAX_FILE);
- EXPECT_TRUE(syntax_file.is_open());
- string line;
- KeywordSet syntax_keys = { "user-context" };
- // Code setting the map entry.
- const string pattern = "ctx.stack_.back()->set(\"";
- while (getline(syntax_file, line)) {
- // Skip comments.
- size_t comment = line.find("//");
- if (comment <= pattern.size()) {
- continue;
- }
- if (comment != string::npos) {
- line.resize(comment);
- }
- // Search for the code pattern.
- size_t key_begin = line.find(pattern);
- if (key_begin == string::npos) {
- continue;
- }
- // Extract keywords.
- line = line.substr(key_begin + pattern.size());
- size_t key_end = line.find_first_of('"');
- EXPECT_NE(string::npos, key_end);
- string keyword = line.substr(0, key_end);
- // Ignore result when adding the keyword to the syntax keyword set.
- static_cast<void>(syntax_keys.insert(keyword));
- }
- syntax_file.close();
-
- // Get keywords from the sample files
- string sample_dir(CFG_EXAMPLES);
- sample_dir += "/";
- ElementPtr sample_json = Element::createList();
- loadFile(sample_dir + "https.json", sample_json);
- loadFile(sample_dir + "simple.json", sample_json);
- KeywordSet sample_keys;
- // Recursively extract keywords.
- static void (*extract)(ConstElementPtr, KeywordSet&) =
- [] (ConstElementPtr json, KeywordSet& set) {
- if (json->getType() == Element::list) {
- // Handle lists.
- for (auto const& elem : json->listValue()) {
- extract(elem, set);
- }
- } else if (json->getType() == Element::map) {
- // Handle maps.
- for (auto const& elem : json->mapValue()) {
- static_cast<void>(set.insert(elem.first));
- // Skip entries with free content.
- if ((elem.first != "user-context") &&
- (elem.first != "parameters")) {
- extract(elem.second, set);
- }
- }
- }
- };
- extract(sample_json, sample_keys);
-
- // Compare.
- EXPECT_EQ(syntax_keys, sample_keys);
-}
-
-/// @brief Tests a duplicate entry.
-///
-/// The entry was duplicated by adding a new <name>DDDD entry.
-/// An error is expected, usually it is a duplicate but there are
-/// a few syntax errors when the syntax allows only one parameter.
-///
-/// @param json the JSON configuration with the duplicate entry.
-void testDuplicate(ConstElementPtr json) {
- string config = json->str();
- size_t where = config.find("DDDD");
- ASSERT_NE(string::npos, where);
- string before = config.substr(0, where);
- string after = config.substr(where + 4, string::npos);
- ParserContext ctx;
- EXPECT_THROW(ctx.parseString(before + after,
- ParserContext::PARSER_AGENT),
- ParseError) << "config: " << config;
-}
-
-// This test checks that duplicate entries make parsing to fail.
-TEST(ParserTest, duplicateMapEntries) {
- // Get the config to work with from the sample file.
- string sample_fname(CFG_EXAMPLES);
- sample_fname += "/simple.json";
- ParserContext ctx;
- ElementPtr sample_json;
- EXPECT_NO_THROW(sample_json =
- ctx.parseFile(sample_fname, ParserContext::PARSER_AGENT));
- ASSERT_TRUE(sample_json);
-
- // Recursively check duplicates.
- static void (*test)(ElementPtr, ElementPtr, size_t&) =
- [] (ElementPtr config, ElementPtr json, size_t& cnt) {
- if (json->getType() == Element::list) {
- // Handle lists.
- for (auto const& elem : json->listValue()) {
- test(config, elem, cnt);
- }
- } else if (json->getType() == Element::map) {
- // Handle maps.
- for (auto const& elem : json->mapValue()) {
- // Skip entries with free content.
- if ((elem.first == "user-context") ||
- (elem.first == "parameters")) {
- continue;
- }
-
- // Perform tests.
- string dup = elem.first + "DDDD";
- json->set(dup, elem.second);
- testDuplicate(config);
- json->remove(dup);
- ++cnt;
-
- // Recursive call.
- ElementPtr mutable_json =
- boost::const_pointer_cast<Element>(elem.second);
- ASSERT_TRUE(mutable_json);
- test(config, mutable_json, cnt);
- }
- }
- };
- size_t cnt = 0;
- test(sample_json, sample_json, cnt);
- cout << "checked " << cnt << " duplicated map entries\n";
-}
-
-/// @brief Test fixture for trailing commas.
-class TrailingCommasTest : public isc::dhcp::test::LogContentTest {
-public:
- /// @brief Add a log entry.
- ///
- /// @param loc Location of the trailing comma.
- void addLog(const string& loc) {
- string log = "CTRL_AGENT_CONFIG_SYNTAX_WARNING Control Agent ";
- log += "configuration syntax warning: " + loc;
- log += ": Extraneous comma. ";
- log += "A piece of configuration may have been omitted.";
- addString(log);
- }
-};
-
-// Test that trailing commas are allowed.
-TEST_F(TrailingCommasTest, tests) {
- string txt(R"({
- "Control-agent": {
- "control-sockets": {
- "d2": {
- "socket-name": "kea-dhcp-ddns-ctrl.sock",
- "socket-type": "unix",
- },
- "dhcp4": {
- "socket-name": "kea-dhcp4-ctrl.sock",
- "socket-type": "unix",
- },
- "dhcp6": {
- "socket-name": "kea-dhcp6-ctrl.sock",
- "socket-type": "unix",
- },
- },
- "http-host": "10.1.0.2",
- "http-port": 8080,
- "loggers": [
- {
- "debuglevel": 99,
- "name": "kea-ctrl-agent",
- "output-options": [
- {
- "output": "stdout",
- },
- ],
- "severity": "DEBUG",
- },
- ],
- },
-})");
- testParser(txt, ParserContext::PARSER_AGENT, false);
-
- addLog("<string>:6.30");
- addLog("<string>:10.30");
- addLog("<string>:14.30");
- addLog("<string>:15.8");
- addLog("<string>:25.31");
- addLog("<string>:26.12");
- addLog("<string>:28.28");
- addLog("<string>:29.8");
- addLog("<string>:30.6");
- addLog("<string>:31.4");
- EXPECT_TRUE(checkFile());
-
- // Test with many consecutive commas.
- boost::replace_all(txt, ",", ",,,,");
- testParser(txt, ParserContext::PARSER_AGENT, false);
-}
-
-} // namespace test
-} // namespace agent
-} // namespace isc
+++ /dev/null
-// Copyright (C) 2025 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#ifndef AGENT_TEST_BASIC_AUTH_LIBRARIES_H
-#define AGENT_TEST_BASIC_AUTH_LIBRARIES_H
-
-#include <config.h>
-
-namespace {
-
-// Names of the libraries used in these tests. These libraries are built using
-// libtool, so we need to look in the hidden ".libs" directory to locate the
-// .so file. Note that we access the .so file - libtool creates this as a
-// like to the real shared library.
-
-// Basic HTTP authentication as a callout library.
-static const char* BASIC_AUTH_LIBRARY = "@abs_builddir@/libbasicauth.so";
-
-} // anonymous namespace
-
-#endif // TEST_BASIC_AUTH_LIBRARIES_H
+++ /dev/null
-// Copyright (C) 2017-2025 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#ifndef AGENT_TEST_CALLOUT_LIBRARIES_H
-#define AGENT_TEST_CALLOUT_LIBRARIES_H
-
-#include <config.h>
-
-namespace {
-
-// Names of the libraries used in these tests. These libraries are built using
-// libtool, so we need to look in the hidden ".libs" directory to locate the
-// .so file. Note that we access the .so file - libtool creates this as a
-// like to the real shared library.
-
-// Basic callout library with context_create and three "standard" callouts.
-static const char* CALLOUT_LIBRARY = "@abs_builddir@/libcallout.so";
-
-// Test path to use for in place of DEFAULT_HOOKS_PATH
-static const char* CA_HOOKS_TEST_PATH = "@abs_builddir@";
-
-} // anonymous namespace
-
-#endif // TEST_LIBRARIES_H
+++ /dev/null
-// Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-/// @brief Path to agent source dir
-#define CA_SRC_DIR "@abs_top_srcdir@/src/bin/agent"
-#define CA_TEST_DATA_DIR "@abs_top_srcdir@/src/bin/agent/tests/testdata"
+++ /dev/null
-{
- "Control-agent": {
- "authentication": {
- "clients": [
- {
- "password": "-----",
- "user": "admin",
- "user-context": {
- "comment": "admin is authorized"
- }
- },
- {
- "password-file": "hiddenp",
- "user-file": "hiddenu"
- },
- {
- "password-file": "hiddens"
- }
- ],
- "directory": "/tmp/kea-creds",
- "realm": "kea-control-agent",
- "type": "basic"
- },
- "control-sockets": {
- "d2": {
- "socket-name": "kea-ddns-ctrl-socket",
- "socket-type": "unix",
- "user-context": {
- "in-use": false
- }
- },
- "dhcp4": {
- "socket-name": "kea4-ctrl-socket",
- "socket-type": "unix",
- "user-context": {
- "comment": "socket to DHCPv4 server"
- }
- },
- "dhcp6": {
- "socket-name": "kea6-ctrl-socket",
- "socket-type": "unix"
- }
- },
- "hooks-libraries": [
- {
- "library": "/opt/local/control-agent-commands.so",
- "parameters": {
- "param1": "foo"
- }
- }
- ],
- "http-headers": [
- {
- "name": "Strict-Transport-Security",
- "user-context": {
- "comment": "HSTS header"
- },
- "value": "max-age=31536000"
- }
- ],
- "http-host": "127.0.0.1",
- "http-port": 8000
- }
-}
+++ /dev/null
-KeaTest
\ No newline at end of file
+++ /dev/null
-kea:test
\ No newline at end of file
+++ /dev/null
-keatest
\ No newline at end of file
+++ /dev/null
-// This is a basic configuration for the Kea Control Agent.
-//
-// This is just a very basic configuration. Kea comes with large suite (over 30)
-// of configuration examples and extensive Kea User's Guide. Please refer to
-// those materials to get better understanding of what this software is able to
-// do. Comments in this configuration file sometimes refer to sections for more
-// details. These are section numbers in Kea User's Guide. The version matching
-// your software should come with your Kea package, but it is also available
-// in ISC's Knowledgebase (https://kea.readthedocs.io; the direct link for
-// the stable version is https://kea.readthedocs.io/).
-//
-// This configuration file contains only Control Agent's configuration.
-// If configurations for other Kea services are also included in this file they
-// are ignored by the Control Agent.
-{
-
-// This is a basic configuration for the Kea Control Agent.
-// RESTful interface to be available at http://127.0.0.1:8000/
-"Control-agent": {
- "http-host": "127.0.0.1",
- // If enabling HA and multi-threading, the 8000 port is used by the HA
- // hook library http listener. When using HA hook library with
- // multi-threading to function, make sure the port used by dedicated
- // listener is different (e.g. 8001) than the one used by CA. Note
- // the commands should still be sent via CA. The dedicated listener
- // is specifically for HA updates only.
- "http-port": 8000,
-
- // Allow access only to kea-api user.
- // To make it work, please store your user name in kea-api-user file.
- // and store your password in the kea-api-password file.
- // Make sure the user and password files have sufficiently restrictive
- // access permissions, in particular that they are not world-readable.
- // The basic HTTP auth offers poor security for unencrypted channels.
- // If possible, a better, stronger HTTPS mechanism should be deployed,
- // in particular when the client authentication is enabled by setting the
- // cert-required to true (the default). See trust-anchor, cert-file,
- // key-file and cert-required below. For more details read the Kea Security
- // section in the ARM.
- "authentication": {
- "type": "basic",
- "realm": "Kea Control Agent",
- "directory": "/etc/kea",
- "clients": [
- {
- "user-file": "kea-api-user",
- "password-file": "kea-api-password"
- }
- ]
- },
-
- // Configuration section containing HTTPS parameters:
- // TLS trust anchor (Certificate Authority). This is a file name or
- // (for OpenSSL only) a directory path.
- // "trust-anchor": "kea-server-ca",
- // TLS server certificate file name.
- // "cert-file": "kea-server-cert",
- // TLS server private key file name.
- // "key-file": "kea-server-key",
- // TLS require client certificates flag. Default is true and means
- // require client certificates. False means they are optional.
- // "cert-required": true
-
- // Specify location of the files to which the Control Agent
- // should connect to forward commands to the DHCPv4, DHCPv6
- // and D2 servers via unix domain sockets.
- "control-sockets": {
- "dhcp4": {
- "socket-type": "unix",
- "socket-name": "kea4-ctrl-socket"
- },
- "dhcp6": {
- "socket-type": "unix",
- "socket-name": "kea6-ctrl-socket"
- },
- "d2": {
- "socket-type": "unix",
- "socket-name": "kea-ddns-ctrl-socket"
- }
- },
-
- // Specify hooks libraries that are attached to the Control Agent.
- // Such hooks libraries should support 'control_command_receive'
- // hook point. This is currently commented out because it has to
- // point to the existing hooks library. Otherwise the Control
- // Agent will fail to start.
- "hooks-libraries": [
-// {
-// "library": "@libdir@/kea/hooks/control-agent-commands.so",
-// "parameters": {
-// "param1": "foo"
-// }
-// }
- ],
-
-// Logging configuration starts here. Kea uses different loggers to log various
-// activities. For details (e.g. names of loggers), see Chapter 18.
- "loggers": [
- {
- // This specifies the logging for Control Agent daemon.
- "name": "kea-ctrl-agent",
- "output-options": [
- {
- // Specifies the output file. There are several special values
- // supported:
- // - stdout (prints on standard output)
- // - stderr (prints on standard error)
- // - syslog (logs to syslog)
- // - syslog:name (logs to syslog using specified name)
- // Any other value is considered a name of the file
- "output": "kea-ctrl-agent.log"
-
- // Shorter log pattern suitable for use with systemd,
- // avoids redundant information
- // "pattern": "%-5p %m\n"
-
- // This governs whether the log output is flushed to disk after
- // every write.
- // "flush": false,
-
- // This specifies the maximum size of the file before it is
- // rotated.
- // "maxsize": 1048576,
-
- // This specifies the maximum number of rotated files to keep.
- // "maxver": 8
- }
- ],
- // This specifies the severity of log messages to keep. Supported values
- // are: FATAL, ERROR, WARN, INFO, DEBUG
- "severity": "INFO",
-
- // If DEBUG level is specified, this value is used. 0 is least verbose,
- // 99 is most verbose. Be cautious, Kea can generate lots and lots
- // of logs if told to do so.
- "debuglevel": 0
- }
- ]
-}
-}
# the startup, shutdown, reconfiguration and gathering the status
# of the Kea's processes.
-# Note that control agent must be launched after servers and netconf last.
-
# shellcheck disable=SC2034
# SC2034: ... appears unused. Verify use (or export if used externally).
kea_dhcp4_config_file="@sysconfdir@/@PACKAGE@/kea-dhcp4.conf"
kea_dhcp6_config_file="@sysconfdir@/@PACKAGE@/kea-dhcp6.conf"
kea_dhcp_ddns_config_file="@sysconfdir@/@PACKAGE@/kea-dhcp-ddns.conf"
-kea_ctrl_agent_config_file="@sysconfdir@/@PACKAGE@/kea-ctrl-agent.conf"
kea_netconf_config_file="@sysconfdir@/@PACKAGE@/kea-netconf.conf"
# Location of Kea binaries.
dhcp4_srv="@sbindir@/kea-dhcp4"
dhcp6_srv="@sbindir@/kea-dhcp6"
dhcp_ddns_srv="@sbindir@/kea-dhcp-ddns"
-ctrl_agent_srv="@sbindir@/kea-ctrl-agent"
netconf_srv="@sbindir@/kea-netconf"
# Start DHCPv4 server?
# Start DHCP DDNS server?
dhcp_ddns=no
-# Start Control Agent?
-ctrl_agent=yes
-
# Start Netconf?
netconf=no
kea-dhcp-ddns)
kea_config_file=${kea_dhcp_ddns_config_file}
;;
- kea-ctrl-agent)
- kea_config_file=${kea_ctrl_agent_config_file}
- ;;
kea-netconf)
kea_config_file=${kea_netconf_config_file}
;;
# and be set to yes, e.g. ${dhcp4} should be equal to yes if server name
# is dhcp4
run_conditional() {
- local server="${1}" # Server name: dhcp4, dhcp6, dhcp_ddns, ctrl_agent, netconf
+ local server="${1}" # Server name: dhcp4, dhcp6, dhcp_ddns, netconf
local commands="${2}" # Commands to execute
local check_file_cfg="${3}" # Check if server enabled in the configuration file
local is_all=0 # is all servers or a specific one
# Validate that the specified server names are correct.
for s in ${servers}
do
- server_list="all dhcp4 dhcp6 dhcp_ddns ctrl_agent"
+ server_list="all dhcp4 dhcp6 dhcp_ddns"
if ${have_netconf}; then
server_list="${server_list} netconf"
fi
exit 1
fi
-# Get location of the Control Agent binary.
-if [ -z "${ctrl_agent_srv+x}" ]; then
- log_error "ctrl_agent_srv parameter not specified"
- exit 1
-fi
-
# Get location of the Netconf binary.
if ${have_netconf}; then
if [ -z "${netconf_srv+x}" ]; then
fi
# dhcp4 and dhcp6 (=yes) indicate if we should start DHCPv4 and DHCPv6 server
-# respectively. The same is true for ddns, ctrl-agent and netconf.
+# respectively. The same is true for ddns and netconf.
dhcp4=$( printf "%s" "${dhcp4}" | tr '[:upper:]' '[:lower:]' )
dhcp6=$( printf "%s" "${dhcp6}" | tr '[:upper:]' '[:lower:]' )
dhcp_ddns=$( printf "%s" "${dhcp_ddns}" | tr '[:upper:]' '[:lower:]' )
-ctrl_agent=$( printf "%s" "${ctrl_agent}" | tr '[:upper:]' '[:lower:]' )
if ${have_netconf}; then
netconf=$( printf "%s" "${netconf}" | tr '[:upper:]' '[:lower:]' )
fi
run_conditional "dhcp4" "start_server ${dhcp4_srv} -c ${kea_dhcp4_config_file} ${args}" 1
run_conditional "dhcp6" "start_server ${dhcp6_srv} -c ${kea_dhcp6_config_file} ${args}" 1
run_conditional "dhcp_ddns" "start_server ${dhcp_ddns_srv} -c ${kea_dhcp_ddns_config_file} \
-${args}" 1
- run_conditional "ctrl_agent" "start_server ${ctrl_agent_srv} -c ${kea_ctrl_agent_config_file} \
${args}" 1
if ${have_netconf}; then
run_conditional "netconf" "start_server ${netconf_srv} -c ${kea_netconf_config_file} \
run_conditional "dhcp4" "stop_server ${dhcp4_srv}" 0
run_conditional "dhcp6" "stop_server ${dhcp6_srv}" 0
run_conditional "dhcp_ddns" "stop_server ${dhcp_ddns_srv}" 0
- run_conditional "ctrl_agent" "stop_server ${ctrl_agent_srv}" 0
if ${have_netconf}; then
run_conditional "netconf" "stop_server ${netconf_srv}" 0
fi
run_conditional "dhcp4" "reload_server ${dhcp4_srv}" 0
run_conditional "dhcp6" "reload_server ${dhcp6_srv}" 0
run_conditional "dhcp_ddns" "reload_server ${dhcp_ddns_srv}" 0
- run_conditional "ctrl_agent" "reload_server ${ctrl_agent_srv}" 0
if ${have_netconf}; then
run_conditional "netconf" "reload_server ${netconf_srv}" 0
fi
fi
printf "DHCP DDNS: %b\n" "${d2_status}"
- agent_status=$inactive
- check_running "$(basename -- "${ctrl_agent_srv}")"
- if [ "${_running}" -eq 1 ]; then
- agent_status=$active
- fi
- printf "Control Agent: %b\n" "${agent_status}"
-
if ${have_netconf}; then
netconf_status=$inactive
check_running "$(basename -- "${netconf_srv}")"
printf "Kea DHCPv4 configuration file: %s\n" "${kea_dhcp4_config_file}"
printf "Kea DHCPv6 configuration file: %s\n" "${kea_dhcp6_config_file}"
printf "Kea DHCP DDNS configuration file: %s\n" "${kea_dhcp_ddns_config_file}"
- printf "Kea Control Agent configuration file: %s\n" "${kea_ctrl_agent_config_file}"
if ${have_netconf}; then
printf "Kea Netconf configuration file: %s\n" "${kea_netconf_config_file}"
fi
check_kea_conf "${kea_dhcp4_config_file}"
check_kea_conf "${kea_dhcp6_config_file}"
check_kea_conf "${kea_dhcp_ddns_config_file}"
- check_kea_conf "${kea_ctrl_agent_config_file}"
if ${have_netconf}; then
check_kea_conf "${kea_netconf_config_file}"
fi
run_conditional "dhcp4" "print_version kea-dhcp4 ${dhcp4_srv}" 0
run_conditional "dhcp6" "print_version kea-dhcp6 ${dhcp6_srv}" 0
run_conditional "dhcp_ddns" "print_version kea-dhcp-ddns ${dhcp_ddns_srv}" 0
- run_conditional "ctrl_agent" "print_version kea-ctrl-agent ${ctrl_agent_srv}" 0
if ${have_netconf}; then
run_conditional "netconf" "print_version kea-netconf ${netconf_srv}" 0
fi
configuration: kea_conf_data,
install_dir: kea_configfiles_destdir,
)
-configure_file(
- input: 'kea-ctrl-agent.conf.pre',
- output: 'kea-ctrl-agent.conf',
- configuration: kea_conf_data,
- install_dir: kea_configfiles_destdir,
-)
configure_file(
input: 'kea-netconf.conf.pre',
output: 'kea-netconf.conf',
# Names for D2
D2_CFG_FILE_NAME="d2_test_config.conf"
D2_CFG_FILE="@abs_top_builddir@/src/bin/keactrl/tests/${D2_CFG_FILE_NAME}.json"
-# Names for CA
-CA_CFG_FILE_NAME="ca_test_config.conf"
-CA_CFG_FILE="@abs_top_builddir@/src/bin/keactrl/tests/${CA_CFG_FILE_NAME}.json"
# Names for Netconf
NC_CFG_FILE_NAME="nc_test_config.conf"
NC_CFG_FILE="@abs_top_builddir@/src/bin/keactrl/tests/${NC_CFG_FILE_NAME}.json"
CFG_FILES="kea_dhcp4_config_file=${DHCP4_CFG_FILE}\n\
kea_dhcp6_config_file=${DHCP6_CFG_FILE}\n\
kea_dhcp_ddns_config_file=${D2_CFG_FILE}\n\
-kea_ctrl_agent_config_file=${CA_CFG_FILE}\n\
kea_netconf_config_file=${NC_CFG_FILE}"
KEACTRL_BUILD_DIR="@abs_top_builddir@"
# A name of the keactrl config file
kea4_name="${wildcard_name}dhcp4"
kea6_name="${wildcard_name}dhcp6"
d2_name="${wildcard_name}dhcp-ddns"
-agent_name="${wildcard_name}ctrl-agent"
netconf_name="${wildcard_name}netconf"
# DHCPv4 configuration
}
}"
-# Control-agent configuration
-control_agent_config="{
- \"Control-agent\": {
- \"http-host\": \"127.0.0.1\",
- \"http-port\": 18080,
- \"loggers\": [
- {
- \"name\": \"kea-ctrl-agent\",
- \"output-options\": [
- {
- \"output\": \"$LOG_FILE\"
- }
- ],
- \"severity\": \"INFO\"
- }
- ]
- }
-}"
-
# Netconf configuration
netconf_config="{
\"Netconf\": {
keactrl_fixed_config="dhcp4_srv=${KEACTRL_BUILD_DIR}/src/bin/dhcp4/kea-dhcp4\n\
dhcp6_srv=${KEACTRL_BUILD_DIR}/src/bin/dhcp6/kea-dhcp6\n\
dhcp_ddns_srv=${KEACTRL_BUILD_DIR}/src/bin/d2/kea-dhcp-ddns\n\
-ctrl_agent_srv=${KEACTRL_BUILD_DIR}/src/bin/agent/kea-ctrl-agent\n\
netconf_srv=${KEACTRL_BUILD_DIR}/src/bin/netconf/kea-netconf\n"
# This test checks that DHCPv4, DHCPv6, D2, CA and Netconf server can
# Create configuration file for keactrl. This configuration enables
# DHCPv4, DHCPv6, D2, CA and netconf.
keactrl_config="${CFG_FILES}\ndhcp4=yes\ndhcp6=yes\n\
-dhcp_ddns=yes\nctrl_agent=yes\nnetconf=yes\n\
+dhcp_ddns=yes\nnetconf=yes\n\
kea_verbose=no\n${keactrl_fixed_config}"
test_start "keactrl.start_all_servers_no_verbose_test"
create_dhcp4_config "${dhcp4_config}"
create_dhcp6_config "${dhcp6_config}"
create_d2_config "${dhcp_ddns_config}"
- create_ca_config "${control_agent_config}"
create_nc_config "${netconf_config}"
create_keactrl_config "${keactrl_config}"
"Timeout waiting for ${d2_name} to start. \
Expected wait_for_message return %d, returned %d."
- wait_for_message 20 "CTRL_AGENT_HTTP_SERVICE_STARTED" 1
- assert_eq 1 "${_WAIT_FOR_MESSAGE}" \
- "Timeout waiting for ${agent_name} to start. \
-Expected wait_for_message return %d, returned %d."
-
if ${have_netconf}; then
wait_for_message 20 "NETCONF_STARTED" 1
assert_eq 1 "${_WAIT_FOR_MESSAGE}" \
assert_eq 1 "${_GET_PIDS_NUM}" \
"Expected %d ${d2_name} process running, found %d processes running"
- get_pid ${agent_name} ${CA_CFG_FILE_NAME}
- assert_eq 1 "${_GET_PIDS_NUM}" \
- "Expected %d ${agent_name} process running, found %d processes running"
-
if ${have_netconf}; then
get_pid ${netconf_name} ${NC_CFG_FILE_NAME}
assert_eq 1 "${_GET_PIDS_NUM}" \
# Create configuration file for keactrl. This configuration enables
# all servers.
keactrl_config="${CFG_FILES}\ndhcp4=yes\ndhcp6=yes\n\
-dhcp_ddns=yes\nctrl_agent=yes\nnetconf=yes\n\
+dhcp_ddns=yes\nnetconf=yes\n\
kea_verbose=yes\n${keactrl_fixed_config}"
test_start "keactrl.start_all_servers_verbose_test"
create_dhcp4_config "${dhcp4_config}"
create_dhcp6_config "${dhcp6_config}"
create_d2_config "${dhcp_ddns_config}"
- create_ca_config "${control_agent_config}"
create_nc_config "${netconf_config}"
create_keactrl_config "${keactrl_config}"
"Timeout waiting for ${d2_name} to start. \
Expected wait_for_message return %d, returned %d."
- wait_for_message 20 "CTRL_AGENT_HTTP_SERVICE_STARTED" 1
- assert_eq 1 "${_WAIT_FOR_MESSAGE}" \
- "Timeout waiting for ${agent_name} to start. \
-Expected wait_for_message return %d, returned %d."
-
if ${have_netconf}; then
wait_for_message 20 "NETCONF_STARTED" 1
assert_eq 1 "${_WAIT_FOR_MESSAGE}" \
assert_eq 1 "${_GET_PIDS_NUM}" \
"Expected %d ${d2_name} process running, found %d processes running"
- get_pid ${agent_name} ${CA_CFG_FILE_NAME}
- assert_eq 1 "${_GET_PIDS_NUM}" \
- "Expected %d ${agent_name} process running, found %d processes running"
-
if ${have_netconf}; then
get_pid ${netconf_name} ${NC_CFG_FILE_NAME}
assert_eq 1 "${_GET_PIDS_NUM}" \
fi
wait_for_message 10 "DCTL_SHUTDOWN" ${expected}
assert_eq 1 "${_WAIT_FOR_MESSAGE}" \
- "Timeout waiting for ${d2_name} and ${agent_name} to shutdown. \
+ "Timeout waiting for ${d2_name} to shutdown. \
Expected wait_for_message return %d, returned %d."
# Make sure that all servers are down.
create_dhcp4_config "${dhcp4_config}"
create_dhcp6_config "${dhcp6_config}"
create_d2_config "${dhcp_ddns_config}"
- create_ca_config "${control_agent_config}"
create_nc_config "${netconf_config}"
create_keactrl_config "${CFG_FILES}
${keactrl_fixed_config}
-ctrl_agent=no
dhcp_ddns=no
dhcp4=yes
dhcp6=yes
'DHCPv4 server: inactive
DHCPv6 server: inactive
DHCP DDNS: inactive
-Control Agent: inactive' \
- "$(printf '%s\n' "${OUTPUT}" | head -n 4)"
if "${have_netconf}"; then
assert_str_eq 'Netconf agent: inactive' \
# Create configuration file for keactrl. This configuration enables
# DHCPv4 server but disables other servers.
keactrl_config="${CFG_FILES}\ndhcp4=yes\ndhcp6=no\n\
-dhcp_ddns=no\nctrl_agent=no\nnetconf=no\n\
+dhcp_ddns=no\nnetconf=no\n\
kea_verbose=no\n${keactrl_fixed_config}"
test_start "keactrl.start_v4_server_test"
create_dhcp4_config "${dhcp4_config}"
create_dhcp6_config "${dhcp6_config}"
create_d2_config "${dhcp_ddns_config}"
- create_ca_config "${control_agent_config}"
create_nc_config "${netconf_config}"
create_keactrl_config "${keactrl_config}"
assert_eq 0 "${_GET_PIDS_NUM}" \
"Expected %d ${d2_name} process running, found %d processes running"
- # Make sure that CA is not running.
- get_pid ${agent_name} ${CA_CFG_FILE_NAME}
- assert_eq 0 "${_GET_PIDS_NUM}" \
- "Expected %d ${agent_name} process running, found %d processes running"
-
# Make sure that Netconf agent is not running.
if ${have_netconf}; then
get_pid ${netconf_name} ${NC_CFG_FILE_NAME}
"Expected keactrl status command return %s"
assert_string_contains "DHCP DDNS: inactive" "${OUTPUT}" \
"Expected keactrl status command return %s"
- assert_string_contains "Control Agent: inactive" "${OUTPUT}" \
- "Expected keactrl status command return %s"
if ${have_netconf}; then
assert_string_contains "Netconf agent: inactive" "${OUTPUT}" \
"Expected keactrl status command return %s"
# Create configuration file for keactrl. This configuration enables
# DHCPv6 server but disables other servers..
keactrl_config="${CFG_FILES}\ndhcp4=no\ndhcp6=yes\n\
-dhcp_ddns=no\nctrl_agent=no\nnetconf=no\n\
+dhcp_ddns=no\nnetconf=no\n\
kea_verbose=no\n${keactrl_fixed_config}"
test_start "keactrl.start_v6_server_test"
create_dhcp4_config "${dhcp4_config}"
create_dhcp6_config "${dhcp6_config}"
create_d2_config "${dhcp_ddns_config}"
- create_ca_config "${control_agent_config}"
create_nc_config "${netconf_config}"
create_keactrl_config "${keactrl_config}"
assert_eq 0 "${_GET_PIDS_NUM}" \
"Expected %d ${d2_name} process running, found %d processes running"
- # Make sure that CA is not running.
- get_pid ${agent_name} ${CA_CFG_FILE_NAME}
- assert_eq 0 "${_GET_PIDS_NUM}" \
- "Expected %d ${agent_name} process running, found %d processes running"
-
# Make sure that Netconf agent is not running.
if ${have_netconf}; then
get_pid ${netconf_name} ${NC_CFG_FILE_NAME}
"Expected keactrl status command return %s"
assert_string_contains "DHCP DDNS: inactive" "${OUTPUT}" \
"Expected keactrl status command return %s"
- assert_string_contains "Control Agent: inactive" "${OUTPUT}" \
- "Expected keactrl status command return %s"
if ${have_netconf}; then
assert_string_contains "Netconf agent: inactive" "${OUTPUT}" \
"Expected keactrl status command return %s"
# Create configuration file for keactrl. This configuration enables
# DHCPv6 server but disables other servers.
keactrl_config="${CFG_FILES}\ndhcp4=no\ndhcp6=yes\n\
-dhcp_ddns=no\nctrl_agent=no\nnetconf=no\n\
+dhcp_ddns=no\nnetconf=no\n\
kea_verbose=no\n${keactrl_fixed_config}"
test_start "keactrl.late_start_v4_server_test"
create_dhcp4_config "${dhcp4_config}"
create_dhcp6_config "${dhcp6_config}"
create_d2_config "${dhcp_ddns_config}"
- create_ca_config "${control_agent_config}"
create_nc_config "${netconf_config}"
create_keactrl_config "${keactrl_config}"
assert_eq 0 "${_GET_PIDS_NUM}" \
"Expected %d ${d2_name} process running, found %d processes running"
- # Make sure that CA is not running.
- get_pid ${agent_name} ${CA_CFG_FILE_NAME}
- assert_eq 0 "${_GET_PIDS_NUM}" \
- "Expected %d ${agent_name} process running, found %d processes running"
-
# Make sure that Netconf agent is not running.
if ${have_netconf}; then
get_pid ${netconf_name} ${NC_CFG_FILE_NAME}
# Update keactrl config to enable other servers.
keactrl_config="${CFG_FILES}\ndhcp4=yes\ndhcp6=yes\n\
-dhcp_ddns=yes\nctrl_agent=yes\nnetconf=yes\n\
+dhcp_ddns=yes\nnetconf=yes\n\
kea_verbose=yes\n${keactrl_fixed_config}"
create_keactrl_config "${keactrl_config}"
assert_eq 1 "${_GET_PIDS_NUM}" \
"Expected %d ${d2_name} process running, found %d processes running"
- # Make sure that CA is running.
- get_pid ${agent_name} ${CA_CFG_FILE_NAME}
- assert_eq 1 "${_GET_PIDS_NUM}" \
- "Expected %d ${agent_name} process running, found %d processes running"
-
# Make sure that Netconf agent is running.
if ${have_netconf}; then
get_pid ${netconf_name} ${NC_CFG_FILE_NAME}
# There should be two completed configurations of D2 and two
# configurations of CA.
wait_for_message 10 "DCTL_CONFIG_COMPLETE" 4
- assert_eq 1 "${_WAIT_FOR_MESSAGE}" "Timeout waiting for ${d2_name} or ${agent_name} \
+ assert_eq 1 "${_WAIT_FOR_MESSAGE}" "Timeout waiting for ${d2_name} \
to reconfigure. Expected wait_for_message to return %d, returned %d."
# Use keactrl stop to shutdown the servers.
fi
wait_for_message 10 "DCTL_SHUTDOWN" ${expected}
assert_eq 1 "${_WAIT_FOR_MESSAGE}" \
- "Timeout waiting for ${d2_name} and ${agent_name} to shutdown. \
+ "Timeout waiting for ${d2_name} to shutdown. \
Expected wait_for_message return %d, returned %d."
# Make sure that all servers are down.
# Create configuration file for keactrl. This configuration enables
# DHCPv4 server but disables DHCPv6 server.
keactrl_config="${CFG_FILES}\ndhcp4=yes\ndhcp6=no\n\
-dhcp_ddns=no\nctrl_agent=no\nnetconf=no\n\
+dhcp_ddns=no\nnetconf=no\n\
kea_verbose=yes\n${keactrl_fixed_config}"
test_start "keactrl.late_start_v6_server_test"
create_dhcp4_config "${dhcp4_config}"
create_dhcp6_config "${dhcp6_config}"
create_d2_config "${dhcp_ddns_config}"
- create_ca_config "${control_agent_config}"
create_nc_config "${netconf_config}"
create_keactrl_config "${keactrl_config}"
assert_eq 0 "${_GET_PIDS_NUM}" \
"Expected %d ${d2_name} process running, found %d processes running"
- # Make sure that CA is not running.
- get_pid ${agent_name} ${CA_CFG_FILE_NAME}
- assert_eq 0 "${_GET_PIDS_NUM}" \
- "Expected %d ${agent_name} process running, found %d processes running"
-
# Make sure that Netconf agent is not running.
if ${have_netconf}; then
get_pid ${netconf_name} ${NC_CFG_FILE_NAME}
# Update keactrl config to enable other servers.
keactrl_config="${CFG_FILES}\ndhcp4=yes\ndhcp6=yes\n\
-dhcp_ddns=yes\nctrl_agent=yes\nnetconf=yes\n\
+dhcp_ddns=yes\nnetconf=yes\n\
kea_verbose=no\n${keactrl_fixed_config}"
create_keactrl_config "${keactrl_config}"
assert_eq 1 "${_GET_PIDS_NUM}" \
"Expected %d ${d2_name} process running, found %d processes running"
- # Make sure that CA is running.
- get_pid ${agent_name} ${CA_CFG_FILE_NAME}
- assert_eq 1 "${_GET_PIDS_NUM}" \
- "Expected %d ${agent_name} process running, found %d processes running"
-
# Make sure that Netconf agent is running.
if ${have_netconf}; then
get_pid ${netconf_name} ${NC_CFG_FILE_NAME}
# Create configuration file for keactrl. This configuration enables
# all servers.
keactrl_config="${CFG_FILES}\ndhcp4=yes\ndhcp6=yes\n\
-dhcp_ddns=yes\nctrl_agent=yes\nnetconf=yes\n\
+dhcp_ddns=yes\nnetconf=yes\n\
kea_verbose=no\n${keactrl_fixed_config}"
test_start "keactrl.stop_selected_server_test"
create_dhcp4_config "${dhcp4_config}"
create_dhcp6_config "${dhcp6_config}"
create_d2_config "${dhcp_ddns_config}"
- create_ca_config "${control_agent_config}"
create_nc_config "${netconf_config}"
create_keactrl_config "${keactrl_config}"
assert_eq 1 "${_GET_PIDS_NUM}" \
"Expected %d ${d2_name} process running, found %d processes running"
- get_pid ${agent_name} ${CA_CFG_FILE_NAME}
- assert_eq 1 "${_GET_PIDS_NUM}" \
- "Expected %d ${agent_name} process running, found %d processes running"
-
if ${have_netconf}; then
get_pid ${netconf_name} ${NC_CFG_FILE_NAME}
assert_eq 1 "${_GET_PIDS_NUM}" \
assert_eq 1 "${_GET_PIDS_NUM}" \
"Expected %d ${d2_name} process running, found %d processes running"
- # Make sure CA is still running
- get_pid ${agent_name} ${CA_CFG_FILE_NAME}
- assert_eq 1 "${_GET_PIDS_NUM}" \
- "Expected %d ${agent_name} process running, found %d processes running"
-
# Make sure Netconf agent is still running
if ${have_netconf}; then
get_pid ${netconf_name} ${NC_CFG_FILE_NAME}
assert_eq 1 "${_GET_PIDS_NUM}" \
"Expected %d ${d2_name} process running, found %d processes running"
- # Make sure CA is still running
- get_pid ${agent_name} ${CA_CFG_FILE_NAME}
- assert_eq 1 "${_GET_PIDS_NUM}" \
- "Expected %d ${agent_name} process running, found %d processes running"
-
# Use keactrl stop to shutdown D2 server.
printf 'Stopping DHCP DDNS server: %s stop -s dhcp_ddns -c %s\n' "${keactrl}" "${KEACTRL_CFG_FILE}"
run_command \
assert_eq 1 "${_WAIT_FOR_SERVER_DOWN}" \
"Expected wait_for_server_down return %d, returned %d"
- # Make sure CA is still running
- get_pid ${agent_name} ${CA_CFG_FILE_NAME}
- assert_eq 1 "${_GET_PIDS_NUM}" \
- "Expected %d ${agent_name} process running, found %d processes running"
-
# Make sure Netconf agent is still running
if ${have_netconf}; then
get_pid ${netconf_name} ${NC_CFG_FILE_NAME}
"Expected %d ${netconf_name} process running, found %d processes running"
fi
- # Use keactrl stop to shutdown CA.
- printf 'Stopping Control Agent: %s stop -s ctrl_agent -c %s\n' "${keactrl}" "${KEACTRL_CFG_FILE}"
- run_command \
- "${keactrl}" stop -s ctrl_agent -c ${KEACTRL_CFG_FILE}
- assert_eq 0 "${EXIT_CODE}" "Expected keactrl to return %d, returned value was %d."
-
- # Wait up to 10s for the CA to stop.
- wait_for_message 10 "DCTL_SHUTDOWN" 2
- assert_eq 1 "${_WAIT_FOR_MESSAGE}" \
- "Timeout waiting for ${agent_name} to shutdown. \
-Expected wait_for_message return %d, returned %d."
-
- # Make sure that the CA is down.
- if ${have_netconf}; then
- expected=6
- else
- expected=5
- fi
- wait_for_server_down ${expected} ${agent_name}
- assert_eq 1 "${_WAIT_FOR_SERVER_DOWN}" \
- "Expected wait_for_server_down return %d, returned %d"
-
# Make sure Netconf agent is still running
if ${have_netconf}; then
get_pid ${netconf_name} ${NC_CFG_FILE_NAME}
"Expected keactrl status command return %s"
assert_string_contains "DHCP DDNS: inactive" "${OUTPUT}" \
"Expected keactrl status command return %s"
- assert_string_contains "Control Agent: inactive" "${OUTPUT}" \
- "Expected keactrl status command return %s"
if ${have_netconf}; then
assert_string_contains "Netconf agent: inactive" "${OUTPUT}" \
"Expected keactrl status command return %s"
# Create configuration file for keactrl.
# Note that += is NOT in POSIX shell so PLEASE do NOT use it.
keactrl_config="${CFG_FILES}\ndhcp4=yes\ndhcp6=yes\ndhcp_ddns=yes\n"
- keactrl_config="${keactrl_config}ctrl_agent=yes\nnetconf=yes\n"
+ keactrl_config="${keactrl_config}netconf=yes\n"
keactrl_config="${keactrl_config}kea_verbose=no\n${keactrl_fixed_config}"
create_keactrl_config "${keactrl_config}"
exp="${exp}kea-dhcp4: @PACKAGE_VERSION@\n"
exp="${exp}kea-dhcp6: @PACKAGE_VERSION@\n"
exp="${exp}kea-dhcp-ddns: @PACKAGE_VERSION@\n"
- exp="${exp}kea-ctrl-agent: @PACKAGE_VERSION@"
if ${have_netconf}; then
exp="${exp}\nkea-netconf: @PACKAGE_VERSION@"
fi
subdir('dhcp4')
subdir('dhcp6')
subdir('d2')
-subdir('agent')
subdir('admin')
subdir('keactrl')
subdir('perfdhcp')
{ "model", Element::string, "kea-dhcp-ddns" }
};
-/// @brief Supplies defaults for ca managed server
-const SimpleDefaults NetconfSimpleParser::CA_DEFAULTS = {
- { "model", Element::string, "kea-ctrl-agent" }
-};
-
/// @brief List of parameters that can be inherited to managed-servers scope.
///
/// Some parameters may be defined on both global (directly in Netconf) and
cnt += setDefaults(server, DHCP6_DEFAULTS);
} else if (name == "d2") {
cnt += setDefaults(server, D2_DEFAULTS);
- } else if (name == "ca") {
- cnt += setDefaults(server, CA_DEFAULTS);
}
ConstElementPtr ctrl_sock = server->get("control-socket");
static const isc::data::SimpleDefaults DHCP4_DEFAULTS;
static const isc::data::SimpleDefaults DHCP6_DEFAULTS;
static const isc::data::SimpleDefaults D2_DEFAULTS;
- static const isc::data::SimpleDefaults CA_DEFAULTS;
static const isc::data::ParamsList INHERIT_TO_SERVERS;
}; // NetconfSimpleParser
"socket3",
Url("http://127.0.0.1:8000/")));
CfgServerPtr server3(new CfgServer("model3", socket3));
- CfgControlSocketPtr
- socket4(new CfgControlSocket(CfgControlSocket::Type::UNIX,
- "socket4",
- Url("http://127.0.0.1:8000/")));
- CfgServerPtr server4(new CfgServer("model4", socket4));
// Ok, now set the server for D2
EXPECT_NO_THROW_LOG(ctx.getCfgServersMap()->insert(make_pair("d2", server1)));
// Finally, set all servers.
EXPECT_NO_THROW_LOG(ctx.getCfgServersMap()->insert(make_pair("dhcp4", server3)));
- EXPECT_NO_THROW_LOG(ctx.getCfgServersMap()->insert(make_pair("ca", server4)));
- EXPECT_EQ(4, ctx.getCfgServersMap()->size());
ASSERT_NO_THROW_LOG(ctx.getCfgServersMap()->at("dhcp4"));
- ASSERT_NO_THROW_LOG(ctx.getCfgServersMap()->at("ca"));
EXPECT_EQ(server3, ctx.getCfgServersMap()->at("dhcp4"));
- EXPECT_EQ(server4, ctx.getCfgServersMap()->at("ca"));
}
// Tests if the context can store and retrieve hook libs information.
" }\n"
"}",
- // Configuration 3: all 4 servers
+ // Configuration 3: all 3 servers
"{\n"
" \"boot-update\": false,\n"
" \"managed-servers\": {\n"
" \"control-socket\": {\n"
" \"socket-name\": \"/tmp/socket-d2\"\n"
" }\n"
- " },\n"
- " \"ca\": {\n"
- " \"control-socket\": {\n"
- " \"socket-name\": \"/tmp/socket-ca\"\n"
- " }\n"
" }\n"
" }\n"
"}",
EXPECT_EQ("/tmp/socket-d2", socket->getName());
EXPECT_EQ("http://127.0.0.1:8000/", socket->getUrl().toText());
- ASSERT_NO_THROW_LOG(ctx->getCfgServersMap()->at("ca"));
- server = ctx->getCfgServersMap()->at("ca");
- ASSERT_TRUE(server);
- EXPECT_EQ(KEA_CTRL_AGENT, server->getModel());
- EXPECT_FALSE(server->getBootUpdate());
- EXPECT_TRUE(server->getSubscribeChanges());
- EXPECT_TRUE(server->getValidateChanges());
- socket = server->getCfgControlSocket();
- ASSERT_TRUE(socket);
- EXPECT_EQ(CfgControlSocket::Type::STDOUT, socket->getType());
- EXPECT_EQ("/tmp/socket-ca", socket->getName());
- EXPECT_EQ("http://127.0.0.1:8000/", socket->getUrl().toText());
-
// Check unparsing.
string expected = "{\n"
" \"Netconf\": {\n"
" \"socket-name\": \"/tmp/socket-d2\",\n"
" \"socket-url\": \"http://127.0.0.1:8000/\"\n"
" }\n"
- " },\n"
- " \"ca\": {\n"
- " \"model\": \"kea-ctrl-agent\",\n"
- " \"boot-update\": false,\n"
- " \"subscribe-changes\": true,\n"
- " \"validate-changes\": true,\n"
- " \"control-socket\": {\n"
- " \"socket-type\": \"stdout\",\n"
- " \"socket-name\": \"/tmp/socket-ca\",\n"
- " \"socket-url\": \"http://127.0.0.1:8000/\"\n"
- " }\n"
" }\n"
" },\n"
" \"hooks-libraries\": [ ]\n"
" \"control-socket\": {"
" \"socket-type\": \"stdout\""
" }"
- " },"
- " \"ca\": {"
- " \"model\": \"kea-ctrl-agent\","
- " \"boot-update\": false,"
- " \"subscribe-changes\": false,"
- " \"validate-changes\": false,"
- " \"control-socket\": {"
- " \"socket-type\": \"http\","
- " \"user-context\": { \"use default\": true }"
- " }"
" }"
" },"
" \"hooks-libraries\": ["
" \"control-socket\": {"
" \"socket-type\": \"stdout\""
" }"
- " },"
- " \"ca\": {"
- " \"model\": \"kea-ctrl-agent\","
- " \"boot-update\": false,"
- " \"subscribe-changes\": false,"
- " \"validate-changes\": false,"
- " \"control-socket\": {"
- " \"socket-type\": \"http\","
- " \"user-context\": { \"use default\": true }"
- " }"
" }"
" },"
" \"hooks-libraries\": ["
sys.path.append('@PKGPYTHONDIR@')
import kea_connector3 as kea_connector
-from kea_conn import CARequest # CAResponse
+from kea_conn import RARequest # RAResponse
VERSION = "@PACKAGE_VERSION@"
'client that uses REST interface to '
'connect to Kea servers over HTTP/HTTPS.')
parser.add_argument('--host', type=str, default='127.0.0.1',
- help='hostname of the CA to connect to '
+ help='hostname of the server to connect to '
'(default:; 127.0.0.1)')
parser.add_argument('--port', type=int, default=8000,
- help='TCP port of the CA to connect to '
+ help='TCP port of the server to connect to '
'(default: 8000)')
parser.add_argument('--path', type=str, default='',
help='Path of the URL to connect to '
'(default: "")')
parser.add_argument('--timeout', type=int, default='10',
help='Timeout (in seconds) when attempting to '
- 'connect to CA (default: 10)')
+ 'connect to the server (default: 10)')
parser.add_argument('--service', nargs="?", action="append",
- help='target specified service. If not specified,'
- 'the destination itself will receive command.')
+ help='obsolete parameter.')
parser.add_argument('--auth-user', type=str, default='',
help='Basic HTTP authentication user')
parser.add_argument('--auth-password', type=str, default='',
# Ok, now it's time to put the parameters parsed into the structure to be
# used by the connection.
- params = CARequest()
+ params = RARequest()
params.command = cmd_args.command
- params.service = cmd_args.service
params.http_host = cmd_args.host
params.http_port = cmd_args.port
params.path += cmd_args.path
"""
-class CARequest:
+class RARequest:
"""
This class defines the HTTP request to be sent.
The supported parameters listed are:
- - path (specifies the path on the server, CA uses only /)
+ - path (specifies the path on the server, Kea uses only /)
- scheme - http or https
- - http_host - hostname of the CA
- - http_port - TCP port of the CA
+ - http_host - hostname of the server
+ - http_port - TCP port of the server
- ca - False or CA file or path
- cert - False or cert file
- key - False or private key file
- command - specifies the command to send (e.g. list-commands)
- - service - specifies service that is target for the command (e.g. dhcp4)
- timeout - timeout (in ms)
- auth - basic HTTP authentication credential
- args - extra arguments my be added here
cert = False
key = False
command = ''
- service = None
timeout = 0
auth = None
args = ''
this stores the output in self.content
"""
self.content = '{ "command": "' + self.command + '"'
- if self.service is not None:
- self.service = [x for x in self.service if x]
- if len(self.service) > 0:
- self.content += ', "service": ["' + '","'.join(self.service) + '"]'
if len(self.args) > 1:
self.content += ', "arguments": { ' + self.args + ' }'
self.content += ' }'
self.headers['Content-Length'] = "%d" % (len(self.content))
-class CAResponse:
+class RAResponse:
"""
This class represents the HTTP response
"""
import ssl
import os
-from kea_conn import CAResponse # CARequest
+from kea_conn import RAResponse # RARequest
def send_to_kea(params):
# Allowing use of file:/ or custom schemes is often unexpected.
# Reason for nosec: url is checked to be http further above.
with urllib.request.urlopen(req, context=ssl_ctx) as resp: # nosec B310
- # Now get the response details, put it in CAResponse and return it
- result = CAResponse(resp.getcode(), resp.reason,
+ # Now get the response details, put it in RAResponse and return it
+ result = RAResponse(resp.getcode(), resp.reason,
resp.read().decode("utf-8"))
return result
+++ /dev/null
-#!/bin/sh
-
-# Copyright (C) 2020-2025 Internet Systems Consortium, Inc. ("ISC")
-#
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-# Exit with error if commands exit with non-zero and if undefined variables are
-# used.
-set -eu
-
-# Test suite for CA
-test_suite="ca"
-
-# Path to the temporary configuration file.
-# shellcheck disable=SC2034
-# SC2034: ... appears unused. Verify use (or export if used externally).
-# reason: used in dhcp_test_lib.sh.in
-CFG_FILE="@abs_top_builddir@/src/bin/shell/tests/test_config.json"
-
-# Path to the Control Agent log file.
-LOG_FILE="@abs_top_builddir@/src/bin/shell/tests/test.log"
-
-# Set env KEA_LOG_FILE_DIR to override default log path.
-export KEA_LOG_FILE_DIR="@abs_top_builddir@/src/bin/shell/tests"
-
-# Control Agent configuration to be stored in the configuration file.
-# todo: use actual configuration once we support it.
-CONFIG="{
- \"Control-agent\":
- {
- \"http-host\": \"127.0.0.1\",
- \"http-port\": 8081,
- \"authentication\":
- {
- \"type\": \"basic\",
- \"realm\": \"ISC.ORG\",
- \"clients\": [
- {
- \"user\": \"pet\",
- \"password\": \"meow\"
- }
- ]
- },
- \"loggers\": [
- {
- \"name\": \"kea-ctrl-agent\",
- \"output-options\": [
- {
- \"output\": \"$LOG_FILE\"
- }
- ],
- \"severity\": \"DEBUG\"
- }
- ]
- }
-}"
-
-# In these tests we need to use two binaries: Control Agent and Kea shell.
-# Using bin and bin_path would be confusing, so we omit defining bin
-# and bin_path on purpose.
-ca_bin="kea-ctrl-agent"
-ca_bin_path="@abs_top_builddir@/src/bin/agent"
-
-shell_bin="kea-shell"
-shell_bin_path="@abs_top_builddir@/src/bin/shell"
-
-tmpfile_path="@abs_top_builddir@/src/bin/shell/tests"
-
-# Import common test library.
-# shellcheck source=src/lib/testutils/dhcp_test_lib.sh.in
-. "@abs_top_builddir@/src/lib/testutils/dhcp_test_lib.sh"
-
-run_kea_shell() {
- # shellcheck disable=SC2086
- # SC2086: Double quote to prevent globbing and word splitting.
- # reason: ${auth} can be empty here, if we quote, it will be interpreted as
- # an empty string which is not desired as it will result in unrecognized
- # argument from kea-shell.
- echo | "${shell_bin_path}/${shell_bin}" --host 127.0.0.1 --port 8081 \
- ${auth} "${cmd}" > "${tmpfile_path}/shell-stdout.txt"
-}
-
-# This test verifies that Control Agent is shut down gracefully when it
-# receives a SIGINT or SIGTERM signal.
-shell_command_test() {
- test_name=${1} # Test name
- auth=${2} # Authentication
- cmd=${3} # Command to be sent
- exp_result=${4} # Expected result
- exp_rsp=${5} # Expected response
-
- # Setup phase: start CA.
-
- # Log the start of the test and print test name.
- test_start "${test_suite}-${test_name}"
-
- # Create new configuration file.
- create_config "${CONFIG}"
-
- # Instruct Control Agent to log to the specific file.
- set_logger
- # Start Control Agent.
- start_kea ${ca_bin_path}/${ca_bin}
- # Wait up to 20s for Control Agent to start.
- wait_for_kea 20
- if [ "${_WAIT_FOR_KEA}" -eq 0 ]; then
- printf "ERROR: timeout waiting for Control Agent to start.\n"
- clean_exit 1
- fi
-
- # Check if it is still running. It could have terminated (e.g. as a result
- # of configuration failure).
- get_pid ${ca_bin}
- if [ "${_GET_PIDS_NUM}" -ne 1 ]; then
- printf "ERROR: expected one Control Agent process to be started.\
- Found %d processes started.\n" "${_GET_PIDS_NUM}"
- clean_exit 1
- fi
-
- # Check in the log file, how many times server has been configured.
- # It should be just once on startup.
- get_reconfigs
- if [ "${_GET_RECONFIGS}" -ne 1 ]; then
- printf "ERROR: server been configured %s time(s),\
- but exactly 1 was expected.\n" "${_GET_RECONFIGS}"
- clean_exit 1
- else
- printf "Server successfully configured.\n"
- fi
-
- # Main test phase: send command, check response.
- tmp="echo | ${shell_bin_path}/${shell_bin} --host \
- 127.0.0.1 --port 8081 ${auth} ${cmd} > ${tmpfile_path}/shell-stdout.txt"
- echo "Executing kea-shell ($tmp)"
-
- run_command \
- run_kea_shell
-
- # Check the exit code
- if [ "${exp_result}" = "fail" ]; then
- if [ "${EXIT_CODE}" -eq 0 ]; then
- echo "ERROR:" \
- "kea-shell returned ${EXIT_CODE} exit code, expected 1."
- else
- echo "kea-shell returned ${EXIT_CODE} exit code as expected."
- fi
- elif [ "${EXIT_CODE}" -ne 0 ]; then
- echo "ERROR:" \
- "kea-shell returned ${EXIT_CODE} exit code, expected 0."
- else
- echo "kea-shell returned ${EXIT_CODE} exit code as expected."
- fi
-
- # Now check the response
- rm -f ${tmpfile_path}/shell-expected.txt
- printf '%s\n' "${exp_rsp}" > ${tmpfile_path}/shell-expected.txt
- if diff "${tmpfile_path}/shell-stdout.txt" "${tmpfile_path}/shell-expected.txt"; then
- echo "Content returned by kea-shell meets expectation."
- rm ${tmpfile_path}/shell-*.txt
- else
- echo "ERROR:" \
- "content returned is different than expected." \
- "See ${tmpfile_path}/shell-*.txt"
- echo "EXPECTED:"
- cat ${tmpfile_path}/shell-expected.txt
- echo "ACTUAL RESULT:"
- cat ${tmpfile_path}/shell-stdout.txt
- clean_exit 1
- fi
- # Main test phase ends.
-
- # Cleanup phase: shutdown CA
- # Send SIGTERM signal to Control Agent
- send_signal 15 ${ca_bin}
-
- # Now wait for process to log that it is exiting.
- wait_for_message 10 "DCTL_SHUTDOWN" 1
- if [ "${_WAIT_FOR_MESSAGE}" -eq 0 ]; then
- printf "ERROR: Control Agent did not log shutdown.\n"
- clean_exit 1
- fi
-
- # Make sure the server is down.
- wait_for_server_down 5 ${ca_bin}
- assert_eq 1 "${_WAIT_FOR_SERVER_DOWN}" \
- "Expected wait_for_server_down return %d, returned %d"
-
- test_finish 0
-}
-
-shell_command_test "shell.no-auth" "" "list-commands" "fail" \
- "Failed to run: HTTP Error 401: Unauthorized"
-shell_command_test "shell.bad-auth" \
- "--auth-user foo --auth-password bar" "list-commands" "fail" \
- "Failed to run: HTTP Error 401: Unauthorized"
-shell_command_test "shell.authorized" \
- "--auth-user pet --auth-password meow" "list-commands" "" \
- "[ { \"arguments\": [ \"build-report\", \"config-get\", \"config-hash-get\", \"config-reload\", \"config-set\", \"config-test\", \"config-write\", \"list-commands\", \"shutdown\", \"status-get\", \"version-get\" ], \"result\": 0 } ]"
-shell_command_test "shell.bad-auth-password-file" \
- "--auth-user foo --auth-password-file foobar" "list-commands" "fail" \
- "Failed to run: [Errno 2] No such file or directory: 'foobar'"
-shell_command_test "shell.bad-auth-password-file-content" \
- "--auth-user foo --auth-password-file ${tmpfile_path}/auth_bad_password_file" "list-commands" "fail" \
- "Failed to run: HTTP Error 401: Unauthorized"
-shell_command_test "shell.good-auth-password-file-content" \
- "--auth-user pet --auth-password-file ${tmpfile_path}/auth_password_file" "list-commands" "" \
- "[ { \"arguments\": [ \"build-report\", \"config-get\", \"config-hash-get\", \"config-reload\", \"config-set\", \"config-test\", \"config-write\", \"list-commands\", \"shutdown\", \"status-get\", \"version-get\" ], \"result\": 0 } ]"
-shell_command_test "shell.flag-precedence" \
- "--auth-user pet --auth-password meow --auth-password-file ${tmpfile_path}/auth_bad_password_file" "list-commands" "fail" \
- "Failed to run: HTTP Error 401: Unauthorized"
env: pythonpath,
suite: 'python-tests',
)
-ca_basic_auth_tests = configure_file(
- input: 'ca_basic_auth_tests.sh.in',
- output: 'ca_basic_auth_tests.sh',
- configuration: shell_tests_conf_data,
-)
-test(
- 'ca_basic_auth_tests.sh',
- ca_basic_auth_tests,
- is_parallel: false,
- priority: -1,
- suite: 'shell-tests',
-)
d2_basic_auth_tests = configure_file(
input: 'd2_basic_auth_tests.sh.in',
output: 'd2_basic_auth_tests.sh',
priority: -1,
suite: 'shell-tests',
)
-shell_ca_process_tests = configure_file(
- input: 'shell_ca_process_tests.sh.in',
- output: 'shell_ca_process_tests.sh',
- configuration: shell_tests_conf_data,
-)
-test(
- 'shell_ca_process_tests.sh',
- shell_ca_process_tests,
- is_parallel: false,
- priority: -1,
- suite: 'shell-tests',
-)
shell_d2_process_tests = configure_file(
input: 'shell_d2_process_tests.sh.in',
output: 'shell_d2_process_tests.sh',
priority: -1,
suite: 'shell-tests',
)
-tls_ca_process_tests = configure_file(
- input: 'tls_ca_process_tests.sh.in',
- output: 'tls_ca_process_tests.sh',
- configuration: shell_tests_conf_data,
-)
-test(
- 'tls_ca_process_tests.sh',
- tls_ca_process_tests,
- is_parallel: false,
- priority: -1,
- suite: 'shell-tests',
-)
tls_d2_process_tests = configure_file(
input: 'tls_d2_process_tests.sh.in',
output: 'tls_d2_process_tests.sh',
+++ /dev/null
-#!/bin/sh
-
-# Copyright (C) 2017-2025 Internet Systems Consortium, Inc. ("ISC")
-#
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-# Exit with error if commands exit with non-zero and if undefined variables are
-# used.
-set -eu
-
-# Test suite for CA
-test_suite="ca"
-
-# Path to the temporary configuration file.
-# shellcheck disable=SC2034
-# SC2034: ... appears unused. Verify use (or export if used externally).
-# reason: used in dhcp_test_lib.sh.in
-CFG_FILE="@abs_top_builddir@/src/bin/shell/tests/test_config.json"
-
-# Path to the Control Agent log file.
-LOG_FILE="@abs_top_builddir@/src/bin/shell/tests/test.log"
-
-# Set env KEA_LOG_FILE_DIR to override default log path.
-export KEA_LOG_FILE_DIR="@abs_top_builddir@/src/bin/shell/tests"
-
-# Control Agent configuration to be stored in the configuration file.
-# todo: use actual configuration once we support it.
-CONFIG="{
- \"Control-agent\":
- {
- \"http-host\": \"127.0.0.1\",
- \"http-port\": 8081,
- \"loggers\": [
- {
- \"name\": \"kea-ctrl-agent\",
- \"output-options\": [
- {
- \"output\": \"$LOG_FILE\"
- }
- ],
- \"severity\": \"DEBUG\"
- }
- ]
- }
-}"
-
-# In these tests we need to use two binaries: Control Agent and Kea shell.
-# Using bin and bin_path would be confusing, so we omit defining bin
-# and bin_path on purpose.
-ca_bin="kea-ctrl-agent"
-ca_bin_path="@abs_top_builddir@/src/bin/agent"
-
-shell_bin="kea-shell"
-shell_bin_path="@abs_top_builddir@/src/bin/shell"
-
-tmpfile_path="@abs_top_builddir@/src/bin/shell/tests"
-
-# Import common test library.
-# shellcheck source=src/lib/testutils/dhcp_test_lib.sh.in
-. "@abs_top_builddir@/src/lib/testutils/dhcp_test_lib.sh"
-
-# This test verifies that Control Agent is shut down gracefully when it
-# receives a SIGINT or SIGTERM signal.
-shell_command_test() {
- test_name=${1} # Test name
- cmd=${2} # Command to be sent
- exp_rsp=${3} # Expected response
- params=${4} # Any extra parameters
-
- # Setup phase: start CA.
-
- # Log the start of the test and print test name.
- test_start "${test_suite}-${test_name}"
-
- # Create new configuration file.
- create_config "${CONFIG}"
-
- # Instruct Control Agent to log to the specific file.
- set_logger
- # Start Control Agent.
- start_kea ${ca_bin_path}/${ca_bin}
- # Wait up to 20s for Control Agent to start.
- wait_for_kea 20
- if [ "${_WAIT_FOR_KEA}" -eq 0 ]; then
- printf "ERROR: timeout waiting for Control Agent to start.\n"
- clean_exit 1
- fi
-
- # Check if it is still running. It could have terminated (e.g. as a result
- # of configuration failure).
- get_pid "${ca_bin}"
- if [ "${_GET_PIDS_NUM}" -ne 1 ]; then
- printf "ERROR: expected one Control Agent process to be started.\
- Found %d processes started.\n" "${_GET_PIDS_NUM}"
- clean_exit 1
- fi
-
- # Check in the log file, how many times server has been configured.
- # It should be just once on startup.
- get_reconfigs
- if [ "${_GET_RECONFIGS}" -ne 1 ]; then
- printf "ERROR: server been configured %s time(s),\
- but exactly 1 was expected.\n" "${_GET_RECONFIGS}"
- clean_exit 1
- else
- printf "Server successfully configured.\n"
- fi
-
- # Main test phase: send command, check response.
- tmp="echo \"${params}\" | ${shell_bin_path}/${shell_bin} --host \
- 127.0.0.1 --port 8081 ${cmd} > ${tmpfile_path}/shell-stdout.txt"
- echo "Executing kea-shell ($tmp)"
-
- echo "${params}" | ${shell_bin_path}/${shell_bin} --host 127.0.0.1 \
- --port 8081 "${cmd}" > ${tmpfile_path}/shell-stdout.txt
- shell_exit_code=$?
-
- # Check the exit code
- if [ "${shell_exit_code}" -ne 0 ]; then
- echo "ERROR:" \
- "kea-shell returned ${shell_exit_code} exit code, expected 0."
- else
- echo "kea-shell returned ${shell_exit_code} exit code as expected."
- fi
-
- # Now check the response
- rm -f ${tmpfile_path}/shell-expected.txt
- printf '%s\n' "${exp_rsp}" > ${tmpfile_path}/shell-expected.txt
- diff ${tmpfile_path}/shell-stdout.txt ${tmpfile_path}/shell-expected.txt
- diff_code=$?
- if [ "${diff_code}" -ne 0 ]; then
- echo "ERROR:" \
- "content returned is different than expected." \
- "See ${tmpfile_path}/shell-*.txt"
- echo "EXPECTED:"
- cat ${tmpfile_path}/shell-expected.txt
- echo "ACTUAL RESULT:"
- cat ${tmpfile_path}/shell-stdout.txt
- clean_exit 1
- else
- echo "Content returned by kea-shell meets expectation."
- rm ${tmpfile_path}/shell-*.txt
- fi
- # Main test phase ends.
-
- # Cleanup phase: shutdown CA
- # Send SIGTERM signal to Control Agent
- send_signal 15 ${ca_bin}
-
- # Now wait for process to log that it is exiting.
- wait_for_message 10 "DCTL_SHUTDOWN" 1
- if [ "${_WAIT_FOR_MESSAGE}" -eq 0 ]; then
- printf "ERROR: Control Agent did not log shutdown.\n"
- clean_exit 1
- fi
-
- # Make sure the server is down.
- wait_for_server_down 5 ${ca_bin}
- assert_eq 1 "${_WAIT_FOR_SERVER_DOWN}" \
- "Expected wait_for_server_down return %d, returned %d"
-
- test_finish 0
-}
-
-shell_command_test "shell.list-commands" "list-commands" \
- "[ { \"arguments\": [ \"build-report\", \"config-get\", \"config-hash-get\", \"config-reload\", \"config-set\", \"config-test\", \"config-write\", \"list-commands\", \"shutdown\", \"status-get\", \"version-get\" ], \"result\": 0 } ]" ""
-shell_command_test "shell.bogus" "give-me-a-beer" \
-"[ { \"result\": 2, \"text\": \"'give-me-a-beer' command not supported. You did not include \\\"service\\\" parameter in the command, which indicates that Kea Control Agent should process this command rather than forward it to one or more Kea servers. If you aimed to send this command to one of the Kea servers you should include the \\\"service\\\" parameter in your request, e.g. \\\"service\\\": [ \\\"dhcp4\\\" ] to forward the command to the DHCPv4 server, or \\\"service\\\": [ \\\"dhcp4\\\", \\\"dhcp6\\\", \\\"d2\\\" ] to forward it to DHCPv4, DHCPv6 and D2 servers etc.\" } ]" ""
-shell_command_test "shell.empty-config-test" "config-test" \
- "[ { \"result\": 1, \"text\": \"Missing mandatory 'arguments' parameter.\" } ]" ""
-shell_command_test "shell.no-app-config-test" "config-test" \
- "[ { \"result\": 1, \"text\": \"Missing mandatory 'Control-agent' parameter.\" } ]" \
- "\"FooBar\": { }"
-shell_command_test "shell.no-map-config-test" "config-test" \
- "[ { \"result\": 1, \"text\": \"'Control-agent' parameter expected to be a map.\" } ]" \
- "\"Control-agent\": [ ]"
-shell_command_test "shell.bad-value-config-test" "config-test" \
- "[ { \"result\": 1, \"text\": \"out of range value (80000) specified for parameter 'http-port' (<string>:1:76)\" } ]" \
- "\"Control-agent\": { \"http-port\": 80000 }"
import sys
from base64 import b64encode
-from kea_conn import CARequest
+from kea_conn import RARequest
-class CARequestUnitTest(unittest.TestCase):
+class RARequestUnitTest(unittest.TestCase):
"""
- This class is dedicated to testing CARequest class. That class
+ This class is dedicated to testing RARequest class. That class
is responsible for generation of the body and headers.
"""
This method is called before each test. Currently it does nothing.
"""
- def test_body_with_service(self):
- """
- This test verifies if the CARequest object generates the request
- content properly when there is one target service.
- """
- request = CARequest()
- request.command = "foo"
- request.service = ["service1"]
- request.generate_body()
- self.assertEqual(request.content,
- '{ "command": "foo", "service": ["service1"] }')
-
- def test_body_with_multiple_service(self):
- """
- This test verifies if the CARequest object generates the request
- content properly when there are two target service.
- """
- request = CARequest()
- request.command = "foo"
- request.service = ["service1", "service2/2"]
- request.generate_body()
- self.assertEqual(request.content,
- '{ "command": "foo", "service": ["service1","service2/2"] }')
-
- def test_body_with_malformed_service(self):
- """
- This test verifies if the CARequest object generates the request
- content properly when there are two target service, one is empty
- """
- request = CARequest()
- request.command = "foo"
- request.service = ["service1", ""]
- request.generate_body()
- self.assertEqual(request.content,
- '{ "command": "foo", "service": ["service1"] }')
-
def test_body_without_args(self):
"""
- This test verifies if the CARequest object generates the request
+ This test verifies if the RARequest object generates the request
content properly when there are no arguments.
"""
- request = CARequest()
+ request = RARequest()
request.command = "foo"
request.generate_body()
self.assertEqual(request.content, '{ "command": "foo" }')
def test_body_with_args(self):
"""
- This test verifies if the CARequest object generates the request
+ This test verifies if the RARequest object generates the request
content properly when there are arguments.
"""
- request = CARequest()
+ request = RARequest()
request.command = "foo"
request.args = '"bar": "baz"'
request.generate_body()
This test checks if the headers are generated properly. Note that since
the content is not specified, it is 0. Therefore Content-Length is 0.
"""
- request = CARequest()
+ request = RARequest()
request.generate_headers()
self.assertTrue(self.check_header(request.headers,
this test there is specific content of non-zero length, and
its size should be reflected in the header.
"""
- request = CARequest()
+ request = RARequest()
request.content = '{ "command": "foo" }'
request.generate_headers()
This test checks if the version reported in HTTP headers is
generated properly.
"""
- request = CARequest()
+ request = RARequest()
request.version = "1.2.3"
request.generate_headers()
self.assertTrue(self.check_header(request.headers, 'User-Agent',
This test checks if the basic HTTP authentication header is
generated properly.
"""
- request = CARequest()
+ request = RARequest()
request.auth = "Zm9vOmJhcg=="
request.generate_headers()
+++ /dev/null
-#!/bin/sh
-
-# Copyright (C) 2016-2025 Internet Systems Consortium, Inc. ("ISC")
-#
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-# Exit with error if commands exit with non-zero and if undefined variables are
-# used.
-set -eu
-
-# Test suite for CA
-test_suite="ca"
-
-# Include common test library.
-# shellcheck source=src/lib/testutils/dhcp_test_lib.sh.in
-. "@abs_top_builddir@/src/lib/testutils/dhcp_test_lib.sh"
-
-# Path to the temporary configuration file.
-CFG_FILE="@abs_top_builddir@/src/bin/shell/tests/test_config.json"
-
-# Path to the Control Agent log file.
-LOG_FILE="@abs_top_builddir@/src/bin/shell/tests/test.log"
-
-# Set env KEA_LOG_FILE_DIR to override default log path.
-export KEA_LOG_FILE_DIR="@abs_top_builddir@/src/bin/shell/tests"
-
-# Path to the test certificate authority directory.
-TEST_CA_DIR="@abs_top_srcdir@/src/lib/asiolink/testutils/ca"
-
-# Configuration without TLS.
-CONFIG_NONE="{
- \"Control-agent\":
- {
- \"http-host\": \"127.0.0.1\",
- \"http-port\": 8443,
- \"loggers\": [
- {
- \"name\": \"kea-ctrl-agent\",
- \"output-options\": [
- {
- \"output\": \"${LOG_FILE}\"
- }
- ],
- \"severity\": \"DEBUG\"
- }
- ]
- }
-}"
-
-# Configuration without mutual authentication i.e. only channel protection.
-CONFIG_NOCR="{
- \"Control-agent\":
- {
- \"http-host\": \"127.0.0.1\",
- \"http-port\": 8443,
- \"trust-anchor\": \"${TEST_CA_DIR}/kea-ca.crt\",
- \"cert-file\": \"${TEST_CA_DIR}/kea-server-addr.crt\",
- \"key-file\": \"${TEST_CA_DIR}/kea-server.key\",
- \"cert-required\": false,
- \"loggers\": [
- {
- \"name\": \"kea-ctrl-agent\",
- \"output-options\": [
- {
- \"output\": \"${LOG_FILE}\"
- }
- ],
- \"severity\": \"DEBUG\"
- }
- ]
- }
-}"
-
-# Configuration with mutual authentication.
-CONFIG="{
- \"Control-agent\":
- {
- \"http-host\": \"127.0.0.1\",
- \"http-port\": 8443,
- \"trust-anchor\": \"${TEST_CA_DIR}/kea-ca.crt\",
- \"cert-file\": \"${TEST_CA_DIR}/kea-server-addr.crt\",
- \"key-file\": \"${TEST_CA_DIR}/kea-server.key\",
- \"cert-required\": true,
- \"loggers\": [
- {
- \"name\": \"kea-ctrl-agent\",
- \"output-options\": [
- {
- \"output\": \"${LOG_FILE}\"
- }
- ],
- \"severity\": \"DEBUG\"
- }
- ]
- }
-}"
-
-# In these tests we need to use two binaries: Control Agent and Kea shell.
-# Using bin and bin_path would be confusing, so we omit defining bin
-# and bin_path on purpose.
-ca_bin="kea-ctrl-agent"
-ca_bin_path="@abs_top_builddir@/src/bin/agent"
-
-shell_bin="kea-shell"
-shell_bin_path="@abs_top_builddir@/src/bin/shell"
-
-tmpfile_path="@abs_top_builddir@/src/bin/shell/tests"
-
-list_commands_test() {
- local test_name="${1}"
- local config="${2}"
- local arguments="${3}"
- local expected_response="${4}"
-
- # Setup phase: start CA.
-
- # Log the start of the test and print test name.
- test_start "${test_suite}-${test_name}"
-
- # Create correct configuration file.
- create_config "${config}"
-
- # Instruct Control Agent to log to the specific file.
- set_logger
-
- # Start Control Agent
- start_kea ${ca_bin_path}/${ca_bin}
-
- # Wait up to 20s for Control Agent to start.
- wait_for_kea 20
- if [ "${_WAIT_FOR_KEA}" -eq 0 ]; then
- printf "ERROR: timeout waiting for Control Agent to start.\n"
- clean_exit 1
- fi
-
- # Check if it is still running. It could have terminated (e.g. as a result
- # of configuration failure).
- get_pid ${ca_bin}
- if [ "${_GET_PIDS_NUM}" -ne 1 ]; then
- printf "ERROR: expected one Control Agent process to be started. \
- Found %d processes started.\n" "${_GET_PIDS_NUM}"
- clean_exit 1
- fi
-
- # Check in the log file, how many times server has been configured.
- # It should be just once on startup.
- get_reconfigs
- if [ "${_GET_RECONFIGS}" -ne 1 ]; then
- printf 'ERROR: server been configured %s time(s), but exactly 1 was expected.\n' "${_GET_RECONFIGS}"
- clean_exit 1
- else
- printf "Server successfully configured.\n"
- fi
-
- # Main test phase: send command, check response.
-
- # shellcheck disable=SC2086
- # SC2086: Double quote to prevent globbing and word splitting.
- # Reason: we specifically want ${arguments} to split because there may be multiple words in it.
- tmp="echo | ${shell_bin_path}/${shell_bin} --port 8443 \
- ${arguments} > ${tmpfile_path}/shell-stdout.txt"
- echo "Executing kea-shell ($tmp)"
-
- # shellcheck disable=SC2086
- # SC2086: Double quote to prevent globbing and word splitting.
- # Reason: we specifically want ${arguments} to split because there may be multiple words in it.
- echo | ${shell_bin_path}/${shell_bin} --port 8443 \
- ${arguments} > ${tmpfile_path}/shell-stdout.txt
- EXIT_CODE=$?
-
- # Check the exit code
- if [ "${EXIT_CODE}" -ne 0 ]; then
- echo "ERROR: kea-shell returned ${EXIT_CODE} exit code, expected 0."
- else
- echo "kea-shell returned ${EXIT_CODE} exit code as expected."
- fi
-
- # Now check the response
- rm -f ${tmpfile_path}/shell-expected.txt
- printf '%s\n' "${expected_response}" > ${tmpfile_path}/shell-expected.txt
- diff ${tmpfile_path}/shell-stdout.txt ${tmpfile_path}/shell-expected.txt
- diff_code=$?
- if [ "${diff_code}" -ne 0 ]; then
- echo "ERROR:" \
- "content returned is different than expected." \
- "See ${tmpfile_path}/shell-*.txt"
- echo "EXPECTED:"
- cat ${tmpfile_path}/shell-expected.txt
- echo "ACTUAL RESULT:"
- cat ${tmpfile_path}/shell-stdout.txt
- clean_exit 1
- else
- echo "Content returned by kea-shell meets expectation."
- rm ${tmpfile_path}/shell-*.txt
- fi
- # Main test phase ends.
-
- # Cleanup phase: shutdown Control Agent
-
- # Send SIGTERM signal to Control Agent
- send_signal 15 ${ca_bin}
-
- # Now wait for process to log that it is exiting.
- wait_for_message 10 "DCTL_SHUTDOWN" 1
- if [ "${_WAIT_FOR_MESSAGE}" -eq 0 ]; then
- printf "ERROR: Control Agent did not log shutdown.\n"
- clean_exit 1
- fi
-
- # Make sure the agent is down.
- wait_for_server_down 5 ${ca_bin}
- assert_eq 1 "${_WAIT_FOR_SERVER_DOWN}" \
- "Expected wait_for_server_down return %d, returned %d"
-
- test_finish 0
-}
-
-list_commands_test "NoTLS" "${CONFIG_NONE}" "" \
-"[ { \"arguments\": [ \"build-report\", \"config-get\", \"config-hash-get\", \"config-reload\", \"config-set\", \"config-test\", \"config-write\", \"list-commands\", \"shutdown\", \"status-get\", \"version-get\" ], \"result\": 0 } ]"
-list_commands_test "Encrypted" "${CONFIG_NOCR}" \
-"--ca ${TEST_CA_DIR}/kea-ca.crt" \
-"[ { \"arguments\": [ \"build-report\", \"config-get\", \"config-hash-get\", \"config-reload\", \"config-set\", \"config-test\", \"config-write\", \"list-commands\", \"shutdown\", \"status-get\", \"version-get\" ], \"result\": 0 } ]"
-list_commands_test "Authenticated" "${CONFIG}" \
-"--ca ${TEST_CA_DIR}/kea-ca.crt --cert ${TEST_CA_DIR}/kea-client.crt --key ${TEST_CA_DIR}/kea-client.key" \
-"[ { \"arguments\": [ \"build-report\", \"config-get\", \"config-hash-get\", \"config-reload\", \"config-set\", \"config-test\", \"config-write\", \"list-commands\", \"shutdown\", \"status-get\", \"version-get\" ], \"result\": 0 } ]"
virtual ~TranslatorControlSocketTestv6() = default;
}; // TranslatorControlSocketTestv6
-class TranslatorControlSocketTestCtrlAgent :
- public GenericTranslatorTest<control_socket, TranslatorControlSocket> {
-public:
- /// @brief Constructor
- TranslatorControlSocketTestCtrlAgent() {
- model_ = KEA_CTRL_AGENT;
- }
-
- virtual ~TranslatorControlSocketTestCtrlAgent() = default;
-}; // TranslatorControlSocketTestCtrlAgent
-
// This test verifies that an empty control socket can be properly
// translated from YANG to JSON.
TEST_F(TranslatorControlSocketTestv4, getEmpty) {
EXPECT_EQ("{ \"foo\": 1 }", context->str());
}
-// This test verifies that a not empty control socket can be properly
-// translated from JSON to YANG.
-TEST_F(TranslatorControlSocketTestCtrlAgent, set) {
- // Set a value.
- const string& xpath =
- "/kea-ctrl-agent:config/control-sockets/control-sockets[server-type='dhcp4']/control-socket";
- ElementPtr sock = Element::createMap();
- sock->set("socket-name", Element::create("/tmp/kea.sock"));
- sock->set("socket-type", Element::create("unix"));
- sock->set("comment", Element::create("a comment"));
- try {
- translator_->setControlSocket(xpath, sock);
- } catch (exception const& ex) {
- cerr << "setControlSocket fail with " << ex.what() << endl;
- }
- ASSERT_NO_THROW_LOG(translator_->setControlSocket(xpath, sock));
-
- // Get it back.
- ConstElementPtr got;
- EXPECT_NO_THROW_LOG(got = translator_->getControlSocketFromAbsoluteXpath(xpath));
- ASSERT_TRUE(got);
- ASSERT_EQ(Element::map, got->getType());
- EXPECT_EQ(3, got->size());
- ConstElementPtr name = got->get("socket-name");
- ASSERT_TRUE(name);
- ASSERT_EQ(Element::string, name->getType());
- EXPECT_EQ("/tmp/kea.sock", name->stringValue());
- ConstElementPtr type = got->get("socket-type");
- ASSERT_TRUE(type);
- ASSERT_EQ(Element::string, type->getType());
- EXPECT_EQ("unix", type->stringValue());
- ConstElementPtr context = got->get("user-context");
- ASSERT_TRUE(context);
- EXPECT_EQ("{ \"comment\": \"a comment\" }", context->str());
-}
-
// This test verifies that an empty control socket can be properly
// translated from JSON to YANG.
TEST_F(TranslatorControlSocketTestv4, setEmpty) {
/// "user-context": { "foo": 1 }
/// }
/// @endcode
-/// @code
-/// /kea-ctrl-agent:config (container)
-/// /kea-ctrl-agent:config/control-sockets (container)
-/// /kea-ctrl-agent:config/control-sockets/
-/// control-sockets[server-type='dhcp4'] (list instance)
-/// /kea-ctrl-agent:config/control-sockets/control-sockets[server-type='dhcp4']/
-/// server-type = dhcp4
-/// /kea-ctrl-agent:config/control-sockets/control-sockets[server-type='dhcp4']/
-/// control-socket (container)
-/// /kea-ctrl-agent:config/control-sockets/control-sockets[server-type='dhcp4']/
-/// control-socket/socket-name = kea.sock
-/// /kea-ctrl-agent:config/control-sockets/control-sockets[server-type='dhcp4']/
-/// control-socket/socket-type = unix
-/// /kea-ctrl-agent:config/control-sockets/control-sockets[server-type='dhcp4']/
-/// control-socket/user-context = { \"foo\": 1 }
-/// @endcode
/// @brief A translator class for converting a control socket between
/// YANG and JSON.
/// - kea-dhcp4-server
/// - kea-dhcp6-server
/// - kea-dhcp-ddns
-/// - kea-ctrl-agent
class TranslatorControlSocket : virtual public Translator {
public:
/// @brief Constructor.
/// - kea-dhcp4-server
/// - kea-dhcp6-server
/// - kea-dhcp-ddns
-/// - kea-ctrl-agent
class TranslatorLogger : virtual public Translator {
public:
/// @brief Constructor.
Tests use these modules which you can find in src/share/yang/modules in addition
to keatest-module:
- ietf-dhcpv6-server
- - kea-ctrl-agent
- kea-dhcp-ddns
- kea-dhcp4-server
- kea-dhcp6-server
/// by ISC in the near future.
static const std::string KEA_DHCP_DDNS = "kea-dhcp-ddns";
-/// This model is currently in prototype phase. It will be developed
-/// by ISC in the near future.
-static const std::string KEA_CTRL_AGENT = "kea-ctrl-agent";
-
} // namespace yang
} // namespace isc
{ "kea-dhcp-types", "2025-06-25" },
{ "kea-dhcp4-server", "2025-06-25" },
{ "kea-dhcp6-server", "2025-06-25" },
- { "kea-ctrl-agent", "2025-06-25" },
{ "kea-dhcp-ddns", "2025-06-25" }
}; // YANG_REVISIONS
"support": [
"kea-dhcp4",
"kea-dhcp6",
- "kea-dhcp-ddns",
- "kea-ctrl-agent"
+ "kea-dhcp-ddns"
]
}
"{",
" \"result\": <integer>,",
" \"arguments\": {",
- " <Dhcp4, Dhcp6, or Control-agent object>: <JSON configuration here> ",
+ " <Dhcp4, Dhcp6, or DhcpDdns object>: <JSON configuration here> ",
" }",
"}"
],
"support": [
"kea-dhcp4",
"kea-dhcp6",
- "kea-dhcp-ddns",
- "kea-ctrl-agent"
+ "kea-dhcp-ddns"
]
}
"support": [
"kea-dhcp4",
"kea-dhcp6",
- "kea-dhcp-ddns",
- "kea-ctrl-agent"
+ "kea-dhcp-ddns"
]
}
"support": [
"kea-dhcp4",
"kea-dhcp6",
- "kea-dhcp-ddns",
- "kea-ctrl-agent"
+ "kea-dhcp-ddns"
]
}
"support": [
"kea-dhcp4",
"kea-dhcp6",
- "kea-dhcp-ddns",
- "kea-ctrl-agent"
+ "kea-dhcp-ddns"
]
}
"support": [
"kea-dhcp4",
"kea-dhcp6",
- "kea-dhcp-ddns",
- "kea-ctrl-agent"
+ "kea-dhcp-ddns"
]
}
"support": [
"kea-dhcp4",
"kea-dhcp6",
- "kea-dhcp-ddns",
- "kea-ctrl-agent"
+ "kea-dhcp-ddns"
]
}
"support": [
"kea-dhcp4",
"kea-dhcp6",
- "kea-dhcp-ddns",
- "kea-ctrl-agent"
+ "kea-dhcp-ddns"
]
}
"support": [
"kea-dhcp4",
"kea-dhcp6",
- "kea-dhcp-ddns",
- "kea-ctrl-agent"
+ "kea-dhcp-ddns"
]
}
"support": [
"kea-dhcp4",
"kea-dhcp6",
- "kea-dhcp-ddns",
- "kea-ctrl-agent"
+ "kea-dhcp-ddns"
]
}
"support": [
"kea-dhcp4",
"kea-dhcp6",
- "kea-dhcp-ddns",
- "kea-ctrl-agent"
+ "kea-dhcp-ddns"
]
}
+++ /dev/null
-58fa8cd6ff1e10129668bb54e214d137ba82017a7827e276a656443e7c8249d9
+++ /dev/null
-module kea-ctrl-agent {
- yang-version 1.1;
- namespace "urn:ietf:params:xml:ns:yang:kea-ctrl-agent";
- prefix "kea-ctrl-agent";
-
- import ietf-inet-types {
- prefix inet;
- }
- import kea-types {
- prefix kea;
- revision-date 2025-06-25;
- }
-
- organization "Internet Systems Consortium";
- contact "kea-dev@lists.isc.org";
- description "This model defines a YANG data model that can be
- used to configure and manage a Kea control agent.";
-
- revision 2025-06-25 {
- description "Added HTTP/HTTPS control socket types.
- Added trust-anchor, cert-file, key-file, cert-required
- authentication and http-headers parameters to control sockets.";
- }
-
- revision 2019-08-12 {
- description "Initial revision";
- reference "";
- }
-
- /*
- * Data Nodes
- */
-
- container config {
- // config true;
- description "Contains control agent configuration.";
-
- leaf http-host {
- type inet:ip-address;
- description "IP address to which HTTP service will be bound.";
- }
-
- leaf http-port {
- type uint16;
- description "Port to which HTTP service will be bound.";
- }
-
- container control-sockets {
- description "Control sockets.";
- list control-sockets {
- key server-type;
- description "List of server control socket.";
- leaf server-type {
- type enumeration {
- enum "dhcp4" {
- description "kea-dhcp4 server";
- }
- enum "dhcp6" {
- description "kea-dhcp6 server";
- }
- enum "d2" {
- description "kea-dhcp-ddns server";
- }
- }
- mandatory true;
- description "Server type.";
- }
- container control-socket {
- description "Control socket information.";
- uses kea:control-socket-info;
- }
- }
- }
-
- uses kea:control-socket-tls;
- uses kea:http-headers;
- uses kea:authentication;
-
- uses kea:hooks-libraries;
-
- leaf user-context {
- type kea:user-context;
- description "Control agent user context.";
- }
-
- uses kea:loggers;
- }
-}
'ietf-inet-types@2013-07-15.yang',
'ietf-interfaces@2018-02-20.yang',
'ietf-yang-types@2013-07-15.yang',
- 'kea-ctrl-agent@2025-06-25.yang',
'kea-dhcp-ddns@2025-06-25.yang',
'kea-dhcp-types@2025-06-25.yang',
'kea-dhcp4-server@2025-06-25.yang',
kea-dhcp-types*.yang \
kea-dhcp4-server*.yang \
kea-dhcp6-server*.yang \
- kea-ctrl-agent*.yang \
kea-dhcp-ddns*.yang
do
if test "${m}" = "${test}"
install_kea_module 'kea-types'
install_kea_module 'kea-dhcp-types'
install_kea_module 'kea-dhcp-ddns'
- install_kea_module 'kea-ctrl-agent'
install_kea_module 'kea-dhcp4-server'
install_kea_module 'kea-dhcp6-server'
}
uninstall_yang_modules() {
uninstall_module 'kea-dhcp6-server'
uninstall_module 'kea-dhcp4-server'
- uninstall_module 'kea-ctrl-agent'
uninstall_module 'kea-dhcp-ddns'
uninstall_module 'kea-dhcp-types'
uninstall_module 'kea-types'