2015-05-10 14:26:29 +00:00
|
|
|
//
|
|
|
|
// UdpSockets.m
|
|
|
|
// react-native-udp
|
|
|
|
//
|
|
|
|
// Created by Mark Vayngrib on 5/8/15.
|
|
|
|
// Copyright (c) 2015 Tradle, Inc. All rights reserved.
|
|
|
|
//
|
|
|
|
|
2017-02-10 04:23:08 +00:00
|
|
|
#import <React/RCTAssert.h>
|
|
|
|
#import <React/RCTBridge.h>
|
|
|
|
#import <React/RCTConvert.h>
|
|
|
|
#import <React/RCTEventDispatcher.h>
|
|
|
|
#import <React/RCTLog.h>
|
2015-05-10 14:26:29 +00:00
|
|
|
#import "UdpSockets.h"
|
|
|
|
#import "UdpSocketClient.h"
|
|
|
|
|
|
|
|
@implementation UdpSockets
|
2015-12-22 03:45:38 +00:00
|
|
|
{
|
|
|
|
NSMutableDictionary<NSNumber *, UdpSocketClient *> *_clients;
|
|
|
|
}
|
2015-05-10 14:26:29 +00:00
|
|
|
|
|
|
|
RCT_EXPORT_MODULE()
|
|
|
|
|
|
|
|
@synthesize bridge = _bridge;
|
|
|
|
|
2015-12-22 03:45:38 +00:00
|
|
|
- (void)dealloc
|
2015-10-12 16:29:39 +00:00
|
|
|
{
|
2015-12-22 03:45:38 +00:00
|
|
|
for (NSNumber *cId in _clients.allKeys) {
|
|
|
|
[self closeClient:cId callback:nil];
|
|
|
|
}
|
2015-10-12 16:29:39 +00:00
|
|
|
}
|
|
|
|
|
2015-12-22 03:45:38 +00:00
|
|
|
|
2015-09-17 19:52:02 +00:00
|
|
|
RCT_EXPORT_METHOD(createSocket:(nonnull NSNumber*)cId withOptions:(NSDictionary*)options)
|
2015-05-10 14:26:29 +00:00
|
|
|
{
|
|
|
|
if (!cId) {
|
|
|
|
RCTLogError(@"%@.createSocket called with nil id parameter.", [self class]);
|
|
|
|
return;
|
|
|
|
}
|
2015-09-17 19:52:02 +00:00
|
|
|
|
2015-12-22 03:45:38 +00:00
|
|
|
if (!_clients) {
|
|
|
|
_clients = [NSMutableDictionary new];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_clients[cId]) {
|
2015-05-10 14:26:29 +00:00
|
|
|
RCTLogError(@"%@.createSocket called twice with the same id.", [self class]);
|
|
|
|
return;
|
|
|
|
}
|
2015-09-17 19:52:02 +00:00
|
|
|
|
2015-12-22 03:45:38 +00:00
|
|
|
_clients[cId] = [UdpSocketClient socketClientWithConfig:self];
|
2015-05-10 14:26:29 +00:00
|
|
|
}
|
|
|
|
|
2015-09-17 19:52:02 +00:00
|
|
|
RCT_EXPORT_METHOD(bind:(nonnull NSNumber*)cId
|
2015-05-10 14:26:29 +00:00
|
|
|
port:(int)port
|
|
|
|
address:(NSString *)address
|
2017-08-22 07:17:03 +00:00
|
|
|
options:(NSDictionary *)options
|
2015-05-10 14:26:29 +00:00
|
|
|
callback:(RCTResponseSenderBlock)callback)
|
|
|
|
{
|
2015-12-22 03:45:38 +00:00
|
|
|
UdpSocketClient* client = [self findClient:cId callback:callback];
|
2015-05-10 14:26:29 +00:00
|
|
|
if (!client) return;
|
2015-09-17 19:52:02 +00:00
|
|
|
|
2015-05-10 14:26:29 +00:00
|
|
|
NSError *error = nil;
|
2017-08-22 07:17:03 +00:00
|
|
|
if (![client bind:port address:address options:options error:&error])
|
2015-05-10 14:26:29 +00:00
|
|
|
{
|
2015-12-31 06:51:26 +00:00
|
|
|
NSString *msg = error.localizedFailureReason ?: error.localizedDescription;
|
2015-12-31 16:39:33 +00:00
|
|
|
callback(@[msg ?: @"unknown error when binding"]);
|
2015-05-10 14:26:29 +00:00
|
|
|
return;
|
|
|
|
}
|
2015-09-17 19:52:02 +00:00
|
|
|
|
2015-05-10 14:26:29 +00:00
|
|
|
callback(@[[NSNull null], [client address]]);
|
|
|
|
}
|
|
|
|
|
2015-09-17 19:52:02 +00:00
|
|
|
RCT_EXPORT_METHOD(send:(nonnull NSNumber*)cId
|
2015-09-21 18:49:55 +00:00
|
|
|
string:(NSString*)base64String
|
2015-05-10 14:26:29 +00:00
|
|
|
port:(int)port
|
2015-09-21 18:49:55 +00:00
|
|
|
address:(NSString*)address
|
2015-05-10 14:26:29 +00:00
|
|
|
callback:(RCTResponseSenderBlock)callback) {
|
2015-12-22 03:45:38 +00:00
|
|
|
UdpSocketClient* client = [self findClient:cId callback:callback];
|
2015-05-10 14:26:29 +00:00
|
|
|
if (!client) return;
|
2015-05-16 15:45:11 +00:00
|
|
|
|
|
|
|
// iOS7+
|
|
|
|
// TODO: use https://github.com/nicklockwood/Base64 for compatibility with earlier iOS versions
|
|
|
|
NSData *data = [[NSData alloc] initWithBase64EncodedString:base64String options:0];
|
2015-05-10 14:26:29 +00:00
|
|
|
[client send:data remotePort:port remoteAddress:address callback:callback];
|
|
|
|
}
|
|
|
|
|
2015-09-17 19:52:02 +00:00
|
|
|
RCT_EXPORT_METHOD(close:(nonnull NSNumber*)cId
|
2015-05-10 14:26:29 +00:00
|
|
|
callback:(RCTResponseSenderBlock)callback) {
|
2015-12-22 03:45:38 +00:00
|
|
|
[self closeClient:cId callback:callback];
|
2015-05-10 14:26:29 +00:00
|
|
|
}
|
|
|
|
|
2015-09-17 19:52:02 +00:00
|
|
|
RCT_EXPORT_METHOD(setBroadcast:(nonnull NSNumber*)cId
|
2015-07-29 16:16:01 +00:00
|
|
|
flag:(BOOL)flag
|
|
|
|
callback:(RCTResponseSenderBlock)callback) {
|
2015-12-22 03:45:38 +00:00
|
|
|
UdpSocketClient* client = [self findClient:cId callback:callback];
|
2015-07-29 16:16:01 +00:00
|
|
|
if (!client) return;
|
|
|
|
|
|
|
|
NSError *error = nil;
|
|
|
|
if (![client setBroadcast:flag error:&error])
|
|
|
|
{
|
2015-12-31 06:51:26 +00:00
|
|
|
NSString *msg = error.localizedFailureReason ?: error.localizedDescription;
|
2015-12-31 16:39:33 +00:00
|
|
|
callback(@[msg ?: @"unknown error when setBroadcast"]);
|
2015-07-29 16:16:01 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
callback(@[[NSNull null]]);
|
|
|
|
}
|
|
|
|
|
2015-11-18 23:11:03 +00:00
|
|
|
RCT_EXPORT_METHOD(addMembership:(nonnull NSNumber*)cId
|
|
|
|
multicastAddress:(NSString *)address) {
|
2016-11-10 17:49:33 +00:00
|
|
|
UdpSocketClient *client = _clients[cId];
|
|
|
|
|
|
|
|
if (!client) return;
|
|
|
|
|
|
|
|
NSError *error = nil;
|
|
|
|
[client joinMulticastGroup:address error:&error];
|
2015-11-18 23:11:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
RCT_EXPORT_METHOD(dropMembership:(nonnull NSNumber*)cId
|
|
|
|
multicastAddress:(NSString *)address) {
|
2016-11-10 17:49:33 +00:00
|
|
|
UdpSocketClient *client = _clients[cId];
|
|
|
|
|
|
|
|
if (!client) return;
|
|
|
|
|
|
|
|
NSError *error = nil;
|
|
|
|
[client leaveMulticastGroup:address error:&error];
|
2015-11-18 23:11:03 +00:00
|
|
|
}
|
|
|
|
|
2015-05-10 14:26:29 +00:00
|
|
|
- (void) onData:(UdpSocketClient*) client data:(NSData *)data host:(NSString *)host port:(uint16_t)port
|
|
|
|
{
|
2015-12-16 19:47:43 +00:00
|
|
|
NSNumber *clientID = [[_clients allKeysForObject:client] objectAtIndex:0];
|
2015-05-16 15:45:11 +00:00
|
|
|
NSString *base64String = [data base64EncodedStringWithOptions:0];
|
2015-05-10 14:26:29 +00:00
|
|
|
[self.bridge.eventDispatcher sendDeviceEventWithName:[NSString stringWithFormat:@"udp-%@-data", clientID]
|
|
|
|
body:@{
|
2015-05-16 15:45:11 +00:00
|
|
|
@"data": base64String,
|
2015-05-10 14:26:29 +00:00
|
|
|
@"address": host,
|
|
|
|
@"port": [NSNumber numberWithInt:port]
|
|
|
|
}
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
2015-12-22 03:45:38 +00:00
|
|
|
-(UdpSocketClient*)findClient:(nonnull NSNumber*)cId callback:(RCTResponseSenderBlock)callback
|
2015-05-10 14:26:29 +00:00
|
|
|
{
|
2015-12-22 03:45:38 +00:00
|
|
|
UdpSocketClient *client = _clients[cId];
|
2015-05-10 14:26:29 +00:00
|
|
|
if (!client) {
|
|
|
|
if (!callback) {
|
|
|
|
RCTLogError(@"%@.missing callback parameter.", [self class]);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
callback(@[[NSString stringWithFormat:@"no client found with id %@", cId]]);
|
|
|
|
}
|
2015-09-17 19:52:02 +00:00
|
|
|
|
2015-05-10 14:26:29 +00:00
|
|
|
return nil;
|
|
|
|
}
|
2015-09-17 19:52:02 +00:00
|
|
|
|
2015-05-10 14:26:29 +00:00
|
|
|
return client;
|
|
|
|
}
|
|
|
|
|
2015-12-22 03:45:38 +00:00
|
|
|
-(void) closeClient:(nonnull NSNumber*)cId
|
2015-10-12 16:29:39 +00:00
|
|
|
callback:(RCTResponseSenderBlock)callback
|
|
|
|
{
|
2015-12-22 03:45:38 +00:00
|
|
|
UdpSocketClient* client = [self findClient:cId callback:callback];
|
2015-10-12 16:29:39 +00:00
|
|
|
if (!client) return;
|
|
|
|
|
2015-12-22 03:45:38 +00:00
|
|
|
client.clientDelegate = nil;
|
2015-10-12 16:29:39 +00:00
|
|
|
[client close];
|
|
|
|
[_clients removeObjectForKey:cId];
|
|
|
|
|
|
|
|
if (callback) callback(@[]);
|
|
|
|
}
|
|
|
|
|
2015-05-10 14:26:29 +00:00
|
|
|
@end
|