Initialize Tizen 2.3
[framework/web/wrt-commons.git] / modules_mobile / socket / include / dpl / socket / generic_socket.h
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        generic_socket.h
18  * @author      Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com)
19  * @version     1.0
20  * @brief       This file is the header file of generic socket
21  */
22 #ifndef DPL_GENERIC_SOCKET_H
23 #define DPL_GENERIC_SOCKET_H
24
25 #include <dpl/socket/abstract_socket.h>
26 #include <dpl/waitable_handle_watch_support.h>
27 #include <dpl/binary_queue.h>
28 #include <dpl/thread.h>
29 #include <dpl/main.h>
30 #include <dpl/log/log.h>
31 #include <dpl/scoped_free.h>
32 #include <sys/types.h>
33 #include <sys/socket.h>
34 #include <fcntl.h>
35 #include <errno.h>
36 #include <dpl/assert.h>
37
38 namespace DPL {
39 namespace Socket {
40 //
41 // Generic abstract socket implementation
42 // Execution context is inherited
43 //
44 template<typename SocketType>
45 class GenericSocket :
46     public AbstractSocket,
47     private WaitableHandleWatchSupport::WaitableHandleListener
48 {
49   protected:
50     /**
51      * Translate generic Address to specific socket kernel structure
52      *
53      * @warning Must be implemented in derived class
54      */
55     virtual std::pair<sockaddr *, socklen_t> TranslateAddressGenericToSpecific(
56         const Address &address) const = 0;
57
58     /**
59      * Translate specific socket kernel structure to generic Address
60      *
61      * @warning Must be implemented in derived class
62      */
63     virtual Address TranslateAddressSpecificToGeneric(sockaddr *,
64                                                       socklen_t) const = 0;
65
66     /**
67      * Get specific socket kernel structure size
68      *
69      * @warning Must be implemented in derived class
70      */
71     virtual socklen_t GetSpecificAddressSize() const = 0;
72
73     /**
74      * Alloc specific implementation of socket from descriptor
75      *
76      * @warning Must be implemented in derived class
77      */
78     virtual SocketType *AllocAcceptedSpecificSocket() const = 0;
79
80     /**
81      * Alloc specific implementation of socket descriptor
82      *
83      * @warning Must be implemented in derived class
84      */
85     virtual int AllocSpecificDescriptor() const = 0;
86
87   private:
88     // Constants
89     static const size_t DEFAULT_READ_BUFFER_SIZE = 4096;
90
91     // Socket handle
92     int m_socket; // FIXME: Consider generalization to WaitableHandle upon
93                   // leaving nix platform
94
95     // Internal state
96     enum InternalState
97     {
98         InternalState_None,        ///< Not connected and not listening state
99         InternalState_Prepare,     ///< Descriptor allocated, but not connected
100         InternalState_Listening,   ///< Listening state
101         InternalState_Connecting,  ///< Connecting state
102         InternalState_Connected    ///< Connected state
103     };
104
105     InternalState m_internalState;
106
107     void SetNonBlocking()
108     {
109         // Set non-blocking mode
110         if (fcntl(m_socket, F_SETFL, O_NONBLOCK |
111                   fcntl(m_socket, F_GETFL)) == -1)
112         {
113             Throw(AbstractSocket::Exception::SetNonBlockingFailed);
114         }
115     }
116
117     // WaitableHandleWatchSupport::WaitableHandleListener
118     virtual void OnWaitableHandleEvent(WaitableHandle waitableHandle,
119                                        WaitMode::Type mode)
120     {
121         (void)waitableHandle;
122         Assert(waitableHandle == m_socket);
123
124         switch (m_internalState) {
125         case InternalState_None:
126             break;
127
128         case InternalState_Prepare:
129             Assert(0 && "Invalid internal generic socket state!");
130             break;
131
132         case InternalState_Listening:
133             Assert(mode == WaitMode::Read);
134
135             // New client waiting for accept
136             DPL::Event::EventSupport<AbstractSocketEvents::AcceptEvent>::
137                 EmitEvent(AbstractSocketEvents::AcceptEvent(
138                               EventSender(this)), DPL::Event::EmitMode::Queued);
139
140             // Done
141             break;
142
143         case InternalState_Connecting:
144             Assert(mode == WaitMode::Write);
145
146             // Connected to server
147             RemoveConnectWatch();
148             m_internalState = InternalState_Connected;
149
150             // Add read watch
151             AddReadWatch();
152
153             // Emit event
154             DPL::Event::EventSupport<AbstractSocketEvents::ConnectedEvent>::
155                 EmitEvent(AbstractSocketEvents::ConnectedEvent(
156                               EventSender(this)), DPL::Event::EmitMode::Queued);
157
158             // Done
159             break;
160
161         case InternalState_Connected:
162             if (mode == WaitMode::Read) {
163                 // Emit ReadEvent
164                 DPL::Event::EventSupport<AbstractSocketEvents::ReadEvent>::
165                     EmitEvent(AbstractSocketEvents::ReadEvent(
166                                   EventSender(
167                                       this)), DPL::Event::EmitMode::Queued);
168             } else if (mode == WaitMode::Write) {
169                 // Emit WriteEvent
170                 DPL::Event::EventSupport<AbstractSocketEvents::WriteEvent>::
171                     EmitEvent(AbstractSocketEvents::WriteEvent(
172                                   EventSender(
173                                       this)), DPL::Event::EmitMode::Queued);
174             } else {
175                 Assert(0);
176             }
177
178             break;
179
180         default:
181             Assert(0);
182             break;
183         }
184     }
185
186     void AddAcceptWatch()
187     {
188         WaitableHandleWatchSupport::InheritedContext()->AddWaitableHandleWatch(
189             this,
190             m_socket,
191             WaitMode::Read);
192     }
193
194     void RemoveAcceptWatch()
195     {
196         WaitableHandleWatchSupport::InheritedContext()->
197             RemoveWaitableHandleWatch(this, m_socket, WaitMode::Read);
198     }
199
200     void AddConnectWatch()
201     {
202         WaitableHandleWatchSupport::InheritedContext()->AddWaitableHandleWatch(
203             this,
204             m_socket,
205             WaitMode::Write);
206     }
207
208     void RemoveConnectWatch()
209     {
210         WaitableHandleWatchSupport::InheritedContext()->
211             RemoveWaitableHandleWatch(this, m_socket, WaitMode::Write);
212     }
213
214     void AddReadWatch()
215     {
216         WaitableHandleWatchSupport::InheritedContext()->AddWaitableHandleWatch(
217             this,
218             m_socket,
219             WaitMode::Read);
220     }
221
222     void RemoveReadWatch()
223     {
224         WaitableHandleWatchSupport::InheritedContext()->
225             RemoveWaitableHandleWatch(this, m_socket, WaitMode::Read);
226     }
227
228     void AddWriteWatch()
229     {
230         WaitableHandleWatchSupport::InheritedContext()->AddWaitableHandleWatch(
231             this,
232             m_socket,
233             WaitMode::Write);
234     }
235
236     void RemoveWriteWatch()
237     {
238         WaitableHandleWatchSupport::InheritedContext()->
239             RemoveWaitableHandleWatch(this, m_socket, WaitMode::Write);
240     }
241
242   public:
243     GenericSocket() :
244         m_socket(-1),
245         m_internalState(InternalState_None)
246     {}
247
248     virtual ~GenericSocket()
249     {
250         // Always ensure to close socket
251         Try
252         {
253             Close();
254         }
255         Catch(Exception::CloseFailed)
256         {
257             LogPedantic("Close failed and ignored");
258         }
259
260         // Check consistency
261         Assert(m_socket == -1);
262     }
263
264     virtual void Open()
265     {
266         if (m_internalState != InternalState_None) {
267             ThrowMsg(AbstractSocket::Exception::OpenFailed,
268                      "Invalid socket state, should be 'None'");
269         }
270
271         LogPedantic("Opening socket...");
272
273         // Check consistency
274         Assert(m_socket == -1);
275
276         // Allocate specific socket descriptor
277         m_socket = AllocSpecificDescriptor();
278
279         // Set socket non-blocking
280         SetNonBlocking();
281
282         // State is prepared
283         m_internalState = InternalState_Prepare;
284
285         LogPedantic("Socket opened");
286     }
287
288     virtual void Connect(const Address &address)
289     {
290         if (m_internalState != InternalState_Prepare) {
291             ThrowMsg(AbstractSocket::Exception::ConnectFailed,
292                      "Invalid socket state, should be 'Prepare'");
293         }
294
295         LogPedantic("Connecting to: " << address.ToString());
296
297         // Try to convert address
298         std::pair<sockaddr *, socklen_t> socketAddress;
299
300         Try
301         {
302             // Translate address to specific socket address struct
303             socketAddress = TranslateAddressGenericToSpecific(address);
304         }
305         Catch(Address::Exception::InvalidAddress)
306         {
307             // This address is invalid. Cannot connect.
308             ReThrowMsg(AbstractSocket::Exception::ConnectFailed,
309                        address.ToString());
310         }
311
312         // Do connect
313         int result =
314             TEMP_FAILURE_RETRY(connect(m_socket, socketAddress.first,
315                                        socketAddress.second));
316
317         if (result == 0) {
318             // Immediate connect
319             LogPedantic("Immediate connected to: " << address.ToString());
320
321             // Add read watch
322             AddReadWatch();
323             m_internalState = InternalState_Connected;
324
325             // Emit connected event
326             DPL::Event::EventSupport<AbstractSocketEvents::ConnectedEvent>::
327                 EmitEvent(AbstractSocketEvents::ConnectedEvent(
328                               EventSender(this)), DPL::Event::EmitMode::Queued);
329         } else {
330             if (errno == EINTR || errno == EINPROGRESS) {
331                 LogPedantic(
332                     "Asynchronous connect in progress: " << address.ToString());
333
334                 // Connecting in progress
335                 AddConnectWatch();
336                 m_internalState = InternalState_Connecting;
337             } else {
338                 // Free translation structure
339                 free(socketAddress.first);
340
341                 // Error occurred
342                 ThrowMsg(AbstractSocket::Exception::ConnectFailed,
343                          address.ToString());
344             }
345         }
346
347         // Free translation structure
348         free(socketAddress.first);
349     }
350
351     virtual void Close()
352     {
353         if (m_internalState == InternalState_None) {
354             return;
355         }
356
357         Assert(m_socket != -1);
358
359         if (m_internalState == InternalState_Listening) {
360             // Remove watch in listening state
361             LogPedantic("Removing accept watch");
362             RemoveAcceptWatch();
363             m_internalState = InternalState_None;
364         } else if (m_internalState == InternalState_Connecting) {
365             // Remove watch in connecting state
366             LogPedantic("Removing connect watch");
367             RemoveConnectWatch();
368             m_internalState = InternalState_None;
369         } else if (m_internalState == InternalState_Connected) {
370             // Remove watch in connected state
371             LogPedantic("Removing read watch");
372             RemoveReadWatch();
373             m_internalState = InternalState_None;
374         } else {
375             // State must be just prepared only
376             Assert(m_internalState == InternalState_Prepare);
377         }
378
379         if (TEMP_FAILURE_RETRY(close(m_socket)) == -1) {
380             Throw(Exception::CloseFailed);
381         }
382
383         // Reset socket
384         m_socket = -1;
385
386         // Reset socket state
387         m_internalState = InternalState_None;
388
389         LogPedantic("Socket closed");
390     }
391
392     virtual void Bind(const Address &address)
393     {
394         if (m_internalState != InternalState_Prepare) {
395             ThrowMsg(AbstractSocket::Exception::BindFailed,
396                      "Invalid socket state, should be 'Prepare'");
397         }
398
399         LogPedantic(
400             "Binding to: " << address.GetAddress() << ":" << address.GetPort());
401
402         // Translate address to specific socket address struct
403         std::pair<sockaddr *,
404                   socklen_t> socketAddress = TranslateAddressGenericToSpecific(
405                 address);
406
407         // Do bind
408         if (::bind(m_socket, socketAddress.first,
409                    socketAddress.second) == -1)
410         {
411             ThrowMsg(AbstractSocket::Exception::BindFailed, address.ToString());
412         }
413
414         // Free translation structure
415         free(socketAddress.first);
416
417         // Show info
418         LogPedantic(
419             "Bound to address: " << address.GetAddress() << ":" <<
420             address.GetPort());
421     }
422
423     virtual void Listen(int backlog)
424     {
425         if (m_internalState != InternalState_Prepare) {
426             ThrowMsg(AbstractSocket::Exception::ListenFailed,
427                      "Invalid socket state, should be 'None'");
428         }
429
430         LogPedantic("Starting to listen...");
431
432         // Do listen
433         if (listen(m_socket, backlog) != 0) {
434             Throw(AbstractSocket::Exception::ListenFailed);
435         }
436
437         // Begin read watch
438         AddAcceptWatch();
439         m_internalState = InternalState_Listening;
440
441         LogPedantic("Listen started");
442     }
443
444     virtual AbstractSocket *Accept()
445     {
446         if (m_internalState != InternalState_Listening) {
447             ThrowMsg(AbstractSocket::Exception::AcceptFailed,
448                      "Invalid socket state, should be 'Listening'");
449         }
450
451         LogPedantic("Accepting...");
452
453         // Do listen
454         socklen_t length = 0;
455         int client = TEMP_FAILURE_RETRY(accept(m_socket, NULL, &length));
456
457         LogPedantic("Socket accept returned " << client);
458         if (client == -1) {
459             // Check if there is any client waiting
460             if (errno == EWOULDBLOCK || errno == EAGAIN) {
461                 return NULL;
462             }
463             int err = errno;
464             if (errno == ENOENT) {
465                 return NULL;
466             }
467             LogPedantic("throwing error. errrno " << err);
468             // Error occurred
469             Throw(AbstractSocket::Exception::AcceptFailed);
470         }
471
472         LogPedantic("Accepted client. Seting up...");
473
474         // Create derived class type
475         GenericSocket *acceptedSocket = AllocAcceptedSpecificSocket();
476
477         // Save client socket specific descriptor
478         acceptedSocket->m_socket = client;
479
480         // Enter proper states and add read watch
481         acceptedSocket->AddReadWatch();
482         acceptedSocket->m_internalState = InternalState_Connected;
483
484         // Set non-blocking mode for new socket
485         acceptedSocket->SetNonBlocking();
486
487         // Show info
488         LogPedantic("Accepted client set up");
489
490         // return new conneced client socket
491         return acceptedSocket;
492     }
493
494     virtual Address GetLocalAddress() const
495     {
496         // FIXME: Additional internal state check
497
498         socklen_t length = GetSpecificAddressSize();
499         ScopedFree<sockaddr> address(static_cast<sockaddr *>(calloc(
500                                                                  static_cast<
501                                                                      size_t>(
502                                                                      length),
503                                                                  1)));
504
505         if (getsockname(m_socket, address.Get(), &length) == -1) {
506             ThrowMsg(AbstractSocket::Exception::GetPeerNameFailed,
507                      "Failed to get local address");
508         }
509
510         return TranslateAddressSpecificToGeneric(address.Get(), length);
511     }
512
513     virtual Address GetRemoteAddress() const
514     {
515         // FIXME: Additional internal state check
516
517         socklen_t length = GetSpecificAddressSize();
518         ScopedFree<sockaddr> address(static_cast<sockaddr *>(calloc(
519                                                                  static_cast<
520                                                                      size_t>(
521                                                                      length),
522                                                                  1)));
523
524         if (getpeername(m_socket, address.Get(), &length) == -1) {
525             ThrowMsg(AbstractSocket::Exception::GetPeerNameFailed,
526                      "Failed to get remote address");
527         }
528
529         return TranslateAddressSpecificToGeneric(address.Get(), length);
530     }
531
532     virtual BinaryQueueAutoPtr Read(size_t size)
533     {
534         if (m_internalState != InternalState_Connected) {
535             ThrowMsg(AbstractSocket::Exception::AcceptFailed,
536                      "Invalid socket state, should be 'Connected'");
537         }
538
539         Try
540         {
541             // Adjust bytes to be read
542             size_t bytesToRead = size >
543                 DEFAULT_READ_BUFFER_SIZE ? DEFAULT_READ_BUFFER_SIZE : size;
544
545             // Malloc default read buffer size
546             // It is unmanaged, so it can be then attached directly to binary
547             // queue
548             void *buffer = malloc(bytesToRead);
549
550             if (buffer == NULL) {
551                 throw std::bad_alloc();
552             }
553
554             // Receive bytes from socket
555             ssize_t result =
556                 TEMP_FAILURE_RETRY(recv(m_socket, buffer, bytesToRead, 0));
557
558             if (result > 0) {
559                 // Succedded to read socket data
560                 BinaryQueueAutoPtr binaryQueue(new BinaryQueue());
561
562                 // Append unmanaged memory
563                 binaryQueue->AppendUnmanaged(buffer,
564                                              result,
565                                              &BinaryQueue::BufferDeleterFree,
566                                              NULL);
567
568                 // Return buffer
569                 return binaryQueue;
570             } else if (result == 0) {
571                 // Socket was gracefuly closed
572                 free(buffer);
573
574                 // Return empty buffer
575                 return BinaryQueueAutoPtr(new BinaryQueue());
576             } else {
577                 // Must first save errno value, because it may be altered
578                 int lastErrno = errno;
579
580                 // Free buffer
581                 free(buffer);
582
583                 // Interpret error result
584                 switch (lastErrno) {
585                 case EAGAIN:     // = EWOULDBLOCK
586                     //
587                     // * The  socket's file descriptor is marked O_NONBLOCK and
588                     // no data is waiting
589                     //   to be received; or MSG_OOB is set and no out-of-band
590                     // data is available
591                     //   and either the socket's file descriptor is marked
592                     // O_NONBLOCK or the socket
593                     //   does not support blocking to await out-of-band data.
594                     //
595                     // return null data buffer to indicate no data waiting
596                     //
597                     return BinaryQueueAutoPtr();
598
599                 case EBADF:
600                     //
601                     // * The socket argument is not a valid file descriptor.
602                     //
603                     // This is internal error
604                     //
605                     ThrowMsg(CommonException::InternalError,
606                              "Invalid socket descriptor");
607
608                 case ECONNRESET:
609                     //
610                     // * A connection was forcibly closed by a peer.
611                     //
612                     // In result, we can interpret this error as a broken
613                     // connection
614                     //
615                     Throw(AbstractSocket::Exception::ConnectionBroken);
616
617                 case EINTR:
618                     //
619                     // * The recv() function was interrupted by a signal that
620                     // was caught, before any
621                     //   data was available.
622                     //
623                     // No interrupt here is expected, due to fact that we used
624                     // TEMP_FAILURE_RETRY
625                     //
626                     ThrowMsg(CommonException::InternalError,
627                              "Unexpected interrupt occurred");
628
629                 case EINVAL:
630                     //
631                     // * The MSG_OOB flag is set and no out-of-band data is
632                     // available.
633                     //
634                     // We did not specified OOB data. This is an error.
635                     //
636                     ThrowMsg(CommonException::InternalError,
637                              "Unexpected OOB error occurred");
638
639                 case ENOTCONN:
640                     //
641                     // * A receive is attempted on a connection-mode socket that
642                     // is not connected.
643                     //
644                     // FIXME: Is this proper exception here ?
645                     //
646                     ThrowMsg(CommonException::InternalError,
647                              "Socket is not connected");
648
649                 case ENOTSOCK:
650                     //
651                     // * The socket argument does not refer to a socket.
652                     //
653                     ThrowMsg(CommonException::InternalError,
654                              "Handle is not a socket");
655
656                 case EOPNOTSUPP:
657                     //
658                     // * The specified flags are not supported for this socket
659                     // type or protocol.
660                     //
661                     ThrowMsg(CommonException::InternalError,
662                              "Socket flags not supported");
663
664                 case ETIMEDOUT:
665                     //
666                     // * The connection timed out during connection
667                     // establishment, or due to a transmission timeout on active
668                     // connection.
669                     //
670                     // In result, we can interpret this error as a broken
671                     // connection
672                     //
673                     Throw(AbstractSocket::Exception::ConnectionBroken);
674
675                 case EIO:
676                     //
677                     // * An I/O error occurred while reading from or writing to
678                     // the file system.
679                     //
680                     // In result, we can interpret this error as a broken
681                     // connection
682                     //
683                     Throw(AbstractSocket::Exception::ConnectionBroken);
684
685                 case ENOBUFS:
686                     //
687                     // * Insufficient resources were available in the system to
688                     // perform the operation.
689                     //
690                     ThrowMsg(CommonException::InternalError,
691                              "Insufficient system resources");
692
693                 case ENOMEM:
694                     //
695                     // * Insufficient memory was available to fulfill the
696                     // request.
697                     //
698                     ThrowMsg(CommonException::InternalError,
699                              "Insufficient system memory");
700
701                 default:
702                     // Some kernel error occurred, should never happen
703                     ThrowMsg(CommonException::InternalError,
704                              "Unknown kernel read error returned");
705                     break;
706                 }
707             }
708         }
709         Catch(CommonException::InternalError)
710         {
711             // If any internal error occurred, this is fatal for Write method
712             // interpret this as WriteError exception and rethrow
713             ReThrow(AbstractSocket::Exception::ReadFailed);
714         }
715     }
716
717     virtual size_t Write(const BinaryQueue &buffer, size_t bufferSize)
718     {
719         if (m_internalState != InternalState_Connected) {
720             ThrowMsg(AbstractSocket::Exception::AcceptFailed,
721                      "Invalid socket state, should be 'Connected'");
722         }
723
724         Try
725         {
726             // Adjust write size
727             if (bufferSize > buffer.Size()) {
728                 bufferSize = buffer.Size();
729             }
730
731             // FIXME: User write visitor to write !
732             // WriteVisitor visitor
733
734             ScopedFree<void> flattened(malloc(bufferSize));
735             buffer.Flatten(flattened.Get(), bufferSize);
736
737             // Linux: MSG_NOSIGNAL is supported, but it is not an ideal solution
738             // FIXME: Should we setup signal PIPE ignoring for whole process ?
739             // In BSD, there is: setsockopt(c, SOL_SOCKET, SO_NOSIGPIPE, (void
740             // *)&on, sizeof(on))
741             ssize_t result =
742                 TEMP_FAILURE_RETRY(send(m_socket, flattened.Get(), bufferSize,
743                                         MSG_NOSIGNAL));
744
745             if (result > 0) {
746                 // Successfuly written some bytes
747                 return static_cast<size_t>(result);
748             } else if (result == 0) {
749                 // This is abnormal result
750                 ThrowMsg(CommonException::InternalError,
751                          "Invalid socket write result, 0 bytes written");
752             } else if (result == -1) {
753                 // Interpret error result
754                 switch (errno) {
755                 case EAGAIN:     // = EWOULDBLOCK
756                     //
757                     // * The socket's file descriptor is marked O_NONBLOCK and
758                     // the requested operation would block.
759                     //
760                     // We should wait for writability
761                     //
762                     return 0;
763
764                 case EBADF:
765                     //
766                     // * The socket argument is not a valid file descriptor.
767                     //
768                     // This is internal error
769                     //
770                     ThrowMsg(CommonException::InternalError,
771                              "Invalid socket descriptor");
772
773                 case ECONNRESET:
774                     //
775                     // * A connection was forcibly closed by a peer.
776                     //
777                     // In result, we can interpret this error as a broken
778                     // connection
779                     //
780                     Throw(AbstractSocket::Exception::ConnectionBroken);
781
782                 case EDESTADDRREQ:
783                     //
784                     // * The socket is not connection-mode and no peer address
785                     // is set.
786                     //
787                     // FIXME: Is this proper exception here ?
788                     //
789                     ThrowMsg(CommonException::InternalError,
790                              "Socket is not connected");
791
792                 case EINTR:
793                     //
794                     // * A signal interrupted send() before any data was
795                     // transmitted.
796                     //
797                     // No interrupt here is expected, due to fact that we used
798                     // TEMP_FAILURE_RETRY
799                     //
800                     ThrowMsg(CommonException::InternalError,
801                              "Unexpected interrupt occurred");
802
803                 case EMSGSIZE:
804                     //
805                     // * The message is too large to be sent all at once, as the
806                     // socket requires.
807                     //
808                     // FIXME: Is this proper exception here ?
809                     //
810                     ThrowMsg(CommonException::InternalError,
811                              "Socket message is too big");
812
813                 case ENOTCONN:
814                     //
815                     // * The socket is not connected or otherwise has not had
816                     // the peer pre-specified.
817                     //
818                     // FIXME: Is this proper exception here ?
819                     //
820                     ThrowMsg(CommonException::InternalError,
821                              "Socket is not connected");
822
823                 case ENOTSOCK:
824                     //
825                     // * The socket argument does not refer to a socket.
826                     //
827                     ThrowMsg(CommonException::InternalError,
828                              "Handle is not a socket");
829
830                 case EOPNOTSUPP:
831                     //
832                     // * The socket argument is associated with a socket that
833                     // does not support one or more of the values set in flags.
834                     //
835                     ThrowMsg(CommonException::InternalError,
836                              "Socket flags not supported");
837
838                 case EPIPE:
839                     //
840                     // * The socket is shut down for writing, or the socket is
841                     // connection-mode and
842                     //   is no longer connected. In the latter case, and if the
843                     // socket is of type
844                     //   SOCK_STREAM, the SIGPIPE signal is  generated to the
845                     // calling thread.
846                     //
847                     // In result, we can interpret this error as a broken
848                     // connection
849                     //
850                     Throw(AbstractSocket::Exception::ConnectionBroken);
851
852                 case EACCES:
853                     //
854                     // * The calling process does not have the appropriate
855                     // privileges.
856                     //
857                     // Priviledges might have changed.
858                     // In result, we can interpret this error as a broken
859                     // connection
860                     //
861                     Throw(AbstractSocket::Exception::ConnectionBroken);
862
863                 case EIO:
864                     //
865                     // * An I/O error occurred while reading from or writing to
866                     // the file system.
867                     //
868                     // In result, we can interpret this error as a broken
869                     // connection
870                     //
871                     Throw(AbstractSocket::Exception::ConnectionBroken);
872
873                 case ENETDOWN:
874                     //
875                     // * The local network interface used to reach the
876                     // destination is down.
877                     //
878                     // In result, we can interpret this error as a broken
879                     // connection
880                     //
881                     Throw(AbstractSocket::Exception::ConnectionBroken);
882
883                 case ENETUNREACH:
884                     //
885                     // * No route to the network is present.
886                     //
887                     // In result, we can interpret this error as a broken
888                     // connection
889                     //
890                     Throw(AbstractSocket::Exception::ConnectionBroken);
891
892                 case ENOBUFS:
893                     //
894                     // * Insufficient resources were available in the system to
895                     // perform the operation.
896                     //
897                     ThrowMsg(CommonException::InternalError,
898                              "Insufficient system resources");
899
900                 default:
901                     // Some kernel error occurred, should never happen
902                     ThrowMsg(CommonException::InternalError,
903                              "Unknown kernel write error returned");
904                     break;
905                 }
906             }
907         }
908         Catch(CommonException::InternalError)
909         {
910             // If any internal error occurred, this is fatal for Write method
911             // interpret this as WriteError exception and rethrow
912             ReThrow(AbstractSocket::Exception::WriteFailed);
913         }
914
915         // Does not apply
916         return 0;
917     }
918
919     // AbstractWaitableInput
920     virtual WaitableHandle WaitableReadHandle() const
921     {
922         return m_socket;
923     }
924
925     // AbstractWaitableOutput
926     virtual WaitableHandle WaitableWriteHandle() const
927     {
928         return m_socket;
929     }
930 };
931 }
932 } // namespace DPL
933
934 #endif // DPL_GENERIC_SOCKET_H