mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-22 16:33:29 +00:00
Fix changelog after merge from master.
This commit is contained in:
commit
ed0a6bd7bd
11 changed files with 561 additions and 82 deletions
24
ChangeLog
24
ChangeLog
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
156
Source/GSTLS.m
156
Source/GSTLS.m
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
42
Tests/base/NSConnection/Resources/Client.m
Normal file
42
Tests/base/NSConnection/Resources/Client.m
Normal 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
|
||||
|
|
@ -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
|
||||
|
||||
|
|
48
Tests/base/NSConnection/Resources/Server.m
Normal file
48
Tests/base/NSConnection/Resources/Server.m
Normal 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
|
||||
|
Loading…
Reference in a new issue