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