1 /*******************************************************************************
2 
3     Application extension for handling requests via a unix socket.
4 
5     Commands can be registered to the extension and when the command is received
6     the provided delegate will be called. Any provided arguments will be split
7     by the space character and provided as an array.
8 
9     The socket will be created under the path defined by the config option
10     `path` under the `[UNIX_SOCKET]` config group. If the config path is not
11     defined then the unix socket will not be created. If there's a need to
12     setup the permissions mode, config option `mode` will be used to read the
13     mode as octal string (usually you want 0600 for this).
14 
15     Copyright:
16         Copyright (c) 2009-2017 dunnhumby Germany GmbH.
17         All rights reserved.
18 
19     License:
20         Boost Software License Version 1.0. See LICENSE_BOOST.txt for details.
21         Alternatively, this file may be distributed under the terms of the Tango
22         3-Clause BSD License (see LICENSE_BSD.txt for details).
23 
24 *******************************************************************************/
25 
26 module ocean.util.app.ext.UnixSocketExt;
27 
28 import ocean.meta.types.Qualifiers;
29 import ocean.core.Verify;
30 
31 import ocean.core.Enforce;
32 import ocean.io.select.EpollSelectDispatcher;
33 import ocean.util.app.model.IApplication;
34 import ocean.util.app.model.IApplicationExtension;
35 import ocean.util.app.ext.model.IConfigExtExtension;
36 
37 /// ditto
38 public class UnixSocketExt : IApplicationExtension, IConfigExtExtension
39 {
40     import ocean.application.components.UnixSocketCommands;
41     import ocean.text.convert.Integer;
42     import ocean.text.util.StringC;
43     import ocean.util.config.ConfigParser;
44     import ocean.net.server.unix.CommandRegistry;
45     import ocean.net.server.unix.UnixListener;
46 
47     /// Handler delegate
48     public alias UnixSocketCommands.Handler Handler;
49 
50     /// Interactive handler delegate
51     public alias UnixSocketCommands.InteractiveHandler InteractiveHandler;
52 
53     /// RawSocketHandler delegate
54     public alias UnixSocketCommands.RawSocketHandler RawSocketHandler;
55 
56     // Unix socket commands wrapper.
57     private UnixSocketCommands unix_socket;
58 
59     /*************************************************************************
60 
61         Constructor
62 
63     **************************************************************************/
64 
65     this ( )
66     {
67         this.unix_socket = new UnixSocketCommands;
68     }
69 
70     /*************************************************************************
71 
72         Initializes the socket listener.
73 
74          Params:
75             epoll = Epoll instance.
76 
77     **************************************************************************/
78 
79     public void initializeSocket ( EpollSelectDispatcher epoll )
80     {
81         this.unix_socket.startEventHandling(epoll);
82     }
83 
84     /***************************************************************************
85 
86         Setup the unix socket listener if the config for the socket path exists.
87 
88         Params:
89             app = the application instance
90             config = configuration instance
91 
92     ***************************************************************************/
93 
94     public override void processConfig ( IApplication app, ConfigParser config )
95     {
96         this.unix_socket.parseConfig(config);
97     }
98 
99     /***************************************************************************
100 
101         Params:
102             command = The command to listen for in the socket listener.
103             handler = The handler to call when command is received.
104 
105     ***************************************************************************/
106 
107     public void addHandler ( istring command, scope Handler handler )
108     {
109         this.unix_socket.commands.addHandler(command, handler);
110     }
111 
112     /***************************************************************************
113 
114         Params:
115             command = The command to listen for in the socket listener.
116             handler = The handler to call when command is received.
117 
118     ***************************************************************************/
119 
120     public void addHandler ( istring command, scope InteractiveHandler handler )
121     {
122         this.unix_socket.commands.addHandler(command, handler);
123     }
124 
125     /***************************************************************************
126 
127         Register a command and raw handler to the unix listener.
128 
129         Params:
130             command = The command to listen for in the socket listener.
131             handler = The handler to call when command is received.
132 
133     ***************************************************************************/
134 
135     public void addHandler ( istring command, scope RawSocketHandler handler )
136     {
137         this.unix_socket.commands.addHandler(command, handler);
138     }
139 
140     /***************************************************************************
141 
142         Unregisters a command and handler to the unix listener.
143 
144         Params:
145             command = The command to be removed from the listener.
146 
147     ***************************************************************************/
148 
149     public void removeHandler ( istring command )
150     {
151         this.unix_socket.commands.removeHandler(command);
152     }
153 
154     /***************************************************************************
155 
156         Shut down the unix listener upon exit of the application.
157 
158         Params:
159             app = Application instance.
160             args = Provided application arguments.
161             status = Return code status.
162             exception = Exception if exists.
163 
164     ***************************************************************************/
165 
166     public override void atExit ( IApplication app, istring[] args, int status,
167             ExitException exception )
168     {
169         this.unix_socket.shutdown();
170     }
171 
172     /***************************************************************************
173 
174         Unused IConfigExtExtension method to satisfy interface.
175 
176         Params:
177             app = the application instance
178             config = configuration instance
179 
180     ***************************************************************************/
181 
182     public override void preParseConfig ( IApplication app, ConfigParser config )
183     {
184         // Unused
185     }
186 
187     /***************************************************************************
188 
189         Unused IConfigExtExtension method to satisfy interface.
190 
191         Params:
192             app = the application instance
193             config = configuration instance
194             files = current list of configuration files to parse
195 
196         Returns:
197             new list of configuration files to parse
198 
199     ***************************************************************************/
200 
201     public override istring[] filterConfigFiles ( IApplication app,
202                                          ConfigParser config,
203                                          istring[] files )
204     {
205         // Unused
206         return files;
207     }
208 
209     /***************************************************************************
210 
211         Return:
212             Use the default ordering.
213 
214     ***************************************************************************/
215 
216     public override int order ( )
217     {
218         return -1;
219     }
220 
221     /***************************************************************************
222 
223         Unused IApplicationExtension methods to satisfy interface.
224 
225     ***************************************************************************/
226 
227     public override void preRun ( IApplication app, istring[] args )
228     {
229     }
230 
231     /// ditto
232     public override void postRun ( IApplication app, istring[] args, int status )
233     {
234     }
235 
236     /// ditto
237     public override ExitException onExitException ( IApplication app, istring[] args,
238             ExitException exception )
239     {
240         return exception;
241     }
242 }
243 
244 version (unittest)
245 {
246     import ocean.util.app.DaemonApp;
247 }
248 
249 ///
250 unittest
251 {
252     class TestApp : DaemonApp
253     {
254         public this ( )
255         {
256             super("TestApp", "Test UnixSocketExt", null);
257         }
258 
259         override public int run ( Arguments args, ConfigParser config )
260         {
261             this.startEventHandling(new EpollSelectDispatcher);
262             this.unix_socket_ext.addHandler("test", &this.test);
263 
264             return 0;
265         }
266 
267         private void test ( cstring[] args,
268             scope void delegate ( cstring response ) send_response,
269             scope void delegate ( ref mstring response ) wait_reply )
270         {
271             send_response("Test request received");
272         }
273     }
274 
275     TestApp app = new TestApp;
276 }