UDP: reuse socket; SCTP: first version v_0
authorFrantišek Kučera <franta-hg@frantovo.cz>
Wed, 17 Aug 2022 23:28:20 +0200
branchv_0
changeset 21 1c6c86697837
parent 20 ad21bff45051
child 22 9a7c42cca24b
UDP: reuse socket; SCTP: first version
src/Socket.cpp
--- a/src/Socket.cpp	Sun Aug 07 15:31:51 2022 +0200
+++ b/src/Socket.cpp	Wed Aug 17 23:28:20 2022 +0200
@@ -124,45 +124,43 @@
 
 };
 
-template<class SocketClass> static std::shared_ptr<SocketClass> openClientSocket(const SocketOptions& options, int socketType, int protocol) {
+template<class SocketClass, class... MoreArgs> static std::shared_ptr<SocketClass> openClientSocket(const SocketOptions& options, int socketType, int protocol, MoreArgs... moreArgs) {
 	AddressInfos remoteAddresses = AddressInfos::getAddressInfos(
 			findOption(options, OPTION_HOST, true),
 			findOption(options, OPTION_PORT, true),
 			socketType,
 			protocol);
 
-	return std::shared_ptr<SocketClass>(new SocketClass(remoteAddresses[0]));
+	return std::shared_ptr<SocketClass>(new SocketClass(remoteAddresses[0], moreArgs...));
 }
 
 class UDPClientSocket : public Socket {
 private:
 	AddressInfos::AddressInfo remoteAddress;
 	useconds_t delay = 0;
+	FD socket;
 
 public:
 
-	UDPClientSocket(AddressInfos::AddressInfo remoteAddress) : remoteAddress(remoteAddress) {
+	UDPClientSocket(AddressInfos::AddressInfo remoteAddress) : remoteAddress(remoteAddress), socket(::socket(remoteAddress.ai->ai_family, remoteAddress.ai->ai_socktype, remoteAddress.ai->ai_protocol)) {
 	}
 
 	static std::shared_ptr<Socket> open(const SocketOptions& options) {
-		bool sctp = findOption(options, OPTION_PROTOCOL) == PROTOCOL_SCTP;
-		auto socket = openClientSocket<UDPClientSocket>(options, sctp ? SOCK_SEQPACKET : SOCK_DGRAM, sctp ? IPPROTO_SCTP : IPPROTO_UDP);
-		socket->delay = std::stol(findOption(options, OPTION_DELAY, false, "0"));
+		auto socket = openClientSocket<UDPClientSocket>(options, SOCK_DGRAM, IPPROTO_UDP);
+		socket->delay = std::stol(findOption(options, OPTION_DELAY, false, "0")); // TODO: Move to SocketHandler? Or delete.
 		return socket;
 	}
 
 	void send(const std::string& message) override {
 		auto ai = remoteAddress.ai;
-		FD s(::socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol));
-		sendto(s.getFD(), message.c_str(), message.size(), 0, ai->ai_addr, ai->ai_addrlen);
+		sendto(socket.getFD(), message.c_str(), message.size(), 0, ai->ai_addr, ai->ai_addrlen);
 		if (delay) usleep(delay);
 	}
 
 	const std::string receive() override {
-		// TODO: TCP receive()
+		// TODO: UDP receive()
 		return "TODO: receive() a message";
 	}
-
 };
 
 class TCPClientSocket : public Socket {
@@ -191,8 +189,35 @@
 		// TODO: TCP receive()
 		return "TODO: receive() a message";
 	}
+};
 
+class SCTPStreamClientSocket : public Socket {
+private:
+	AddressInfos::AddressInfo remoteAddress;
 
+public:
+
+	SCTPStreamClientSocket(AddressInfos::AddressInfo remoteAddress) : remoteAddress(remoteAddress) {
+	}
+
+	static std::shared_ptr<Socket> open(const SocketOptions& options) {
+		auto socket = openClientSocket<SCTPStreamClientSocket>(options, SOCK_STREAM, IPPROTO_SCTP);
+		return socket;
+	}
+
+	void send(const std::string& message) override {
+		auto ai = remoteAddress.ai;
+		FD s(::socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol));
+		check(::connect(s.getFD(), ai->ai_addr, ai->ai_addrlen), "connect socket");
+		ssize_t written = ::write(s.getFD(), message.c_str(), message.size());
+		if (written != message.size()) throw std::logic_error("writing to the socket failed");
+		// TODO: partial writes, repeat
+	}
+
+	const std::string receive() override {
+		// TODO: SCTP receive()
+		return "TODO: receive() a message";
+	}
 };
 
 template<const char* protocol, const char* role, const char* mode, typename SocketClass>
@@ -216,9 +241,9 @@
 			std::make_shared<TemplateSocketFactory<PROTOCOL_TCP, ROLE_SERVER, MODE_STREAM, TCPClientSocket >> (), // TODO: correct class
 			std::make_shared<TemplateSocketFactory<PROTOCOL_UDP, ROLE_CLIENT, MODE_DATAGRAM, UDPClientSocket >> (),
 			std::make_shared<TemplateSocketFactory<PROTOCOL_UDP, ROLE_SERVER, MODE_DATAGRAM, UDPClientSocket >> (), // TODO: correct class
-			std::make_shared<TemplateSocketFactory<PROTOCOL_SCTP, ROLE_CLIENT, MODE_STREAM, UDPClientSocket >> (), // TODO: correct class
-			std::make_shared<TemplateSocketFactory<PROTOCOL_SCTP, ROLE_CLIENT, MODE_DATAGRAM, UDPClientSocket >> (), // TODO: correct class
-			std::make_shared<TemplateSocketFactory<PROTOCOL_SCTP, ROLE_SERVER, MODE_STREAM, UDPClientSocket >> (), // TODO: correct class
+			std::make_shared<TemplateSocketFactory<PROTOCOL_SCTP, ROLE_CLIENT, MODE_STREAM, SCTPStreamClientSocket >> (), // TODO: do we need a stream-mode SCTP?
+			std::make_shared<TemplateSocketFactory<PROTOCOL_SCTP, ROLE_CLIENT, MODE_DATAGRAM, SCTPStreamClientSocket >> (),
+			std::make_shared<TemplateSocketFactory<PROTOCOL_SCTP, ROLE_SERVER, MODE_STREAM, UDPClientSocket >> (), // TODO: do we need a stream-mode SCTP?
 			std::make_shared<TemplateSocketFactory<PROTOCOL_SCTP, ROLE_SERVER, MODE_DATAGRAM, UDPClientSocket >> (), // TODO: correct class
 			std::make_shared<TemplateSocketFactory<PROTOCOL_UDS, ROLE_CLIENT, MODE_STREAM, UDPClientSocket >> (), // TODO: correct class
 			std::make_shared<TemplateSocketFactory<PROTOCOL_UDS, ROLE_CLIENT, MODE_DATAGRAM, UDPClientSocket >> (), // TODO: correct class