Fix changelog after merge from master.

This commit is contained in:
Gregory John Casamento 2021-06-02 08:37:41 -04:00
commit ed0a6bd7bd
11 changed files with 561 additions and 82 deletions

View file

@ -1,8 +1,32 @@
2021-06-02 Gregory John Casamento <greg.casamento@gmail.com>
* Headers/Foundation/Foundation.h: Add missing import for
NSByteCountFormatter.
2021-05-31 Richard Frith-Macdonald <rfm@gnu.org>
* Headers/GNUstepBase/GSTLS.h: ([GSTLSCredentials selfSigned:])
* Source/GSTLS.m: Add new method to use certtool to generate a
key and a self-signed certificate. Use the new method to set up
server sessions if no certificate/key is configured.
* Headers/Foundation/NSPort.h: ([NSSocketPost setOptionsForTLS:])
* Source/NSSocketPort.m: New methods to configure socket ports to
use TLS so that inter-host distributed object connections can be
securely encrypted. The class method should turn on encryption
for all subsequent connections using socket ports (the instance
method can be used to override the effects of the class method
for an individual instance).
2021-05-23 Richard Frith-Macdonald <rfm@gnu.org>
* Source/GSStream.m:
When we get an event saying that there is space available, we should
change the stream status from writing to open (because the write
operation completed). This makes the -hasSpaceAvailable method return
the correct value when a callback routine is checking to see if it
can write.
2021-05-19 Richard Frith-Macdonald <rfm@gnu.org>
* Source/win32/GSFileHandle.m:

View file

@ -208,6 +208,7 @@ GS_EXPORT_CLASS
uint16_t portNum; /* TCP port in host byte order. */
SOCKET listener;
NSMapTable *handles; /* Handles indexed by socket. */
NSDictionary *tlsopts; /* TLS options */
#if defined(_WIN32)
WSAEVENT eventListener;
NSMapTable *events;
@ -273,6 +274,21 @@ GS_EXPORT_CLASS
* Returns port number of underlying socket.
*/
- (uint16_t) portNumber;
#if !NO_GNUSTEP
/** Sets the default options for use of TLS by socket ports.<br />
* Setting nil (the default) means that TLS is not used.<br />
* Setting an empty dictionary means that TLS is used with normal options.
*/
+ (void) setOptionsForTLS: (NSDictionary*)opts;
/** Overrides the default options for use of TLS by the receiver.<br />
* Setting nil (the default) means that TLS is not used.<br />
* Setting an empty dictionary means that TLS is used with normal options.<br />
* This method has no effect on network sessions which are already established.
*/
- (void) setOptionsForTLS: (NSDictionary*)opts;
#endif
@end

View file

@ -175,6 +175,7 @@ GS_EXPORT_CLASS
certificateKeyPassword: (NSString*)cp
asClient: (BOOL)client
debug: (BOOL)debug;
+ (GSTLSCredentials*) selfSigned: (BOOL)debug;
- (gnutls_certificate_credentials_t) credentials;
- (GSTLSPrivateKey*) key;
- (GSTLSCertificateList*) list;

View file

