command-socket.dox 8.46 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.

/**
 @page ctrlSocket Control Channel

@section ctrlSocketOverview Control Channel Overview

20
21
22
In many cases it is useful to manage certain aspects of the DHCP servers
while they are running. In Kea, this may be done via the Control Channel.
Control Channel allows an external entity (e.g. a tool run by a sysadmin
23
or a script) to issue commands to the server which can influence its
24
behavior or retreive information from it. Several notable examples
25
envisioned are: reconfiguration, statistics retrieval and manipulation,
Tomek Mrugalski's avatar
Tomek Mrugalski committed
26
and shutdown.
27
28

Communication over Control Channel is conducted using JSON structures.
29
30
As of Kea 0.9.2, the only supported communication channel is UNIX stream
socket, but additional types may be added in the future.
31
32
33

If configured, Kea will open a socket and will listen for any incoming
connections. A process connecting to this socket is expected to send JSON
34
commands structured as follows:
35
36
37

@code
{
38
    "command": "foo",
39
40
41
42
43
44
45
46
    "arguments": {
        "param_foo": "value1",
        "param_bar": "value2",
        ...
    }
}
@endcode

Tomek Mrugalski's avatar
Tomek Mrugalski committed
47
- command - is the name of command to execute and is mandatory.
48
- arguments - contain a single parameter or a map or parameters
49
50
51
required to carry out the given command.  The exact content and format is command specific.

The server will process the incoming command and then send a response of the form:
52
53
54
55
56
57
58
59
60
61
62
63
64

@code
{
    "result": 0|1,
    "text": "textual description",
    "arguments": {
        "argument1": "value1",
        "argument2": "value2",
        ...
    }
}
@endcode

65
66
67
68
69
- result - indicates the outcome of the command. A value of 0 means a success while
any non-zero value designates an error. Currently 1 is used as a generic error, but additional
error codes may be added in the future.
- text field - typically appears when result is non-zero and contains description of the error
encountered.
Tomek Mrugalski's avatar
Tomek Mrugalski committed
70
- arguments - is a map of additional data values returned by the server, specific to the
71
command issue. The map is always present, even if it contains no data values.
72

73
@section ctrlSocketClient Using Control Channel
74

75
Here are two examples of how to access the Control Channel:
76
77
78
79
80
81

1. Use socat tool, which is available in many Linux and BSD distributions.
See http://www.dest-unreach.org/socat/ for details. To use it:
@code
socat UNIX:/var/run/kea/kea4.sock -
@endcode
82
You then can type JSON commands and get responses (also in JSON format).
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105

2. Here's an example C code that connects and gets a list of supported commands:
@code
// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.

#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

106
int main(int argc, const char* argv[]) {
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121

    if (argc != 2) {
        printf("Usage: %s socket_path\n", argv[0]);
        return (1);
    }

    // Create UNIX stream socket.
    int socket_fd;
    if ((socket_fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
    {
        perror("Failed to create UNIX stream");
        return (1);
    }

    // Specify the address to connect to (unix path)
122
    struct sockaddr_un srv_addr;
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
    memset(&srv_addr, 0, sizeof(struct sockaddr_un));
    srv_addr.sun_family = AF_UNIX;
    strcpy(srv_addr.sun_path, argv[1]);
    socklen_t len = sizeof(srv_addr);

    // Try to connect.
    if (connect(socket_fd, (struct sockaddr*) &srv_addr, len) == -1) {
        perror("Failed to connect");
        return (1);
    }

    // Send a command to list all available commands.
    char buf[1024];
    sprintf(buf, "{ \"command\": \"list-commands\" }");
    int bytes_sent = send(socket_fd, buf, strlen(buf), 0);
    printf("%d bytes sent\n", bytes_sent);

    // Receive a response (should be JSON formatted list of commands)
    int bytes_rcvd = recv(socket_fd, buf, sizeof(buf), 0);
    printf("%d bytes received: [%s]\n", bytes_rcvd, buf);

    // Close the socket
    close(socket_fd);

    return 0;
}
@endcode

@section ctrlSocketImpl Control Channel Implementation

Control Channel is implemented in @ref isc::config::CommandMgr. It is a signleton
class that allows registration of callbacks that handle specific commands.
It internally supports a single command: @c list-commands that returns a list
of supported commands. This component is expected to be shared among all daemons.

There are 3 main methods that are expected to be used by developers:
- @ref isc::config::CommandMgr::registerCommand, which allows registration of
  additional commands.
- @ref isc::config::CommandMgr::deregisterCommand, which allows removing previously
  registered command.
- @ref isc::config::CommandMgr::processCommand, which allows handling specified
  command.

There are also two methods for managing control sockets. They are not expected
167
to be used directly, unless someone implements a new Control Channel (e.g. TCP
168
169
170
171
172
or HTTPS connection):

- @ref isc::config::CommandMgr::openCommandSocket that passes structure defined
  in the configuration file. Currently only two parameters are supported: socket-type
  (which must contain value 'unix') and socket-name (which contains unix path for
173
  the named socket to be created). This method calls @ref
Tomek Mrugalski's avatar
Tomek Mrugalski committed
174
175
176
  isc::config::CommandSocketFactory::create method, which parses the parameters
  and instantiates one object from a class derived from @ref isc::config::CommandSocket.
  Again, currently only UNIX type is supported, but the factory
177
178
  class is expected to be extended to cover additional types.
- @ref isc::config::CommandMgr::closeCommandSocket() - it is used to close the
Tomek Mrugalski's avatar
Tomek Mrugalski committed
179
180
181
  socket. It calls close method on the @ref isc::config::CommandSocket object, if
  one exists. In particular, for UNIX socket, it also deletes the file after socket
  was closed.
182
183
184

@section ctrlSocketConnections Accepting connections

185
Control Channel is connection oriented communication. In that sense it is
186
different than all other communications supported so far in Kea. To facilitate
Tomek Mrugalski's avatar
Tomek Mrugalski committed
187
188
189
190
191
connections, several mechanisms were implemented. Intially a single UNIX socket
it opened (see isc::config::UnixCommandSocket). Its @ref
isc::config::UnixCommandSocket::receiveHandler callback method is
installed in @ref isc::dhcp::IfaceMgr to process incoming connections. When the
select call in @ref isc::dhcp::IfaceMgr::receive4 indicates that there is some data to be
192
processed, this callback calls accept, which creates a new socket for handling
Tomek Mrugalski's avatar
Tomek Mrugalski committed
193
194
195
196
this particular incoming connection. Once the socket descriptor is known, a new
instance of @ref isc::config::ConnectionSocket is created to represent that
socket (and the whole ongoing connection). It installs another callback
(@ref isc::config::ConnectionSocket::receiveHandler that calls
197
198
199
200
201
202
203
204
205
206
207
(@ref isc::config::CommandMgr::commandReader) that will process incoming
data or will close the socket when necessary. CommandReader reads data from
incoming socket and attempts to parse it as JSON structures. If successful,
it calls isc::config::CommandMgr::processCommand(), serializes the structure
returned and attempts to send it back.

@todo Currently commands and responses up to 64KB are supported. It was deemed
sufficient for the current needs, but in the future we may need to extend
it to handle bigger structures.

*/