Sunday, 18 December 2016

Creating a publicly accessible REST Web API on a Raspberry Pi3

One of the easiest ways to expose your Raspberry Pi publicly is by using ngrok. Ngrok is a lightweight alternative to VPN that creates introspected tunnels to localhost. If you have been following my articles, you will know that I managed to built a REST Web API to check the status of my Raspberry Pi Grid. The project works on my local network and I also have an Android app also that checks if the Grid is alive or not. But the point of building all this is that I should be able to check the status of it anywhere just to make sure that the system is up and running. The easiest way I could find without having to forward ports on my router is by just running Ngrok. 


Why do you need to expose your Raspberry Pi?


Get the latest version of Ngrok for ARM here and unzip the content of it on your local computer (in my case a Windows 10 machine). Then transfer the unzipped file to your Raspberry Pi using your preferred method (in my case I use WinSCP).

Now that the file is in the Raspberry Pi, we need to give it running permissions using the chmod command (I assume here that you know how to SSH to your RPi using putty):

Now we just need to run the ngrok command: ./ngrok http 3000 and all our http traffic on port 3000 will be automatically forwarded:

Notice that now, Ngrok is giving you a public URL that points to your local Raspberry Pi. This means that Ngrok is providing you with a publicly accessible IP address and domain name to your localhost:

Now that Ngrok is running, I need to run my Web API Service on that port 3000. To do that, I will just launch another session to my Raspberry Pi and start my node.js:

Notice that now I can browse that URL (http:/61184bba.ngrok.io/) and check the status of my Raspberri Pis over the internet:
Notice that every time your stop/start ngrok, a new URL is being generated. As you are exposing your data over the internet you need to make sure that this URL is just known by yourself and that you add extra security on your API if required (Now the Raspberry Pi is able to take requests from anyone on the web!).

Using this approach you can publish your applications easily so other can see them while developing them and you can even set up a home server to share data, etc. Possibilities are endless here.

If you check my mobile application (created with my Delphi 10.1 Berlin update 2) you will see that I just need to point the RestClient component to the exposed URL and voila! we'll be able to access that service over the internet:


All the source code is available here:
  • Mobile application (Delphi 10.1 Berlin update 2).
  • Node.js server (Web Api).
Here is the application in action:

Let me know if you have any questions.
Jordi

Sunday, 11 December 2016

“Could not load SSL library” Error message on Android 6 Marshmallow with TidHTTP

I have recently upgraded from Android 4.4 KitKat to Android 6 Marshmallow and to my surprise I found out that the some of my applications stopped working. The main issue is related to HTTPS communications using Indy components. As you might know Indy does not implement SSL natively. What the component does is to implement a flexible IOHandler architecture that allows for any SSL implementation to be plugged into Indy. Indy itself implements its own IOHandler class that is based on OpenSSL
The problem is that for Android 6, Google decided not to support OpenSSL anymore. Google replaced OpenSLL with a custom fork called BoringSSL to meet it's needs. BoringSSL includes additional changes and patches to the OpenSSL API and it's not backwards-compatible with OpenSSL. Android 6.0 will use the pre-loaded BoringSSL binaries when any application tries to load the OpenSSL library and it will throw an error (the reason why is because BoringSSL and OpenSSL share the same file names).

If you try to debug your Android application, you will see the following message when trying to use the TIdSSLIOHandlerSocketOpenSSL handler:


How to fix this error?

I found few comments in different forums and in the end the solution was not clear at all and I had to spend few hours fixing the issue myself. The best way to solve this is by deploying a recompiled version of the OpenSSL libraries with your Android application and then tell Indy to use those files. Indy operates at the NDK level so to make Indy avoid BoringSSL you will have to do that.

Get a precompiled version of OpenSSL here:

Place these files in your project and reference them in the deployment section. Go to Project -> Deployment and add the two files that are inside of that zip file and specify the destination folder in your Android device as .\assets\internal.


Now the last thing to do is to tell Indy where to look for these files. To do this, you will have to call the IdOpenSSLSetLibPath method with the TPath.GetDocumentsPath during startup (FormCreate for example). Here is an example:


Once completed, your applications should be able to use the correct version of Indy. You can review my solution and test it here: