Index: src/OFTCPSocket.h ================================================================== --- src/OFTCPSocket.h +++ src/OFTCPSocket.h @@ -87,11 +87,12 @@ OFString *_Nullable _SOCKS5Host; uint16_t _SOCKS5Port; #ifdef OF_WII uint16_t _port; #endif - OF_RESERVE_IVARS(OFTCPSocket, 4) + uintptr_t _usesMPTCP; /* Change to bool on ABI bump */ + OF_RESERVE_IVARS(OFTCPSocket, 3) } #ifdef OF_HAVE_CLASS_PROPERTIES @property (class, nullable, copy, nonatomic) OFString *SOCKS5Host; @property (class, nonatomic) uint16_t SOCKS5Port; @@ -120,10 +121,18 @@ * @throw OFSetOptionFailedException The option could not be set */ @property (nonatomic) bool canDelaySendingSegments; #endif +/** + * @brief Whether the socket uses MPTCP. + * + * If you want to use MPTCP, set this to true before connecting or binding. + * After connecting or binding, this returns whether MPTCP was used. + */ +@property (nonatomic) bool usesMPTCP; + /** * @brief The host to use as a SOCKS5 proxy. */ @property OF_NULLABLE_PROPERTY (copy, nonatomic) OFString *SOCKS5Host; Index: src/OFTCPSocket.m ================================================================== --- src/OFTCPSocket.m +++ src/OFTCPSocket.m @@ -50,10 +50,14 @@ #import "OFBindIPSocketFailedException.h" #import "OFGetOptionFailedException.h" #import "OFNotImplementedException.h" #import "OFNotOpenException.h" #import "OFSetOptionFailedException.h" + +#ifdef OF_LINUX +# include +#endif static const OFRunLoopMode connectRunLoopMode = @"OFTCPSocketConnectRunLoopMode"; static OFString *defaultSOCKS5Host = nil; @@ -141,19 +145,36 @@ { #if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL) && defined(FD_CLOEXEC) int flags; #endif - if (_socket != OFInvalidSocketHandle) + if (_socket != OFInvalidSocketHandle) { @throw [OFAlreadyOpenException exceptionWithObject: self]; - - if ((_socket = socket( - ((struct sockaddr *)&address->sockaddr)->sa_family, - SOCK_STREAM | SOCK_CLOEXEC, 0)) == OFInvalidSocketHandle) { - *errNo = _OFSocketErrNo(); - return false; } + +#ifdef OF_LINUX + if (_usesMPTCP) { + if ((_socket = socket( + ((struct sockaddr *)&address->sockaddr)->sa_family, + SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_MPTCP)) == + OFInvalidSocketHandle) { + if ((_socket = socket( + ((struct sockaddr *)&address->sockaddr)->sa_family, + SOCK_STREAM | SOCK_CLOEXEC, 0)) == + OFInvalidSocketHandle) { + *errNo = _OFSocketErrNo(); + return false; + } + } + } else +#endif + if ((_socket = socket( + ((struct sockaddr *)&address->sockaddr)->sa_family, + SOCK_STREAM | SOCK_CLOEXEC, 0)) == OFInvalidSocketHandle) { + *errNo = _OFSocketErrNo(); + return false; + } #if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL) && defined(FD_CLOEXEC) if ((flags = fcntl(_socket, F_GETFD, 0)) != -1) fcntl(_socket, F_SETFD, flags | FD_CLOEXEC); #endif @@ -346,18 +367,36 @@ addressFamily: OFSocketAddressFamilyAny]; address = *(OFSocketAddress *)[socketAddresses itemAtIndex: 0]; OFSocketAddressSetIPPort(&address, port); - if ((_socket = socket( - ((struct sockaddr *)&address.sockaddr)->sa_family, - SOCK_STREAM | SOCK_CLOEXEC, 0)) == OFInvalidSocketHandle) - @throw [OFBindIPSocketFailedException - exceptionWithHost: host - port: port - socket: self - errNo: _OFSocketErrNo()]; +#ifdef OF_LINUX + if (_usesMPTCP) { + if ((_socket = socket( + ((struct sockaddr *)&address.sockaddr)->sa_family, + SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_MPTCP)) == + OFInvalidSocketHandle) { + if ((_socket = socket( + ((struct sockaddr *)&address.sockaddr)->sa_family, + SOCK_STREAM | SOCK_CLOEXEC, 0)) == + OFInvalidSocketHandle) + @throw [OFBindIPSocketFailedException + exceptionWithHost: host + port: port + socket: self + errNo: _OFSocketErrNo()]; + } + } else +#endif + if ((_socket = socket( + ((struct sockaddr *)&address.sockaddr)->sa_family, + SOCK_STREAM | SOCK_CLOEXEC, 0)) == OFInvalidSocketHandle) + @throw [OFBindIPSocketFailedException + exceptionWithHost: host + port: port + socket: self + errNo: _OFSocketErrNo()]; _canBlock = true; #if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL) && defined(FD_CLOEXEC) if ((flags = fcntl(_socket, F_GETFD, 0)) != -1) @@ -509,10 +548,28 @@ errNo: _OFSocketErrNo()]; return !v; } #endif + +- (void)setUsesMPTCP: (bool)usesMPTCP +{ + _usesMPTCP = usesMPTCP; +} + +- (bool)usesMPTCP +{ +#ifdef OF_LINUX + struct mptcp_info info; + socklen_t infoLen = (socklen_t)sizeof(info); + + if (getsockopt(_socket, SOL_MPTCP, MPTCP_INFO, &info, &infoLen) != -1) + return true; +#endif + + return false; +} - (void)close { #ifdef OF_WII _port = 0;