tizen 2.4 release
[framework/web/wrt-commons.git] / modules / socket / src / waitable_input_output_execution_context_support.cpp
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16 /*
17  * @file        waitable_input_output_execution_context_support.cpp
18  * @author      Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com)
19  * @version     1.0
20  * @brief       This file is the implementation file of waitable input-output
21  * execution context support
22  */
23 #include <stddef.h>
24 #include <dpl/socket/waitable_input_output_execution_context_support.h>
25 #include <dpl/socket/abstract_socket.h> // FIXME: Remove !!!
26 #include <dpl/log/wrt_log.h>
27 #include <dpl/assert.h>
28
29 namespace DPL {
30 namespace Socket {
31 namespace // anonymous
32 {
33 const size_t DEFAULT_READ_SIZE = 2048;
34 } // namespace anonymous
35
36 WaitableInputOutputExecutionContextSupport::
37     WaitableInputOutputExecutionContextSupport() :
38     m_opened(false),
39     m_waitableInputOutput(NULL),
40     m_hasReadWatch(false),
41     m_hasWriteWatch(false)
42 {}
43
44 WaitableInputOutputExecutionContextSupport::~
45 WaitableInputOutputExecutionContextSupport()
46 {
47     // Ensure support is closed
48     Close();
49 }
50
51 void WaitableInputOutputExecutionContextSupport::Open(
52     AbstractWaitableInputOutput *inputOutput)
53 {
54     if (m_opened) {
55         Throw(Exception::AlreadyOpened);
56     }
57
58     WrtLogD("Opening waitable input-output execution context support...");
59
60     // Save IO handle
61     m_waitableInputOutput = inputOutput;
62
63     // Register read watch
64     Assert(m_hasReadWatch == false);
65
66     AddReadWatch();
67     m_hasReadWatch = true;
68
69     // Done
70     m_opened = true;
71
72     WrtLogD("Waitable input-output execution context support opened");
73 }
74
75 void WaitableInputOutputExecutionContextSupport::Close()
76 {
77     if (!m_opened) {
78         return;
79     }
80
81     WrtLogD("Closing waitable input-output execution context support...");
82
83     // Remove read and write watches
84     CheckedRemoveReadWriteWatch();
85
86     // Set proper state
87     m_opened = false;
88
89     WrtLogD("Waitable input-output execution context support closed");
90 }
91
92 void WaitableInputOutputExecutionContextSupport::AddReadWatch()
93 {
94     WaitableHandleWatchSupport* ctx =
95         WaitableHandleWatchSupport::InheritedContext();
96     if(ctx)
97         ctx->AddWaitableHandleWatch(
98             this,
99             m_waitableInputOutput->WaitableReadHandle(),
100             WaitMode::Read);
101 }
102
103 void WaitableInputOutputExecutionContextSupport::RemoveReadWatch()
104 {
105     WaitableHandleWatchSupport* ctx =
106         WaitableHandleWatchSupport::InheritedContext();
107     if(ctx)
108         ctx->RemoveWaitableHandleWatch(
109             this,
110             m_waitableInputOutput->WaitableReadHandle(),
111             WaitMode::Read);
112 }
113
114 void WaitableInputOutputExecutionContextSupport::AddWriteWatch()
115 {
116     WaitableHandleWatchSupport* ctx =
117         WaitableHandleWatchSupport::InheritedContext();
118     if(ctx)
119         ctx->AddWaitableHandleWatch(
120             this,
121             m_waitableInputOutput->WaitableWriteHandle(),
122             WaitMode::Write);
123 }
124
125 void WaitableInputOutputExecutionContextSupport::RemoveWriteWatch()
126 {
127     WaitableHandleWatchSupport* ctx =
128         WaitableHandleWatchSupport::InheritedContext();
129     if(ctx)
130         ctx->RemoveWaitableHandleWatch(
131             this,
132             m_waitableInputOutput->WaitableWriteHandle(),
133             WaitMode::Write);
134 }
135
136 void WaitableInputOutputExecutionContextSupport::CheckedRemoveReadWatch()
137 {
138     if (!m_hasReadWatch) {
139         return;
140     }
141
142     RemoveReadWatch();
143     m_hasReadWatch = false;
144 }
145
146 void WaitableInputOutputExecutionContextSupport::CheckedRemoveWriteWatch()
147 {
148     if (!m_hasWriteWatch) {
149         return;
150     }
151
152     RemoveWriteWatch();
153     m_hasWriteWatch = false;
154 }
155
156 void WaitableInputOutputExecutionContextSupport::CheckedRemoveReadWriteWatch()
157 {
158     // Remove read watch if any
159     CheckedRemoveReadWatch();
160
161     // Remove write watch if any
162     CheckedRemoveWriteWatch();
163 }
164
165 void WaitableInputOutputExecutionContextSupport::OnWaitableHandleEvent(
166     WaitableHandle waitableHandle,
167     WaitMode::Type mode)
168 {
169     (void)waitableHandle;
170
171     switch (mode) {
172     case WaitMode::Read:
173         WrtLogD("Read event occurred");
174
175         // Read and parse bytes
176         ReadInput();
177
178         // Done
179         break;
180
181     case WaitMode::Write:
182         WrtLogD("Write event occurred");
183
184         // Push bytes and unregister from write event
185         FeedOutput();
186
187         // Unregister write watch only if no more data is available
188         if (m_outputStream.Empty()) {
189             Assert(m_hasWriteWatch == true);
190             CheckedRemoveWriteWatch();
191         }
192
193         // Done
194         break;
195
196     default:
197         Assert(0);
198         break;
199     }
200 }
201
202 void WaitableInputOutputExecutionContextSupport::ReadInput()
203 {
204     WrtLogD("Reading input bytes");
205
206     Try
207     {
208         BinaryQueueAutoPtr inputBuffer = m_waitableInputOutput->Read(
209                 DEFAULT_READ_SIZE);
210
211         if (inputBuffer.get() == NULL) {
212             // No data, should not occur
213             WrtLogD("WARNING: Spontaneous ReadSocket occurred");
214             return;
215         }
216
217         if (inputBuffer->Empty()) {
218             // Connection was closed
219             OnInputStreamClosed();
220
221             // Unregister from further event insisting
222             Assert(m_hasReadWatch == true);
223             CheckedRemoveReadWriteWatch();
224
225             // Set proper state
226             m_opened = false;
227
228             // Done
229             return;
230         }
231
232         WrtLogD("Read %i input bytes", inputBuffer->Size());
233
234         // Append all read data
235         m_inputStream.AppendMoveFrom(*inputBuffer);
236     }
237     Catch(AbstractSocket::Exception::ConnectionBroken)
238     {
239         //FIXME: Inproper exception abstraction!!!
240         // Some errors occurred while feeding abstract IO
241         // Interpret connection broken errors, and pass futher other ones
242         WrtLogD("Abstract IO connection was broken during read");
243
244         // Signal broken connection
245         OnInputStreamBroken();
246
247         // Unregister from further event insisting
248         Assert(m_hasReadWatch == true);
249         CheckedRemoveReadWriteWatch();
250
251         // Set proper state
252         m_opened = false;
253
254         // Do not continue
255         return;
256     }
257
258     // Interpret data
259     OnInputStreamRead();
260 }
261
262 void WaitableInputOutputExecutionContextSupport::FeedOutput()
263 {
264     if (!m_opened) {
265         Throw(Exception::NotOpened);
266     }
267
268     // Anything to feed ?
269     if (m_outputStream.Empty()) {
270         return;
271     }
272
273     // OK to feed output
274     WrtLogD("Feeding output");
275
276     Try
277     {
278         // Try to write some bytes
279         size_t bytes = m_waitableInputOutput->Write(m_outputStream,
280                                                     m_outputStream.Size());
281
282         if (bytes < m_outputStream.Size()) {
283             // Start exhaustive output feeding if it is blocked and not already
284             // started
285             if (!m_hasWriteWatch) {
286                 AddWriteWatch();
287                 m_hasWriteWatch = true;
288
289                 WrtLogD("Started exhaustive output feeding");
290             }
291         }
292
293         // Some bytes were written, consume them
294         m_outputStream.Consume(bytes);
295     }
296     Catch(AbstractSocket::Exception::ConnectionBroken)  // FIXME: Inproper
297                                                         // exception abstraction
298                                                         // !!!
299     {
300         // Some errors occurred while feeding abstract IO
301         // Interpret connection broken errors, and pass futher other ones
302         WrtLogD("Abstract IO connection was broken during write");
303
304         // Signal broken connection
305         OnInputStreamBroken();
306
307         // Unregister from further event insisting
308         Assert(m_hasReadWatch == true);
309         CheckedRemoveReadWriteWatch();
310
311         // Set proper state
312         m_opened = false;
313
314         // Do not continue
315         return;
316     }
317 }
318 }
319 } // namespace DPL