110
110
kDidBind = 1 << 1 , // If set, bind has been called.
111
111
kConnecting = 1 << 2 , // If set, a connection attempt is in progress.
112
112
kDidConnect = 1 << 3 , // If set, socket is connected.
113
- kReceive = 1 << 4 , // If set, receive is enabled
114
- kIPv4Deactivated = 1 << 5 , // If set, socket4 was closed due to bind or connect on IPv6.
115
- kIPv6Deactivated = 1 << 6 , // If set, socket6 was closed due to bind or connect on IPv4.
116
- kSend4SourceSuspended = 1 << 7 , // If set, send4Source is suspended.
117
- kSend6SourceSuspended = 1 << 8 , // If set, send6Source is suspended.
118
- kReceive4SourceSuspended = 1 << 9 , // If set, receive4Source is suspended.
119
- kReceive6SourceSuspended = 1 << 10 , // If set, receive6Source is suspended.
120
- kSock4CanAcceptBytes = 1 << 11 , // If set, we know socket4 can accept bytes. If unset, it's unknown.
121
- kSock6CanAcceptBytes = 1 << 12 , // If set, we know socket6 can accept bytes. If unset, it's unknown.
122
- kForbidSendReceive = 1 << 13 , // If set, no new send or receive operations are allowed to be queued.
123
- kCloseAfterSends = 1 << 14 , // If set, close as soon as no more sends are queued.
124
- kFlipFlop = 1 << 15 , // Used to alternate between IPv4 and IPv6 sockets.
113
+ kReceiveOnce = 1 << 4 , // If set, one-at-a-time receive is enabled
114
+ kReceiveContinuous = 1 << 5 , // If set, continuous receive is enabled
115
+ kIPv4Deactivated = 1 << 6 , // If set, socket4 was closed due to bind or connect on IPv6.
116
+ kIPv6Deactivated = 1 << 7 , // If set, socket6 was closed due to bind or connect on IPv4.
117
+ kSend4SourceSuspended = 1 << 8 , // If set, send4Source is suspended.
118
+ kSend6SourceSuspended = 1 << 9 , // If set, send6Source is suspended.
119
+ kReceive4SourceSuspended = 1 << 10 , // If set, receive4Source is suspended.
120
+ kReceive6SourceSuspended = 1 << 11 , // If set, receive6Source is suspended.
121
+ kSock4CanAcceptBytes = 1 << 12 , // If set, we know socket4 can accept bytes. If unset, it's unknown.
122
+ kSock6CanAcceptBytes = 1 << 13 , // If set, we know socket6 can accept bytes. If unset, it's unknown.
123
+ kForbidSendReceive = 1 << 14 , // If set, no new send or receive operations are allowed to be queued.
124
+ kCloseAfterSends = 1 << 15 , // If set, close as soon as no more sends are queued.
125
+ kFlipFlop = 1 << 16 , // Used to alternate between IPv4 and IPv6 sockets.
125
126
#if TARGET_OS_IPHONE
126
- kAddedStreamListener = 1 << 16 , // If set, CFStreams have been added to listener thread
127
+ kAddedStreamListener = 1 << 17 , // If set, CFStreams have been added to listener thread
127
128
#endif
128
129
};
129
130
@@ -170,6 +171,8 @@ @interface GCDAsyncUdpSocket ()
170
171
unsigned long socket4FDBytesAvailable;
171
172
unsigned long socket6FDBytesAvailable;
172
173
174
+ uint32_t pendingFilterOperations;
175
+
173
176
NSData *cachedLocalAddress4;
174
177
NSString *cachedLocalHost4;
175
178
uint16_t cachedLocalPort4;
@@ -3805,6 +3808,52 @@ - (void)setupSendTimerWithTimeout:(NSTimeInterval)timeout
3805
3808
#pragma mark Receiving
3806
3809
// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3807
3810
3811
+ - (BOOL )receiveOnce : (NSError **)errPtr
3812
+ {
3813
+ LogTrace ();
3814
+
3815
+ __block BOOL result = NO ;
3816
+ __block NSError *err = nil ;
3817
+
3818
+ dispatch_block_t block = ^{
3819
+
3820
+ if ((flags & kReceiveOnce ) == 0 )
3821
+ {
3822
+ if ((flags & kDidCreateSockets ) == 0 )
3823
+ {
3824
+ NSString *msg = @" Must bind socket before you can receive data. "
3825
+ @" You can do this explicitly via bind, or implicitly via connect or by sending data." ;
3826
+
3827
+ err = [self badConfigError: msg];
3828
+ return_from_block;
3829
+ }
3830
+
3831
+ flags |= kReceiveOnce ; // Enable
3832
+ flags &= ~kReceiveContinuous ; // Disable
3833
+
3834
+ dispatch_async (socketQueue, ^{ @autoreleasepool {
3835
+
3836
+ [self doReceive ];
3837
+ }});
3838
+ }
3839
+
3840
+ result = YES ;
3841
+ };
3842
+
3843
+ if (dispatch_get_current_queue () == socketQueue)
3844
+ block ();
3845
+ else
3846
+ dispatch_sync (socketQueue, block);
3847
+
3848
+ if (err)
3849
+ LogError (@" Error in beginReceiving: %@ " , err);
3850
+
3851
+ if (errPtr)
3852
+ *errPtr = err;
3853
+
3854
+ return result;
3855
+ }
3856
+
3808
3857
- (BOOL )beginReceiving : (NSError **)errPtr
3809
3858
{
3810
3859
LogTrace ();
@@ -3814,7 +3863,7 @@ - (BOOL)beginReceiving:(NSError **)errPtr
3814
3863
3815
3864
dispatch_block_t block = ^{
3816
3865
3817
- if ((flags & kReceive ) == 0 )
3866
+ if ((flags & kReceiveContinuous ) == 0 )
3818
3867
{
3819
3868
if ((flags & kDidCreateSockets ) == 0 )
3820
3869
{
@@ -3825,7 +3874,8 @@ - (BOOL)beginReceiving:(NSError **)errPtr
3825
3874
return_from_block;
3826
3875
}
3827
3876
3828
- flags |= kReceive ;
3877
+ flags |= kReceiveContinuous ; // Enable
3878
+ flags &= ~kReceiveOnce ; // Disable
3829
3879
3830
3880
dispatch_async (socketQueue, ^{ @autoreleasepool {
3831
3881
@@ -3856,7 +3906,8 @@ - (void)pauseReceiving
3856
3906
3857
3907
dispatch_block_t block = ^{
3858
3908
3859
- flags &= ~kReceive ;
3909
+ flags &= ~kReceiveOnce ; // Disable
3910
+ flags &= ~kReceiveContinuous ; // Disable
3860
3911
3861
3912
if (socket4FDBytesAvailable > 0 ) {
3862
3913
[self suspendReceive4Source ];
@@ -3911,7 +3962,7 @@ - (void)doReceive
3911
3962
{
3912
3963
LogTrace ();
3913
3964
3914
- if ((flags & kReceive ) == 0 )
3965
+ if ((flags & ( kReceiveOnce | kReceiveContinuous ) ) == 0 )
3915
3966
{
3916
3967
LogVerbose (@" Receiving is paused..." );
3917
3968
@@ -3925,6 +3976,20 @@ - (void)doReceive
3925
3976
return ;
3926
3977
}
3927
3978
3979
+ if ((flags & kReceiveOnce ) && (pendingFilterOperations > 0 ))
3980
+ {
3981
+ LogVerbose (@" Receiving is temporarily paused (pending filter operations)..." );
3982
+
3983
+ if (socket4FDBytesAvailable > 0 ) {
3984
+ [self suspendReceive4Source ];
3985
+ }
3986
+ if (socket6FDBytesAvailable > 0 ) {
3987
+ [self suspendReceive6Source ];
3988
+ }
3989
+
3990
+ return ;
3991
+ }
3992
+
3928
3993
if ((socket4FDBytesAvailable == 0 ) && (socket6FDBytesAvailable == 0 ))
3929
3994
{
3930
3995
LogVerbose (@" No data available to receive..." );
@@ -4053,6 +4118,8 @@ - (void)doReceive
4053
4118
4054
4119
4055
4120
BOOL waitingForSocket = NO ;
4121
+ BOOL ignoredDueToAddress = NO ;
4122
+
4056
4123
NSError *error = nil ;
4057
4124
4058
4125
if (result == 0 )
@@ -4068,34 +4135,56 @@ - (void)doReceive
4068
4135
}
4069
4136
else
4070
4137
{
4071
- BOOL ignored = NO ;
4072
-
4073
4138
if (flags & kDidConnect )
4074
4139
{
4075
4140
if (addr4 && ![self isConnectedToAddress4: addr4])
4076
- ignored = YES ;
4141
+ ignoredDueToAddress = YES ;
4077
4142
if (addr6 && ![self isConnectedToAddress6: addr6])
4078
- ignored = YES ;
4143
+ ignoredDueToAddress = YES ;
4079
4144
}
4080
4145
4081
4146
NSData *addr = (addr4 != nil ) ? addr4 : addr6;
4082
4147
4083
- if (!ignored )
4148
+ if (!ignoredDueToAddress )
4084
4149
{
4085
4150
if (filterBlock && filterQueue)
4086
4151
{
4087
4152
// Run data through filter, and if approved, notify delegate
4153
+ pendingFilterOperations++;
4154
+
4088
4155
dispatch_async (filterQueue, ^{ @autoreleasepool {
4089
4156
4090
4157
id filterContext = nil ;
4158
+ BOOL allowed = filterBlock (data, addr, &filterContext);
4091
4159
4092
- if (filterBlock (data, addr, &filterContext))
4093
- {
4094
- // Transition back to socketQueue to get the current delegate / delegateQueue
4095
- dispatch_async (socketQueue, ^{
4160
+ // Transition back to socketQueue to get the current delegate / delegateQueue
4161
+
4162
+ dispatch_async (socketQueue, ^{ @autoreleasepool {
4163
+
4164
+ pendingFilterOperations--;
4165
+
4166
+ if (allowed)
4167
+ {
4096
4168
[self notifyDidReceiveData: data fromAddress: addr withFilterContext: filterContext];
4097
- });
4098
- }
4169
+ }
4170
+
4171
+ if (flags & kReceiveOnce )
4172
+ {
4173
+ if (allowed)
4174
+ {
4175
+ // The delegate has been notified,
4176
+ // so our receive once operation has completed.
4177
+ flags &= ~kReceiveOnce ;
4178
+ }
4179
+ else if (pendingFilterOperations == 0 )
4180
+ {
4181
+ // All pending filter operations have completed,
4182
+ // and none were allowed through.
4183
+ // Our receive once operation hasn't completed yet.
4184
+ [self doReceive ];
4185
+ }
4186
+ }
4187
+ }});
4099
4188
4100
4189
}});
4101
4190
}
@@ -4124,7 +4213,25 @@ - (void)doReceive
4124
4213
}
4125
4214
else
4126
4215
{
4127
- [self doReceive ];
4216
+ if (flags & kReceiveContinuous )
4217
+ {
4218
+ // Continuous receive mode
4219
+ [self doReceive ];
4220
+ }
4221
+ else
4222
+ {
4223
+ // One-at-a-time receive mode
4224
+ if (ignoredDueToAddress)
4225
+ {
4226
+ [self doReceive ];
4227
+ }
4228
+ else if (pendingFilterOperations == 0 )
4229
+ {
4230
+ // The delegate has been notified (no set filter).
4231
+ // So our receive once operation has completed.
4232
+ flags &= ~kReceiveOnce ;
4233
+ }
4234
+ }
4128
4235
}
4129
4236
}
4130
4237
0 commit comments