Initialize Tizen 2.3
[framework/web/wrt-commons.git] / modules_wearable / 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/scoped_array.h>
26 #include <dpl/socket/abstract_socket.h> // FIXME: Remove !!!
27 #include <dpl/log/log.h>
28 #include <dpl/assert.h>
29
30 namespace DPL {
31 namespace Socket {
32 namespace // anonymous
33 {
34 const size_t DEFAULT_READ_SIZE = 2048;
35 } // namespace anonymous
36
37 WaitableInputOutputExecutionContextSupport::
38     WaitableInputOutputExecutionContextSupport() :
39     m_opened(false),
40     m_waitableInputOutput(NULL),
41     m_hasReadWatch(false),
42     m_hasWriteWatch(false)
43 {}
44
45 WaitableInputOutputExecutionContextSupport::~
46 WaitableInputOutputExecutionContextSupport()
47 {
48     // Ensure support is closed
49     Close();
50 }
51
52 void WaitableInputOutputExecutionContextSupport::Open(
53     AbstractWaitableInputOutput *inputOutput)
54 {
55     if (m_opened) {
56         Throw(Exception::AlreadyOpened);
57     }
58
59     LogPedantic("Opening waitable input-output execution context support...");
60
61     // Save IO handle
62     m_waitableInputOutput = inputOutput;
63
64     // Register read watch
65     Assert(m_hasReadWatch == false);
66
67     AddReadWatch();
68     m_hasReadWatch = true;
69
70     // Done
71     m_opened = true;
72
73     LogPedantic("Waitable input-output execution context support opened");
74 }
75
76 void WaitableInputOutputExecutionContextSupport::Close()
77 {
78     if (!m_opened) {
79         return;
80     }
81
82     LogPedantic("Closing waitable input-output execution context support...");
83
84     // Remove read and write watches
85     CheckedRemoveReadWriteWatch();
86
87     // Set proper state
88     m_opened = false;
89
90     LogPedantic("Waitable input-output execution context support closed");
91 }
92
93 void WaitableInputOutputExecutionContextSupport::AddReadWatch()
94 {
95     WaitableHandleWatchSupport::InheritedContext()->AddWaitableHandleWatch(
96         this,
97         m_waitableInputOutput
98             ->WaitableReadHandle(),
99         WaitMode
100             ::Read);
101 }
102
103 void WaitableInputOutputExecutionContextSupport::RemoveReadWatch()
104 {
105     WaitableHandleWatchSupport::InheritedContext()->RemoveWaitableHandleWatch(
106         this,
107         m_waitableInputOutput->WaitableReadHandle(),
108         WaitMode::Read);
109 }
110
111 void WaitableInputOutputExecutionContextSupport::AddWriteWatch()
112 {
113     WaitableHandleWatchSupport::InheritedContext()->AddWaitableHandleWatch(
114         this,
115         m_waitableInputOutput
116             ->WaitableWriteHandle(),
117         WaitMode
118             ::Write);
119 }
120
121 void WaitableInputOutputExecutionContextSupport::RemoveWriteWatch()
122 {
123     WaitableHandleWatchSupport::InheritedContext()->RemoveWaitableHandleWatch(
124         this,
125         m_waitableInputOutput->WaitableWriteHandle(),
126         WaitMode::Write);
127 }
128
129 void WaitableInputOutputExecutionContextSupport::CheckedRemoveReadWatch()
130 {
131     if (!m_hasReadWatch) {
132         return;
133     }
134
135     RemoveReadWatch();
136     m_hasReadWatch = false;
137 }
138
139 void WaitableInputOutputExecutionContextSupport::CheckedRemoveWriteWatch()
140 {
141     if (!m_hasWriteWatch) {
142         return;
143     }
144
145     RemoveWriteWatch();
146     m_hasWriteWatch = false;
147 }
148
149 void WaitableInputOutputExecutionContextSupport::CheckedRemoveReadWriteWatch()
150 {
151     // Remove read watch if any
152     CheckedRemoveReadWatch();
153
154     // Remove write watch if any
155     CheckedRemoveWriteWatch();
156 }
157
158 void WaitableInputOutputExecutionContextSupport::OnWaitableHandleEvent(
159     WaitableHandle waitableHandle,
160     WaitMode::Type mode)
161 {
162     (void)waitableHandle;
163
164     switch (mode) {
165     case WaitMode::Read:
166         LogPedantic("Read event occurred");
167
168         // Read and parse bytes
169         ReadInput();
170
171         // Done
172         break;
173
174     case WaitMode::Write:
175         LogPedantic("Write event occurred");
176
177         // Push bytes and unregister from write event
178         FeedOutput();
179
180         // Unregister write watch only if no more data is available
181         if (m_outputStream.Empty()) {
182             Assert(m_hasWriteWatch == true);
183             CheckedRemoveWriteWatch();
184         }
185
186         // Done
187         break;
188
189     default:
190         Assert(0);
191         break;
192     }
193 }
194
195 void WaitableInputOutputExecutionContextSupport::ReadInput()
196 {
197     LogPedantic("Reading input bytes");
198
199     Try
200     {
201         BinaryQueueAutoPtr inputBuffer = m_waitableInputOutput->Read(
202                 DEFAULT_READ_SIZE);
203
204         if (inputBuffer.get() == NULL) {
205             // No data, should not occur
206             LogPedantic("WARNING: Spontaneous ReadSocket occurred");
207             return;
208         }
209
210         if (inputBuffer->Empty()) {
211             // Connection was closed
212             OnInputStreamClosed();
213
214             // Unregister from further event insisting
215             Assert(m_hasReadWatch == true);
216             CheckedRemoveReadWriteWatch();
217
218             // Set proper state
219             m_opened = false;
220
221             // Done
222             return;
223         }
224
225         LogPedantic("Read " << inputBuffer->Size() << " input bytes");
226
227         // Append all read data
228         m_inputStream.AppendMoveFrom(*inputBuffer);
229     }
230     Catch(AbstractSocket::Exception::ConnectionBroken)
231     {
232         //FIXME: Inproper exception abstraction!!!
233         // Some errors occurred while feeding abstract IO
234         // Interpret connection broken errors, and pass futher other ones
235         LogPedantic("Abstract IO connection was broken during read");
236
237         // Signal broken connection
238         OnInputStreamBroken();
239
240         // Unregister from further event insisting
241         Assert(m_hasReadWatch == true);
242         CheckedRemoveReadWriteWatch();
243
244         // Set proper state
245         m_opened = false;
246
247         // Do not continue
248         return;
249     }
250
251     // Interpret data
252     OnInputStreamRead();
253 }
254
255 void WaitableInputOutputExecutionContextSupport::FeedOutput()
256 {
257     if (!m_opened) {
258         Throw(Exception::NotOpened);
259     }
260
261     // Anything to feed ?
262     if (m_outputStream.Empty()) {
263         return;
264     }
265
266     // OK to feed output
267     LogPedantic("Feeding output");
268
269     Try
270     {
271         // Try to write some bytes
272         size_t bytes = m_waitableInputOutput->Write(m_outputStream,
273                                                     m_outputStream.Size());
274
275         if (bytes < m_outputStream.Size()) {
276             // Start exhaustive output feeding if it is blocked and not already
277             // started
278             if (!m_hasWriteWatch) {
279                 AddWriteWatch();
280                 m_hasWriteWatch = true;
281
282                 LogPedantic("Started exhaustive output feeding");
283             }
284         }
285
286         // Some bytes were written, consume them
287         m_outputStream.Consume(bytes);
288     }
289     Catch(AbstractSocket::Exception::ConnectionBroken)  // FIXME: Inproper
290                                                         // exception abstraction
291                                                         // !!!
292     {
293         // Some errors occurred while feeding abstract IO
294         // Interpret connection broken errors, and pass futher other ones
295         LogPedantic("Abstract IO connection was broken during write");
296
297         // Signal broken connection
298         OnInputStreamBroken();
299
300         // Unregister from further event insisting
301         Assert(m_hasReadWatch == true);
302         CheckedRemoveReadWriteWatch();
303
304         // Set proper state
305         m_opened = false;
306
307         // Do not continue
308         return;
309     }
310 }
311 }
312 } // namespace DPL