Permalink
Browse files

Untested first draft.

  • Loading branch information...
1 parent 6b3a91a commit 28b214025aa3c47665640232da7903ad4c667f71 @jeremy-w committed Jul 3, 2010
Showing with 364 additions and 1 deletion.
  1. +5 −0 dylib.xcconfig
  2. +2 −1 project.xcconfig
  3. +25 −0 src/ZMQContext.h
  4. +57 −0 src/ZMQContext.m
  5. +38 −0 src/ZMQSocket.h
  6. +190 −0 src/ZMQSocket.m
  7. +47 −0 zmqobjc.xcodeproj/project.pbxproj
View
@@ -0,0 +1,5 @@
+// Dylib target build settings
+DYLIB_COMPATIBILITY_VERSION = 1.0.0;
+DYLIB_CURRENT_VERSION = 1.0.0;
+
+ONLY_ACTIVE_ARCH=YES // build thin by default
View
@@ -1,6 +1,6 @@
// Project-level build settings - all configurations
SDKROOT = macosx10.6
-MACOSX_DEPLOYMENT_TARGET = 10.4
+MACOSX_DEPLOYMENT_TARGET = 10.5
ARCHS = i386 x86_64 ppc
ARCHS[sdk=macosx10.6*] = i386 x86_64 ppc
@@ -22,3 +22,4 @@ OTHER_CPLUSPLUSFLAGS = $(SHARED_C_CPP_FLAGS) -Wabi -Wctor-dtor-privacy -Wstrict-
ZERO_LINK = NO
PREBINDING = NO
+HEADER_SEARCH_PATHS = /usr/local/include /opt/local/include
View
@@ -0,0 +1,25 @@
+#import <Foundation/Foundation.h>
+#import "ZMQSocket.h" // ZMQSocketType
+
+@interface ZMQContext : NSObject {
+ void *context;
+ NSMutableArray *sockets;
+ BOOL terminated;
+}
++ (void)getZMQVersionMajor:(int *)major minor:(int *)minor patch:(int *)patch;
+
+// Creates a ZMQContext using |threadCount| threads for I/O.
+- (id)initWithIOThreads:(NSUInteger)threadCount;
+
+- (ZMQSocket *)socketWithType:(ZMQSocketType)type;
+// Sockets associated with this context.
+@property(readonly, retain, NS_NONATOMIC_IPHONEONLY) NSArray *sockets;
+
+// Initiates termination. All associated sockets will be shut down.
+- (void)terminate;
+
+// YES if termination has been initiated.
+// KVOable.
+@property(readonly, getter=isTerminated, NS_NONATOMIC_IPHONEONLY)
+ BOOL terminated;
+@end
View
@@ -0,0 +1,57 @@
+#import "ZMQContext.h"
+
+@interface ZMQSocket (ZMQContextIsFriend)
+- (id)initWithContext:(ZMQContext *)context type:(ZMQSocketType)type;
+@end
+
+@interface ZMQContext ()
+@property(readonly) void *context;
+@property(readwrite, getter=isTerminated, NS_NONATOMIC_IPHONEONLY)
+ BOOL terminated;
+@end
+
+@implementation ZMQContext
++ (void)getZMQVersionMajor:(int *)major minor:(int *)minor patch:(int *)patch {
+ (void)zmq_version(major, minor, patch);
+}
+
+- (id)initWithIOThreads:(NSUInteger)threadCount {
+ self = [super init];
+ if (!self) return nil;
+
+ context = zmq_init(threadCount);
+ if (!context) {
+ NSLog(@"%s: *** Error creating ZMQContext: zmq_init: %s",
+ __func__, zmq_strerror(zmq_errno()));
+ [self release];
+ return nil;
+ }
+
+ sockets = [[NSMutableArray alloc] init];
+ return self;
+}
+
+@synthesize context;
+- (void)dealloc {
+ [self terminate];
+ context = NULL;
+ [sockets release], sockets = nil;
+ [super dealloc];
+}
+
+@synthesize sockets;
+- (ZMQSocket *)socketWithType:(ZMQSocketType)type {
+ ZMQSocket *
+ socket = [[[ZMQSocket alloc] initWithContext:self type:type] autorelease];
+ if (socket) {
+ [(NSMutableArray *)self.sockets addObject:socket];
+ }
+ return socket;
+}
+
+@synthesize terminated;
+- (void)terminate {
+ (void)zmq_term(self.context);
+ self.terminated = YES;
+}
+@end
View
@@ -0,0 +1,38 @@
+#import <Foundation/Foundation.h>
+#import <zmq.h>
+@class ZMQContext;
+
+typedef int ZMQSocketType;
+typedef int ZMQSocketOption;
+typedef int ZMQMessageSendFlags;
+typedef int ZMQMessageReceiveFlags;
+
+@interface ZMQSocket : NSObject {
+ void *socket;
+ ZMQContext *context; // not retained
+ ZMQSocketType type;
+ BOOL closed;
+}
+// Create a socket using -[ZMQContext socketWithType:].
+@property(readonly, assign, NS_NONATOMIC_IPHONEONLY) ZMQContext *context;
+@property(readonly, NS_NONATOMIC_IPHONEONLY) ZMQSocketType type;
+
+- (void)close;
+// KVOable.
+@property(readonly, getter=isClosed, NS_NONATOMIC_IPHONEONLY) BOOL closed;
+
+#pragma mark Socket Options
+- (BOOL)setData:(NSData *)data forOption:(ZMQSocketOption)option;
+- (NSData *)dataForOption:(ZMQSocketOption)option;
+
+#pragma mark Endpoint Configuration
+- (BOOL)bindToEndpoint:(NSString *)endpoint;
+- (BOOL)connectToEndpoint:(NSString *)endpoint;
+
+#pragma mark Communication
+- (BOOL)sendData:(NSData *)messageData withFlags:(ZMQMessageSendFlags)flags;
+- (NSData *)receiveDataWithFlags:(ZMQMessageReceiveFlags)flags;
+
+#pragma mark Polling
+- (void)getPollItem:(zmq_pollitem_t *)outItem forEvents:(short)events;
+@end
View
@@ -0,0 +1,190 @@
+#import "ZMQSocket.h"
+#import "ZMQContext.h"
+
+enum {
+ ZMQ_SOCKET_OPTION_MAX_LENGTH = 255, // ZMQ_IDENTITY
+};
+
+@interface ZMQContext (ZMQSocketIsFriend)
+@property(readonly) void *context;
+@end
+
+@interface ZMQSocket ()
+@property(readwrite, getter=isClosed, NS_NONATOMIC_IPHONEONLY) BOOL closed;
+@property(readonly) void *socket;
+@end
+
+static inline void ZMQLogError(id object, NSString *msg);
+
+@implementation ZMQSocket
+- (id)init {
+ self = [super init];
+ if (self) [self release];
+ NSString *
+ err = [NSString stringWithFormat:
+ @"%s: *** Create sockets using -[ZMQContext socketWithType:].",
+ __func__];
+ NSLog(@"%@", err);
+ @throw err;
+ return nil;
+}
+
+- (id)initWithContext:(ZMQContext *)context_ type:(ZMQSocketType)type_ {
+ self = [super init];
+ if (!self) return nil;
+
+ socket = zmq_socket(context_.context, type_);
+ if (!socket) {
+ ZMQLogError(self, @"zmq_socket");
+ [self release];
+ return nil;
+ }
+
+ context = context_;
+ type = type_;
+ return self;
+}
+
+@synthesize socket;
+@synthesize closed;
+- (void)close {
+ int err = zmq_close(self.socket);
+ if (err) {
+ ZMQLogError(self, @"zmq_close");
+ return;
+ }
+ self.closed = YES;
+}
+
+- (void)dealloc {
+ [self close];
+ [super dealloc];
+}
+
+@synthesize context;
+@synthesize type;
+- (NSString *)description {
+ NSString *
+ desc = [NSString stringWithFormat:@"<%@: %p (ctx=%p, type=%d, closed=%d)>",
+ [self class], self, self.context, (int)self.type, (int)self.closed];
+ return desc;
+}
+
+#pragma mark Socket Options
+- (BOOL)setData:(NSData *)data forOption:(ZMQSocketOption)option {
+ int err = zmq_setsockopt(self.socket, option, [data bytes], [data length]);
+ if (err) {
+ ZMQLogError(self, @"zmq_setsockopt");
+ return NO;
+ }
+ return YES;
+}
+
+- (NSData *)dataForOption:(ZMQSocketOption)option {
+ size_t length = ZMQ_SOCKET_OPTION_MAX_LENGTH;
+ void *storage = malloc(length);
+ if (!storage) return nil;
+
+ int err = zmq_getsockopt(self.socket, option, storage, &length);
+ if (err) {
+ ZMQLogError(self, @"zmq_getsockopt");
+ free(storage);
+ return nil;
+ }
+
+ NSData *
+ data = [NSData dataWithBytesNoCopy:storage length:length freeWhenDone:YES];
+ return data;
+}
+
+#pragma mark Endpoint Configuration
+- (BOOL)bindToEndpoint:(NSString *)endpoint {
+ const char *addr = [endpoint UTF8String];
+ int err = zmq_bind(self.socket, addr);
+ if (err) {
+ ZMQLogError(self, @"zmq_bind");
+ return NO;
+ }
+ return YES;
+}
+
+- (BOOL)connectToEndpoint:(NSString *)endpoint {
+ const char *addr = [endpoint UTF8String];
+ int err = zmq_connect(self.socket, addr);
+ if (err) {
+ ZMQLogError(self, @"zmq_connect");
+ return NO;
+ }
+ return YES;
+}
+
+#pragma mark Communication
+- (BOOL)sendData:(NSData *)messageData withFlags:(ZMQMessageSendFlags)flags {
+ zmq_msg_t msg;
+ int err = zmq_msg_init_size(&msg, [messageData length]);
+ if (err) {
+ ZMQLogError(self, @"zmq_msg_init_size");
+ return NO;
+ }
+
+ [messageData getBytes:zmq_msg_data(&msg) length:zmq_msg_size(&msg)];
+
+ err = zmq_send(self.socket, &msg, flags);
+ BOOL didSendData = (0 == err);
+ if (!didSendData) {
+ ZMQLogError(self, @"zmq_send");
+ /* fall through */
+ }
+
+ err = zmq_msg_close(&msg);
+ if (err) {
+ ZMQLogError(self, @"zmq_msg_close");
+ /* fall through */
+ }
+ return didSendData;
+}
+
+- (NSData *)receiveDataWithFlags:(ZMQMessageReceiveFlags)flags {
+ zmq_msg_t msg;
+ int err = zmq_msg_init(&msg);
+ if (err) {
+ ZMQLogError(self, @"zmq_msg_init");
+ return nil;
+ }
+
+ err = zmq_recv(self.socket, &msg, flags);
+ if (err) {
+ ZMQLogError(self, @"zmq_recv");
+ err = zmq_msg_close(&msg);
+ if (err) {
+ ZMQLogError(self, @"zmq_msg_close");
+ }
+ return nil;
+ }
+
+ size_t length = zmq_msg_size(&msg);
+ NSData *data = [NSData dataWithBytes:zmq_msg_data(&msg) length:length];
+
+ err = zmq_msg_close(&msg);
+ if (err) {
+ ZMQLogError(self, @"zmq_msg_close");
+ /* fall through */
+ }
+ return data;
+}
+
+#pragma mark Polling
+- (void)getPollItem:(zmq_pollitem_t *)outItem forEvents:(short)events {
+ NSParameterAssert(NULL != outItem);
+
+ outItem->socket = self.socket;
+ outItem->events = events;
+ outItem->revents = 0;
+}
+@end
+
+void
+ZMQLogError(id object, NSString *msg) {
+ NSLog(@"%s: *** %@: %@: %s",
+ __func__, object, msg, zmq_strerror(zmq_errno()));
+}
Oops, something went wrong.

0 comments on commit 28b2140

Please sign in to comment.