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