1//
2// Copyright (c) ZeroC, Inc. All rights reserved.
3//
4
5#import <ConnectionI.h>
6#import <EndpointI.h>
7#import <IdentityI.h>
8#import <ObjectAdapterI.h>
9#import <ProxyI.h>
10#import <Util.h>
11#import <LocalObjectI.h>
12
13#import <objc/Ice/LocalException.h>
14
15#import <objc/runtime.h>
16
17#define CONNECTION dynamic_cast<Ice::Connection*>(static_cast<IceUtil::Shared*>(cxxObject_))
18
19namespace
20{
21
22std::vector<Class>* connectionInfoClasses = 0;
23
24}
25
26namespace IceObjC
27{
28
29void
30registerConnectionInfoClass(Class cl)
31{
32    if(!connectionInfoClasses)
33    {
34        connectionInfoClasses = new std::vector<Class>();
35    }
36    connectionInfoClasses->push_back(cl);
37}
38
39}
40
41@implementation ICEConnectionInfo (ICEInternal)
42
43+(id) checkedConnectionInfoWithConnectionInfo:(Ice::ConnectionInfo*)__unused connectionInfo
44{
45    assert(false);
46    return nil;
47}
48
49+(id) connectionInfoWithConnectionInfo:(NSValue*)v
50{
51    Ice::ConnectionInfo* info = dynamic_cast<Ice::ConnectionInfo*>(reinterpret_cast<IceUtil::Shared*>(v.pointerValue));
52    if(!info)
53    {
54        return nil;
55    }
56
57    Ice::UDPConnectionInfoPtr udpInfo = Ice::UDPConnectionInfoPtr::dynamicCast(info);
58    if(udpInfo)
59    {
60        return [[ICEUDPConnectionInfo alloc] initWithUDPConnectionInfo:udpInfo.get()];
61    }
62
63    Ice::WSConnectionInfoPtr wsInfo = Ice::WSConnectionInfoPtr::dynamicCast(info);
64    if(wsInfo)
65    {
66        return [[ICEWSConnectionInfo alloc] initWithWSConnectionInfo:wsInfo.get()];
67    }
68
69    Ice::TCPConnectionInfoPtr tcpInfo = Ice::TCPConnectionInfoPtr::dynamicCast(info);
70    if(tcpInfo)
71    {
72        return [[ICETCPConnectionInfo alloc] initWithTCPConnectionInfo:tcpInfo.get()];
73    }
74
75    if(connectionInfoClasses)
76    {
77        for(std::vector<Class>::const_iterator p = connectionInfoClasses->begin(); p != connectionInfoClasses->end();
78            ++p)
79        {
80            ICEConnectionInfo* r = [*p checkedConnectionInfoWithConnectionInfo:info];
81            if(r)
82            {
83                return r;
84            }
85        }
86    }
87
88    Ice::IPConnectionInfoPtr ipInfo = Ice::IPConnectionInfoPtr::dynamicCast(info);
89    if(ipInfo)
90    {
91        return [[ICEIPConnectionInfo alloc] initWithIPConnectionInfo:ipInfo.get()];
92    }
93
94    return [[ICEConnectionInfo alloc] initWithConnectionInfo:info];
95}
96
97-(id) initWithConnectionInfo:(Ice::ConnectionInfo*)connectionInfo
98{
99    self = [super initWithCxxObject:connectionInfo];
100    if(self != nil)
101    {
102        self->underlying = [ICEConnectionInfo localObjectWithCxxObjectNoAutoRelease:connectionInfo->underlying.get()
103                                                            allocator:@selector(connectionInfoWithConnectionInfo:)];
104        self->incoming = connectionInfo->incoming;
105        self->adapterName = [[NSString alloc] initWithUTF8String:connectionInfo->adapterName.c_str()];
106        self->connectionId = [[NSString alloc] initWithUTF8String:connectionInfo->connectionId.c_str()];
107    }
108    return self;
109}
110
111@end
112
113@implementation ICEIPConnectionInfo (ICEInternal)
114
115-(id) initWithIPConnectionInfo:(Ice::IPConnectionInfo*)ipConnectionInfo
116{
117    self = [super initWithConnectionInfo:ipConnectionInfo];
118    if(self)
119    {
120        self->localAddress = [[NSString alloc] initWithUTF8String:ipConnectionInfo->localAddress.c_str()];
121        self->localPort = ipConnectionInfo->localPort;
122        self->remoteAddress = [[NSString alloc] initWithUTF8String:ipConnectionInfo->remoteAddress.c_str()];
123        self->remotePort = ipConnectionInfo->remotePort;
124    }
125    return self;
126}
127
128@end
129
130@implementation ICETCPConnectionInfo (ICEInternal)
131-(id) initWithTCPConnectionInfo:(Ice::TCPConnectionInfo*)tcpConnectionInfo
132{
133    self = [super initWithIPConnectionInfo:tcpConnectionInfo];
134    if(self)
135    {
136        self->rcvSize = tcpConnectionInfo->rcvSize;
137        self->sndSize = tcpConnectionInfo->sndSize;
138    }
139    return self;
140}
141@end
142
143@implementation ICEUDPConnectionInfo (ICEInternal)
144
145-(id) initWithUDPConnectionInfo:(Ice::UDPConnectionInfo*)udpConnectionInfo
146{
147    self = [super initWithIPConnectionInfo:udpConnectionInfo];
148    if(self)
149    {
150        self->mcastAddress = [[NSString alloc] initWithUTF8String:udpConnectionInfo->mcastAddress.c_str()];
151        self->mcastPort = udpConnectionInfo->mcastPort;
152        self->rcvSize = udpConnectionInfo->rcvSize;
153        self->sndSize = udpConnectionInfo->sndSize;
154    }
155    return self;
156}
157
158@end
159
160@implementation ICEWSConnectionInfo (ICEInternal)
161-(id) initWithWSConnectionInfo:(Ice::WSConnectionInfo*)wsConnectionInfo
162{
163    self = [super initWithConnectionInfo:wsConnectionInfo];
164    if(self)
165    {
166        self->headers = toNSDictionary(wsConnectionInfo->headers);
167    }
168    return self;
169}
170@end
171
172namespace
173{
174
175class CloseCallbackI : public Ice::CloseCallback
176{
177public:
178
179    CloseCallbackI(id<ICEConnection> connection, ICECloseCallback callback) :
180        _connection(connection), _callback(Block_copy(callback))
181    {
182        [_connection retain];
183    }
184
185    ~CloseCallbackI()
186    {
187        [_connection release];
188        [_callback release];
189    }
190
191    void
192    closed(const Ice::ConnectionPtr&)
193    {
194        NSException* ex = nil;
195        @autoreleasepool
196        {
197            @try
198            {
199                _callback(_connection);
200            }
201            @catch(id e)
202            {
203                ex = [e retain];
204            }
205        }
206        if(ex != nil)
207        {
208            rethrowCxxException(ex, true); // True = release the exception.
209        }
210    }
211
212private:
213
214    id<ICEConnection> _connection;
215    ICECloseCallback _callback;
216};
217
218class HeartbeatCallbackI : public Ice::HeartbeatCallback
219{
220public:
221
222    HeartbeatCallbackI(id<ICEConnection> connection, ICEHeartbeatCallback callback) :
223        _connection(connection), _callback(Block_copy(callback))
224    {
225        [_connection retain];
226    }
227
228    ~HeartbeatCallbackI()
229    {
230        [_connection release];
231        [_callback release];
232    }
233
234    void
235    heartbeat(const Ice::ConnectionPtr&)
236    {
237        NSException* ex = nil;
238        @autoreleasepool
239        {
240            @try
241            {
242                _callback(_connection);
243            }
244            @catch(id e)
245            {
246                ex = [e retain];
247            }
248        }
249        if(ex != nil)
250        {
251            rethrowCxxException(ex, true); // True = release the exception.
252        }
253    }
254
255private:
256
257    id<ICEConnection> _connection;
258    ICEHeartbeatCallback _callback;
259};
260
261}
262
263@implementation ICEConnection
264-(void) close:(ICEConnectionClose)mode
265{
266    NSException* nsex = nil;
267    try
268    {
269        CONNECTION->close((Ice::ConnectionClose)mode);
270    }
271    catch(const std::exception& ex)
272    {
273        nsex = toObjCException(ex);
274    }
275    if(nsex != nil)
276    {
277        @throw nsex;
278    }
279}
280-(id<ICEObjectPrx>) createProxy:(ICEIdentity*)identity
281{
282    NSException* nsex = nil;
283    try
284    {
285        return [ICEObjectPrx iceObjectPrxWithObjectPrx:CONNECTION->createProxy([identity identity])];
286    }
287    catch(const std::exception& ex)
288    {
289        nsex = toObjCException(ex);
290    }
291    @throw nsex;
292    return nil; // Keep the compiler happy.
293}
294-(void) setAdapter:(id<ICEObjectAdapter>)adapter
295{
296    NSException* nsex = nil;
297    try
298    {
299        CONNECTION->setAdapter([(ICEObjectAdapter*)adapter adapter]);
300    }
301    catch(const std::exception& ex)
302    {
303        nsex = toObjCException(ex);
304    }
305    if(nsex != nil)
306    {
307        @throw nsex;
308    }
309}
310-(id<ICEObjectAdapter>) getAdapter
311{
312    NSException* nsex = nil;
313    try
314    {
315        return [ICEObjectAdapter localObjectWithCxxObject:CONNECTION->getAdapter().get()];
316    }
317    catch(const std::exception& ex)
318    {
319        nsex = toObjCException(ex);
320    }
321    @throw nsex;
322    return nil; // Keep the compiler happy.
323}
324-(void) flushBatchRequests:(ICECompressBatch)compress
325{
326    NSException* nsex = nil;
327    try
328    {
329        CONNECTION->flushBatchRequests((Ice::CompressBatch)compress);
330    }
331    catch(const std::exception& ex)
332    {
333        nsex = toObjCException(ex);
334    }
335    if(nsex != nil)
336    {
337        @throw nsex;
338    }
339}
340-(id<ICEAsyncResult>) begin_flushBatchRequests:(ICECompressBatch)compress
341{
342    return beginCppCall(^(Ice::AsyncResultPtr& result)
343                        {
344                            result = CONNECTION->begin_flushBatchRequests((Ice::CompressBatch)compress);
345                        });
346}
347-(id<ICEAsyncResult>) begin_flushBatchRequests:(ICECompressBatch)compress exception:(void(^)(ICEException*))exception
348{
349    return [self begin_flushBatchRequests:compress exception:exception sent:nil];
350}
351-(id<ICEAsyncResult>) begin_flushBatchRequests:(ICECompressBatch)compress
352                                     exception:(void(^)(ICEException*))exception
353                                          sent:(void(^)(BOOL))sent
354{
355    return beginCppCall(^(Ice::AsyncResultPtr& result, const Ice::CallbackPtr& cb)
356                        {
357                            result = CONNECTION->begin_flushBatchRequests((Ice::CompressBatch)compress, cb);
358                        },
359                        ^(const Ice::AsyncResultPtr& result) {
360                            CONNECTION->end_flushBatchRequests(result);
361                        },
362                        exception, sent);
363}
364-(void) end_flushBatchRequests:(id<ICEAsyncResult>)result
365{
366    endCppCall(^(const Ice::AsyncResultPtr& r)
367               {
368                   CONNECTION->end_flushBatchRequests(r);
369               }, result);
370}
371-(void) setCloseCallback:(ICECloseCallback)callback
372{
373    CONNECTION->setCloseCallback(new CloseCallbackI(self, callback));
374}
375-(void) setHeartbeatCallback:(ICEHeartbeatCallback)callback
376{
377    CONNECTION->setHeartbeatCallback(new HeartbeatCallbackI(self, callback));
378}
379-(void) heartbeat
380{
381    NSException* nsex = nil;
382    try
383    {
384        CONNECTION->heartbeat();
385    }
386    catch(const std::exception& ex)
387    {
388        nsex = toObjCException(ex);
389    }
390    if(nsex != nil)
391    {
392        @throw nsex;
393    }
394}
395-(id<ICEAsyncResult>) begin_heartbeat
396{
397    return beginCppCall(^(Ice::AsyncResultPtr& result)
398                        {
399                            result = CONNECTION->begin_heartbeat();
400                        });
401}
402-(id<ICEAsyncResult>) begin_heartbeat:(void(^)(ICEException*))exception
403{
404    return [self begin_heartbeat:exception sent:nil];
405}
406-(id<ICEAsyncResult>) begin_heartbeat:(void(^)(ICEException*))exception sent:(void(^)(BOOL))sent
407{
408    return beginCppCall(^(Ice::AsyncResultPtr& result, const Ice::CallbackPtr& cb)
409                        {
410                            result = CONNECTION->begin_heartbeat(cb);
411                        },
412                        ^(const Ice::AsyncResultPtr& result)
413                        {
414                            CONNECTION->end_heartbeat(result);
415                        },
416                        exception, sent);
417}
418-(void) end_heartbeat:(id<ICEAsyncResult>)result
419{
420    endCppCall(^(const Ice::AsyncResultPtr& r)
421               {
422                   CONNECTION->end_heartbeat(r);
423               }, result);
424}
425-(void) setACM:(id)timeout close:(id)close heartbeat:(id)heartbeat
426{
427    IceUtil::Optional<int> to;
428    ICEInt intValue;
429    if([ICEOptionalGetter getInt:timeout value:&intValue])
430    {
431        to = intValue;
432    }
433    IceUtil::Optional<Ice::ACMClose> c;
434    if([ICEOptionalGetter getInt:close value:&intValue])
435    {
436        c = (Ice::ACMClose)intValue;
437    }
438    IceUtil::Optional<Ice::ACMHeartbeat> hb;
439    if([ICEOptionalGetter getInt:heartbeat value:&intValue])
440    {
441        hb = (Ice::ACMHeartbeat)intValue;
442    }
443
444    NSException* nsex;
445    try
446    {
447        CONNECTION->setACM(to, c, hb);
448        return;
449    }
450    catch(const std::exception& ex)
451    {
452        nsex = toObjCException(ex);
453    }
454    @throw nsex;
455}
456-(ICEACM*) getACM
457{
458    Ice::ACM acm = CONNECTION->getACM();
459    return [ICEACM acm:acm.timeout close:(ICEACMClose)acm.close heartbeat:(ICEACMHeartbeat)acm.heartbeat];
460}
461-(NSMutableString*) type
462{
463    return [toNSMutableString(CONNECTION->type()) autorelease];
464}
465-(ICEInt) timeout
466{
467    return CONNECTION->timeout();
468}
469-(NSMutableString*) toString
470{
471    return [toNSMutableString(CONNECTION->toString()) autorelease];
472}
473-(NSString*) description
474{
475    return [toNSString(CONNECTION->toString()) autorelease];
476}
477
478-(ICEConnectionInfo*) getInfo
479{
480    NSException* nsex = nil;
481    try
482    {
483        return [ICEConnectionInfo localObjectWithCxxObject:CONNECTION->getInfo().get()
484                                                 allocator:@selector(connectionInfoWithConnectionInfo:)];
485    }
486    catch(const std::exception& ex)
487    {
488        nsex = toObjCException(ex);
489    }
490    if(nsex != nil)
491    {
492        @throw nsex;
493    }
494    return nil;
495}
496
497-(void) setBufferSize:(int)rcvSize sndSize:(int)sndSize
498{
499    NSException* nsex = nil;
500    try
501    {
502        CONNECTION->setBufferSize(rcvSize, sndSize);
503    }
504    catch(const std::exception& ex)
505    {
506        nsex = toObjCException(ex);
507    }
508    if(nsex != nil)
509    {
510        @throw nsex;
511    }
512}
513
514-(void) throwException
515{
516    NSException* nsex = nil;
517    try
518    {
519        CONNECTION->throwException();
520    }
521    catch(const std::exception& ex)
522    {
523        nsex = toObjCException(ex);
524    }
525    if(nsex != nil)
526    {
527        @throw nsex;
528    }
529}
530
531-(ICEEndpoint*) getEndpoint
532{
533    NSException* nsex = nil;
534    try
535    {
536        return [ICEEndpoint localObjectWithCxxObject:CONNECTION->getEndpoint().get()];
537    }
538    catch(const std::exception& ex)
539    {
540        nsex = toObjCException(ex);
541    }
542    if(nsex != nil)
543    {
544        @throw nsex;
545    }
546    return nil;
547}
548@end
549