|
|
@@ -35,6 +35,7 @@ void MACAddress::findAllAddresses (Array<MACAddress>& result) |
|
|
|
for (const ifaddrs* cursor = addrs; cursor != nullptr; cursor = cursor->ifa_next)
|
|
|
|
{
|
|
|
|
sockaddr_storage* sto = (sockaddr_storage*) cursor->ifa_addr;
|
|
|
|
|
|
|
|
if (sto->ss_family == AF_LINK)
|
|
|
|
{
|
|
|
|
const sockaddr_dl* const sadd = (const sockaddr_dl*) cursor->ifa_addr;
|
|
|
@@ -45,7 +46,7 @@ void MACAddress::findAllAddresses (Array<MACAddress>& result) |
|
|
|
|
|
|
|
if (sadd->sdl_type == IFT_ETHER)
|
|
|
|
{
|
|
|
|
MACAddress ma (MACAddress (((const uint8*) sadd->sdl_data) + sadd->sdl_nlen));
|
|
|
|
MACAddress ma (((const uint8*) sadd->sdl_data) + sadd->sdl_nlen);
|
|
|
|
|
|
|
|
if (! ma.isNull())
|
|
|
|
result.addIfNotAlreadyThere (ma);
|
|
|
@@ -109,7 +110,7 @@ bool JUCE_CALLTYPE Process::openEmailWithAttachments (const String& targetEmailA |
|
|
|
}
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
class URLConnectionState : public Thread
|
|
|
|
class URLConnectionState : private Thread
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
URLConnectionState (NSURLRequest* req, const int maxRedirects)
|
|
|
@@ -117,7 +118,8 @@ public: |
|
|
|
contentLength (-1),
|
|
|
|
delegate (nil),
|
|
|
|
request ([req retain]),
|
|
|
|
connection (nil),
|
|
|
|
session (nil),
|
|
|
|
task (nil),
|
|
|
|
data ([[NSMutableData data] retain]),
|
|
|
|
headers (nil),
|
|
|
|
statusCode (0),
|
|
|
@@ -136,10 +138,10 @@ public: |
|
|
|
~URLConnectionState()
|
|
|
|
{
|
|
|
|
stop();
|
|
|
|
[connection release];
|
|
|
|
[data release];
|
|
|
|
[request release];
|
|
|
|
[headers release];
|
|
|
|
[session release];
|
|
|
|
[delegate release];
|
|
|
|
}
|
|
|
|
|
|
|
@@ -150,18 +152,20 @@ public: |
|
|
|
while (isThreadRunning() && ! initialised)
|
|
|
|
{
|
|
|
|
if (callback != nullptr)
|
|
|
|
callback (context, latestTotalBytes, (int) [[request HTTPBody] length]);
|
|
|
|
callback (context, (int) latestTotalBytes, (int) [[request HTTPBody] length]);
|
|
|
|
|
|
|
|
Thread::sleep (1);
|
|
|
|
}
|
|
|
|
|
|
|
|
return connection != nil && ! hasFailed;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void stop()
|
|
|
|
{
|
|
|
|
[connection cancel];
|
|
|
|
[task cancel];
|
|
|
|
stopThread (10000);
|
|
|
|
[task release];
|
|
|
|
task = nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
int read (char* dest, int numBytes)
|
|
|
@@ -194,7 +198,7 @@ public: |
|
|
|
return numDone;
|
|
|
|
}
|
|
|
|
|
|
|
|
void didReceiveResponse (NSURLResponse* response)
|
|
|
|
void didReceiveResponse (NSURLResponse* response, id completionHandler)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
const ScopedLock sl (dataLock);
|
|
|
@@ -214,22 +218,17 @@ public: |
|
|
|
}
|
|
|
|
|
|
|
|
initialised = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
NSURLRequest* willSendRequest (NSURLRequest* newRequest, NSURLResponse* redirectResponse)
|
|
|
|
{
|
|
|
|
if (redirectResponse != nullptr)
|
|
|
|
if (completionHandler != nil)
|
|
|
|
{
|
|
|
|
if (numRedirects >= numRedirectsToFollow)
|
|
|
|
return nil; // Cancel redirect and allow connection to continue
|
|
|
|
|
|
|
|
++numRedirects;
|
|
|
|
// Need to wrangle this parameter back into an obj-C block,
|
|
|
|
// and call it to allow the transfer to continue..
|
|
|
|
void (^callbackBlock)(NSURLSessionResponseDisposition) = completionHandler;
|
|
|
|
callbackBlock (NSURLSessionResponseAllow);
|
|
|
|
}
|
|
|
|
|
|
|
|
return newRequest;
|
|
|
|
}
|
|
|
|
|
|
|
|
void didFailWithError (NSError* error)
|
|
|
|
void didBecomeInvalidWithError (NSError* error)
|
|
|
|
{
|
|
|
|
DBG (nsStringToJuce ([error description])); ignoreUnused (error);
|
|
|
|
hasFailed = true;
|
|
|
@@ -244,60 +243,67 @@ public: |
|
|
|
initialised = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void didSendBodyData (NSInteger totalBytesWritten, NSInteger /*totalBytesExpected*/)
|
|
|
|
void didSendBodyData (int64_t totalBytesWritten)
|
|
|
|
{
|
|
|
|
latestTotalBytes = static_cast<int> (totalBytesWritten);
|
|
|
|
}
|
|
|
|
|
|
|
|
void finishedLoading()
|
|
|
|
{
|
|
|
|
hasFinished = true;
|
|
|
|
initialised = true;
|
|
|
|
signalThreadShouldExit();
|
|
|
|
}
|
|
|
|
|
|
|
|
void run() override
|
|
|
|
{
|
|
|
|
connection = [[NSURLConnection alloc] initWithRequest: request
|
|
|
|
delegate: delegate];
|
|
|
|
jassert (task == nil && session == nil);
|
|
|
|
|
|
|
|
session = [[NSURLSession sessionWithConfiguration: [NSURLSessionConfiguration defaultSessionConfiguration]
|
|
|
|
delegate: delegate
|
|
|
|
delegateQueue: [NSOperationQueue currentQueue]] retain];
|
|
|
|
|
|
|
|
task = [session dataTaskWithRequest: request];
|
|
|
|
|
|
|
|
if (task == nil)
|
|
|
|
return;
|
|
|
|
|
|
|
|
[task retain];
|
|
|
|
[task resume];
|
|
|
|
|
|
|
|
while (! threadShouldExit())
|
|
|
|
{
|
|
|
|
JUCE_AUTORELEASEPOOL
|
|
|
|
{
|
|
|
|
[[NSRunLoop currentRunLoop] runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.01]];
|
|
|
|
}
|
|
|
|
wait (5);
|
|
|
|
|
|
|
|
if (task.state != NSURLSessionTaskStateRunning)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
hasFinished = true;
|
|
|
|
initialised = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
int64 contentLength;
|
|
|
|
CriticalSection dataLock;
|
|
|
|
NSObject* delegate;
|
|
|
|
id delegate;
|
|
|
|
NSURLRequest* request;
|
|
|
|
NSURLConnection* connection;
|
|
|
|
NSURLSession* session;
|
|
|
|
NSURLSessionTask* task;
|
|
|
|
NSMutableData* data;
|
|
|
|
NSDictionary* headers;
|
|
|
|
int statusCode;
|
|
|
|
bool initialised, hasFailed, hasFinished;
|
|
|
|
const int numRedirectsToFollow;
|
|
|
|
int numRedirects;
|
|
|
|
int latestTotalBytes;
|
|
|
|
int64 latestTotalBytes;
|
|
|
|
|
|
|
|
private:
|
|
|
|
//==============================================================================
|
|
|
|
struct DelegateClass : public ObjCClass<NSObject>
|
|
|
|
{
|
|
|
|
DelegateClass() : ObjCClass<NSObject> ("JUCEAppDelegate_")
|
|
|
|
DelegateClass() : ObjCClass<NSObject> ("JUCE_URLDelegate_")
|
|
|
|
{
|
|
|
|
addIvar<URLConnectionState*> ("state");
|
|
|
|
|
|
|
|
addMethod (@selector (connection:didReceiveResponse:), didReceiveResponse, "v@:@@");
|
|
|
|
addMethod (@selector (connection:didFailWithError:), didFailWithError, "v@:@@");
|
|
|
|
addMethod (@selector (connection:didReceiveData:), didReceiveData, "v@:@@");
|
|
|
|
addMethod (@selector (connection:didSendBodyData:totalBytesWritten:totalBytesExpectedToWrite:),
|
|
|
|
connectionDidSendBodyData, "v@:@iii");
|
|
|
|
addMethod (@selector (connectionDidFinishLoading:), connectionDidFinishLoading, "v@:@");
|
|
|
|
addMethod (@selector (connection:willSendRequest:redirectResponse:), willSendRequest, "@@:@@@");
|
|
|
|
|
|
|
|
addMethod (@selector (URLSession:dataTask:didReceiveResponse:completionHandler:),
|
|
|
|
didReceiveResponse, "v@:@@@@");
|
|
|
|
addMethod (@selector (URLSession:didBecomeInvalidWithError:), didBecomeInvalidWithError, "v@:@@");
|
|
|
|
addMethod (@selector (URLSession:dataTask:didReceiveData:), didReceiveData, "v@:@@@");
|
|
|
|
addMethod (@selector (URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:),
|
|
|
|
didSendBodyData, "v@:@@qqq");
|
|
|
|
registerClass();
|
|
|
|
}
|
|
|
|
|
|
|
@@ -305,34 +311,24 @@ private: |
|
|
|
static URLConnectionState* getState (id self) { return getIvar<URLConnectionState*> (self, "state"); }
|
|
|
|
|
|
|
|
private:
|
|
|
|
static void didReceiveResponse (id self, SEL, NSURLConnection*, NSURLResponse* response)
|
|
|
|
static void didReceiveResponse (id self, SEL, NSURLSession*, NSURLSessionDataTask*, NSURLResponse* response, id completionHandler)
|
|
|
|
{
|
|
|
|
getState (self)->didReceiveResponse (response);
|
|
|
|
getState (self)->didReceiveResponse (response, completionHandler);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void didFailWithError (id self, SEL, NSURLConnection*, NSError* error)
|
|
|
|
static void didBecomeInvalidWithError (id self, SEL, NSURLSession*, NSError* error)
|
|
|
|
{
|
|
|
|
getState (self)->didFailWithError (error);
|
|
|
|
getState (self)->didBecomeInvalidWithError (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void didReceiveData (id self, SEL, NSURLConnection*, NSData* newData)
|
|
|
|
static void didReceiveData (id self, SEL, NSURLSession*, NSURLSessionDataTask*, NSData* newData)
|
|
|
|
{
|
|
|
|
getState (self)->didReceiveData (newData);
|
|
|
|
}
|
|
|
|
|
|
|
|
static NSURLRequest* willSendRequest (id self, SEL, NSURLConnection*, NSURLRequest* request, NSURLResponse* response)
|
|
|
|
static void didSendBodyData (id self, SEL, NSURLSession*, NSURLSessionTask*, int64_t, int64_t totalBytesWritten, int64_t)
|
|
|
|
{
|
|
|
|
return getState (self)->willSendRequest (request, response);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void connectionDidSendBodyData (id self, SEL, NSURLConnection*, NSInteger, NSInteger totalBytesWritten, NSInteger totalBytesExpected)
|
|
|
|
{
|
|
|
|
getState (self)->didSendBodyData (totalBytesWritten, totalBytesExpected);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void connectionDidFinishLoading (id self, SEL, NSURLConnection*)
|
|
|
|
{
|
|
|
|
getState (self)->finishedLoading();
|
|
|
|
getState (self)->didSendBodyData (totalBytesWritten);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
@@ -433,14 +429,11 @@ private: |
|
|
|
{
|
|
|
|
jassert (connection == nullptr);
|
|
|
|
|
|
|
|
NSMutableURLRequest* req = [NSMutableURLRequest requestWithURL: [NSURL URLWithString: juceStringToNS (address)]
|
|
|
|
cachePolicy: NSURLRequestReloadIgnoringLocalCacheData
|
|
|
|
timeoutInterval: timeOutMs <= 0 ? 60.0 : (timeOutMs / 1000.0)];
|
|
|
|
|
|
|
|
if (req != nil)
|
|
|
|
if (NSMutableURLRequest* req = [NSMutableURLRequest requestWithURL: [NSURL URLWithString: juceStringToNS (address)]
|
|
|
|
cachePolicy: NSURLRequestReloadIgnoringLocalCacheData
|
|
|
|
timeoutInterval: timeOutMs <= 0 ? 60.0 : (timeOutMs / 1000.0)])
|
|
|
|
{
|
|
|
|
[req setHTTPMethod: [NSString stringWithUTF8String: httpRequestCmd.toRawUTF8()]];
|
|
|
|
//[req setCachePolicy: NSURLRequestReloadIgnoringLocalAndRemoteCacheData];
|
|
|
|
|
|
|
|
StringArray headerLines;
|
|
|
|
headerLines.addLines (headers);
|
|
|
@@ -448,8 +441,8 @@ private: |
|
|
|
|
|
|
|
for (int i = 0; i < headerLines.size(); ++i)
|
|
|
|
{
|
|
|
|
const String key (headerLines[i].upToFirstOccurrenceOf (":", false, false).trim());
|
|
|
|
const String value (headerLines[i].fromFirstOccurrenceOf (":", false, false).trim());
|
|
|
|
String key = headerLines[i].upToFirstOccurrenceOf (":", false, false).trim();
|
|
|
|
String value = headerLines[i].fromFirstOccurrenceOf (":", false, false).trim();
|
|
|
|
|
|
|
|
if (key.isNotEmpty() && value.isNotEmpty())
|
|
|
|
[req addValue: juceStringToNS (value) forHTTPHeaderField: juceStringToNS (key)];
|
|
|
|