LOL 绝地求生美服是哪个Disconnected from chat, attempting to reconnect...

/ ios_xmpp_chat
项目语言:OBJECT-C
权限:read-only(如需更高权限请先加入项目)
ios_xmpp_chat/
Index: XMPPReconnect.m
===================================================================
--- XMPPReconnect.m (revision 0)
+++ XMPPReconnect.m (revision 2)
@@ -0,0 +1,651 @@
+#import &XMPPReconnect.h&
+#import &XMPPStream.h&
+#import &XMPPLogging.h&
+#import &NSXMLElement+XMPP.h&
+#if ! __has_feature(objc_arc)
+#warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
+#define IMPOSSIBLE_REACHABILITY_FLAGS 0xFFFFFFFF
+// Log levels: off, error, warn, info, verbose
+#if DEBUG
static const int xmppLogLevel = XMPP_LOG_LEVEL_WARN;
static const int xmppLogLevel = XMPP_LOG_LEVEL_WARN;
+enum XMPPReconnectFlags
+ kShouldReconnect
// If set, disconnection was accidental, and autoReconnect may be used
+ kMultipleChanges
// If set, there have been reachability changes during a connection attempt
+ kManuallyStarted
// If set, we were started manually via manualStart method
+ kQueryingDelegates = 1 && 3,
// If set, we are awaiting response(s) from the delegate(s)
+enum XMPPReconnectConfig
+ kAutoReconnect
// If set, automatically attempts to reconnect after a disconnection
+#if MAC_OS_X_VERSION_MIN_REQUIRED &= MAC_OS_X_VERSION_10_5
+// SCNetworkConnectionFlags was renamed to SCNetworkReachabilityFlags in 10.6
+typedef SCNetworkConnectionFlags SCNetworkReachabilityF
+@interface XMPPReconnect (PrivateAPI)
+- (void)setupReconnectT
+- (void)teardownReconnectT
+- (void)setupNetworkM
+- (void)teardownNetworkM
+- (void)maybeAttemptR
+- (void)maybeAttemptReconnectWithTicket:(int)
+- (void)maybeAttemptReconnectWithReachabilityFlags:(SCNetworkReachabilityFlags)reachabilityF
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark -
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+@implementation XMPPReconnect
+@synthesize reconnectD
+@synthesize reconnectTimerI
+- (id)init
+ return [self initWithDispatchQueue:NULL];
+- (id)initWithDispatchQueue:(dispatch_queue_t)queue
+ if ((self = [super initWithDispatchQueue:queue]))
flags = 0;
config = kAutoR
reconnectDelay = DEFAULT_XMPP_RECONNECT_DELAY;
reconnectTimerInterval = DEFAULT_XMPP_RECONNECT_TIMER_INTERVAL;
reconnectTicket = 0;
previousReachabilityFlags = IMPOSSIBLE_REACHABILITY_FLAGS;
+- (void)dealloc
+ dispatch_block_t block = ^{
[self teardownReconnectTimer];
[self teardownNetworkMonitoring];
+ if (dispatch_get_specific(moduleQueueTag))
dispatch_sync(moduleQueue, block);
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark Configuration and Flags
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+- (BOOL)autoReconnect
+ __block BOOL result = NO;
+ dispatch_block_t block = ^{
result = (config & kAutoReconnect) ? YES : NO;
+ if (dispatch_get_specific(moduleQueueTag))
dispatch_sync(moduleQueue, block);
+- (void)setAutoReconnect:(BOOL)flag
+ dispatch_block_t block = ^{
config |= kAutoR
config &= ~kAutoR
+ if (dispatch_get_specific(moduleQueueTag))
dispatch_async(moduleQueue, block);
+- (BOOL)shouldReconnect
+ NSAssert(dispatch_get_specific(moduleQueueTag), @&Invoked private method outside moduleQueue&);
+ return (flags & kShouldReconnect) ? YES : NO;
+- (void)setShouldReconnect:(BOOL)flag
+ NSAssert(dispatch_get_specific(moduleQueueTag), @&Invoked private method outside moduleQueue&);
+ if (flag)
flags |= kShouldR
flags &= ~kShouldR
+- (BOOL)multipleReachabilityChanges
+ NSAssert(dispatch_get_specific(moduleQueueTag), @&Invoked private method outside moduleQueue&);
+ return (flags & kMultipleChanges) ? YES : NO;
+- (void)setMultipleReachabilityChanges:(BOOL)flag
+ NSAssert(dispatch_get_specific(moduleQueueTag), @&Invoked private method outside moduleQueue&);
+ if (flag)
flags |= kMultipleC
flags &= ~kMultipleC
+- (BOOL)manuallyStarted
+ NSAssert(dispatch_get_specific(moduleQueueTag), @&Invoked private method outside moduleQueue&);
+ return (flags & kManuallyStarted) ? YES : NO;
+- (void)setManuallyStarted:(BOOL)flag
+ NSAssert(dispatch_get_specific(moduleQueueTag), @&Invoked private method outside moduleQueue&);
+ if (flag)
flags |= kManuallyS
flags &= ~kManuallyS
+- (BOOL)queryingDelegates
+ NSAssert(dispatch_get_specific(moduleQueueTag), @&Invoked private method outside moduleQueue&);
+ return (flags & kQueryingDelegates) ? YES : NO;
+- (void)setQueryingDelegates:(BOOL)flag
+ NSAssert(dispatch_get_specific(moduleQueueTag), @&Invoked private method outside moduleQueue&);
+ if (flag)
flags |= kQueryingD
flags &= ~kQueryingD
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark Manual Manipulation
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+- (void)manualStart
+ dispatch_block_t block = ^{ @autoreleasepool {
if ([xmppStream isDisconnected] && [self manuallyStarted] == NO)
[self setManuallyStarted:YES];
[self setupReconnectTimer];
[self setupNetworkMonitoring];
+ if (dispatch_get_specific(moduleQueueTag))
dispatch_async(moduleQueue, block);
+- (void)stop
+ dispatch_block_t block = ^{ @autoreleasepool {
// Clear all flags to disable any further reconnect attemts regardless of the state we're in.
flags = 0;
// Stop any planned reconnect attempts and stop monitoring the network.
reconnectTicket++;
[self teardownReconnectTimer];
[self teardownNetworkMonitoring];
+ if (dispatch_get_specific(moduleQueueTag))
dispatch_async(moduleQueue, block);
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark XMPPStream Delegate
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+- (void)xmppStreamDidConnect:(XMPPStream *)sender
+ // This method is executed on our moduleQueue.
+ // The stream is up so we can stop our reconnect attempts now.
+ // We essentially want to do the same thing as the stop method with one exception:
+ // We do not want to clear the shouldReconnect flag.
+ // Remember the shouldReconnect flag gets set upon authentication.
+ // A combination of this flag and the autoReconnect flag controls the auto reconnect mechanism.
+ // It is possible for us to get accidentally disconnected after
+ // the stream opens but prior to authentication completing.
+ // If this happens we still want to abide by the previous shouldReconnect setting.
+ [self setMultipleReachabilityChanges:NO];
+ [self setManuallyStarted:NO];
+ reconnectTicket++;
+ [self teardownReconnectTimer];
+ [self teardownNetworkMonitoring];
+- (void)xmppStreamDidAuthenticate:(XMPPStream *)sender
+ // This method is executed on our moduleQueue.
+ // We're now connected and properly authenticated.
+ // Should we get accidentally disconnected we should automatically reconnect (if autoReconnect is set).
+ [self setShouldReconnect:YES];
+- (void)xmppStream:(XMPPStream *)sender didReceiveError:(NSXMLElement *)element
+ // This method is executed on our moduleQueue.
+ // &stream:error&
&conflict xmlns=&urn:ietf:params:xml:ns:xmpp-streams&/&
&text xmlns=&urn:ietf:params:xml:ns:xmpp-streams& xml:lang=&&&Replaced by new connection&/text&
+ // &/stream:error&
+ // If our connection ever gets replaced, we shouldn't attempt a reconnect,
+ // because the user has logged in on another device.
+ // If we still applied the reconnect logic,
+ // the two devices may get into an infinite loop of kicking each other off the system.
+ NSString *elementName = [element name];
+ if ([elementName isEqualToString:@&stream:error&] || [elementName isEqualToString:@&error&])
NSXMLElement *conflict = [element elementForName:@&conflict& xmlns:@&urn:ietf:params:xml:ns:xmpp-streams&];
if (conflict)
[self setShouldReconnect:NO];
+- (void)xmppStreamWasToldToDisconnect:(XMPPStream *)sender
+ // This method is executed on our moduleQueue.
+ // We should not automatically attempt to reconnect when the connection closes.
+ [self stop];
+- (void)xmppStreamDidDisconnect:(XMPPStream *)sender withError:(NSError *)error
+ // This method is executed on our moduleQueue.
+ if ([self autoReconnect] && [self shouldReconnect])
[self setupReconnectTimer];
[self setupNetworkMonitoring];
SCNetworkReachabilityFlags reachabilityFlags = 0;
SCNetworkReachabilityGetFlags(reachability, &reachabilityFlags);
[multicastDelegate xmppReconnect:self didDetectAccidentalDisconnect:reachabilityFlags];
+ if ([self multipleReachabilityChanges])
// While the previous connection attempt was in progress, the reachability of the xmpp host changed.
// This means that while the previous attempt failed, an attempt now might succeed.
int ticket = ++reconnectT
dispatch_time_t tt = dispatch_time(DISPATCH_TIME_NOW, (0.1 * NSEC_PER_SEC));
dispatch_after(tt, moduleQueue, ^{ @autoreleasepool {
[self maybeAttemptReconnectWithTicket:ticket];
// Note: We delay the method call.
// This allows the other delegates to be notified of the closed stream prior to our reconnect attempt.
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark Reachability
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+static void XMPPReconnectReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void *info)
+ @autoreleasepool {
XMPPReconnect *instance = (__bridge XMPPReconnect *)
[instance maybeAttemptReconnectWithReachabilityFlags:flags];
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark Logic
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+- (void)setupReconnectTimer
+ NSAssert(dispatch_get_specific(moduleQueueTag) , @&Invoked on incorrect queue&);
+ if (reconnectTimer == NULL)
if ((reconnectDelay &= 0.0) && (reconnectTimerInterval &= 0.0))
// All timed reconnect attempts are disabled
reconnectTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, moduleQueue);
dispatch_source_set_event_handler(reconnectTimer, ^{ @autoreleasepool {
[self maybeAttemptReconnect];
#if !OS_OBJECT_USE_OBJC
dispatch_source_t theReconnectTimer = reconnectT
dispatch_source_set_cancel_handler(reconnectTimer, ^{
XMPPLogVerbose(@&dispatch_release(reconnectTimer)&);
dispatch_release(theReconnectTimer);
dispatch_time_t startT
if (reconnectDelay & 0.0)
startTime = dispatch_time(DISPATCH_TIME_NOW, (reconnectDelay * NSEC_PER_SEC));
startTime = dispatch_time(DISPATCH_TIME_NOW, (reconnectTimerInterval * NSEC_PER_SEC));
uint64_t intervalT
if (reconnectTimerInterval & 0.0)
intervalTime = reconnectTimerInterval * NSEC_PER_SEC;
intervalTime = 0.0;
dispatch_source_set_timer(reconnectTimer, startTime, intervalTime, 0.25);
dispatch_resume(reconnectTimer);
+- (void)teardownReconnectTimer
+ NSAssert(dispatch_get_specific(moduleQueueTag) , @&Invoked on incorrect queue&);
+ if (reconnectTimer)
dispatch_source_cancel(reconnectTimer);
reconnectTimer = NULL;
+- (void)setupNetworkMonitoring
+ NSAssert(dispatch_get_specific(moduleQueueTag) , @&Invoked on incorrect queue&);
+ if (reachability == NULL)
NSString *domain = xmppStream.hostN
if (domain == nil)
domain = @&&;
reachability = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, [domain UTF8String]);
if (reachability)
SCNetworkReachabilityContext context = {0, (__bridge void *)(self), NULL, NULL, NULL};
SCNetworkReachabilitySetCallback(reachability, XMPPReconnectReachabilityCallback, &context);
if (moduleQueue)
SCNetworkReachabilitySetDispatchQueue(reachability,moduleQueue);
XMPPLogWarn(@&%@: %@ - No xmpp moduleQueue!&, THIS_FILE, THIS_METHOD);
+- (void)teardownNetworkMonitoring
+ NSAssert(dispatch_get_specific(moduleQueueTag) , @&Invoked on incorrect queue&);
+ if (reachability)
if (moduleQueue)
SCNetworkReachabilitySetDispatchQueue(reachability,NULL);
XMPPLogWarn(@&%@: %@ - No xmpp moduleQueue!&, THIS_FILE, THIS_METHOD);
SCNetworkReachabilitySetCallback(reachability, NULL, NULL);
CFRelease(reachability);
reachability = NULL;
+ * This method may be invoked by the reconnectTimer.
+ * During auto reconnection it is invoked reconnectDelay seconds after an accidental disconnection.
+ * After that, it is then invoked every reconnectTimerInterval seconds.
+ * This handles disconnections that were not the result of an internet connectivity issue.
+- (void)maybeAttemptReconnect
+ NSAssert(dispatch_get_specific(moduleQueueTag) , @&Invoked on incorrect queue&);
+ if (reachability)
SCNetworkReachabilityFlags reachabilityF
if (SCNetworkReachabilityGetFlags(reachability, &reachabilityFlags))
[self maybeAttemptReconnectWithReachabilityFlags:reachabilityFlags];
+ * This method is invoked (after a short delay) if the reachability changed while
+ * a reconnection attempt was in progress.
+- (void)maybeAttemptReconnectWithTicket:(int)ticket
+ NSAssert(dispatch_get_specific(moduleQueueTag) , @&Invoked on incorrect queue&);
+ if (ticket != reconnectTicket)
// The dispatched task was cancelled.
+ if (reachability)
SCNetworkReachabilityFlags reachabilityF
if (SCNetworkReachabilityGetFlags(reachability, &reachabilityFlags))
[self maybeAttemptReconnectWithReachabilityFlags:reachabilityFlags];
+- (void)maybeAttemptReconnectWithReachabilityFlags:(SCNetworkReachabilityFlags)reachabilityFlags
+ if (!dispatch_get_specific(moduleQueueTag))
dispatch_async(moduleQueue, ^{ @autoreleasepool {
[self maybeAttemptReconnectWithReachabilityFlags:reachabilityFlags];
+ if (([self manuallyStarted]) || ([self autoReconnect] && [self shouldReconnect]))
if ([xmppStream isDisconnected] && ([self queryingDelegates] == NO))
// The xmpp stream is disconnected, and is not attempting reconnection
// Delegate rules:
// If ALL of the delegates return YES, then the result is YES.
// If ANY of the delegates return NO, then the result is NO.
// If there are no delegates, the default answer is YES.
GCDMulticastDelegateEnumerator *delegateEnumerator = [multicastDelegate delegateEnumerator];
dispatch_queue_
SEL selector = @selector(xmppReconnect:shouldAttemptAutoReconnect:);
NSUInteger delegateCount = [delegateEnumerator countForSelector:selector];
dispatch_semaphore_t delSemaphore = dispatch_semaphore_create(0);
dispatch_group_t delGroup = dispatch_group_create();
while ([delegateEnumerator getNextDelegate:&del delegateQueue:&dq forSelector:selector])
dispatch_group_async(delGroup, dq, ^{ @autoreleasepool {
if (![del xmppReconnect:self shouldAttemptAutoReconnect:reachabilityFlags])
dispatch_semaphore_signal(delSemaphore);
[self setQueryingDelegates:YES];
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(concurrentQueue, ^{ @autoreleasepool {
dispatch_group_wait(delGroup, DISPATCH_TIME_FOREVER);
// What was the delegate response?
BOOL shouldAttemptR
if (delegateCount == 0)
shouldAttemptReconnect = YES;
shouldAttemptReconnect = (dispatch_semaphore_wait(delSemaphore, DISPATCH_TIME_NOW) != 0);
dispatch_async(moduleQueue, ^{ @autoreleasepool {
[self setQueryingDelegates:NO];
if (shouldAttemptReconnect)
[self setMultipleReachabilityChanges:NO];
previousReachabilityFlags = reachabilityF
if (self.usesOldSchoolSecureConnect)
[xmppStream oldSchoolSecureConnectWithTimeout:XMPPStreamTimeoutNone error:nil];
[xmppStream connectWithTimeout:XMPPStreamTimeoutNone error:nil];
else if ([self multipleReachabilityChanges])
[self setMultipleReachabilityChanges:NO];
previousReachabilityFlags = IMPOSSIBLE_REACHABILITY_FLAGS;
[self maybeAttemptReconnect];
previousReachabilityFlags = IMPOSSIBLE_REACHABILITY_FLAGS;
#if !OS_OBJECT_USE_OBJC
dispatch_release(delSemaphore);
dispatch_release(delGroup);
// The xmpp stream is already attempting a connection.
if (reachabilityFlags != previousReachabilityFlags)
// It seems that the reachability of our xmpp host has changed in the middle of either
// a reconnection attempt or while querying our delegates for permission to attempt reconnect.
// This may mean that the current attempt will fail,
// but an another attempt after the failure will succeed.
// We make a note of the multiple changes,
// and if the current attempt fails, we'll try again after a short delay.
[self setMultipleReachabilityChanges:YES];
Property changes on: XMPPReconnect.m
___________________________________________________________________
Added: svn:executable
(C)&&2013&&Alibaba&&Inc.&&All&&rights&&resvered.
Powered by}

我要回帖

更多关于 美服战网 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信