/* * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, * 2018, 2019, 2020 * Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in * the packaging of this file. * * Alternatively, it may be distributed under the terms of the GNU General * Public License, either version 2 or 3, which can be found in the file * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #include "config.h" #import "OFTCPSocket.h" #ifdef HAVE_FCNTL_H # include #endif #import "OFAlreadyConnectedException.h" #import "OFGetOptionFailedException.h" #import "OFNotImplementedException.h" #import "OFSetOptionFailedException.h" #import "socket.h" #import "socket_helpers.h" Class of_tls_socket_class = Nil; static OFString *defaultSOCKS5Host = nil; static uint16_t defaultSOCKS5Port = 1080; @implementation OFTCPSocket @synthesize SOCKS5Host = _SOCKS5Host, SOCKS5Port = _SOCKS5Port; @dynamic delegate; + (void)setSOCKS5Host: (OFString *)host { id old = defaultSOCKS5Host; defaultSOCKS5Host = [host copy]; [old release]; } + (OFString *)SOCKS5Host { return defaultSOCKS5Host; } + (void)setSOCKS5Port: (uint16_t)port { defaultSOCKS5Port = port; } + (uint16_t)SOCKS5Port { return defaultSOCKS5Port; } - (instancetype)init { self = [super init]; @try { _SOCKS5Host = [defaultSOCKS5Host copy]; _SOCKS5Port = defaultSOCKS5Port; } @catch (id e) { [self release]; @throw e; } return self; } - (void)dealloc { [_SOCKS5Host release]; [super dealloc]; } - (bool)of_createSocketForAddress: (const of_socket_address_t *)address errNo: (int *)errNo { #if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL) && defined(FD_CLOEXEC) int flags; #endif if (_socket != INVALID_SOCKET) @throw [OFAlreadyConnectedException exceptionWithSocket: self]; if ((_socket = socket(address->sockaddr.sockaddr.sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0)) == INVALID_SOCKET) { *errNo = of_socket_errno(); 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 return true; } #if !defined(OF_WII) && !defined(OF_NINTENDO_3DS) - (void)setKeepAliveEnabled: (bool)enabled { int v = enabled; if (setsockopt(_socket, SOL_SOCKET, SO_KEEPALIVE, (char *)&v, (socklen_t)sizeof(v)) != 0) @throw [OFSetOptionFailedException exceptionWithObject: self errNo: of_socket_errno()]; } - (bool)isKeepAliveEnabled { int v; socklen_t len = sizeof(v); if (getsockopt(_socket, SOL_SOCKET, SO_KEEPALIVE, (char *)&v, &len) != 0 || len != sizeof(v)) @throw [OFGetOptionFailedException exceptionWithStream: self errNo: of_socket_errno()]; return v; } #endif #ifndef OF_WII - (void)setNoDelayEnabled: (bool)enabled { int v = enabled; if (setsockopt(_socket, IPPROTO_TCP, TCP_NODELAY, (char *)&v, (socklen_t)sizeof(v)) != 0) @throw [OFSetOptionFailedException exceptionWithObject: self errNo: of_socket_errno()]; } - (bool)isNoDelayEnabled { int v; socklen_t len = sizeof(v); if (getsockopt(_socket, IPPROTO_TCP, TCP_NODELAY, (char *)&v, &len) != 0 || len != sizeof(v)) @throw [OFGetOptionFailedException exceptionWithStream: self errNo: of_socket_errno()]; return v; } #endif - (uint16_t)bindToHost: (OFString *)host port: (uint16_t)port { if (_SOCKS5Host != nil) @throw [OFNotImplementedException exceptionWithSelector: _cmd object: self]; return [super bindToHost: host port: port]; } @end