1 /*******************************************************************************
2 
3     Base class for a connection handler for use with SelectListener, using
4     tasks.
5 
6     Copyright:
7         Copyright (c) 2017 dunnhumby Germany GmbH.
8         All rights reserved.
9 
10     License:
11         Boost Software License Version 1.0. See LICENSE_BOOST.txt for details.
12         Alternatively, this file may be distributed under the terms of the Tango
13         3-Clause BSD License (see LICENSE_BSD.txt for details).
14 
15 *******************************************************************************/
16 
17 module ocean.net.server.connection.TaskConnectionHandler;
18 
19 import ocean.net.server.connection.IConnectionHandler;
20 import ocean.util.container.pool.model.IResettable;
21 
22 /// ditto
23 
24 abstract class TaskConnectionHandler : IConnectionHandler, Resettable
25 {
26     import ocean.sys.socket.model.ISocket;
27     import ocean.io.select.protocol.task.TaskSelectTransceiver;
28     import ocean.io.select.protocol.generic.ErrnoIOException: IOWarning;
29     import ocean.task.Task: Task;
30     import ocean.task.IScheduler: theScheduler;
31 
32     import ocean.meta.types.Qualifiers;
33 
34     /***************************************************************************
35 
36         Reads data from and writes data to the connection socket.
37 
38     ***************************************************************************/
39 
40     protected TaskSelectTransceiver transceiver;
41 
42     /***************************************************************************
43 
44         IOWarning exception instance used by the reader/writer and subclass.
45 
46     ***************************************************************************/
47 
48     protected IOWarning io_warning;
49 
50     /***************************************************************************
51 
52         Connection handler task, runs the abstract `handle` method and calls the
53         finalizer callback on termination.
54 
55     ***************************************************************************/
56 
57     private class ConnectionHandlerTask: Task
58     {
59         /// Constructor.
60         private this ( )
61         {
62             this.terminationHook = &this.outer.finalize;
63         }
64 
65         /// Task method, runs `TaskConnectionHandler.handle.`
66         override protected void run ( )
67         {
68             this.outer.handle();
69         }
70     }
71 
72     /// ditto
73     private Task task;
74 
75     /***************************************************************************
76 
77         Constructor
78 
79         Params:
80             socket       = the socket
81             error_dg_    = optional user-specified error handler, called when a
82                            connection error occurs
83 
84      ***************************************************************************/
85 
86     protected this ( ISocket socket, scope ErrorDg error_dg_ = null )
87     {
88         this(socket, null, error_dg_);
89     }
90 
91     /***************************************************************************
92 
93         Constructor
94 
95         Params:
96             socket       = the socket
97             finalize_dg_ = finalizer callback of the select listener, called
98                            when the connection is shut down
99             error_dg_    = optional user-specified error handler, called when a
100                            connection error occurs
101 
102     ***************************************************************************/
103 
104     protected this ( ISocket socket, scope FinalizeDg finalize_dg_,
105         scope ErrorDg error_dg_ = null )
106     {
107         super(socket, finalize_dg_, error_dg_);
108         this.io_warning = new IOWarning(this.socket);
109         this.transceiver = new TaskSelectTransceiver(
110             this.socket, this.io_warning, this.socket_error
111         );
112         this.task = this.new ConnectionHandlerTask;
113     }
114 
115     /**************************************************************************
116 
117         Called by `finalize` to unregister the connection socket from epoll
118         before closing it. This is done because closing a socket does not always
119         mean that it is unregistered from epoll -- in situations where the
120         process has forked, the fork's reference to the underlying kernel file
121         description will prevent it from being unregistered until the fork
122         exits. Therefore, to be certain that the socket will not fire again in
123         epoll, we need to explicitly unregister it.
124 
125     ***************************************************************************/
126 
127     protected override void unregisterSocket ()
128     {
129         this.transceiver.reset();
130     }
131 
132     /***************************************************************************
133 
134         Called by the select listener right after the client connection has been
135         assigned.
136         If this method throws an exception, error() and finalize() will be
137         called by the select listener.
138 
139     ***************************************************************************/
140 
141     override public void handleConnection ( )
142     {
143         theScheduler.schedule(this.task);
144     }
145 
146     /***************************************************************************
147 
148         Connection handler method, called from a running task.
149 
150     ***************************************************************************/
151 
152     abstract protected void handle ( );
153 
154     /**************************************************************************
155 
156         Called by IConnectionHandler.finalize(), in order to determine if an I/O
157         error was reported for the connection conduit which made the connection
158         automatically being closed.
159         (See comment for IConnectionHandler.finalize() method.)
160 
161         Returns:
162             true if an I/O error was reported to the reader or the writer for
163             the connection conduit which made the connection automatically being
164             closed or false otherwise.
165 
166      **************************************************************************/
167 
168     override public bool io_error ( )
169     {
170         return !!this.socket.error;
171     }
172 }