// // Beacon.m // // This class implements a simple UDP broadcast facilty for discovery of // devices on the same subnet. // // Created by Simon Urbanek on 2/6/12. // Copyright 2012 Simon Urbanek. All rights reserved. // #import "Beacon.h" #include #include #include #include #include // for now it uses static payload static const char beacon_pkt[] = "BEACON1!"; @implementation Beacon - (id) initWithPort: (int) beaconPort { self = [super init]; if (self != nil) { int broadcast = 1; send_sock = -1; active = 1; port = beaconPort; recv_sock = socket(AF_INET, SOCK_DGRAM, 0); if (recv_sock != -1) { setsockopt(recv_sock, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof (broadcast)); struct sockaddr_in saSocket; memset(&saSocket, 0, sizeof(saSocket)); saSocket.sin_family = AF_INET; saSocket.sin_addr.s_addr = htonl(INADDR_ANY); saSocket.sin_port = htons(port); bind(recv_sock, (struct sockaddr *) &saSocket, sizeof(saSocket)); [NSThread detachNewThreadSelector:@selector(receivingThread:) toTarget:self withObject:nil]; [NSThread detachNewThreadSelector:@selector(broadcastThread:) toTarget:self withObject:nil]; } } return self; } + (Beacon*) beaconWithPort: (int) port { Beacon *beacon = [[Beacon alloc] initWithPort:port]; if (beacon) [beacon autorelease]; return beacon; } - (void) sendBeaconTo: (struct in_addr) dstAddr { if (send_sock == -1) { int broadcast = 1; send_sock = socket(AF_INET, SOCK_DGRAM, 0); if (send_sock != -1) setsockopt(send_sock, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof (broadcast)); } if (send_sock != -1) { struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr = dstAddr; char dbuf[64]; NSLog(@" - sending beacon to %s", inet_ntop(addr.sin_family, &addr.sin_addr, dbuf, sizeof(dbuf))); sendto(send_sock, beacon_pkt, 8, 0, (struct sockaddr*) &addr, sizeof(addr)); } } - (void) broadcast { struct ifaddrs *ia, *root; if (!getifaddrs(&root)) { ia = root; while (ia) { NSLog(@"interface '%s', family: %d (expecting %d)", ia->ifa_name, ia->ifa_dstaddr ? ia->ifa_dstaddr->sa_family : -1, AF_INET); if (ia->ifa_dstaddr && ia->ifa_dstaddr->sa_family == AF_INET) [self sendBeaconTo:((struct sockaddr_in*)ia->ifa_dstaddr)->sin_addr]; ia = ia->ifa_next; } freeifaddrs(ia); } } - (void) receivingThread: (id) dummy { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; while (active) { char buf[64], dbuf[64]; struct sockaddr_in addr; socklen_t al = sizeof(addr); int n = recvfrom(recv_sock, buf, sizeof(buf), 0, (struct sockaddr*) &addr, &al); inet_ntop(addr.sin_family, &addr.sin_addr, dbuf, sizeof(dbuf)); NSLog(@" - received %d bytes from %s", n, dbuf); if (n == 8 && !memcmp(buf, beacon_pkt, 8) && delegate && [delegate respondsToSelector:@selector(didReceiveBeaconFrom:)]) [delegate performSelectorOnMainThread:@selector(didReceiveBeaconFrom:) withObject:[NSString stringWithUTF8String:dbuf] waitUntilDone:NO]; } [pool release]; } - (void) broadcastThread: (id) dummy { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; while (active) { [self broadcast]; [NSThread sleepForTimeInterval:10.0]; } [pool release]; } - (id) delegate { return delegate; } - (void) setDelegate: (id) newDelegate { if (delegate == newDelegate) return; if (delegate) [delegate release]; [delegate = newDelegate retain]; } #ifdef TEST_ME - (void) didReceiveBeaconFrom: (NSString*) src { NSLog(@"didReceiveBeaconFrom: %@", src); } #endif @end #ifdef TEST_ME int main(int ac, char**av) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; Beacon *beacon = [[Beacon alloc] initWithPort:12345]; [beacon setDelegate:beacon]; [[NSRunLoop currentRunLoop] run]; [pool release]; return 0; } #endif