forked from mikeash/MAAsyncIO
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMAAsyncSocketUtils.m
More file actions
80 lines (69 loc) · 2.38 KB
/
MAAsyncSocketUtils.m
File metadata and controls
80 lines (69 loc) · 2.38 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
//
// MAAsyncSocketUtils.m
// MAAsyncIO
//
// Created by Michael Ash on 12/8/10.
// Copyright 2010 Michael Ash. All rights reserved.
//
#import "MAAsyncSocketUtils.h"
#import <netinet/in.h>
#import "MAAsyncReader.h"
#import "MAAsyncWriter.h"
#import "MAFDRefcount.h"
#import "MAFDSource.h"
void MAAsyncSocketConnect(NSData *address, int port, void (^block)(MAAsyncReader *reader, MAAsyncWriter *writer, NSError *error))
{
char localaddr[[address length]];
[address getBytes: localaddr];
struct sockaddr *sockaddr = (struct sockaddr *)localaddr;
((struct sockaddr_in *)sockaddr)->sin_port = htons(port);
int fd = socket(sockaddr->sa_family, SOCK_STREAM, 0);
if(fd == -1)
{
block(nil, nil, [NSError errorWithDomain: NSPOSIXErrorDomain code: errno userInfo: nil]);
}
else
{
// implicitly sets the socket nonblocking
MAFDSource *source = [[MAFDSource alloc] initWithFileDescriptor: fd type: DISPATCH_SOURCE_TYPE_WRITE];
MAFDRelease(fd);
int result = connect(fd, sockaddr, [address length]);
void (^completion)(void) = ^{
[source suspend];
int so_err, gso_err;
socklen_t len = sizeof(so_err);
gso_err = getsockopt(fd, SOL_SOCKET, SO_ERROR, &so_err, &len);
if(gso_err)
{
block(nil, nil, [NSError errorWithDomain: NSPOSIXErrorDomain code:gso_err userInfo: nil]);
}
else if(so_err)
{
block(nil, nil, [NSError errorWithDomain: NSPOSIXErrorDomain code:so_err userInfo: nil]);
}
else
{
MAAsyncReader *reader = [[MAAsyncReader alloc] initWithFileDescriptor: fd];
MAAsyncWriter *writer = [[MAAsyncWriter alloc] initWithFileDescriptor: fd];
block(reader, writer, nil);
[reader release];
[writer release];
}
[source invalidate];
[source release];
};
if(result != -1)
{
completion();
}
else if(errno == EINPROGRESS)
{
[source setEventCallback: completion];
[source resume];
}
else
{
block(nil, nil, [NSError errorWithDomain: NSPOSIXErrorDomain code: errno userInfo: nil]);
}
}
}