1 /*******************************************************************************
2 
3     Sample unix socket server, which is based on fiber select listener.
4 
5     Copyright:
6         Copyright (c) 2016-2017 dunnhumby Germany GmbH.
7         All rights reserved.
8 
9     License:
10         Boost Software License Version 1.0. See LICENSE_BOOST.txt for details.
11         Alternatively, this file may be distributed under the terms of the Tango
12         3-Clause BSD License (see LICENSE_BSD.txt for details).
13 
14 *******************************************************************************/
15 
16 module integrationtest.selectlistener.UnixServer;
17 
18 import ocean.io.select.EpollSelectDispatcher;
19 import ocean.io.select.protocol.fiber.FiberSelectReader;
20 import ocean.io.select.protocol.fiber.FiberSelectWriter;
21 import ocean.io.select.protocol.generic.ErrnoIOException : SocketError;
22 import ocean.net.server.SelectListener;
23 import ocean.net.server.connection.IFiberConnectionHandler;
24 import ocean.sys.socket.UnixSocket;
25 
26 
27 /*******************************************************************************
28 
29     The server is based on SelectListener.
30 
31 *******************************************************************************/
32 
33 public alias SelectListener!(UnixConnectionHandler, EpollSelectDispatcher) UnixServer;
34 
35 
36 /*******************************************************************************
37 
38     The connection handler is based on IFiberConnectionHandler
39 
40 *******************************************************************************/
41 
42 private class UnixConnectionHandler: IFiberConnectionHandler
43 {
44     /***************************************************************************
45 
46         Keeps data between `consume` calls.
47 
48     ***************************************************************************/
49 
50     char[] buffer;
51 
52 
53     /***************************************************************************
54 
55         Shuts down the server when one request is served.
56 
57     ***************************************************************************/
58 
59     EpollSelectDispatcher epoll;
60 
61 
62     /***************************************************************************
63 
64         Consumer callback delegate type
65 
66         Params:
67             data = data to consume
68 
69         Returns:
70             - if finished, a value of [0, data.length] reflecting the number of
71               elements (bytes) consumed or
72             - a value greater than data.length if more data is required.
73 
74     ***************************************************************************/
75 
76     private size_t consume( void[] data )
77     {
78         char[] input = cast(char[])data;
79         size_t n = 0;
80 
81         foreach ( size_t i, char c; input )
82         {
83             n++;
84             if ( c == '\n' )
85             {
86                 return n;
87             }
88             buffer ~= c;
89         }
90 
91         // If we need more data, we must return a value greater than data.length.
92         return data.length + 1;
93     }
94 
95 
96     /***************************************************************************
97 
98         Constructor
99 
100     ***************************************************************************/
101 
102     public this ( scope FinalizeDg finalize_dg, EpollSelectDispatcher epoll )
103     {
104         super(epoll, new UnixSocket, finalize_dg);
105 
106         this.epoll = epoll;
107     }
108 
109 
110     /***************************************************************************
111 
112         Connection handler method. If it catches exceptions, it must rethrow
113         those of type KilledException.
114 
115     ***************************************************************************/
116 
117     protected override void handle ( )
118     {
119         auto exception = new SocketError(this.socket);
120 
121         FiberSelectReader reader = new FiberSelectReader(this.socket,
122             this.fiber, exception, exception);
123         this.reader.error_reporter = this;
124 
125         FiberSelectWriter writer = new FiberSelectWriter(this.socket,
126             this.fiber, exception, exception);
127         this.reader.error_reporter = this;
128 
129         scope(exit)
130         {
131             this.epoll.shutdown();
132                 // Is anything else needed?
133         }
134 
135         // In production code, this may be to be wrapped in a `while`.
136         buffer.length = 0;
137         reader.readConsume(&this.consume);
138         buffer ~= "\n";
139         writer.send(buffer);
140     }
141 }