libBsdSockets
C++ Wrapper classes to the BSD Socket API
ServerSocket.cpp
Go to the documentation of this file.
1 /*
2 
3 Copyright (c) 2013, Komodo Does Inc
4 All rights reserved.
5 
6 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
7 
8 Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
9 Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
10 Neither the name of the Komodo Does Inc nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
11 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
12 
13 */
14 
15 #include <sys/socket.h>
16 #include <system_error>
17 #include <memory>
18 #include <functional>
19 #include <thread>
20 
21 #include "ServerSocket.h"
22 #include "Address.h"
23 #include "LowLevelAddress.h"
24 
25 namespace {
26  using namespace BsdSockets;
27 
28  /** Helper method and compound result for Accepting a socket
29  */
30  class AcceptedSocketData {
31  public:
32  /** Create with data
33  *
34  * @param theLowLevelSocket of the accepted socket
35  * @param theAddress of the accepted socket
36  */
37  AcceptedSocketData(int theLowLevelSocket, Address::Ptr theAddress)
38  :lowLevelSocket(theLowLevelSocket), address(theAddress)
39  {
40  }
41 
42  public:
43  /** low-level socket id */
44  const int lowLevelSocket;
45 
46  /** Address connected to */
47  Address::Ptr address;
48  };
49 
50  /** Do low level socket accept and prepare Address connected to
51  *
52  * @param serverLowLevelSocket low-level socket id for server to accept from
53  * @param serverAddress address of the server socket to build the address of the accepted socket
54  *
55  * @return data for the accepted socket
56  */
57  AcceptedSocketData lowLevelAccept(int serverLowLevelSocket, Address::Ptr serverAddress) {
58  // Accept the socket
59  LowLevelAddress::Ptr lowLevelAddress = serverAddress->makeTempLowLevelAddress();
60  socklen_t len;
61  const int lowLevelSocket = ::accept(serverLowLevelSocket, &lowLevelAddress->getSockAddr(), &len);
62 
63  // Verify results
64  if(len > lowLevelAddress->getSockAddrLen()) {
65  throw std::runtime_error("accept over-write the length of the sockaddr for the ServerSocket Address");
66  }
67 
68  if(-1 == lowLevelSocket) {
69  throw std::system_error(errno, std::system_category());
70  }
71 
72  // Assume the server socket's type if unspecified
73  // TODO: I'd like to do better, but there are no guarantees if we are getting a different
74  // address tyle, like unspecified accepting from a local socket
75  if(AF_UNSPEC == lowLevelAddress->getSockAddr().sa_family) {
76  lowLevelAddress->getSockAddr().sa_family = serverAddress->getLowLevelAddress().getSockAddr().sa_family;
77  }
78 
79  // Build the results
80  return AcceptedSocketData(lowLevelSocket, serverAddress->create(lowLevelAddress));
81  }
82 
83 } // namespace
84 
85 namespace BsdSockets {
86 
88  return ServerSocket::Ptr (new ServerSocket(theAddress));
89  }
90 
91  ServerSocket::Ptr ServerSocket::open(Address::Ptr theAddress, int backlog, bool reuse) {
92  ServerSocket::Ptr socket = create(theAddress);
93  if(reuse) {
94  const int reuse = 1;
95  socket->setSocketOption(SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
96  socket->setSocketOption(SOL_SOCKET, SO_REUSEPORT, &reuse, sizeof(reuse));
97  }
98  socket->bind();
99  socket->listen(backlog);
100  return socket;
101  }
102 
104  }
105 
107  : Socket(theAddress)
108  {
109  }
110 
111  void ServerSocket::bind() const {
112  const LowLevelAddress& lowLevelAddress = getAddress()->getLowLevelAddress();
113 
114  if(-1 == ::bind(getLowLevelSocket(), &lowLevelAddress.getSockAddr(), lowLevelAddress.getSockAddrLen())) {
115  throw std::system_error(errno, std::system_category());
116  }
117  }
118 
119  void ServerSocket::listen(int backlog) const {
120  if(-1 == ::listen(getLowLevelSocket(), backlog)) {
121  throw std::system_error(errno, std::system_category());
122  }
123  }
124 
126  AcceptedSocketData data = lowLevelAccept(getLowLevelSocket(), getAddress());
127  return Socket::create(data.address, data.lowLevelSocket);
128  }
129 
130  std::thread ServerSocket::acceptInNewThread(std::function<void (Socket::Ptr)> toCall) {
131  // Note: We rely on the thread-safety of shared_ptr for the address....
132  // This shouldn't be a big deal since it will clear from data in this frame
133  // and thus this thread
134  AcceptedSocketData data = lowLevelAccept(getLowLevelSocket(), getAddress());
135  return std::thread ([=]() {
136  toCall(Socket::create(data.address, data.lowLevelSocket));
137  });
138  }
139 
140 } // namespace BsdSockets
std::shared_ptr< Address > Ptr
Definition: Address.h:38
Interface for the low-level address implementation.
std::shared_ptr< LowLevelAddress > Ptr
virtual socklen_t getSockAddrLen() const =0
virtual const struct sockaddr & getSockAddr() const =0
std::thread acceptInNewThread(std::function< void(Socket::Ptr)> toCall)
static ServerSocket::Ptr open(std::shared_ptr< Address > theAddress, int backlog=128, bool reuse=false)
Socket::Ptr accept() const
static ServerSocket::Ptr create(std::shared_ptr< Address > theAddress)
void listen(int backlog=128) const
std::shared_ptr< ServerSocket > Ptr
Definition: ServerSocket.h:40
ServerSocket(std::shared_ptr< Address > theAddress)
BSD Socket base class providing the basic, common functionality between ServerSockets and ClientSocke...
Definition: Socket.h:66
static Socket::Ptr create(std::shared_ptr< Address > theAddress, int existingLowLevelSocket)
Definition: Socket.cpp:38
int getLowLevelSocket() const
Definition: Socket.cpp:139
std::shared_ptr< Socket > Ptr
Definition: Socket.h:68
std::shared_ptr< Address > getAddress() const
Definition: Socket.cpp:135
Namespace of the BsdSockets library.
Definition: Address.cpp:20