Skip to content

Commit

Permalink
Merge pull request #746 from dsmurfin/master
Browse files Browse the repository at this point in the history
Fix for sending UDP multicast on IPv6
  • Loading branch information
chrisballinger committed Oct 30, 2020
2 parents 72e0fa9 + be19a56 commit 36ecfd0
Show file tree
Hide file tree
Showing 2 changed files with 127 additions and 0 deletions.
12 changes: 12 additions & 0 deletions Source/GCD/GCDAsyncUdpSocket.h
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,18 @@ typedef BOOL (^GCDAsyncUdpSocketSendFilterBlock)(NSData *data, NSData *address,
- (BOOL)leaveMulticastGroup:(NSString *)group error:(NSError **)errPtr;
- (BOOL)leaveMulticastGroup:(NSString *)group onInterface:(nullable NSString *)interface error:(NSError **)errPtr;

/**
* Send multicast on a specified interface.
* For IPv4, interface should be the the IP address of the interface (eg @"192.168.10.1").
* For IPv6, interface should be the a network interface name (eg @"en0").
*
* On success, returns YES.
* Otherwise returns NO, and sets errPtr. If you don't care about the error, you can pass nil for errPtr.
**/

- (BOOL)sendIPv4MulticastOnInterface:(NSString*)interface error:(NSError **)errPtr;
- (BOOL)sendIPv6MulticastOnInterface:(NSString*)interface error:(NSError **)errPtr;

#pragma mark Reuse Port

/**
Expand Down
115 changes: 115 additions & 0 deletions Source/GCD/GCDAsyncUdpSocket.m
Original file line number Diff line number Diff line change
Expand Up @@ -3531,6 +3531,121 @@ - (BOOL)performMulticastRequest:(int)requestType
return result;
}

- (BOOL)sendIPv4MulticastOnInterface:(NSString*)interface error:(NSError **)errPtr
{
__block BOOL result = NO;
__block NSError *err = nil;

dispatch_block_t block = ^{ @autoreleasepool {

if (![self preOp:&err])
{
return_from_block;
}

if ((self->flags & kDidCreateSockets) == 0)
{
if (![self createSockets:&err])
{
return_from_block;
}
}

// Convert interface to address

NSData *interfaceAddr4 = nil;
NSData *interfaceAddr6 = nil;

[self convertIntefaceDescription:interface port:0 intoAddress4:&interfaceAddr4 address6:&interfaceAddr6];

if (interfaceAddr4 == nil)
{
NSString *msg = @"Unknown interface. Specify valid interface by IP address.";
err = [self badParamError:msg];
return_from_block;
}

if (self->socket4FD != SOCKET_NULL) {
const struct sockaddr_in *nativeIface = (struct sockaddr_in *)[interfaceAddr4 bytes];
struct in_addr interface_addr = nativeIface->sin_addr;
int status = setsockopt(self->socket4FD, IPPROTO_IP, IP_MULTICAST_IF, &interface_addr, sizeof(interface_addr));
if (status != 0) {
err = [self errnoErrorWithReason:@"Error in setsockopt() function"];
return_from_block;
result = YES;
}
}

}};

if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
block();
else
dispatch_sync(socketQueue, block);

if (errPtr)
*errPtr = err;

return result;
}

- (BOOL)sendIPv6MulticastOnInterface:(NSString*)interface error:(NSError **)errPtr
{
__block BOOL result = NO;
__block NSError *err = nil;

dispatch_block_t block = ^{ @autoreleasepool {

if (![self preOp:&err])
{
return_from_block;
}

if ((self->flags & kDidCreateSockets) == 0)
{
if (![self createSockets:&err])
{
return_from_block;
}
}

// Convert interface to address

NSData *interfaceAddr4 = nil;
NSData *interfaceAddr6 = nil;

[self convertIntefaceDescription:interface port:0 intoAddress4:&interfaceAddr4 address6:&interfaceAddr6];

if (interfaceAddr6 == nil)
{
NSString *msg = @"Unknown interface. Specify valid interface by name (e.g. \"en1\").";
err = [self badParamError:msg];
return_from_block;
}

if ((self->socket6FD != SOCKET_NULL)) {
uint32_t scope_id = [self indexOfInterfaceAddr6:interfaceAddr6];
int status = setsockopt(self->socket6FD, IPPROTO_IPV6, IPV6_MULTICAST_IF, &scope_id, sizeof(scope_id));
if (status != 0) {
err = [self errnoErrorWithReason:@"Error in setsockopt() function"];
return_from_block;
}
result = YES;
}

}};

if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
block();
else
dispatch_sync(socketQueue, block);

if (errPtr)
*errPtr = err;

return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark Reuse port
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Expand Down

0 comments on commit 36ecfd0

Please sign in to comment.