Client cannot receive image data from gcdwebserver - objective-c

I try to create a web server on iPhone to provide urls of images in ablum.
Before sending response to client, I need to do some adjustment on images (something like re-size).
These actions take up to 1 or 1.5 sec per image before response to client. (especially on iPhone 4)
The client side cannot receive data even though messages on xcode console already showed how many bytes has been GET on some sockets.
What options can I use to solve this problem?
Another question is what happens if I increase ConnectedStateCoalescingInterval value up to 2.0 or 3.0 seconds?
Thanks.
========= 2015/08/24 13:05 Updated
Here is my addHandlerForMethod:path:requestClass:asyncProcessBlock:
[_webServer addHandlerForMethod:#"GET" path:[NSString stringWithFormat:#"/image/%#",assetId] requestClass:[GCDWebServerRequest class] asyncProcessBlock:^(GCDWebServerRequest *request, GCDWebServerCompletionBlock completionBlock)
{
__strong typeof(weakself) strongself = weakself;
[strongself requestImageDataByAssetURL:assetURL completionCb:^(NSData *photoData) {
GCDWebServerDataResponse* response = [GCDWebServerDataResponse responseWithData:photoData contentType:#"image/png"];
completionBlock(response);
}];
}];
Here is requestImageDataByAssetURL:completionCb:
- (void)requestImageDataByAssetURL:(NSURL *)assetURL completionCb:(void(^)(NSData *photoData))cbfunc {
__block NSData *photoData;
ALAssetsLibrary* library = [[ALAssetsLibrary alloc] init];
[library assetForURL:assetURL resultBlock:^(ALAsset *asset) {
#autoreleasepool {
uint64_t begin = mach_absolute_time();
// <do some image processing here>
uint64_t end = mach_absolute_time();
NSLog(#"Time taken to imageResize %g s", MachTimeToSecs(end - begin));
cbfunc(photoData);
}
} failureBlock:^(NSError *error) {
NSLog(#"[%#] fail. Error=%#", NSStringFromSelector(_cmd), error.localizedDescription);
cbfunc(nil);
}];
}
Here is the log:
[DEBUG] [2015-08-24 04:48:09 +0000] Did open connection on socket 32
[DEBUG] Connection received 221 bytes on socket 32
[DEBUG] Connection on socket 32 preflighting request "GET /image/9D959040-9FA8-4197-8150-8DC72339955D" with 221 bytes body
[DEBUG] Connection on socket 32 processing request "GET /image/9D959040-9FA8-4197-8150-8DC72339955D" with 221 bytes body
[DEBUG] [2015-08-24 04:48:10 +0000] Did open connection on socket 34
2015-08-24 12:48:10.799 xBoard[2981:3707] Time taken to imageResize 1.52039 s
[DEBUG] Connection received 221 bytes on socket 34
[DEBUG] Connection on socket 34 preflighting request "GET /image/9D959040-9FA8-4197-8150-8DC72339955D" with 221 bytes body
[DEBUG] Connection on socket 34 processing request "GET /image/9D959040-9FA8-4197-8150-8DC72339955D" with 221 bytes body
[DEBUG] Connection sent 171 bytes on socket 32
[DEBUG] Connection sent 123575 bytes on socket 32
[DEBUG] Did close connection on socket 32
[VERBOSE] [172.16.20.174:8080] 172.16.21.97:34450 200 "GET /image/9D959040-9FA8-4197-8150-8DC72339955D" (221 | 123746)
2015-08-24 12:48:12.028 xBoard[2981:4f0b] Time taken to imageResize 1.06382 s
[DEBUG] Connection sent 171 bytes on socket 34
[DEBUG] Connection sent 123575 bytes on socket 34
[DEBUG] Did close connection on socket 34
[VERBOSE] [172.16.20.174:8080] 172.16.21.97:50852 200 "GET /image/9D959040-9FA8-4197-8150-8DC72339955D" (221 | 123746)
We can see it creates the first socket(32).
Then creates the second socket(34) for the same image request immediately.
It seems that GCDWebServer close the first socket immediately. But why?
P.S. By the way, the client side use Android Volley library to download image instead of using web browsers.

There doesn't seem to be anything wrong according to the log: 2 GET requests for the path /image/9D959040-9FA8-4197-8150-8DC72339955D are processed on sockets 32 and 34, and each return 123,575 bytes.
Try using a desktop web browser like Chrome and its web inspector. If everything works correctly, then the problem is with your Android app.

Related

arduino gets response 301 when making a HTTPS GET request

I am making a simple arduino app that send a GET request to a HTTPS site. The code I'm using is exactly the same as the code in the MKRGSM library examples (GsmSslWebClient). But for whatever reason I always get the same response when connecting to a HTTPS site: "301 moved permanently". I kind of know what that means, I am aware that you are supposed to just make another request to the location specified in the header. But I don't know what I have to change to be able to address a https site. I'm sorry for my ignorance and I do know that in the example it clearly states that it connects to http://www.arduino.cc/asciilogo.txt but why is it then any different than the normal http example?
I would also point out here, that I have tried changing port to 80 and client settings, to work for unprotected http which works just fine. So its just the https that doesn't work.
this is the code:
/*
Web client
This sketch connects to a website using SSL through a MKR GSM 1400 board. Specifically,
this example downloads the URL "http://www.arduino.cc/asciilogo.txt" and
prints it to the Serial monitor.
Circuit:
* MKR GSM 1400 board
* Antenna
* SIM card with a data plan
created 8 Mar 2012
by Tom Igoe
*/
// libraries
#include <MKRGSM.h>
#include "arduino_secrets.h"
// Please enter your sensitive data in the Secret tab or arduino_secrets.h
// PIN Number
const char PINNUMBER[] = SECRET_PINNUMBER;
// APN data
const char GPRS_APN[] = SECRET_GPRS_APN;
const char GPRS_LOGIN[] = SECRET_GPRS_LOGIN;
const char GPRS_PASSWORD[] = SECRET_GPRS_PASSWORD;
// initialize the library instance
GSMSSLClient client;
GPRS gprs;
GSM gsmAccess;
// URL, path and port (for example: arduino.cc)
char server[] = "arduino.cc";
char path[] = "/asciilogo.txt";
int port = 443; // port 443 is the default for HTTPS
void setup() {
// initialize serial communications and wait for port to open:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
Serial.println("Starting Arduino web client.");
// connection state
bool connected = false;
// After starting the modem with GSM.begin()
// attach the shield to the GPRS network with the APN, login and password
while (!connected) {
if ((gsmAccess.begin(PINNUMBER) == GSM_READY) &&
(gprs.attachGPRS(GPRS_APN, GPRS_LOGIN, GPRS_PASSWORD) == GPRS_READY)) {
connected = true;
} else {
Serial.println("Not connected");
delay(1000);
}
}
Serial.println("connecting...");
// if you get a connection, report back via serial:
if (client.connect(server, port)) {
Serial.println("connected");
// Make a HTTP request:
client.print("GET ");
client.print(path);
client.println(" HTTP/1.1");
client.print("Host: ");
client.println(server);
client.println("Connection: close");
client.println();
} else {
// if you didn't get a connection to the server:
Serial.println("connection failed");
}
}
void loop() {
// if there are incoming bytes available
// from the server, read them and print them:
if (client.available()) {
char c = client.read();
Serial.print(c);
}
// if the server's disconnected, stop the client:
if (!client.available() && !client.connected()) {
Serial.println();
Serial.println("disconnecting.");
client.stop();
// do nothing forevermore:
for (;;)
;
}
}
and this is the output:
Starting Arduino web client.
connecting...
connected
HTTP/1.1 301 Moved Permanently
Server: nginx
Date: Thu, 19 Nov 2020 20:24:07 GMT
Content-Type: text/html
Content-Length: 178
Connection: close
Location: https://www.arduino.cc/asciilogo.txt
Strict-Transport-Security: max-age=500; includeSubDomains
X-Frame-Options: SAMEORIGIN
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
<html>
<head><title>301 Moved Permanently</title></head>
<body bgcolor="white">
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx</center>
</body>
</html>
disconnecting.
It is also possible that I'm just stupid and the answer is clear as day, but if somebody could please tell me exactly what to do, maybe even put an example, that would be greatly appreciated.
I haven't really tried much except changing the setting to see if they work for normal http and some other libraries that worked even worse. Sadly that's all I could find on the internet since I'm not that skilled to be messing with libraries on my own. I am using arduino mkr gsm 1400.
Be sure to call me out if I missed to mention any detail that could help solving this issue
Thanks to anybody that can help me in advance.

SSL_error_SSL error on tls_read

In a production setup, randomly a opensips error comes up indicating tls_read failed due to SSL_error_SSL error.
Opensips fails the tls/tcp session and a new session is created and it works fine.
Please provide any pointers on why tls_read would fail with ssl_error_ssl return code.
Opensips code invokes,
ssl = c->extra_data;
ret = SSL_read(ssl, buf, len);
if (ret >0)
{
}
else
{
err = SSL_get_error(ssl, ret);
switch (err) {
case SSL_ERROR_ZERO_RETURN:
LM_INFO("TLS connection to %s:%d closed cleanly\n",
ip_addr2a(&c->rcv.src_ip), c->rcv.src_port);
/*
* mark end of file
*/
c->state = S_CONN_EOF;
return 0;
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
return 0;
case SSL_ERROR_SYSCALL:
LM_ERR("SYSCALL error -> (%d) <%s>\n",errno,strerror(errno));
default:
LM_ERR("TLS connection to %s:%d read failed\n", ip_addr2a(&c->rcv.src_ip), c->rcv.src_port);
LM_ERR("TLS read error: %d\n",err);
c->state = S_CONN_BAD;
tls_print_errstack();
return -1;
}
I want to highlight that TLS connection was established fine and a message is successfully received and send. When the second message is received and SSL_read is invoked there is below error,
2018-05-11T11:23:16.000-04:00 [local2] [err] ffd-alpha-zone1-ccm1.ipc.com /usr/sbin/opensipsInternal[10325]: ERROR:core:_tls_read: TLS connection to 10.204.34.62:51519 read failed
2018-05-11T11:23:16.000-04:00 [local2] [err] ffd-alpha-zone1-ccm1.ipc.com /usr/sbin/opensipsInternal[10325]: ERROR:core:_tls_read: TLS read error: 1
2018-05-11T11:23:16.000-04:00 [local2] [err] ffd-alpha-zone1-ccm1.ipc.com /usr/sbin/opensipsInternal[10325]: ERROR:core:tls_print_errstack: TLS errstack: error:140890B2:SSL routines:SSL3_GET_CLIENT_CERTIFICATE:no certificate returned
In the pcap, there is re-transmission of every tls packet both sides and when this packet is read, there seems the packet is the second portion of fragemented packet.
Thanks,

Inserting client certificates into an HTTPS POST request

I'm building a hardware device which connects to the AWS IOT platform. According to the documentation the authentication with the aws iot platform is done with TLS. I have the Root CA, client key and client certificate files on the device that authorize the access. Is there a way to use these files in the HTTP header while making the POST request? If so, how? So far here is the code for the Energia IDE (based on the Arduino IDE) and using the WiFiClient methods.
if (client.sslConnect(aws_endpoint, 443))
{
Serial.println("\nConnected to AWS endpoint");
String PostData = "{\"value1\" : \"testValue\", \"value2\" : \"Hello\", \"value3\" : \"World!\" }";
request = "POST /things/";
request += thingname;
request += "/shadow";
request += " HTTP/1.1";
Serial.print("Request:\t"); Serial.println(request);
Serial.print("Post data:\t"); Serial.println(PostData);
client.println(request);
client.println("Host: ");
client.println(aws_endpoint);
client.println(":443");
client.println("User-Agent: Energia/1.1");
client.println("Connection: close");
client.println("Content-Type: application/json");
client.print("Content-Length: "); client.println(PostData.length());
client.println();
client.println(PostData);
client.println();
}
else
{
Serial.println("Connection failed");
}
Serial.println();
Serial.println("Server response:");
Serial.println();
// Capture response from the server. (10 second timeout)
long timeOut = 5000;
long lastTime = millis();
while((millis()-lastTime) < timeOut)
{ // Wait for incoming response from server
while (client.available())
{ // Characters incoming from the server
char c = client.read(); // Read characters
Serial.write(c);
}
}
This however, gives an authentication error:
HTTP/1.1 403 Forbidden
content-type: application/json
content-length: 91
date: Tue, 26 Jul 2016 11:46:59 GMT
x-amzn-RequestId: 4d5388a9-e3c4-460a-b674-c3f971f3330d
connection: Keep-Alive
x-amzn-ErrorType: ForbiddenException:
{"message":"Missing Authentication Token","traceId":"4d5388a9-e3c4-460a-b674-c3f971f3330d"}
The TLS client certificates would be sent/used as part of your client.sslConnect() call, not as part of the HTTP request. The TLS handshake (and exchange/validation of client and server certificates) happens before any HTTP message is sent.
This AWS forums post suggests that you may need to be using port 8443 (not port 443), for the shadow API. It looks like the use/requirement of TLS mutual authentication (via certificates), versus the use of AWS SIGv4 headers, is determined by AWS IOT based on the port used.
Hope this helps!

fail to forward bye when using mobicents proxy

when testing proxy in mobicents, mobicents cannot forward bye message to the other one.
when one user send bye, it just receives 481 and the other user remains in talking.
Such exception only occurs when call duration >= 10s.
and i can see that sip application session is closed before user send bye. i dont konw how to avoid this.
please help me !!!
below is my test code:
#Override
protected void doInvite(SipServletRequest request) throws ServletException, IOException {
List<SipURI> forks = new ArrayList<SipURI>();
SipURI toURI = (SipURI) request.getTo().getURI();
SipFactory sipFactory = (SipFactory) getServletContext().getAttribute(SIP_FACTORY);
forks.add( sipFactory.createSipURI(toURI.getUser(),"192.168.4.160:11180") );
forks.add( sipFactory.createSipURI("9988003","192.168.4.30:5080") );
//request.getProxy().setParallel(true);
List<ProxyBranch> branches = request.getProxy().createProxyBranches( forks );
for(ProxyBranch branch: branches){
branch.setRecordRoute(true);
}
request.getProxy().startProxy();
}
and i get an exception in my log:
org.mobicents.servlet.sip.core.DispatcherException: Cannot find the corresponding sip application session to this subsequent request BYE sip:9988002#192.168.4.160:11180;transport=udp SIP/2.0
Via: SIP/2.0/UDP 192.168.4.204:11180;rport=11180;branch=z9hG4bKBH36Ht963rXeB;received=192.168.4.204
Max-Forwards: 70
From: "Extension 9988001" <sip:9988001#192.168.4.204>;tag=KtgZ29USetpNj
To: <sip:9988002#192.168.4.89>;tag=vN8t8Xm8yXg2K
Call-ID: 0e0bee76-943b-1234-4ba8-000c29680286
CSeq: 91266548 BYE
Contact: <sip:mod_sofia#192.168.4.204:11180>
User-Agent: FreeSWITCH-mod_sofia/1.2.23~64bit
Allow: INVITE,ACK,BYE,CANCEL,OPTIONS,MESSAGE,INFO,UPDATE,REGISTER,REFER,NOTIFY
Supported: timer,path,replaces
Reason: Q.850;cause=16;text="NORMAL_CLEARING"
Content-Length: 0
with the following popped route header <sip:192.168.4.89:5060;transport=udp;as=ded31d5f-500e-4c2d-84bb-370065d85c87;appname=1180947b;proxy=true;app_id=7599adf4;lr>, it may already have been invalidated or timed out
at org.mobicents.servlet.sip.core.dispatchers.SubsequentRequestDispatcher.dispatchMessage(SubsequentRequestDispatcher.java:248)
at org.mobicents.servlet.sip.core.SipApplicationDispatcherImpl.processRequest(SipApplicationDispatcherImpl.java:861)
at gov.nist.javax.sip.EventScanner.deliverRequestEvent(EventScanner.java:250)
at gov.nist.javax.sip.EventScanner.deliverEvent(EventScanner.java:146)
at gov.nist.javax.sip.SipProviderImpl.handleEvent(SipProviderImpl.java:185)
at gov.nist.javax.sip.DialogFilter.processRequest(DialogFilter.java:1324)
at gov.nist.javax.sip.stack.SIPServerTransactionImpl.processRequest(SIPServerTransactionImpl.java:811)
at gov.nist.javax.sip.stack.UDPMessageChannel.processMessage(UDPMessageChannel.java:578)
at gov.nist.javax.sip.stack.UDPMessageChannel.processIncomingDataPacket(UDPMessageChannel.java:524)
at gov.nist.javax.sip.stack.UDPMessageChannel.run(UDPMessageChannel.java:319)
at java.lang.Thread.run(Thread.java:722)
Is this happening only for calls whose duration is > 3 minutes ?
The sip servlets specification defines the default duration for sip session to be 3 minutes. You can modify it in the sip.xml session-timeout attribute or programatically in your app.

WLPushOptions not being passed on WLPush subscribe

I have a native app that is subscribing/unsubscribing and pushing notifications successfully, however, the API doesn't seem to pass in the WLPushOptions object that I'm using.
The call in my obj c code:
NSLog(#"Trying to subscribe ...");
id options = [WLPushOptions new];
[options addSubscriptionParameter:#"param3" :#"Testing3"];
NSLog(#"Connecting to server and initializing push notification … ");
ReadyToSubscribeListener *readyToSubscribeListener = [[ReadyToSubscribeListener alloc] initWithContext:ctx];
readyToSubscribeListener.alias = #"iOSPushAlias";
readyToSubscribeListener.adapterName = #"PushAdapter";
readyToSubscribeListener.eventSourceName = #"PushEventSource";
NSLog(#"Creating subscribe listener...");
MySubscribeListener *mySubscribeListener = [[MySubscribeListener alloc] initWithContext:ctx];
[[WLPush sharedInstance]subscribe:#"iOSPushAlias" :options :mySubscribeListener];
NSLog(#"Finished subscribe.");
The log:
Nov 4 20:29:44 Davids-iPhone-5 xxxx [771] <Warning>: Trying to subscribe ...
Nov 4 20:29:44 Davids-iPhone-5 xxxx [771] <Warning>: [WorklightNativeExtensionTemplateiOS] Connecting to server and initializing push notification ...
Nov 4 20:29:44 Davids-iPhone-5 xxxx [771] <Warning>: Creating subscribe listener...
Nov 4 20:29:44 Davids-iPhone-5 xxxx [771] <Warning>: Finished subscribe.
Nov 4 20:29:44 Davids-iPhone-5 xxxx [771] <Warning>: [INFO] Successfully subscribed to alias iOSPushAlias
Then, in the HSQL db log (using the local Worklight Developer client):
DELETE FROM NOTIFICATION_DEVICE WHERE ID=91
INSERT INTO NOTIFICATION_DEVICE VALUES(91,'iOSPushAlias','MYAPPNAME-iOSnative-1.0','XXXXXXXX-0C65-4BEF-BE3E-098B21BDFCEF','{}','Apple','XXXXXXXX324CA75650BB85853B946F3D1D9881E5D2E4F3E02268AA6CAA3254B3','XXXXXXXXXX-debug 1.2.0 (iPhone; iPhone OS 7.0.2; en_US)',91)
COMMIT
I've X'ed out the app and subscription id.
As you can see in the INSERT statement, the fifth field (the OPTIONS field in the NOTIFICATION_DEVICE table), is inserting an empty JSON object, where I passed in the key "param3" and value "Testing3", so, I would expect it to be:
{'param3':'Testing3'}
This seems to be what the the native iOS API docs expect (NSString parameters) to the addSubscriptionParameter method. I'm very new to Objective C, but, this looks correct to me.
Anyone know what I'm doing wrong?
This is a defect and has been logged. Fortunately there is an easy workaround:
WLPushOptions *options = [WLPushOptions new];
options.parameters = [NSMutableDictionary new];
[options addSubscriptionParameter:#"param3" :#"Testing3"];