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>
41 // Generic abstract socket implementation
42 // Execution context is inherited
44 template<typename SocketType>
46 public AbstractSocket,
47 private WaitableHandleWatchSupport::WaitableHandleListener
51 * Translate generic Address to specific socket kernel structure
53 * @warning Must be implemented in derived class
55 virtual std::pair<sockaddr *, socklen_t> TranslateAddressGenericToSpecific(
56 const Address &address) const = 0;
59 * Translate specific socket kernel structure to generic Address
61 * @warning Must be implemented in derived class
63 virtual Address TranslateAddressSpecificToGeneric(sockaddr *,
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
93 // leaving nix platform
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
105 InternalState m_internalState;
107 void SetNonBlocking()
109 // Set non-blocking mode
110 if (fcntl(m_socket, F_SETFL, O_NONBLOCK |
111 fcntl(m_socket, F_GETFL)) == -1)
113 Throw(AbstractSocket::Exception::SetNonBlockingFailed);
117 // WaitableHandleWatchSupport::WaitableHandleListener
118 virtual void OnWaitableHandleEvent(WaitableHandle waitableHandle,
121 (void)waitableHandle;
122 Assert(waitableHandle == m_socket);
124 switch (m_internalState) {
125 case InternalState_None:
128 case InternalState_Prepare:
129 Assert(0 && "Invalid internal generic socket state!");
132 case InternalState_Listening:
133 Assert(mode == WaitMode::Read);
135 // New client waiting for accept
136 DPL::Event::EventSupport<AbstractSocketEvents::AcceptEvent>::
137 EmitEvent(AbstractSocketEvents::AcceptEvent(
138 EventSender(this)), DPL::Event::EmitMode::Queued);
143 case InternalState_Connecting:
144 Assert(mode == WaitMode::Write);
146 // Connected to server
147 RemoveConnectWatch();
148 m_internalState = InternalState_Connected;
154 DPL::Event::EventSupport<AbstractSocketEvents::ConnectedEvent>::
155 EmitEvent(AbstractSocketEvents::ConnectedEvent(
156 EventSender(this)), DPL::Event::EmitMode::Queued);
161 case InternalState_Connected:
162 if (mode == WaitMode::Read) {
164 DPL::Event::EventSupport<AbstractSocketEvents::ReadEvent>::
165 EmitEvent(AbstractSocketEvents::ReadEvent(
167 this)), DPL::Event::EmitMode::Queued);
168 } else if (mode == WaitMode::Write) {
170 DPL::Event::EventSupport<AbstractSocketEvents::WriteEvent>::
171 EmitEvent(AbstractSocketEvents::WriteEvent(
173 this)), DPL::Event::EmitMode::Queued);
186 void AddAcceptWatch()
188 WaitableHandleWatchSupport::InheritedContext()->AddWaitableHandleWatch(
194 void RemoveAcceptWatch()
196 WaitableHandleWatchSupport::InheritedContext()->
197 RemoveWaitableHandleWatch(this, m_socket, WaitMode::Read);
200 void AddConnectWatch()
202 WaitableHandleWatchSupport::InheritedContext()->AddWaitableHandleWatch(
208 void RemoveConnectWatch()
210 WaitableHandleWatchSupport::InheritedContext()->
211 RemoveWaitableHandleWatch(this, m_socket, WaitMode::Write);
216 WaitableHandleWatchSupport::InheritedContext()->AddWaitableHandleWatch(
222 void RemoveReadWatch()
224 WaitableHandleWatchSupport::InheritedContext()->
225 RemoveWaitableHandleWatch(this, m_socket, WaitMode::Read);
230 WaitableHandleWatchSupport::InheritedContext()->AddWaitableHandleWatch(
236 void RemoveWriteWatch()
238 WaitableHandleWatchSupport::InheritedContext()->
239 RemoveWaitableHandleWatch(this, m_socket, WaitMode::Write);
245 m_internalState(InternalState_None)
248 virtual ~GenericSocket()
250 // Always ensure to close socket
255 Catch(Exception::CloseFailed)
257 LogPedantic("Close failed and ignored");
261 Assert(m_socket == -1);
266 if (m_internalState != InternalState_None) {
267 ThrowMsg(AbstractSocket::Exception::OpenFailed,
268 "Invalid socket state, should be 'None'");
271 LogPedantic("Opening socket...");
274 Assert(m_socket == -1);
276 // Allocate specific socket descriptor
277 m_socket = AllocSpecificDescriptor();
279 // Set socket non-blocking
283 m_internalState = InternalState_Prepare;
285 LogPedantic("Socket opened");
288 virtual void Connect(const Address &address)
290 if (m_internalState != InternalState_Prepare) {
291 ThrowMsg(AbstractSocket::Exception::ConnectFailed,
292 "Invalid socket state, should be 'Prepare'");
295 LogPedantic("Connecting to: " << address.ToString());
297 // Try to convert address
298 std::pair<sockaddr *, socklen_t> socketAddress;
302 // Translate address to specific socket address struct
303 socketAddress = TranslateAddressGenericToSpecific(address);
305 Catch(Address::Exception::InvalidAddress)
307 // This address is invalid. Cannot connect.
308 ReThrowMsg(AbstractSocket::Exception::ConnectFailed,
314 TEMP_FAILURE_RETRY(connect(m_socket, socketAddress.first,
315 socketAddress.second));
319 LogPedantic("Immediate connected to: " << address.ToString());
323 m_internalState = InternalState_Connected;
325 // Emit connected event
326 DPL::Event::EventSupport<AbstractSocketEvents::ConnectedEvent>::
327 EmitEvent(AbstractSocketEvents::ConnectedEvent(
328 EventSender(this)), DPL::Event::EmitMode::Queued);
330 if (errno == EINTR || errno == EINPROGRESS) {
332 "Asynchronous connect in progress: " << address.ToString());
334 // Connecting in progress
336 m_internalState = InternalState_Connecting;
338 // Free translation structure
339 free(socketAddress.first);
342 ThrowMsg(AbstractSocket::Exception::ConnectFailed,
347 // Free translation structure
348 free(socketAddress.first);
353 if (m_internalState == InternalState_None) {
357 Assert(m_socket != -1);
359 if (m_internalState == InternalState_Listening) {
360 // Remove watch in listening state
361 LogPedantic("Removing accept watch");
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");
373 m_internalState = InternalState_None;
375 // State must be just prepared only
376 Assert(m_internalState == InternalState_Prepare);
379 if (TEMP_FAILURE_RETRY(close(m_socket)) == -1) {
380 Throw(Exception::CloseFailed);
386 // Reset socket state
387 m_internalState = InternalState_None;
389 LogPedantic("Socket closed");
392 virtual void Bind(const Address &address)
394 if (m_internalState != InternalState_Prepare) {
395 ThrowMsg(AbstractSocket::Exception::BindFailed,
396 "Invalid socket state, should be 'Prepare'");
400 "Binding to: " << address.GetAddress() << ":" << address.GetPort());
402 // Translate address to specific socket address struct
403 std::pair<sockaddr *,
404 socklen_t> socketAddress = TranslateAddressGenericToSpecific(
408 if (::bind(m_socket, socketAddress.first,
409 socketAddress.second) == -1)
411 ThrowMsg(AbstractSocket::Exception::BindFailed, address.ToString());
414 // Free translation structure
415 free(socketAddress.first);
419 "Bound to address: " << address.GetAddress() << ":" <<
423 virtual void Listen(int backlog)
425 if (m_internalState != InternalState_Prepare) {
426 ThrowMsg(AbstractSocket::Exception::ListenFailed,
427 "Invalid socket state, should be 'None'");
430 LogPedantic("Starting to listen...");
433 if (listen(m_socket, backlog) != 0) {
434 Throw(AbstractSocket::Exception::ListenFailed);
439 m_internalState = InternalState_Listening;
441 LogPedantic("Listen started");
444 virtual AbstractSocket *Accept()
446 if (m_internalState != InternalState_Listening) {
447 ThrowMsg(AbstractSocket::Exception::AcceptFailed,
448 "Invalid socket state, should be 'Listening'");
451 LogPedantic("Accepting...");
454 socklen_t length = 0;
455 int client = TEMP_FAILURE_RETRY(accept(m_socket, NULL, &length));
457 LogPedantic("Socket accept returned " << client);
459 // Check if there is any client waiting
460 if (errno == EWOULDBLOCK || errno == EAGAIN) {
464 if (errno == ENOENT) {
467 LogPedantic("throwing error. errrno " << err);
469 Throw(AbstractSocket::Exception::AcceptFailed);
472 LogPedantic("Accepted client. Seting up...");
474 // Create derived class type
475 GenericSocket *acceptedSocket = AllocAcceptedSpecificSocket();
477 // Save client socket specific descriptor
478 acceptedSocket->m_socket = client;
480 // Enter proper states and add read watch
481 acceptedSocket->AddReadWatch();
482 acceptedSocket->m_internalState = InternalState_Connected;
484 // Set non-blocking mode for new socket
485 acceptedSocket->SetNonBlocking();
488 LogPedantic("Accepted client set up");
490 // return new conneced client socket
491 return acceptedSocket;
494 virtual Address GetLocalAddress() const
496 // FIXME: Additional internal state check
498 socklen_t length = GetSpecificAddressSize();
499 ScopedFree<sockaddr> address(static_cast<sockaddr *>(calloc(
505 if (getsockname(m_socket, address.Get(), &length) == -1) {
506 ThrowMsg(AbstractSocket::Exception::GetPeerNameFailed,
507 "Failed to get local address");
510 return TranslateAddressSpecificToGeneric(address.Get(), length);
513 virtual Address GetRemoteAddress() const
515 // FIXME: Additional internal state check
517 socklen_t length = GetSpecificAddressSize();
518 ScopedFree<sockaddr> address(static_cast<sockaddr *>(calloc(
524 if (getpeername(m_socket, address.Get(), &length) == -1) {
525 ThrowMsg(AbstractSocket::Exception::GetPeerNameFailed,
526 "Failed to get remote address");
529 return TranslateAddressSpecificToGeneric(address.Get(), length);
532 virtual BinaryQueueAutoPtr Read(size_t size)
534 if (m_internalState != InternalState_Connected) {
535 ThrowMsg(AbstractSocket::Exception::AcceptFailed,
536 "Invalid socket state, should be 'Connected'");
541 // Adjust bytes to be read
542 size_t bytesToRead = size >
543 DEFAULT_READ_BUFFER_SIZE ? DEFAULT_READ_BUFFER_SIZE : size;
545 // Malloc default read buffer size
546 // It is unmanaged, so it can be then attached directly to binary
548 void *buffer = malloc(bytesToRead);
550 if (buffer == NULL) {
551 throw std::bad_alloc();
554 // Receive bytes from socket
556 TEMP_FAILURE_RETRY(recv(m_socket, buffer, bytesToRead, 0));
559 // Succedded to read socket data
560 BinaryQueueAutoPtr binaryQueue(new BinaryQueue());
562 // Append unmanaged memory
563 binaryQueue->AppendUnmanaged(buffer,
565 &BinaryQueue::BufferDeleterFree,
570 } else if (result == 0) {
571 // Socket was gracefuly closed
574 // Return empty buffer
575 return BinaryQueueAutoPtr(new BinaryQueue());
577 // Must first save errno value, because it may be altered
578 int lastErrno = errno;
583 // Interpret error result
585 case EAGAIN: // = EWOULDBLOCK
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
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.
595 // return null data buffer to indicate no data waiting
597 return BinaryQueueAutoPtr();
601 // * The socket argument is not a valid file descriptor.
603 // This is internal error
605 ThrowMsg(CommonException::InternalError,
606 "Invalid socket descriptor");
610 // * A connection was forcibly closed by a peer.
612 // In result, we can interpret this error as a broken
615 Throw(AbstractSocket::Exception::ConnectionBroken);
619 // * The recv() function was interrupted by a signal that
620 // was caught, before any
621 // data was available.
623 // No interrupt here is expected, due to fact that we used
624 // TEMP_FAILURE_RETRY
626 ThrowMsg(CommonException::InternalError,
627 "Unexpected interrupt occurred");
631 // * The MSG_OOB flag is set and no out-of-band data is
634 // We did not specified OOB data. This is an error.
636 ThrowMsg(CommonException::InternalError,
637 "Unexpected OOB error occurred");
641 // * A receive is attempted on a connection-mode socket that
644 // FIXME: Is this proper exception here ?
646 ThrowMsg(CommonException::InternalError,
647 "Socket is not connected");
651 // * The socket argument does not refer to a socket.
653 ThrowMsg(CommonException::InternalError,
654 "Handle is not a socket");
658 // * The specified flags are not supported for this socket
661 ThrowMsg(CommonException::InternalError,
662 "Socket flags not supported");
666 // * The connection timed out during connection
667 // establishment, or due to a transmission timeout on active
670 // In result, we can interpret this error as a broken
673 Throw(AbstractSocket::Exception::ConnectionBroken);
677 // * An I/O error occurred while reading from or writing to
680 // In result, we can interpret this error as a broken
683 Throw(AbstractSocket::Exception::ConnectionBroken);
687 // * Insufficient resources were available in the system to
688 // perform the operation.
690 ThrowMsg(CommonException::InternalError,
691 "Insufficient system resources");
695 // * Insufficient memory was available to fulfill the
698 ThrowMsg(CommonException::InternalError,
699 "Insufficient system memory");
702 // Some kernel error occurred, should never happen
703 ThrowMsg(CommonException::InternalError,
704 "Unknown kernel read error returned");
709 Catch(CommonException::InternalError)
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);
717 virtual size_t Write(const BinaryQueue &buffer, size_t bufferSize)
719 if (m_internalState != InternalState_Connected) {
720 ThrowMsg(AbstractSocket::Exception::AcceptFailed,
721 "Invalid socket state, should be 'Connected'");
727 if (bufferSize > buffer.Size()) {
728 bufferSize = buffer.Size();
731 // FIXME: User write visitor to write !
732 // WriteVisitor visitor
734 ScopedFree<void> flattened(malloc(bufferSize));
735 buffer.Flatten(flattened.Get(), bufferSize);
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))
742 TEMP_FAILURE_RETRY(send(m_socket, flattened.Get(), bufferSize,
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
755 case EAGAIN: // = EWOULDBLOCK
757 // * The socket's file descriptor is marked O_NONBLOCK and
758 // the requested operation would block.
760 // We should wait for writability
766 // * The socket argument is not a valid file descriptor.
768 // This is internal error
770 ThrowMsg(CommonException::InternalError,
771 "Invalid socket descriptor");
775 // * A connection was forcibly closed by a peer.
777 // In result, we can interpret this error as a broken
780 Throw(AbstractSocket::Exception::ConnectionBroken);
784 // * The socket is not connection-mode and no peer address
787 // FIXME: Is this proper exception here ?
789 ThrowMsg(CommonException::InternalError,
790 "Socket is not connected");
794 // * A signal interrupted send() before any data was
797 // No interrupt here is expected, due to fact that we used
798 // TEMP_FAILURE_RETRY
800 ThrowMsg(CommonException::InternalError,
801 "Unexpected interrupt occurred");
805 // * The message is too large to be sent all at once, as the
808 // FIXME: Is this proper exception here ?
810 ThrowMsg(CommonException::InternalError,
811 "Socket message is too big");
815 // * The socket is not connected or otherwise has not had
816 // the peer pre-specified.
818 // FIXME: Is this proper exception here ?
820 ThrowMsg(CommonException::InternalError,
821 "Socket is not connected");
825 // * The socket argument does not refer to a socket.
827 ThrowMsg(CommonException::InternalError,
828 "Handle is not a socket");
832 // * The socket argument is associated with a socket that
833 // does not support one or more of the values set in flags.
835 ThrowMsg(CommonException::InternalError,
836 "Socket flags not supported");
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
844 // SOCK_STREAM, the SIGPIPE signal is generated to the
847 // In result, we can interpret this error as a broken
850 Throw(AbstractSocket::Exception::ConnectionBroken);
854 // * The calling process does not have the appropriate
857 // Priviledges might have changed.
858 // In result, we can interpret this error as a broken
861 Throw(AbstractSocket::Exception::ConnectionBroken);
865 // * An I/O error occurred while reading from or writing to
868 // In result, we can interpret this error as a broken
871 Throw(AbstractSocket::Exception::ConnectionBroken);
875 // * The local network interface used to reach the
876 // destination is down.
878 // In result, we can interpret this error as a broken
881 Throw(AbstractSocket::Exception::ConnectionBroken);
885 // * No route to the network is present.
887 // In result, we can interpret this error as a broken
890 Throw(AbstractSocket::Exception::ConnectionBroken);
894 // * Insufficient resources were available in the system to
895 // perform the operation.
897 ThrowMsg(CommonException::InternalError,
898 "Insufficient system resources");
901 // Some kernel error occurred, should never happen
902 ThrowMsg(CommonException::InternalError,
903 "Unknown kernel write error returned");
908 Catch(CommonException::InternalError)
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);
919 // AbstractWaitableInput
920 virtual WaitableHandle WaitableReadHandle() const
925 // AbstractWaitableOutput
926 virtual WaitableHandle WaitableWriteHandle() const
934 #endif // DPL_GENERIC_SOCKET_H