@ -598,6 +598,10 @@ static RunLoopEventType typeForStream(NSStream *aStream)
if ((_events & NSStreamEventHasSpaceAvailable) == 0)
{
_events |= NSStreamEventHasSpaceAvailable;
if (_currentStatus == NSStreamStatusWriting)
{
[self _setStatus: NSStreamStatusOpen];
}
if (delegate != nil)
{
[delegate stream: self

View file

@ -35,8 +35,10 @@
#import "Foundation/NSNotification.h"
#import "Foundation/NSProcessInfo.h"
#import "Foundation/NSStream.h"
#import "Foundation/NSTask.h"
#import "Foundation/NSThread.h"
#import "Foundation/NSUserDefaults.h"
#import "Foundation/NSUUID.h"
#import "GNUstepBase/GSTLS.h"
@ -1091,6 +1093,89 @@ static NSMutableDictionary *credentialsCache = nil;
}
}
+ (GSTLSCredentials*) selfSigned: (BOOL)debug
{
NSString *crtPath = standardizedPath(@"self-signed-crt");
NSString *keyPath = standardizedPath(@"self-signed-key");
NSData *crt = [self dataForTLSFile: crtPath];
NSData *key = [self dataForTLSFile: keyPath];
if (nil == crt || nil == key)
{
static NSString *tmp = @"organization = SelfSigned\n"
@"state = Example\n"
@"country = EX\n"
@"cn = SelfSigned\n"
@"serial = 007\n"
@"expiration_days = 730\n"
@"dns_name = server.selfsigned.com\n"
@"tls_www_server\n"
@"encryption_key\n";
NSFileManager *mgr = [NSFileManager defaultManager];
NSString *path = NSTemporaryDirectory();
NSTask *task;
NSString *tmpPath;
path = [path stringByAppendingPathComponent: [[NSUUID UUID] UUIDString]];
keyPath = [path stringByAppendingPathExtension: @"key"];
tmpPath = [path stringByAppendingPathExtension: @"tmp"];
crtPath = [path stringByAppendingPathExtension: @"crt"];
[tmp writeToFile: tmpPath atomically: NO];
task = [NSTask new];
[task setLaunchPath: @"certtool"];
[task setArguments: [NSArray arrayWithObjects:
@"--generate-privkey", @"--sec-param", @"high", @"--outfile", keyPath,
nil]];
[task setStandardOutput: [NSFileHandle fileHandleWithNullDevice]];
[task setStandardError: [NSFileHandle fileHandleWithNullDevice]];
[task launch];
[task waitUntilExit];
RELEASE(task);
key = [NSData dataWithContentsOfFile: keyPath];
task = [NSTask new];
[task setLaunchPath: @"certtool"];
[task setArguments: [NSArray arrayWithObjects:
@"--generate-self-signed", @"--load-privkey", keyPath,
@"--template", tmpPath, @"--outfile", crtPath,
nil]];
[task setStandardOutput: [NSFileHandle fileHandleWithNullDevice]];
[task setStandardError: [NSFileHandle fileHandleWithNullDevice]];
[task launch];
[task waitUntilExit];
crt = [NSData dataWithContentsOfFile: crtPath];
[mgr removeFileAtPath: keyPath handler: nil];
[mgr removeFileAtPath: tmpPath handler: nil];
[mgr removeFileAtPath: crtPath handler: nil];
if (nil == key)
{
NSLog(@"Failed to make self-signed certificate key using 'certtool'");
return nil;
}
if (nil == crt)
{
NSLog(@"Failed to make self-signed certificate using 'certtool'");
return nil;
}
keyPath = standardizedPath(@"self-signed-key");
[self setData: key forTLSFile: keyPath];
crtPath = standardizedPath(@"self-signed-crt-");
[self setData: crt forTLSFile: crtPath];
}
return [self credentialsFromCAFile: nil
defaultCAFile: nil
revokeFile: nil
defaultRevokeFile: nil
certificateFile: crtPath
certificateKeyFile: keyPath
certificateKeyPassword: nil
asClient: NO
debug: debug];
}
+ (GSTLSCredentials*) credentialsFromCAFile: (NSString*)ca
defaultCAFile: (NSString*)dca
revokeFile: (NSString*)rv
@ -1322,6 +1407,7 @@ static NSMutableDictionary *credentialsCache = nil;
return [c autorelease];
}
- (void) dealloc
{
if (nil != name)
@ -1539,17 +1625,18 @@ retrieve_callback(gnutls_session_t session,
{
if (nil != (self = [super init]))
{
NSString *ca;
NSString *dca;
NSString *rv;
NSString *drv;
NSString *cf;
NSString *ck;
NSString *cp;
NSString *pri;
NSString *str;
BOOL trust;
BOOL verify;
GSTLSCredentials *cr;
NSString *ca;
NSString *dca;
NSString *rv;
NSString *drv;
NSString *cf;
NSString *ck;
NSString *cp;
NSString *pri;
NSString *str;
BOOL trust;
BOOL verify;
created = [NSDate timeIntervalSinceReferenceDate];
opts = [options copy];
@ -1632,28 +1719,41 @@ retrieve_callback(gnutls_session_t session,
}
setup = YES;
ca = [opts objectForKey: GSTLSCAFile];
dca = caFile;
rv = [opts objectForKey: GSTLSRevokeFile];
drv = revokeFile;
cf = [opts objectForKey: GSTLSCertificateFile];
ck = [opts objectForKey: GSTLSCertificateKeyFile];
cp = [opts objectForKey: GSTLSCertificateKeyPassword];
credentials = [[GSTLSCredentials credentialsFromCAFile: ca
defaultCAFile: dca
revokeFile: rv
defaultRevokeFile: drv
certificateFile: cf
certificateKeyFile: ck
certificateKeyPassword: cp
asClient: outgoing
debug: debug] retain];
if (nil == cf && NO == outgoing)
{
/* Server with no certiticate supplied: generate self signed one.
*/
cr = [GSTLSCredentials selfSigned: debug];
}
else
{
ca = [opts objectForKey: GSTLSCAFile];
dca = caFile;
rv = [opts objectForKey: GSTLSRevokeFile];
drv = revokeFile;
ck = [opts objectForKey: GSTLSCertificateKeyFile];
cp = [opts objectForKey: GSTLSCertificateKeyPassword];
cr = [GSTLSCredentials credentialsFromCAFile: ca
defaultCAFile: dca
revokeFile: rv
defaultRevokeFile: drv
certificateFile: cf
certificateKeyFile: ck
certificateKeyPassword: cp
asClient: outgoing
debug: debug];
}
if (nil == credentials)
if (cr)
{
[self release];
ASSIGN(credentials, cr);
}
else
{
RELEASE(self);
return nil;
}

View file

@ -2017,8 +2017,7 @@ static NSLock *cached_proxies_gate = nil;
[self _sendOutRmc: op type: METHOD_REQUEST sequence: seq];
name = sel_getName([inv selector]);
NSDebugMLLog(@"NSConnection", @"Sent message %s RMC %d to 0x%"PRIxPTR,
name, seq, (NSUInteger)self);
NSDebugMLLog(@"RMC", @"Sent message %s RMC %d to %p", name, seq, self);
if (needsResponse == NO)
{
@ -3134,8 +3133,8 @@ static NSLock *cached_proxies_gate = nil;
{
BOOL warned = NO;
if (debug_connection > 5)
NSLog(@"Waiting for reply %d (%s) on %@", sn, request, self);
NSDebugMLLog(@"RMC", @"Waiting for reply RMC %d (%s) on %@",
sn, request, self);
GS_M_LOCK(IrefGate); isLocked = YES;
while (IisValid == YES
&& (node = GSIMapNodeForKey(IreplyMap, (GSIMapKey)(NSUInteger)sn)) != 0
@ -3244,8 +3243,8 @@ static NSLock *cached_proxies_gate = nil;
}
NS_ENDHANDLER
NSDebugMLLog(@"NSConnection", @"Consuming reply %d (%s) on %"PRIxPTR,
sn, request, (NSUInteger)self);
NSDebugMLLog(@"RMC", @"Consuming reply RMC %d (%s) on %p",
sn, request, self);
return rmc;
}

View file

@ -26,6 +26,7 @@
#define EXPOSE_NSPort_IVARS 1
#define EXPOSE_NSSocketPort_IVARS 1
#import "GNUstepBase/GSLock.h"
#import "GNUstepBase/GSTLS.h"
#import "Foundation/NSArray.h"
#import "Foundation/NSNotification.h"
#import "Foundation/NSNotificationQueue.h"
@ -122,6 +123,11 @@
*/
static uint32_t maxDataLength = 32 * 1024 * 1024;
/* Options for TLS encryption of connections
*/
static NSDictionary *tlsOptions;
static NSLock *tlsLock;
#if 0
#define M_LOCK(X) {NSDebugMLLog(@"GSTcpHandleLock",@"lock %@ in %@",X,[NSThread currentThread]); [X lock];}
#define M_UNLOCK(X) {NSDebugMLLog(@"GSTcpHandleLock",@"unlock %@ in %@",X,[NSThread currentThread]); [X unlock];}
@ -200,9 +206,15 @@ typedef enum {
GS_H_CONNECTED // Currently connected.
} GSHandleState;
@interface NSSocketPort (GSTcpHandle)
- (NSDictionary*) optionsForTLS;
@end
@interface GSTcpHandle : NSObject <RunLoopEvents>
{
SOCKET desc; /* File descriptor for I/O. */
NSData *cData; /* Connection data. */
unsigned cLength; /* Connection data written. */
unsigned wItem; /* Index of item being written. */
NSMutableData *wData; /* Data object being written. */
unsigned wLength; /* Ammount written so far. */
@ -223,7 +235,6 @@ typedef enum {
BOOL inReplyMode; /* Indicate when have addEvent self */
BOOL readyToSend; /* Indicate when send */
#endif
@public
NSRecursiveLock *myLock; /* Lock for this handle. */
BOOL caller; /* Did we connect to other end? */
@ -232,6 +243,7 @@ typedef enum {
NSSocketPort *sendPort;
struct sockaddr sockAddr; /* Far end of connection. */
NSString *defaultAddress;
GSTLSSession *session; /* Session for encryption. */
}
+ (GSTcpHandle*) handleWithDescriptor: (SOCKET)d;
@ -256,6 +268,91 @@ typedef enum {
@end
#if defined(HAVE_GNUTLS)
/* Callback to allow the TLS code to pull data from the remote system.
* If the operation fails, this sets the error number.
*/
static ssize_t
GSTLSHandlePull(gnutls_transport_ptr_t handle, void *buffer, size_t len)
{
ssize_t result = 0;
GSTcpHandle *tls = (GSTcpHandle*)handle;
int descriptor = [tls descriptor];
result = recv(descriptor, buffer, len, 0);
if (result < 0)
{
#if HAVE_GNUTLS_TRANSPORT_SET_ERRNO
if (tls->session && tls->session->session)
{
int e;
#if defined(_WIN32)
/* For windows, we need to map winsock errors to unix ones that
* gnutls understands.
*/
e = WSAGetLastError();
if (WSAEWOULDBLOCK == e)
{
e = EAGAIN;
}
else if (WSAEINTR == e)
{
e = EINTR;
}
#else
e = errno;
#endif
gnutls_transport_set_errno (tls->session->session, e);
}
#endif
}
return result;
}
/* Callback to allow the TLS code to push data to the remote system.
* If the operation fails, this sets the error number.
*/
static ssize_t
GSTLSHandlePush(gnutls_transport_ptr_t handle, const void *buffer, size_t len)
{
ssize_t result = 0;
GSTcpHandle *tls = (GSTcpHandle*)handle;
int descriptor = [tls descriptor];
result = send(descriptor, buffer, len, 0);
if (result < 0)
{
#if HAVE_GNUTLS_TRANSPORT_SET_ERRNO
if (tls->session && tls->session->session)
{
int e;
#if defined(_WIN32)
/* For windows, we need to map winsock errors to unix ones that
* gnutls understands.
*/
e = WSAGetLastError();
if (WSAEWOULDBLOCK == e)
{
e = EAGAIN;
}
else if (WSAEINTR == e)
{
e = EINTR;
}
#else
e = errno;
#endif
gnutls_transport_set_errno(tls->session->session, e);
}
#endif
}
return result;
}
#endif
/*
* Utility functions for encoding and decoding ports.
*/
@ -449,6 +546,8 @@ static Class runLoopClass;
{
if (self == [GSTcpHandle class])
{
tlsLock = [NSLock new];
[[NSObject leakAt: &tlsLock] release];
#ifdef _WIN32
WORD wVersionRequested;
WSADATA wsaData;
@ -534,8 +633,7 @@ static Class runLoopClass;
NSRunLoop *l;
M_LOCK(myLock);
NSDebugMLLog(@"GSTcpHandle",
@"Connecting on 0x%"PRIxPTR" before %@", (NSUInteger)self, when);
NSDebugMLLog(@"GSTcpHandle", @"Connecting on %p before %@", self, when);
if (state != GS_H_UNCON)
{
BOOL result;
@ -696,6 +794,7 @@ static Class runLoopClass;
{
[self finalize];
DESTROY(defaultAddress);
DESTROY(cData);
DESTROY(rData);
DESTROY(rItems);
DESTROY(wMsgs);
@ -724,6 +823,11 @@ static Class runLoopClass;
- (void) finalize
{
[self invalidate];
if (session)
{
[session disconnect: NO];
DESTROY(session);
}
#if defined(_WIN32)
if (event != WSA_INVALID_EVENT)
{
@ -746,8 +850,7 @@ static Class runLoopClass;
if (valid == YES)
{
valid = NO;
NSDebugMLLog(@"GSTcpHandle",
@"invalidated 0x%"PRIxPTR, (NSUInteger)self);
NSDebugMLLog(@"GSTcpHandle", @"invalidated %p", self);
[[self recvPort] removeHandle: self];
[[self sendPort] removeHandle: self];
}
@ -804,13 +907,26 @@ static Class runLoopClass;
* Now try to fill the buffer with data.
*/
bytes = [rData mutableBytes];
res = recv(desc, bytes + rLength, want - rLength, 0);
if (session)
{
if ([session handshake])
{
res = [session read: bytes + rLength length: want - rLength];
}
else
{
res = -1;
}
}
else
{
res = recv(desc, bytes + rLength, want - rLength, 0);
}
if (res <= 0)
{
if (res == 0)
{
NSDebugMLLog(@"GSTcpHandle",
@"read eof on 0x%"PRIxPTR, (NSUInteger)self);
NSDebugMLLog(@"GSTcpHandle", @"read eof on %p", self);
[self invalidate];
return;
}
@ -828,8 +944,7 @@ static Class runLoopClass;
}
res = 0; /* Interrupted - continue */
}
NSDebugMLLog(@"GSTcpHandle",
@"read %d bytes on 0x%"PRIxPTR, res, (NSUInteger)self);
NSDebugMLLog(@"GSTcpHandle", @"read %d bytes on %p", res, self);
rLength += res;
while (valid == YES && rLength >= rWant)
@ -1044,12 +1159,13 @@ static Class runLoopClass;
if (state == GS_H_ACCEPT)
{
/*
* This is the initial port information on a new
/* This is the initial port information on a new
* connection - set up port relationships.
*/
state = GS_H_CONNECTED;
[p addHandle: self forSend: YES];
NSDebugMLLog(@"GSTcpHandle",
@"accepted connection from %@ on %p", p, self);
}
else
{
@ -1070,7 +1186,7 @@ static Class runLoopClass;
if (shouldDispatch == YES)
{
NSPortMessage *pm;
NSSocketPort *rp = [self recvPort];
NSSocketPort *rp = [self recvPort];
pm = [portMessageClass allocWithZone: NSDefaultMallocZone()];
pm = [pm initWithSendPort: [self sendPort]
@ -1079,8 +1195,7 @@ static Class runLoopClass;
[pm setMsgid: rId];
rId = 0;
DESTROY(rItems);
NSDebugMLLog(@"GSTcpHandle",
@"got message %@ on 0x%"PRIxPTR, pm, (NSUInteger)self);
NSDebugMLLog(@"GSTcpHandle", @"got message %@ on %p", pm, self);
IF_NO_GC(RETAIN(rp);)
M_UNLOCK(myLock);
NS_DURING
@ -1123,29 +1238,89 @@ static Class runLoopClass;
}
else
{
NSData *d = newDataWithEncodedPort([self recvPort]);
unsigned l;
const void *b;
len = send(desc, [d bytes], [d length], 0);
if (len == (int)[d length])
{
ASSIGN(defaultAddress, GSPrivateSockaddrHost(&sockAddr));
NSDebugMLLog(@"GSTcpHandle",
@"wrote %d bytes on 0x%"PRIxPTR, len, (NSUInteger)self);
state = GS_H_CONNECTED;
/* We have established a new network (TCP/IP) connection and the
* first thing to do is send out port information (after setting
* up a TLS session if necessary).
*/
if (nil == cData)
{
NSSocketPort *p = [self recvPort];
NSDictionary *t = [p optionsForTLS];
ASSIGN(cData, newDataWithEncodedPort(p));
cLength = 0;
DESTROY(session);
if (t)
{
session = [[GSTLSSession alloc]
initWithOptions: t
direction: YES // as client
transport: self
push: GSTLSHandlePush
pull: GSTLSHandlePull];
}
}
b = [cData bytes];
l = [cData length];
if (session)
{
if ([session handshake])
{
len = [session write: b + cLength length: l - cLength];
}
else
{
len = -1;
}
}
else
{
state = GS_H_UNCON;
NSLog(@"connect write attempt failed - %@",
[NSError _last]);
len = send(desc, b + cLength, l - cLength, 0);
}
if (len <= 0)
{
#ifdef _WIN32
if (WSAGetLastError() != WSAEINTR
&& WSAGetLastError() != WSAEWOULDBLOCK)
#else
if (errno != EINTR && errno != EAGAIN)
#endif /* !_WIN32 */
{
DESTROY(cData);
state = GS_H_UNCON;
NSLog(@"connect write attempt failed - %@",
[NSError _last]);
return;
}
#ifdef _WIN32
if (WSAGetLastError() == WSAEWOULDBLOCK)
{
readyToSend = NO;
}
#endif /* !_WIN32 */
}
else
{
cLength += len;
if (cLength >= l)
{
DESTROY(cData);
ASSIGN(defaultAddress, GSPrivateSockaddrHost(&sockAddr));
NSDebugMLLog(@"GSTcpHandle",
@"connect wrote %d bytes on %p", len, self);
state = GS_H_CONNECTED;
}
}
RELEASE(d);
}
}
else
{
int res;
unsigned l;
unsigned l;
const void *b;
if (wData == nil)
@ -1159,13 +1334,27 @@ static Class runLoopClass;
}
else
{
// NSLog(@"No messages to write on 0x%"PRIxPTR".", (NSUInteger)self);
// NSLog(@"No messages to write on %p.", self);
return;
}
}
b = [wData bytes];
l = [wData length];
res = send(desc, b + wLength, l - wLength, 0);
if (session)
{
if ([session handshake])
{
res = [session write: b + wLength length: l - wLength];
}
else
{
res = -1;
}
}
else
{
res = send(desc, b + wLength, l - wLength, 0);
}
if (res < 0)
{
#ifdef _WIN32
@ -1188,8 +1377,7 @@ static Class runLoopClass;
}
else
{
NSDebugMLLog(@"GSTcpHandle",
@"wrote %d bytes on 0x%"PRIxPTR, res, (NSUInteger)self);
NSDebugMLLog(@"GSTcpHandle", @"wrote %d bytes on %p", res, self);
wLength += res;
if (wLength == l)
{
@ -1214,8 +1402,7 @@ static Class runLoopClass;
* message completed - remove from list.
*/
NSDebugMLLog(@"GSTcpHandle",
@"completed 0x%"PRIxPTR" on 0x%"PRIxPTR,
(NSUInteger)components, (NSUInteger)self);
@"completed %p on %p", components, self);
wData = nil;
wItem = 0;
[wMsgs removeObjectAtIndex: 0];
@ -1352,8 +1539,8 @@ static Class runLoopClass;
NSAssert([components count] > 0, NSInternalInconsistencyException);
NSDebugMLLog(@"GSTcpHandle",
@"Sending message 0x%"PRIxPTR" %@ on 0x%"PRIxPTR"(%d) before %@",
(NSUInteger)components, components, (NSUInteger)self, desc, when);
@"Sending message %p %@ on %p(%d) before %@",
components, components, self, desc, when);
M_LOCK(myLock);
[wMsgs addObject: components];
@ -1403,8 +1590,8 @@ static Class runLoopClass;
}
M_UNLOCK(myLock);
NSDebugMLLog(@"GSTcpHandle",
@"Message send 0x%"PRIxPTR" on 0x%"PRIxPTR" status %d",
(NSUInteger)components, (NSUInteger)self, sent);
@"Message send %p on %p status %d",
components, self, sent);
RELEASE(self);
return sent;
}
@ -1700,6 +1887,12 @@ static Class tcpPortClass;
NSMapInsert(thePorts, (void*)aHost, (void*)port);
NSDebugMLLog(@"NSPort", @"Created speaking port: %@", port);
}
if (tlsOptions != nil)
{
[tlsLock lock];
[port setOptionsForTLS: tlsOptions];
[tlsLock unlock];
}
}
else
{
@ -1712,6 +1905,16 @@ static Class tcpPortClass;
return port;
}
+ (void) setOptionsForTLS: (NSDictionary*)options
{
if (options != tlsOptions)
{
[tlsLock lock];
ASSIGNCOPY(tlsOptions, options);
[tlsLock unlock];
}
}
- (void) addHandle: (GSTcpHandle*)handle forSend: (BOOL)send
{
M_LOCK(myLock);
@ -1763,8 +1966,7 @@ static Class tcpPortClass;
- (void) finalize
{
NSDebugMLLog(@"NSPort",
@"NSSocketPort 0x%"PRIxPTR" finalized", (NSUInteger)self);
NSDebugMLLog(@"NSPort", @"NSSocketPort %p finalized", self);
M_LOCK(tcpPortLock);
NSMapRemove(tcpPortMap, (void*)(uintptr_t)portNum);
M_UNLOCK(tcpPortLock);
@ -1774,6 +1976,7 @@ static Class tcpPortClass;
NSFreeMapTable(handles);
handles = 0;
}
DESTROY(tlsopts);
DESTROY(host);
TEST_RELEASE(address);
DESTROY(myLock);
@ -2085,6 +2288,16 @@ static Class tcpPortClass;
return NO;
}
- (NSDictionary*) optionsForTLS
{
NSDictionary *opts;
M_LOCK(myLock);
opts = RETAIN(tlsopts);
M_UNLOCK(myLock);
return AUTORELEASE(opts);
}
- (uint16_t) portNumber
{
return portNum;
@ -2103,8 +2316,8 @@ static Class tcpPortClass;
#endif
GSTcpHandle *handle;
NSDebugMLLog(@"NSPort", @"received %s event %p on 0x%"PRIxPTR,
type == ET_RPORT ? "read" : "write", extra, (NSUInteger)self);
NSDebugMLLog(@"NSPort", @"received %s event %p on %p",
type == ET_RPORT ? "read" : "write", extra, self);
#if defined(_WIN32)
if (event == eventListener)
@ -2122,7 +2335,8 @@ static Class tcpPortClass;
}
else
{
int status = 1;
int status = 1;
NSDictionary *o;
if (setsockopt(desc, SOL_SOCKET, SO_KEEPALIVE, (char*)&status,
(OPTLEN)sizeof(status)) < 0)
@ -2142,8 +2356,16 @@ static Class tcpPortClass;
handle = [GSTcpHandle handleWithDescriptor: desc];
memcpy(&handle->sockAddr, &sockAddr, sizeof(sockAddr));
ASSIGN(handle->defaultAddress, GSPrivateSockaddrHost(&sockAddr));
[handle setState: GS_H_ACCEPT];
if ((o = [self optionsForTLS]) != nil)
{
handle->session = [[GSTLSSession alloc]
initWithOptions: o
direction: NO // as server
transport: handle
push: GSTLSHandlePush
pull: GSTLSHandlePull];
}
[self addHandle: handle forSend: NO];
}
}
@ -2437,4 +2659,13 @@ static Class tcpPortClass;
return sent;
}
/** Sets the TLS options for network connections created by this port.
*/
- (void) setOptionsForTLS: (NSDictionary*)options
{
M_LOCK(myLock);
ASSIGNCOPY(tlsopts, options);
M_UNLOCK(myLock);
}
@end

View file

@ -11,10 +11,11 @@ START_SET("TLS support")
#ifndef HAVE_GNUTLS_X509_PRIVKEY_IMPORT2
testHopeful = YES;
#endif
GSTLSPrivateKey *k;
GSTLSCertificateList *c;
NSDateFormatter *dateFormatter;
NSDate *expiresAt;
GSTLSPrivateKey *k;
GSTLSCertificateList *c;
GSTLSCredentials *cred;
NSDateFormatter *dateFormatter;
NSDate *expiresAt;
k = [GSTLSPrivateKey keyFromFile: @"test.key" withPassword: @"asdf"];
PASS(k != nil, "OpenSSL encrypted key can be loaded");
@ -39,6 +40,12 @@ START_SET("TLS support")
#else
SKIP("TLS support disabled");
#endif
cred = [GSTLSCredentials selfSigned: YES];
NSLog(@"%@", cred);
PASS(cred != nil, "generates self signed certificate");
END_SET("TLS support");
DESTROY(arp);
return 0;

View file

@ -0,0 +1,42 @@
#import <Foundation/Foundation.h>
#import <GNUstepBase/GSTLS.h>
@interface TestServer : NSObject
{
}
- (int) doIt;
@end
int
main()
{
ENTER_POOL
NSSocketPortNameServer *ns = [NSSocketPortNameServer sharedInstance];
NSString *name = @"TestServer";
NSConnection *conn;
NSDistantObject *proxy;
TestServer *test;
int result;
[NSSocketPort setOptionsForTLS: [NSDictionary dictionaryWithObjectsAndKeys:
@"9", GSTLSDebug,
nil]];
conn = [NSConnection connectionWithRegisteredName: name
host: @""
usingNameServer: ns];
proxy = [conn rootProxy];
test = (TestServer*)proxy;
result = [test doIt];
printf("Result is %d\n", result);
LEAVE_POOL
exit(0);
}
@implementation TestServer
- (int) doIt
{
return 42;
}
@end

View file

@ -2,6 +2,13 @@ include $(GNUSTEP_MAKEFILES)/common.make
BUNDLE_NAME=TestConnection
TestConnection_NEEDS_GUI = NO
TestConnection_OBJC_FILES=Connection.m
TEST_TOOL_NAME=Client Server
Client_NEEDS_GUI = NO
Client_OBJC_FILES=Client.m
Server_NEEDS_GUI = NO
Server_OBJC_FILES=Server.m
include $(GNUSTEP_MAKEFILES)/bundle.make
include $(GNUSTEP_MAKEFILES)/test-tool.make

View file

@ -0,0 +1,48 @@
#import <Foundation/Foundation.h>
#import <GNUstepBase/GSTLS.h>
@interface TestServer : NSObject
{
}
- (int) doIt;
@end
int
main()
{
ENTER_POOL
NSSocketPortNameServer *ns = [NSSocketPortNameServer sharedInstance];
NSString *name = @"TestServer";
NSConnection *conn;
NSPort *port;
TestServer *test = AUTORELEASE([TestServer new]);
port = [NSSocketPort port];
[(NSSocketPort*)port setOptionsForTLS:
[NSDictionary dictionaryWithObjectsAndKeys:
@"9", GSTLSDebug,
nil]];
conn = [[NSConnection alloc] initWithReceivePort: port
sendPort: nil];
[conn setRootObject: test];
if ([conn registerName: name withNameServer: ns] == NO)
{
NSPort *p = [ns portForName: name onHost: @""];
DESTROY(conn);
NSLog(@"There is already a process: %@, on %@", name, p);
return NO;
}
[[NSRunLoop currentRunLoop] run];
LEAVE_POOL
exit(0);
}
@implementation TestServer
- (int) doIt
{
return 42;
}
@end