2 * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 * @file generic_socket.h
18 * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com)
20 * @brief This file is the header file of generic socket
22 #ifndef DPL_GENERIC_SOCKET_H
23 #define DPL_GENERIC_SOCKET_H
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>
30 #include <dpl/log/log.h>
31 #include <dpl/scoped_free.h>
32 #include <sys/types.h>
33 #include <sys/socket.h>
36 #include <dpl/assert.h>
43 // Generic abstract socket implementation
44 // Execution context is inherited
46 template<typename SocketType>
48 : public AbstractSocket,
49 private WaitableHandleWatchSupport::WaitableHandleListener
53 * Translate generic Address to specific socket kernel structure
55 * @warning Must be implemented in derived class
57 virtual std::pair<sockaddr *, socklen_t> TranslateAddressGenericToSpecific(const Address &address) const = 0;
60 * Translate specific socket kernel structure to generic Address
62 * @warning Must be implemented in derived class
64 virtual Address TranslateAddressSpecificToGeneric(sockaddr *, socklen_t) const = 0;
67 * Get specific socket kernel structure size
69 * @warning Must be implemented in derived class
71 virtual socklen_t GetSpecificAddressSize() const = 0;
74 * Alloc specific implementation of socket from descriptor
76 * @warning Must be implemented in derived class
78 virtual SocketType *AllocAcceptedSpecificSocket() const = 0;
81 * Alloc specific implementation of socket descriptor
83 * @warning Must be implemented in derived class
85 virtual int AllocSpecificDescriptor() const = 0;
89 static const size_t DEFAULT_READ_BUFFER_SIZE = 4096;
92 int m_socket; // FIXME: Consider generalization to WaitableHandle upon leaving nix platform
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
104 InternalState m_internalState;
106 void SetNonBlocking()
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);
113 // WaitableHandleWatchSupport::WaitableHandleListener
114 virtual void OnWaitableHandleEvent(WaitableHandle waitableHandle, WaitMode::Type mode)
116 (void)waitableHandle;
117 Assert(waitableHandle == m_socket);
119 switch (m_internalState)
121 case InternalState_None:
124 case InternalState_Prepare:
125 Assert(0 && "Invalid internal generic socket state!");
128 case InternalState_Listening:
129 Assert(mode == WaitMode::Read);
131 // New client waiting for accept
132 DPL::Event::EventSupport<AbstractSocketEvents::AcceptEvent>::
133 EmitEvent(AbstractSocketEvents::AcceptEvent(
134 EventSender(this)), DPL::Event::EmitMode::Queued);
139 case InternalState_Connecting:
140 Assert(mode == WaitMode::Write);
142 // Connected to server
143 RemoveConnectWatch();
144 m_internalState = InternalState_Connected;
150 DPL::Event::EventSupport<AbstractSocketEvents::ConnectedEvent>::
151 EmitEvent(AbstractSocketEvents::ConnectedEvent(
152 EventSender(this)), DPL::Event::EmitMode::Queued);
157 case InternalState_Connected:
158 if (mode == WaitMode::Read)
161 DPL::Event::EventSupport<AbstractSocketEvents::ReadEvent>::
162 EmitEvent(AbstractSocketEvents::ReadEvent(
163 EventSender(this)), DPL::Event::EmitMode::Queued);
165 else if (mode == WaitMode::Write)
168 DPL::Event::EventSupport<AbstractSocketEvents::WriteEvent>::
169 EmitEvent(AbstractSocketEvents::WriteEvent(
170 EventSender(this)), DPL::Event::EmitMode::Queued);
185 void AddAcceptWatch()
187 WaitableHandleWatchSupport::InheritedContext()->AddWaitableHandleWatch(this, m_socket, WaitMode::Read);
190 void RemoveAcceptWatch()
192 WaitableHandleWatchSupport::InheritedContext()->RemoveWaitableHandleWatch(this, m_socket, WaitMode::Read);
195 void AddConnectWatch()
197 WaitableHandleWatchSupport::InheritedContext()->AddWaitableHandleWatch(this, m_socket, WaitMode::Write);
200 void RemoveConnectWatch()
202 WaitableHandleWatchSupport::InheritedContext()->RemoveWaitableHandleWatch(this, m_socket, WaitMode::Write);
207 WaitableHandleWatchSupport::InheritedContext()->AddWaitableHandleWatch(this, m_socket, WaitMode::Read);
210 void RemoveReadWatch()
212 WaitableHandleWatchSupport::InheritedContext()->RemoveWaitableHandleWatch(this, m_socket, WaitMode::Read);
217 WaitableHandleWatchSupport::InheritedContext()->AddWaitableHandleWatch(this, m_socket, WaitMode::Write);
220 void RemoveWriteWatch()
222 WaitableHandleWatchSupport::InheritedContext()->RemoveWaitableHandleWatch(this, m_socket, WaitMode::Write);
228 m_internalState(InternalState_None)
232 virtual ~GenericSocket()
234 // Always ensure to close socket
239 Catch(Exception::CloseFailed)
241 LogPedantic("Close failed and ignored");
245 Assert(m_socket == -1);
250 if (m_internalState != InternalState_None)
251 ThrowMsg(AbstractSocket::Exception::OpenFailed, "Invalid socket state, should be 'None'");
253 LogPedantic("Opening socket...");
256 Assert(m_socket == -1);
258 // Allocate specific socket descriptor
259 m_socket = AllocSpecificDescriptor();
261 // Set socket non-blocking
265 m_internalState = InternalState_Prepare;
267 LogPedantic("Socket opened");
270 virtual void Connect(const Address &address)
272 if (m_internalState != InternalState_Prepare)
273 ThrowMsg(AbstractSocket::Exception::ConnectFailed, "Invalid socket state, should be 'Prepare'");
275 LogPedantic("Connecting to: " << address.ToString());
277 // Try to convert address
278 std::pair<sockaddr *, socklen_t> socketAddress;
282 // Translate address to specific socket address struct
283 socketAddress = TranslateAddressGenericToSpecific(address);
285 Catch (Address::Exception::InvalidAddress)
287 // This address is invalid. Cannot connect.
288 ReThrowMsg(AbstractSocket::Exception::ConnectFailed, address.ToString());
292 int result = TEMP_FAILURE_RETRY(connect(m_socket, socketAddress.first, socketAddress.second));
297 LogPedantic("Immediate connected to: " << address.ToString());
301 m_internalState = InternalState_Connected;
303 // Emit connected event
304 DPL::Event::EventSupport<AbstractSocketEvents::ConnectedEvent>::
305 EmitEvent(AbstractSocketEvents::ConnectedEvent(
306 EventSender(this)), DPL::Event::EmitMode::Queued);
310 if (errno == EINTR || errno == EINPROGRESS)
312 LogPedantic("Asynchronous connect in progress: " << address.ToString());
314 // Connecting in progress
316 m_internalState = InternalState_Connecting;
320 // Free translation structure
321 free(socketAddress.first);
324 ThrowMsg(AbstractSocket::Exception::ConnectFailed, address.ToString());
328 // Free translation structure
329 free(socketAddress.first);
334 if (m_internalState == InternalState_None)
337 Assert(m_socket != -1);
339 if (m_internalState == InternalState_Listening)
341 // Remove watch in listening state
342 LogPedantic("Removing accept watch");
344 m_internalState = InternalState_None;
346 else if (m_internalState == InternalState_Connecting)
348 // Remove watch in connecting state
349 LogPedantic("Removing connect watch");
350 RemoveConnectWatch();
351 m_internalState = InternalState_None;
353 else if (m_internalState == InternalState_Connected)
355 // Remove watch in connected state
356 LogPedantic("Removing read watch");
358 m_internalState = InternalState_None;
362 // State must be just prepared only
363 Assert(m_internalState == InternalState_Prepare);
366 if (TEMP_FAILURE_RETRY(close(m_socket)) == -1)
367 Throw(Exception::CloseFailed);
372 // Reset socket state
373 m_internalState = InternalState_None;
375 LogPedantic("Socket closed");
378 virtual void Bind(const Address &address)
380 if (m_internalState != InternalState_Prepare)
381 ThrowMsg(AbstractSocket::Exception::BindFailed, "Invalid socket state, should be 'Prepare'");
383 LogPedantic("Binding to: " << address.GetAddress() << ":" << address.GetPort());
385 // Translate address to specific socket address struct
386 std::pair<sockaddr *, socklen_t> socketAddress = TranslateAddressGenericToSpecific(address);
389 if (::bind(m_socket, socketAddress.first, socketAddress.second) == -1)
390 ThrowMsg(AbstractSocket::Exception::BindFailed, address.ToString());
392 // Free translation structure
393 free(socketAddress.first);
396 LogPedantic("Bound to address: " << address.GetAddress() << ":" << address.GetPort());
399 virtual void Listen(int backlog)
401 if (m_internalState != InternalState_Prepare)
402 ThrowMsg(AbstractSocket::Exception::ListenFailed, "Invalid socket state, should be 'None'");
404 LogPedantic("Starting to listen...");
407 if (listen(m_socket, backlog) != 0)
408 Throw(AbstractSocket::Exception::ListenFailed);
412 m_internalState = InternalState_Listening;
414 LogPedantic("Listen started");
417 virtual AbstractSocket *Accept()
419 if (m_internalState != InternalState_Listening)
420 ThrowMsg(AbstractSocket::Exception::AcceptFailed, "Invalid socket state, should be 'Listening'");
422 LogPedantic("Accepting...");
425 socklen_t length = 0;
426 int client = TEMP_FAILURE_RETRY(accept(m_socket, NULL, &length));
428 LogPedantic("Socket accept returned " << client);
431 // Check if there is any client waiting
432 if (errno == EWOULDBLOCK || errno == EAGAIN)
437 LogPedantic("throwing error. errrno " << err);
439 Throw(AbstractSocket::Exception::AcceptFailed);
442 LogPedantic("Accepted client. Seting up...");
444 // Create derived class type
445 GenericSocket *acceptedSocket = AllocAcceptedSpecificSocket();
447 // Save client socket specific descriptor
448 acceptedSocket->m_socket = client;
450 // Enter proper states and add read watch
451 acceptedSocket->AddReadWatch();
452 acceptedSocket->m_internalState = InternalState_Connected;
454 // Set non-blocking mode for new socket
455 acceptedSocket->SetNonBlocking();
458 LogPedantic("Accepted client set up");
460 // return new conneced client socket
461 return acceptedSocket;
464 virtual Address GetLocalAddress() const
466 // FIXME: Additional internal state check
468 socklen_t length = GetSpecificAddressSize();
469 ScopedFree<sockaddr> address(static_cast<sockaddr *>(calloc(static_cast<size_t>(length), 1)));
471 if (getsockname(m_socket, address.Get(), &length) == -1)
472 ThrowMsg(AbstractSocket::Exception::GetPeerNameFailed, "Failed to get local address");
474 return TranslateAddressSpecificToGeneric(address.Get(), length);
477 virtual Address GetRemoteAddress() const
479 // FIXME: Additional internal state check
481 socklen_t length = GetSpecificAddressSize();
482 ScopedFree<sockaddr> address(static_cast<sockaddr *>(calloc(static_cast<size_t>(length), 1)));
484 if (getpeername(m_socket, address.Get(), &length) == -1)
485 ThrowMsg(AbstractSocket::Exception::GetPeerNameFailed, "Failed to get remote address");
487 return TranslateAddressSpecificToGeneric(address.Get(), length);
490 virtual BinaryQueueAutoPtr Read(size_t size)
492 if (m_internalState != InternalState_Connected)
493 ThrowMsg(AbstractSocket::Exception::AcceptFailed, "Invalid socket state, should be 'Connected'");
497 // Adjust bytes to be read
498 size_t bytesToRead = size > DEFAULT_READ_BUFFER_SIZE ? DEFAULT_READ_BUFFER_SIZE : size;
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);
505 throw std::bad_alloc();
507 // Receive bytes from socket
508 ssize_t result = TEMP_FAILURE_RETRY(recv(m_socket, buffer, bytesToRead, 0));
512 // Succedded to read socket data
513 BinaryQueueAutoPtr binaryQueue(new BinaryQueue());
515 // Append unmanaged memory
516 binaryQueue->AppendUnmanaged(buffer, result, &BinaryQueue::BufferDeleterFree, NULL);
521 else if (result == 0)
523 // Socket was gracefuly closed
526 // Return empty buffer
527 return BinaryQueueAutoPtr(new BinaryQueue());
531 // Must first save errno value, because it may be altered
532 int lastErrno = errno;
537 // Interpret error result
540 case EAGAIN: // = EWOULDBLOCK
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.
547 // return null data buffer to indicate no data waiting
549 return BinaryQueueAutoPtr();
553 // * The socket argument is not a valid file descriptor.
555 // This is internal error
557 ThrowMsg(CommonException::InternalError, "Invalid socket descriptor");
561 // * A connection was forcibly closed by a peer.
563 // In result, we can interpret this error as a broken connection
565 Throw(AbstractSocket::Exception::ConnectionBroken);
569 // * The recv() function was interrupted by a signal that was caught, before any
570 // data was available.
572 // No interrupt here is expected, due to fact that we used TEMP_FAILURE_RETRY
574 ThrowMsg(CommonException::InternalError, "Unexpected interrupt occurred");
578 // * The MSG_OOB flag is set and no out-of-band data is available.
580 // We did not specified OOB data. This is an error.
582 ThrowMsg(CommonException::InternalError, "Unexpected OOB error occurred");
586 // * A receive is attempted on a connection-mode socket that is not connected.
588 // FIXME: Is this proper exception here ?
590 ThrowMsg(CommonException::InternalError, "Socket is not connected");
594 // * The socket argument does not refer to a socket.
596 ThrowMsg(CommonException::InternalError, "Handle is not a socket");
600 // * The specified flags are not supported for this socket type or protocol.
602 ThrowMsg(CommonException::InternalError, "Socket flags not supported");
606 // * The connection timed out during connection establishment, or due to a transmission timeout on active connection.
608 // In result, we can interpret this error as a broken connection
610 Throw(AbstractSocket::Exception::ConnectionBroken);
614 // * An I/O error occurred while reading from or writing to the file system.
616 // In result, we can interpret this error as a broken connection
618 Throw(AbstractSocket::Exception::ConnectionBroken);
622 // * Insufficient resources were available in the system to perform the operation.
624 ThrowMsg(CommonException::InternalError, "Insufficient system resources");
628 // * Insufficient memory was available to fulfill the request.
630 ThrowMsg(CommonException::InternalError, "Insufficient system memory");
633 // Some kernel error occurred, should never happen
634 ThrowMsg(CommonException::InternalError, "Unknown kernel read error returned");
639 Catch (CommonException::InternalError)
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);
647 virtual size_t Write(const BinaryQueue &buffer, size_t bufferSize)
649 if (m_internalState != InternalState_Connected)
650 ThrowMsg(AbstractSocket::Exception::AcceptFailed, "Invalid socket state, should be 'Connected'");
655 if (bufferSize > buffer.Size())
656 bufferSize = buffer.Size();
658 // FIXME: User write visitor to write !
659 // WriteVisitor visitor
661 ScopedFree<void> flattened(malloc(bufferSize));
662 buffer.Flatten(flattened.Get(), bufferSize);
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));
671 // Successfuly written some bytes
672 return static_cast<size_t>(result);
674 else if (result == 0)
676 // This is abnormal result
677 ThrowMsg(CommonException::InternalError, "Invalid socket write result, 0 bytes written");
679 else if (result == -1)
681 // Interpret error result
684 case EAGAIN: // = EWOULDBLOCK
686 // * The socket's file descriptor is marked O_NONBLOCK and the requested operation would block.
688 // We should wait for writability
694 // * The socket argument is not a valid file descriptor.
696 // This is internal error
698 ThrowMsg(CommonException::InternalError, "Invalid socket descriptor");
702 // * A connection was forcibly closed by a peer.
704 // In result, we can interpret this error as a broken connection
706 Throw(AbstractSocket::Exception::ConnectionBroken);
710 // * The socket is not connection-mode and no peer address is set.
712 // FIXME: Is this proper exception here ?
714 ThrowMsg(CommonException::InternalError, "Socket is not connected");
718 // * A signal interrupted send() before any data was transmitted.
720 // No interrupt here is expected, due to fact that we used TEMP_FAILURE_RETRY
722 ThrowMsg(CommonException::InternalError, "Unexpected interrupt occurred");
726 // * The message is too large to be sent all at once, as the socket requires.
728 // FIXME: Is this proper exception here ?
730 ThrowMsg(CommonException::InternalError, "Socket message is too big");
734 // * The socket is not connected or otherwise has not had the peer pre-specified.
736 // FIXME: Is this proper exception here ?
738 ThrowMsg(CommonException::InternalError, "Socket is not connected");
742 // * The socket argument does not refer to a socket.
744 ThrowMsg(CommonException::InternalError, "Handle is not a socket");
748 // * The socket argument is associated with a socket that does not support one or more of the values set in flags.
750 ThrowMsg(CommonException::InternalError, "Socket flags not supported");
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.
758 // In result, we can interpret this error as a broken connection
760 Throw(AbstractSocket::Exception::ConnectionBroken);
764 // * The calling process does not have the appropriate privileges.
766 // Priviledges might have changed.
767 // In result, we can interpret this error as a broken connection
769 Throw(AbstractSocket::Exception::ConnectionBroken);
773 // * An I/O error occurred while reading from or writing to the file system.
775 // In result, we can interpret this error as a broken connection
777 Throw(AbstractSocket::Exception::ConnectionBroken);
781 // * The local network interface used to reach the destination is down.
783 // In result, we can interpret this error as a broken connection
785 Throw(AbstractSocket::Exception::ConnectionBroken);
789 // * No route to the network is present.
791 // In result, we can interpret this error as a broken connection
793 Throw(AbstractSocket::Exception::ConnectionBroken);
797 // * Insufficient resources were available in the system to perform the operation.
799 ThrowMsg(CommonException::InternalError, "Insufficient system resources");
802 // Some kernel error occurred, should never happen
803 ThrowMsg(CommonException::InternalError, "Unknown kernel write error returned");
808 Catch (CommonException::InternalError)
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);
819 // AbstractWaitableInput
820 virtual WaitableHandle WaitableReadHandle() const
825 // AbstractWaitableOutput
826 virtual WaitableHandle WaitableWriteHandle() const
835 #endif // DPL_GENERIC_SOCKET_H