122 throw std::out_of_range("invalid index for AddressInfo: " + std::to_string(index)); |
122 throw std::out_of_range("invalid index for AddressInfo: " + std::to_string(index)); |
123 } |
123 } |
124 |
124 |
125 }; |
125 }; |
126 |
126 |
127 template<class SocketClass> static std::shared_ptr<SocketClass> openClientSocket(const SocketOptions& options, int socketType, int protocol) { |
127 template<class SocketClass, class... MoreArgs> static std::shared_ptr<SocketClass> openClientSocket(const SocketOptions& options, int socketType, int protocol, MoreArgs... moreArgs) { |
128 AddressInfos remoteAddresses = AddressInfos::getAddressInfos( |
128 AddressInfos remoteAddresses = AddressInfos::getAddressInfos( |
129 findOption(options, OPTION_HOST, true), |
129 findOption(options, OPTION_HOST, true), |
130 findOption(options, OPTION_PORT, true), |
130 findOption(options, OPTION_PORT, true), |
131 socketType, |
131 socketType, |
132 protocol); |
132 protocol); |
133 |
133 |
134 return std::shared_ptr<SocketClass>(new SocketClass(remoteAddresses[0])); |
134 return std::shared_ptr<SocketClass>(new SocketClass(remoteAddresses[0], moreArgs...)); |
135 } |
135 } |
136 |
136 |
137 class UDPClientSocket : public Socket { |
137 class UDPClientSocket : public Socket { |
138 private: |
138 private: |
139 AddressInfos::AddressInfo remoteAddress; |
139 AddressInfos::AddressInfo remoteAddress; |
140 useconds_t delay = 0; |
140 useconds_t delay = 0; |
141 |
141 FD socket; |
142 public: |
142 |
143 |
143 public: |
144 UDPClientSocket(AddressInfos::AddressInfo remoteAddress) : remoteAddress(remoteAddress) { |
144 |
|
145 UDPClientSocket(AddressInfos::AddressInfo remoteAddress) : remoteAddress(remoteAddress), socket(::socket(remoteAddress.ai->ai_family, remoteAddress.ai->ai_socktype, remoteAddress.ai->ai_protocol)) { |
145 } |
146 } |
146 |
147 |
147 static std::shared_ptr<Socket> open(const SocketOptions& options) { |
148 static std::shared_ptr<Socket> open(const SocketOptions& options) { |
148 bool sctp = findOption(options, OPTION_PROTOCOL) == PROTOCOL_SCTP; |
149 auto socket = openClientSocket<UDPClientSocket>(options, SOCK_DGRAM, IPPROTO_UDP); |
149 auto socket = openClientSocket<UDPClientSocket>(options, sctp ? SOCK_SEQPACKET : SOCK_DGRAM, sctp ? IPPROTO_SCTP : IPPROTO_UDP); |
150 socket->delay = std::stol(findOption(options, OPTION_DELAY, false, "0")); // TODO: Move to SocketHandler? Or delete. |
150 socket->delay = std::stol(findOption(options, OPTION_DELAY, false, "0")); |
|
151 return socket; |
151 return socket; |
152 } |
152 } |
153 |
153 |
154 void send(const std::string& message) override { |
154 void send(const std::string& message) override { |
155 auto ai = remoteAddress.ai; |
155 auto ai = remoteAddress.ai; |
156 FD s(::socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)); |
156 sendto(socket.getFD(), message.c_str(), message.size(), 0, ai->ai_addr, ai->ai_addrlen); |
157 sendto(s.getFD(), message.c_str(), message.size(), 0, ai->ai_addr, ai->ai_addrlen); |
|
158 if (delay) usleep(delay); |
157 if (delay) usleep(delay); |
159 } |
158 } |
160 |
159 |
161 const std::string receive() override { |
160 const std::string receive() override { |
162 // TODO: TCP receive() |
161 // TODO: UDP receive() |
163 return "TODO: receive() a message"; |
162 return "TODO: receive() a message"; |
164 } |
163 } |
165 |
|
166 }; |
164 }; |
167 |
165 |
168 class TCPClientSocket : public Socket { |
166 class TCPClientSocket : public Socket { |
169 private: |
167 private: |
170 AddressInfos::AddressInfo remoteAddress; |
168 AddressInfos::AddressInfo remoteAddress; |
189 |
187 |
190 const std::string receive() override { |
188 const std::string receive() override { |
191 // TODO: TCP receive() |
189 // TODO: TCP receive() |
192 return "TODO: receive() a message"; |
190 return "TODO: receive() a message"; |
193 } |
191 } |
194 |
192 }; |
195 |
193 |
|
194 class SCTPStreamClientSocket : public Socket { |
|
195 private: |
|
196 AddressInfos::AddressInfo remoteAddress; |
|
197 |
|
198 public: |
|
199 |
|
200 SCTPStreamClientSocket(AddressInfos::AddressInfo remoteAddress) : remoteAddress(remoteAddress) { |
|
201 } |
|
202 |
|
203 static std::shared_ptr<Socket> open(const SocketOptions& options) { |
|
204 auto socket = openClientSocket<SCTPStreamClientSocket>(options, SOCK_STREAM, IPPROTO_SCTP); |
|
205 return socket; |
|
206 } |
|
207 |
|
208 void send(const std::string& message) override { |
|
209 auto ai = remoteAddress.ai; |
|
210 FD s(::socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)); |
|
211 check(::connect(s.getFD(), ai->ai_addr, ai->ai_addrlen), "connect socket"); |
|
212 ssize_t written = ::write(s.getFD(), message.c_str(), message.size()); |
|
213 if (written != message.size()) throw std::logic_error("writing to the socket failed"); |
|
214 // TODO: partial writes, repeat |
|
215 } |
|
216 |
|
217 const std::string receive() override { |
|
218 // TODO: SCTP receive() |
|
219 return "TODO: receive() a message"; |
|
220 } |
196 }; |
221 }; |
197 |
222 |
198 template<const char* protocol, const char* role, const char* mode, typename SocketClass> |
223 template<const char* protocol, const char* role, const char* mode, typename SocketClass> |
199 class TemplateSocketFactory : public SocketFactory { |
224 class TemplateSocketFactory : public SocketFactory { |
200 public: |
225 public: |
214 { |
239 { |
215 std::make_shared<TemplateSocketFactory<PROTOCOL_TCP, ROLE_CLIENT, MODE_STREAM, TCPClientSocket >> (), |
240 std::make_shared<TemplateSocketFactory<PROTOCOL_TCP, ROLE_CLIENT, MODE_STREAM, TCPClientSocket >> (), |
216 std::make_shared<TemplateSocketFactory<PROTOCOL_TCP, ROLE_SERVER, MODE_STREAM, TCPClientSocket >> (), // TODO: correct class |
241 std::make_shared<TemplateSocketFactory<PROTOCOL_TCP, ROLE_SERVER, MODE_STREAM, TCPClientSocket >> (), // TODO: correct class |
217 std::make_shared<TemplateSocketFactory<PROTOCOL_UDP, ROLE_CLIENT, MODE_DATAGRAM, UDPClientSocket >> (), |
242 std::make_shared<TemplateSocketFactory<PROTOCOL_UDP, ROLE_CLIENT, MODE_DATAGRAM, UDPClientSocket >> (), |
218 std::make_shared<TemplateSocketFactory<PROTOCOL_UDP, ROLE_SERVER, MODE_DATAGRAM, UDPClientSocket >> (), // TODO: correct class |
243 std::make_shared<TemplateSocketFactory<PROTOCOL_UDP, ROLE_SERVER, MODE_DATAGRAM, UDPClientSocket >> (), // TODO: correct class |
219 std::make_shared<TemplateSocketFactory<PROTOCOL_SCTP, ROLE_CLIENT, MODE_STREAM, UDPClientSocket >> (), // TODO: correct class |
244 std::make_shared<TemplateSocketFactory<PROTOCOL_SCTP, ROLE_CLIENT, MODE_STREAM, SCTPStreamClientSocket >> (), // TODO: do we need a stream-mode SCTP? |
220 std::make_shared<TemplateSocketFactory<PROTOCOL_SCTP, ROLE_CLIENT, MODE_DATAGRAM, UDPClientSocket >> (), // TODO: correct class |
245 std::make_shared<TemplateSocketFactory<PROTOCOL_SCTP, ROLE_CLIENT, MODE_DATAGRAM, SCTPStreamClientSocket >> (), |
221 std::make_shared<TemplateSocketFactory<PROTOCOL_SCTP, ROLE_SERVER, MODE_STREAM, UDPClientSocket >> (), // TODO: correct class |
246 std::make_shared<TemplateSocketFactory<PROTOCOL_SCTP, ROLE_SERVER, MODE_STREAM, UDPClientSocket >> (), // TODO: do we need a stream-mode SCTP? |
222 std::make_shared<TemplateSocketFactory<PROTOCOL_SCTP, ROLE_SERVER, MODE_DATAGRAM, UDPClientSocket >> (), // TODO: correct class |
247 std::make_shared<TemplateSocketFactory<PROTOCOL_SCTP, ROLE_SERVER, MODE_DATAGRAM, UDPClientSocket >> (), // TODO: correct class |
223 std::make_shared<TemplateSocketFactory<PROTOCOL_UDS, ROLE_CLIENT, MODE_STREAM, UDPClientSocket >> (), // TODO: correct class |
248 std::make_shared<TemplateSocketFactory<PROTOCOL_UDS, ROLE_CLIENT, MODE_STREAM, UDPClientSocket >> (), // TODO: correct class |
224 std::make_shared<TemplateSocketFactory<PROTOCOL_UDS, ROLE_CLIENT, MODE_DATAGRAM, UDPClientSocket >> (), // TODO: correct class |
249 std::make_shared<TemplateSocketFactory<PROTOCOL_UDS, ROLE_CLIENT, MODE_DATAGRAM, UDPClientSocket >> (), // TODO: correct class |
225 std::make_shared<TemplateSocketFactory<PROTOCOL_UDS, ROLE_SERVER, MODE_STREAM, UDPClientSocket >> (), // TODO: correct class |
250 std::make_shared<TemplateSocketFactory<PROTOCOL_UDS, ROLE_SERVER, MODE_STREAM, UDPClientSocket >> (), // TODO: correct class |
226 std::make_shared<TemplateSocketFactory<PROTOCOL_UDS, ROLE_SERVER, MODE_DATAGRAM, UDPClientSocket >> (), // TODO: correct class |
251 std::make_shared<TemplateSocketFactory<PROTOCOL_UDS, ROLE_SERVER, MODE_DATAGRAM, UDPClientSocket >> (), // TODO: correct class |