//
// UIDevice-Reachability.h
// testSearchVC
//
// Created by mifit on 15/9/1.
// Copyright (c) 2015年 mifit. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface UIDevice(Reachability)
/// 本机名字
+ (NSString *) hostname;
/// 连接的wifi名字
+ (NSString *) wifiName;
/// 连接的WiFi ip
+ (NSString *) localWiFiIPAddress;
/// 是否连接到WLAN+ (BOOL) activeWLAN;
@end
//
// UIDevice-Reachability.m
// testSearchVC
//
// Created by mifit on 15/9/1.
// Copyright (c) 2015年 mifit. All rights reserved.
//
#include <unistd.h>
#include <sys/sysctl.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <netinet/in.h>
#include <ifaddrs.h>
#import <SystemConfiguration/CaptiveNetwork.h>
#import "wwanconnect.h"
#import "UIDevice-Reachability.h"
@implementation UIDevice(Reachability)
+ (NSString *)wifiName{
NSString *wifiName = nil;
CFArrayRef wifiInterfaces =CNCopySupportedInterfaces();
if (!wifiInterfaces) {
return nil;
}
NSArray *interfaces = (__bridgeNSArray *)wifiInterfaces;
for (NSString *interfaceNamein interfaces) {
CFDictionaryRef dictRef =CNCopyCurrentNetworkInfo((__bridgeCFStringRef)(interfaceName));
if (dictRef) {
NSDictionary *networkInfo = (__bridgeNSDictionary *)dictRef;
wifiName = [networkInfo objectForKey:(__bridgeNSString *)kCNNetworkInfoKeySSID];
CFRelease(dictRef);
}
}
CFRelease(wifiInterfaces);
return wifiName;
}
+ (NSString *) hostname{
char baseHostName[255];
int success = gethostname(baseHostName, 255);
if (success != 0) return nil;
baseHostName[255] = '\0';
#if !TARGET_IPHONE_SIMULATOR
return [NSStringstringWithFormat:@"%s.local", baseHostName];
#else
return [NSString stringWithFormat:@"%s", baseHostName];
#endif
}
// Direct from Apple. Thank you Apple
+ (BOOL)addressFromString:(NSString *)IPAddress address:(structsockaddr_in *)address{
if (!IPAddress || ![IPAddress length]) {
return NO;
}
memset((char *) address,sizeof(structsockaddr_in), 0);
address->sin_family = AF_INET;
address->sin_len = sizeof(struct sockaddr_in);
int conversionResult = inet_aton([IPAddress UTF8String], &address->sin_addr);
if (conversionResult == 0) {
NSAssert1(conversionResult !=1, @"Failed to convert the IP address string into a sockaddr_in: %@", IPAddress);
return NO;
}
return YES;
}
+ (NSString *) getIPAddressForHost: (NSString *) theHost{
structhostent *host = gethostbyname([theHostUTF8String]);
if (host == NULL) {
herror("resolv");
return NULL;
}
struct in_addr **list = (structin_addr **)host->h_addr_list;
NSString *addressString = [NSStringstringWithCString:inet_ntoa(*list[0])];
return addressString;
}
#if ! defined(IFT_ETHER)
#define IFT_ETHER 0x6 // Ethernet CSMACD
#endif
// Matt Brown's get WiFi IP addy solution
// Author gave permission to use in Cookbook under cookbook license
// http://mattbsoftware.blogspot.com/2009/04/how-to-get-ip-address-of-iphone-os-v221.html
+ (NSString *) localWiFiIPAddress{
BOOL success;
struct ifaddrs * addrs;
const structifaddrs * cursor;
success = getifaddrs(&addrs) == 0;
if (success) {
cursor = addrs;
while (cursor != NULL) {
// the second test keeps from picking up the loopback address
if (cursor->ifa_addr->sa_family ==AF_INET && (cursor->ifa_flags &IFF_LOOPBACK) == 0)
{
NSString *name = [NSStringstringWithUTF8String:cursor->ifa_name];
if ([name isEqualToString:@"en0"]) { // found the WiFi adapter
return [NSStringstringWithUTF8String:inet_ntoa(((structsockaddr_in *)cursor->ifa_addr)->sin_addr)];
}
}
cursor = cursor->ifa_next;
}
freeifaddrs(addrs);
}
return nil;
}
// Return the local IP address
+ (NSString *) localIPAddress{
structhostent *host = gethostbyname([[selfhostname] UTF8String]);
if (host == NULL)
{
herror("resolv");
return nil;
}
else {
struct in_addr **list = (structin_addr **)host->h_addr_list;
return [NSStringstringWithCString:inet_ntoa(*list[0])];
}
return nil;
}
+ (NSString *) whatismyipdotcom{
NSError *error;
NSURL *ipURL = [NSURLURLWithString:@"http://www.whatismyip.com/automation/n09230945.asp"];
NSString *ip = [NSStringstringWithContentsOfURL:ipURL encoding:1error:&error];
if (!ip) return [errorlocalizedDescription];
return ip;
}
+ (BOOL) activeWLAN{
return ([selflocalWiFiIPAddress] != nil);
}
#pragma mark Forcing WWAN connection
MyStreamInfoPtr myInfoPtr;
static void myClientCallback(void *refCon){
int *val = (int*)refCon;
printf("myClientCallback entered - value from refCon is %d\n", *val);
}
+ (void) forceWWAN{
int value = 0;
myInfoPtr = (MyStreamInfoPtr)StartWWAN(myClientCallback, &value);
if (myInfoPtr)
{
printf("Started WWAN\n");
}
else
{
printf("Failed to start WWAN\n");
}
}
+ (void) shutdownWWAN{
if (myInfoPtr)StopWWAN((MyInfoRef)myInfoPtr);
}
@end
//
// wwanconnect.h
// testSearchVC
//
// Created by mifit on 15/9/1.
// Copyright (c) 2015年 mifit. All rights reserved.
//
// Direct from Apple. Thank you Apple
// Direct from Apple. Thank you Apple
#if !defined(__WWAN_CONNECT__)
#define __WWAN_CONNECT__ 1
#include <CoreFoundation/CoreFoundation.h>
#include <assert.h>
#define kTestHost "www.whatismyip.com"
#define kTestPort 80
typedef void (*ConnectClientCallBack)(void *refCon);
struct MyStreamInfoStruct{
CFWriteStreamRefwStreamRef;
CFReadStreamRefrStreamRef;
ConnectClientCallBackclientCB;
void *refCon;
CFStreamErrorerror;
Boolean errorOccurred;
Boolean isConnected;
Boolean isStreamInitd;
Boolean isClientSet;
};
typedef structMyStreamInfoStruct MyStreamInfo;
typedef structMyStreamInfoStruct *MyStreamInfoPtr;
typedef struct__MyInfoRef *MyInfoRef;
/*
* StartWWAN()
*
* Discussion:
* This function will initiate a Wireless Wide Area Network (WWAN)
* connection by using the CFSocketStream API to connect with a
* server system defined by kTestHost:kTestPort above.
* No communications are expected to happen over the CFSocketStream
* connection.
*
* clientCB:
* if the connection is opened, the callback routine, if not NULL
* will be called. function defintion - see ConnectClientCallBack above
*
* refCon:
* if a client callback, clientCB is defined, then the refCon
* parameter will be the argument to the client callback
*
* return:
* if the WWAN connection is successful, a MyInfoRef value is returned
* The MyInfoRef value must be passed to StopWWAN to stop the WWAN
* connection.
* A NULL result indicates that the connection was unsuccessful
*
*/
extern MyInfoRef StartWWAN(ConnectClientCallBack clientCB,void *refCon);
/*
* StopWWAN()
*
* Discussion:
* This function closes the CFSocketStream which was used to establish the
* WWAN connection. Once the WWAN connection has been started, BSD
* network functions can be used to communicate across the WWAN connection.
* As of the writing of this sample, there is no guarantee that the use of
* only BSD socket API's will maintain the WWAN connection.
*
* infoRef:
* pass in the MyInfoRef result from the StartWWAN function.
*
*/
extern void StopWWAN(MyInfoRef infoRef);
#endif // __WWAN_CONNECT__
// Direct from Apple. Thank you Apple
#include "wwanconnect.h"
#include <CFNetwork/CFSocketStream.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <ifaddrs.h>
#include <stdio.h>
static Boolean TestGetIFAddrs(void);
static void MyCFWriteStreamClientCallBack(CFWriteStreamRef stream,CFStreamEventType type, void *clientCallBackInfo);
static void CleanupAfterWAAN(MyStreamInfoPtr myInfoPtr);
static void CloseStreams(MyStreamInfoPtr myInfoPtr);
static Boolean TestGetIFAddrs(void)
{
int result;
struct ifaddrs*ifbase, *ifiterator;
int done =0;
Boolean addrFound = FALSE;
char loopbackname[] = "lo0/0";
result = getifaddrs(&ifbase);
ifiterator = ifbase;
while (!done && (ifiterator != NULL))
{
if (ifiterator->ifa_addr->sa_family ==AF_INET)
{
if (memcmp(ifiterator->ifa_name, loopbackname,3))
{
structsockaddr *saddr, *netmask, *daddr;
saddr = ifiterator->ifa_addr;
netmask = ifiterator->ifa_netmask;
daddr = ifiterator->ifa_dstaddr;
// we've found an entry for the IP address
struct sockaddr_in *iaddr;
charaddrstr[64];
iaddr = (struct sockaddr_in *)saddr;
inet_ntop(saddr->sa_family, &iaddr->sin_addr, addrstr,sizeof(addrstr));
fprintf(stderr,"ipv4 interface name %s, source IP addr %s ", ifiterator->ifa_name, addrstr);
iaddr = (struct sockaddr_in *)netmask;
if (iaddr)
{
inet_ntop(saddr->sa_family, &iaddr->sin_addr, addrstr,sizeof(addrstr));
fprintf(stderr,"netmask IP addr %s ", addrstr);
}
iaddr = (struct sockaddr_in *)daddr;
if (iaddr)
{
inet_ntop(saddr->sa_family, &iaddr->sin_addr, addrstr,sizeof(addrstr));
fprintf(stderr,"dest/broadcast IP addr %s.\n\n", addrstr);
}
return TRUE;
}
}
else if (ifiterator->ifa_addr->sa_family ==AF_INET6)
{
// we've found an entry for the IP address
struct sockaddr_in6 *iaddr6 = (structsockaddr_in6 *)ifiterator->ifa_addr;
charaddrstr[256];
inet_ntop(ifiterator->ifa_addr->sa_family, iaddr6, addrstr,sizeof(addrstr));
fprintf(stderr,"ipv6 interface name %s, source IP addr %s \n\n", ifiterator->ifa_name, addrstr);
}
ifiterator = ifiterator->ifa_next;
}
if (ifbase)
freeifaddrs(ifbase);/* done with the memory allocated by getifaddrs */
return addrFound;
}
static void MyCFWriteStreamClientCallBack(CFWriteStreamRef stream,CFStreamEventType type, void *clientCallBackInfo)
{
MyStreamInfoPtrmyInfoPtr = (MyStreamInfoPtr) clientCallBackInfo;
printf("MyCFWriteStreamClientCallBack entered - event is %lu \n", type);
switch (type)
{
casekCFStreamEventOpenCompleted:
myInfoPtr->isConnected = TRUE;
TestGetIFAddrs();// call the test function to return the local ip address associated with this connection.
if (myInfoPtr->clientCB)
{
// call client callback routine
myInfoPtr->clientCB(myInfoPtr->refCon);
}
printf("write stream connected\n");
break;
casekCFStreamEventErrorOccurred:
myInfoPtr->errorOccurred = TRUE;
myInfoPtr->error = CFWriteStreamGetError(myInfoPtr->wStreamRef);
printf("write stream error %d .. giving up\n", myInfoPtr->error.error);
break;
default:
printf("event type %lu occurred\n",type);
break;
}
// stop the run loop at this point
CFRunLoopStop(CFRunLoopGetCurrent());
}
extern MyInfoRef StartWWAN(ConnectClientCallBack clientCB,void *refCon)
{
char host[] = kTestHost;
int portNum =kTestPort;
CFDataRef addressData;
MyStreamInfoPtrmyInfoPtr;
CFStreamClientContextctxt = {0, NULL, NULL, NULL, NULL};
Boolean errorOccurred = FALSE;
myInfoPtr = malloc(sizeof(MyStreamInfo));
if (!myInfoPtr)
{
return NULL;
}
// init the allocated memory
memset(myInfoPtr, 0, sizeof(MyStreamInfo));
myInfoPtr->clientCB = clientCB;
myInfoPtr->refCon = refCon;
ctxt.info = myInfoPtr;
// Check for a dotted-quad address, if so skip any host lookups
in_addr_t addr = inet_addr(host);
if (addr != INADDR_NONE) {
// Create the streams from numberical host
struct sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
sin.sin_len= sizeof(sin);
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = addr;
sin.sin_port = htons(portNum);
addressData = CFDataCreate(NULL, (UInt8 *)&sin,sizeof(sin));
CFSocketSignature sig = { AF_INET, SOCK_STREAM, IPPROTO_TCP, addressData };
// Create the streams.
CFStreamCreatePairWithPeerSocketSignature(kCFAllocatorDefault, &sig, &(myInfoPtr->rStreamRef), &(myInfoPtr->wStreamRef));
CFRelease(addressData);
} else {
// Create the streams from ascii host name
CFStringRef hostStr =CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, host,kCFStringEncodingUTF8, kCFAllocatorNull);
CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, hostStr, portNum, &(myInfoPtr->rStreamRef), &(myInfoPtr->wStreamRef));
}
myInfoPtr->isConnected = FALSE;
myInfoPtr->isStreamInitd = TRUE;
myInfoPtr->isClientSet = FALSE;
// Inform the streams to kill the socket when it is done with it.
// This effects the write stream too since the pair shares the
// one socket.
CFWriteStreamSetProperty(myInfoPtr->wStreamRef,kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
// set up the client
if (!CFWriteStreamSetClient(myInfoPtr->wStreamRef,kCFStreamEventOpenCompleted | kCFStreamEventErrorOccurred |kCFStreamEventEndEncountered,
MyCFWriteStreamClientCallBack, &ctxt))
{
printf("CFWriteStreamSetClient failed\n");
errorOccurred = TRUE;
}
else
myInfoPtr->isClientSet = TRUE;
if (!errorOccurred)
{
// schedule the stream
CFWriteStreamScheduleWithRunLoop(myInfoPtr->wStreamRef,CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
// Try to open the stream.
if (!CFWriteStreamOpen(myInfoPtr->wStreamRef))
{
printf("CFWriteStreamOpen failed\n");
errorOccurred = TRUE;
}
}
if (!errorOccurred)
{
// everything worked so far, so run the runloop - when the callback gets called, it will stop the run loop
printf("CFWriteStreamOpen returned with no error - calling CFRunLoopRun\n");
CFRunLoopRun();
if (myInfoPtr->errorOccurred)
errorOccurred = TRUE;
printf("after CFRunLoopRun - returning\n");
}
if (errorOccurred)
{
myInfoPtr->isConnected = FALSE;
CleanupAfterWAAN(myInfoPtr);
CloseStreams(myInfoPtr);
if (myInfoPtr->isStreamInitd)
{
CFRelease(myInfoPtr->rStreamRef);
CFRelease(myInfoPtr->wStreamRef);
myInfoPtr->isStreamInitd = FALSE;
}
free(myInfoPtr);
return NULL;
}
return (MyInfoRef)myInfoPtr;
}
static void CleanupAfterWAAN(MyStreamInfoPtr myInfoPtr)
{
assert(myInfoPtr != NULL);
if (myInfoPtr->isClientSet)
{
CFWriteStreamSetClient(myInfoPtr->wStreamRef,0, NULL, NULL);
CFWriteStreamUnscheduleFromRunLoop(myInfoPtr->wStreamRef,CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
myInfoPtr->isClientSet = FALSE;
}
}
static void CloseStreams(MyStreamInfoPtr myInfoPtr)
{
assert(myInfoPtr != NULL);
if (myInfoPtr->rStreamRef)
{
CFReadStreamClose(myInfoPtr->rStreamRef);
myInfoPtr->rStreamRef = NULL;
}
if (myInfoPtr->wStreamRef)
{
CFWriteStreamClose(myInfoPtr->wStreamRef);
myInfoPtr->wStreamRef = NULL;
}
}
extern void StopWWAN(MyInfoRef infoRef)
{
MyStreamInfoPtr myInfoPtr = (MyStreamInfoPtr)infoRef;
printf("stopWWAN entered\n");
assert(myInfoPtr != NULL);
myInfoPtr->isConnected = FALSE;
CleanupAfterWAAN(myInfoPtr);
CloseStreams(myInfoPtr);
free(myInfoPtr);
}