RonRonDK
RonRonDK

Reputation: 435

Arduino EthernetClient cannot connect to Web API

I am trying to get my Arduino Ethernet connecting as a client to my ASP.NET Web API on Azure. It is supposed to POST some data to the API which will then be persisted in a MSSQL DB.

Because I could not get it working I choose to go back to the basic EthernetClient examples and get them working. Initially I got my Arduino firing a GET request to my webpage and got the HTML data back with the response. No problems there. But if I try to fetch JSON data from my Web API I am getting errors.

First I thought that it might be my Web API that caused some problem so I found a public test API called jsonplaceholder.typicode.com which just sends out dummy JSON data. This did not work either. Below is the code I am working with right now:

#include <SPI.h>
#include <Ethernet.h>

byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x69, 0xE6 };
byte ip[] = { 192, 168, 0, 20 };
char server[] = "http://jsonplaceholder.typicode.com";

EthernetClient client;

void setup() {
  Serial.begin(9600);
  if (Ethernet.begin(mac) == 0) {
    Serial.println("Failed to configure Ethernet using DHCP");
    Ethernet.begin(mac, ip);
  }
  delay(1000);
  Serial.println("connecting...");
  Serial.println(client.connect(server, 80)); // Returns -5.
  if (client.connect(server, 80)) {
    Serial.println("connected");
    client.println("GET http://jsonplaceholder.typicode.com/posts/1 HTTP/1.1");
    client.println("Host: jsonplaceholder.typicode.com");
    client.println("Connection: close");
    client.println("Content-Type: application/json");
    client.println();
  }
  else {
    Serial.println("connection failed");
  }
}

void loop()
{
  if (client.available()) {
    char c = client.read();
    Serial.print(c);
  }

  if (!client.connected()) {
    Serial.println();
    Serial.println("disconnecting.");
    client.stop();

    while (true);
  }
}

When the Arduino tries to connect to the server I get the following output on the Serial monitor:

coconnecting...
-5 
connected

disconnecting.

The if (client.connect(server, 80)) statement returns -5 which should not be possible. According to www.arduino.cc/en/Reference/ClientConnect possible return values is supposed to be as follows:

So as you see -5 should not be a possible return value. Oh and by the way. When connecting to my webpage in the working example and fetching the HTML data the same line returns 0 which should not be a possible value as well. But it enters the if statement anyway. I would have believed that it should return 1 to enter??

Can anyone please shed some light on why I cannot connect to Web API's?? I mean there shouldn't be any difference? Thanks in advance.

Upvotes: 0

Views: 1343

Answers (1)

RonRonDK
RonRonDK

Reputation: 435

With the help of a user in an Arduino usergroup on Facebook, I got this issue somewhat solved. So for anyone running into the same issue in the future, here is the explanation of my solution.

The problem seems to lie in the DNS resolving when passing the hostname. EthernetClient.connect() calls DNSClient.getHostByName() to resolve the URL. For some reason this doesn't work out very well. My lack of ability in C/C++ prevents me to figure out why. But in the end EthernetClient.connect() returns -5 which is both unhandled in the EthernetClient library nor documented. So this is why the Arduino never connects to the Web API.

In my further experiments I then found that if I pass the servers IP address instead to EthernetClient.connect() it connects. Then in the HTTP header I can pass the URL for the request and for the Host header field. Following code shows the working solution:

#include <SPI.h>
#include <Ethernet.h>

byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x69, 0xE6 };
byte ip[] = { 192, 168, 0, 20 };
byte serverIP[] = {54, 243, 62, 12}; // Get server IP address by running TRACERT on server hostname.

EthernetClient client;

void setup() {
  Serial.begin(9600);
  if (Ethernet.begin(mac) == 0) {
    Serial.println("Failed to configure Ethernet using DHCP");
    Ethernet.begin(mac, ip);
  }
  delay(1000);
  Serial.println("connecting...");
  if (client.connect(serverIP, 80)) { // Remember to pass IP address for server since DNS resolution apparently doesn't work.
    Serial.println("connected");
    client.println("GET http://jsonplaceholder.typicode.com/posts/1 HTTP/1.1");
    client.println("Host: jsonplaceholder.typicode.com");
    client.println("Connection: close");
    client.println("Content-Type: application/json");
    client.println();
  }
  else {
    Serial.println("connection failed");
  }
}

void loop()
{
  if (client.available()) {
    char c = client.read();
    Serial.print(c);
  }

  if (!client.connected()) {
    Serial.println();
    Serial.println("disconnecting.");
    client.stop();

    while (true);
  }
}

I would however like to find out exactly why the DNS resolving doesn't work. If anyone would too here is the relevant libraries:

https://github.com/arduino/Arduino/blob/master/libraries/Ethernet/src/EthernetClient.cpp

https://github.com/arduino/Arduino/blob/master/libraries/Ethernet/src/Dns.cpp

Upvotes: 1

Related Questions