@@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2024 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 @@ -19,11 +19,10 @@ # define _XOPEN_SOURCE_EXTENDED #endif #define __NO_EXT_QNX #define _HPUX_ALT_XOPEN_SOCKET_API -#include #include #include #import "OFStreamSocket.h" #import "OFStreamSocket+Private.h" @@ -30,19 +29,25 @@ #import "OFRunLoop.h" #import "OFRunLoop+Private.h" #import "OFSocket+Private.h" #import "OFAcceptSocketFailedException.h" +#import "OFAlreadyOpenException.h" #import "OFInitializationFailedException.h" #import "OFInvalidArgumentException.h" #import "OFListenOnSocketFailedException.h" #import "OFNotImplementedException.h" #import "OFNotOpenException.h" +#import "OFOutOfMemoryException.h" #import "OFOutOfRangeException.h" #import "OFReadFailedException.h" #import "OFSetOptionFailedException.h" #import "OFWriteFailedException.h" + +#if defined(OF_AMIGAOS) && !defined(UNIQUE_ID) +# define UNIQUE_ID -1 +#endif @implementation OFStreamSocket @dynamic delegate; @synthesize listening = _listening; @@ -70,10 +75,13 @@ [self doesNotRecognizeSelector: _cmd]; abort(); } _socket = OFInvalidSocketHandle; +#ifdef OF_AMIGAOS + _socketID = -1; +#endif } @catch (id e) { [self release]; @throw e; } @@ -241,17 +249,21 @@ _listening = true; } - (instancetype)accept { - OFStreamSocket *client = [[[[self class] alloc] init] autorelease]; + OFStreamSocket *client; #if (!defined(HAVE_PACCEPT) && !defined(HAVE_ACCEPT4)) || !defined(SOCK_CLOEXEC) # if defined(HAVE_FCNTL) && defined(FD_CLOEXEC) int flags; # endif #endif + if (_socket == OFInvalidSocketHandle) + @throw [OFNotOpenException exceptionWithObject: self]; + + client = [[[[self class] alloc] init] autorelease]; client->_remoteAddress.length = (socklen_t)sizeof(client->_remoteAddress.sockaddr); #if defined(HAVE_PACCEPT) && defined(SOCK_CLOEXEC) if ((client->_socket = paccept(_socket, @@ -281,11 +293,11 @@ if ((flags = fcntl(client->_socket, F_GETFD, 0)) != -1) fcntl(client->_socket, F_SETFD, flags | FD_CLOEXEC); # endif #endif - assert(client->_remoteAddress.length <= + OFAssert(client->_remoteAddress.length <= (socklen_t)sizeof(client->_remoteAddress.sockaddr)); switch (((struct sockaddr *)&client->_remoteAddress.sockaddr) ->sa_family) { case AF_INET: @@ -354,10 +366,55 @@ if (_remoteAddress.length > (socklen_t)sizeof(_remoteAddress.sockaddr)) @throw [OFOutOfRangeException exception]; return &_remoteAddress; } + +- (void)releaseSocketFromCurrentThread +{ +#ifdef OF_AMIGAOS + if (_socket == OFInvalidSocketHandle) + @throw [OFNotOpenException exceptionWithObject: self]; + + if ((_socketID = ReleaseSocket(_socket, UNIQUE_ID)) == -1) { + switch (Errno()) { + case ENOMEM: + @throw [OFOutOfMemoryException + exceptionWithRequestedSize: 0]; + case EBADF: + @throw [OFNotOpenException exceptionWithObject: self]; + default: + OFEnsure(0); + } + } + + _socket = OFInvalidSocketHandle; +#endif +} + +- (void)obtainSocketForCurrentThread +{ +#ifdef OF_AMIGAOS + if (_socket != OFInvalidSocketHandle) + @throw [OFAlreadyOpenException exceptionWithObject: self]; + + if (_socketID == -1) + @throw [OFNotOpenException exceptionWithObject: self]; + + /* + * FIXME: We should store these, but that requires changing all + * subclasses. This only becomes a problem if IPv6 support ever + * gets added. + */ + _socket = ObtainSocket(_socketID, AF_INET, SOCK_STREAM, 0); + if (_socket == OFInvalidSocketHandle) + @throw [OFInitializationFailedException + exceptionWithClass: self.class]; + + _socketID = -1; +#endif +} - (void)close { if (_socket == OFInvalidSocketHandle) @throw [OFNotOpenException exceptionWithObject: self];