diff --git a/README.md b/README.md index 9208fbb..c5005f6 100644 --- a/README.md +++ b/README.md @@ -189,6 +189,7 @@ int main() # TODO +- [ ] Proper namespacing in socket options - [ ] Add more unit tests, increase coverage - [ ] Add examples for non-blocking socket operations - [ ] Add support for more protocols other than TCP, UDP, UNIX diff --git a/include/socket_options.hpp b/include/socket_options.hpp index 7e98b49..a3815f9 100644 --- a/include/socket_options.hpp +++ b/include/socket_options.hpp @@ -3,6 +3,7 @@ #include #include +#include extern "C" { #include @@ -60,7 +61,13 @@ enum class Opt { TYPE = SO_TYPE, #endif #ifdef SO_USELOOPBACK - USELOOPBACK = SO_USELOOPBACK + USELOOPBACK = SO_USELOOPBACK, +#endif +#ifdef TCP_MAXSEG + MAXSEG = TCP_MAXSEG, +#endif +#ifdef TCP_NODELAY + NODELAY = TCP_NODELAY #endif }; diff --git a/src/socket.cpp b/src/socket.cpp index dc57c9b..c0b5098 100644 --- a/src/socket.cpp +++ b/src/socket.cpp @@ -298,6 +298,19 @@ void Socket::setOpt(Opt _opType, SockOpt _opValue) const break; } + case Opt::MAXSEG: + case Opt::NODELAY: { + if (_opValue.getType() != type::INT) { + throw std::invalid_argument("Invalid socket option"); + } + + const auto i = _opValue.getValue(); + const socklen_t len = sizeof(i); + + res = setsockopt(sockfd, IPPROTO_TCP, optname, &i, len); + break; + } + default: { if (_opValue.getType() != type::INT) { throw std::invalid_argument("Invalid socket option"); @@ -306,6 +319,7 @@ void Socket::setOpt(Opt _opType, SockOpt _opValue) const const socklen_t len = sizeof(i); res = setsockopt(sockfd, SOL_SOCKET, optname, &i, len); + break; } } @@ -347,6 +361,19 @@ SockOpt Socket::getOpt(Opt _opType) const return opt; } + case Opt::MAXSEG: + case Opt::NODELAY: { + int i; + socklen_t len = sizeof(i); + const auto res = getsockopt(sockfd, IPPROTO_TCP, optname, &i, &len); + const auto currErrno = errno; + if (res == -1) { + throw std::runtime_error(net::methods::getErrorMsg(currErrno)); + } + SockOpt opt(i); + return opt; + } + default: { int i; socklen_t len = sizeof(i); diff --git a/test/socket_options_test.cpp b/test/socket_options_test.cpp index a57ebfe..4ba7bdf 100644 --- a/test/socket_options_test.cpp +++ b/test/socket_options_test.cpp @@ -93,8 +93,8 @@ TEST(SocketOptions, Broadcast) EXPECT_EQ( 0, setsockopt(s6.getSocket(), SOL_SOCKET, SO_BROADCAST, &optval, optlen)); - auto opt4 = s4.getOpt(Opt::BROADCAST); - auto opt6 = s6.getOpt(Opt::BROADCAST); + const auto opt4 = s4.getOpt(Opt::BROADCAST); + const auto opt6 = s6.getOpt(Opt::BROADCAST); ASSERT_EQ(0, opt4.getValue()); ASSERT_EQ(0, opt6.getValue()); @@ -148,7 +148,7 @@ TEST(SocketOptions, DontRoute) ASSERT_EQ( 0, setsockopt(s.getSocket(), SOL_SOCKET, SO_DONTROUTE, &optval, optlen)); - auto opt2 = s.getOpt(Opt::DONTROUTE); + const auto opt2 = s.getOpt(Opt::DONTROUTE); ASSERT_EQ(0, opt2); } @@ -171,7 +171,7 @@ TEST(SocketOptions, KeepAlive) ASSERT_EQ( 0, setsockopt(s.getSocket(), SOL_SOCKET, SO_KEEPALIVE, &optval, optlen)); - auto opt2 = s.getOpt(Opt::KEEPALIVE); + const auto opt2 = s.getOpt(Opt::KEEPALIVE); ASSERT_EQ(0, opt2); } @@ -192,7 +192,7 @@ TEST(SocketOptions, OOBInline) ASSERT_EQ( 0, setsockopt(s.getSocket(), SOL_SOCKET, SO_OOBINLINE, &optval, optlen)); - auto opt2 = s.getOpt(Opt::OOBINLINE); + const auto opt2 = s.getOpt(Opt::OOBINLINE); ASSERT_EQ(0, opt2); } @@ -213,7 +213,7 @@ TEST(SocketOptions, RCVLOWAT) ASSERT_EQ( 0, setsockopt(s.getSocket(), SOL_SOCKET, SO_RCVLOWAT, &optval, optlen)); - auto opt2 = s.getOpt(Opt::RCVLOWAT); + const auto opt2 = s.getOpt(Opt::RCVLOWAT); ASSERT_EQ(10, opt2); } @@ -267,3 +267,34 @@ TEST(SocketOptions, SNDTIMEO) const auto opt3 = s.getOpt(Opt::SNDTIMEO); ASSERT_EQ(t.tv_sec, opt3.getTime().first); } + + +TEST(SocketOptions, MAXSEG) +{ + // This option ignores any value being set, atleast on my machine! + Socket s(Domain::IPv4, Type::TCP); + SockOpt opt(1024); + ASSERT_NO_THROW(s.setOpt(Opt::MAXSEG, opt)); + ASSERT_NO_THROW(s.getOpt(Opt::MAXSEG)); +} + + +TEST(SocketOptions, NODELAY) +{ + Socket s(Domain::IPv4, Type::TCP); + + int optval; + socklen_t optlen = sizeof(optval); + + SockOpt opt(1); + s.setOpt(Opt::NODELAY, opt); + ASSERT_EQ( + 0, getsockopt(s.getSocket(), IPPROTO_TCP, TCP_NODELAY, &optval, &optlen)); + ASSERT_EQ(1, optval); + optval = 0; + + ASSERT_EQ( + 0, setsockopt(s.getSocket(), IPPROTO_TCP, TCP_NODELAY, &optval, optlen)); + const auto opt2 = s.getOpt(Opt::NODELAY); + ASSERT_EQ(0, opt2); +}