Arduino: HTTP_UPDATE_FAILD Error (-106): Verify bin header failed

Created on 7 Oct 2017  路  2Comments  路  Source: esp8266/Arduino

Basic Infos

Hardware

Hardware: ESP8266 ESP-12E nodemcu v1.0
Core Version: 2.4.0-rc1 (https://github.com/esp8266/Arduino/releases/download/2.4.0-rc1/package_esp8266com_index.json)

Description

ESP8266 loops with a HTTP_UPDATE_FAILD Error (-106) when no update required. Serial output as follows:

[SETUP] WAIT 5...
~tate: 0 -> 2 (b0)
state: 2 -> 3 (0)
state: 3 -> 5 (10)
add 0
aid 1
cnt

connected with MYSSID, channel 6
dhcp client start...
ip:192.168.2.205,mask:255.255.255.0,gw:192.168.2.1
[SETUP] WAIT 4...
[SETUP] WAIT 3...
[SETUP] WAIT 2...
[SETUP] WAIT 1...
HTTP_UPDATE_FAILD Error (-106): Verify bin header failed
HTTP_UPDATE_FAILD Error (-106): Verify bin header failed
HTTP_UPDATE_FAILD Error (-106): Verify bin header failed
HTTP_UPDATE_FAILD Error (-106): Verify bin header failed
...

Settings in IDE

Module: NodeMCU 1.0 (ESP-12E Module)
Flash Size: 4M (3M SPIFFS)
CPU Frequency: 80 MHz
Flash Mode: not sure
Flash Frequency: not sure
Upload Using: not sure
Reset Method: not sure

Sketch

```#include

include

include

include

include

define USE_SERIAL Serial

define LED_OFF digitalWrite(LED_BUILTIN,HIGH)

define LED_ON digitalWrite(LED_BUILTIN,LOW)

ESP8266WiFiMulti WiFiMulti;

void setup() {
USE_SERIAL.begin(115200);
USE_SERIAL.setDebugOutput(true);

USE_SERIAL.println();
USE_SERIAL.println();
USE_SERIAL.println();

for(uint8_t t = 5; t > 0; t--) {
    USE_SERIAL.printf("[SETUP] WAIT %d...\n", t);
    USE_SERIAL.flush();
    delay(1000);
}

WiFiMulti.addAP("MYSSID", "password");

}

void loop() {
// wait for WiFi connection
if((WiFiMulti.run() == WL_CONNECTED)) {
t_httpUpdate_return ret = ESPhttpUpdate.update("192.168.2.110",80,"/index.php","httpUpdateDev.ino.nodemcu");

    switch(ret) {
        case HTTP_UPDATE_FAILED:
            USE_SERIAL.printf("HTTP_UPDATE_FAILD Error (%d): %s\n", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str());
            break;

        case HTTP_UPDATE_NO_UPDATES:
            USE_SERIAL.println("HTTP_UPDATE_NO_UPDATES");
            break;

        case HTTP_UPDATE_OK:
            USE_SERIAL.println("HTTP_UPDATE_OK");
            break;
    }

}

}

This is the php script running on the server:

header('Content-type: text/plain; charset=utf8', true);

function check_header($name, $value = false) {
if(!isset($_SERVER[$name])) {
return false;
}
if($value && $_SERVER[$name] != $value) {
return false;
}
return true;
}

function sendFile($path) {
header($_SERVER["SERVER_PROTOCOL"].' 200 OK', true, 200);
header('Content-Type: application/octet-stream', true);
header('Content-Disposition: attachment; filename='.basename($path));
header('Content-Length: '.filesize($path), true);
header('x-MD5: '.md5_file($path), true);
readfile($path);
}

echo "PHP script starts\n";

if(!check_header('HTTP_USER_AGENT', 'ESP8266-http-Update')) {
header($_SERVER["SERVER_PROTOCOL"].' 403 Forbidden', true, 403);
echo "Invalid USER AGENT. This is only for ESP8266 updater!\n";
exit();
}
echo "User agent test okay\n";

if(
!check_header('HTTP_X_ESP8266_STA_MAC') ||
!check_header('HTTP_X_ESP8266_AP_MAC') ||
!check_header('HTTP_X_ESP8266_FREE_SPACE') ||
!check_header('HTTP_X_ESP8266_SKETCH_SIZE') ||
!check_header('HTTP_X_ESP8266_SKETCH_MD5') ||
!check_header('HTTP_X_ESP8266_CHIP_SIZE') ||
!check_header('HTTP_X_ESP8266_SDK_VERSION')
) {
header($_SERVER["SERVER_PROTOCOL"].' 403 Forbidden', true, 403);
echo "Problem with HTTP header from ESP8266 --- only for ESP8266 updater!\n";
exit();
}

echo "Headers tested okay\n";

$db = array(
"18:FE:AA:AA:AA:AA" => "DOOR-7-g14f53a19",
"5C:CF:7F:B0:F2:14" => "httpUpdateDev.ino.nodemcu",
"18:FE:AA:AA:AA:BB" => "TEMP-1.0.0"
);

echo "MAC Database defined\n";

if(!isset($db[$_SERVER['HTTP_X_ESP8266_STA_MAC']])) {
echo "MAC address not found in db\n";
header($_SERVER["SERVER_PROTOCOL"].' 500 ESP MAC not configured for updates', true, 500);
} else {
echo "MAC address found in db\n";
}

$localBinary = "./bin/".$db[$_SERVER['HTTP_X_ESP8266_STA_MAC']].".bin";
echo "File name requested: $localBinary\n";
$localBinaryMD5 = md5_file($localBinary);
// Check if version has been set and does not match, if not, check if
// MD5 hash between local binary and ESP8266 binary do not match if not.
// then no update has been found.

$v1 = check_header('HTTP_X_ESP8266_SDK_VERSION');

echo "Version check parameters:\n
HTTP_X_ESP8266_SDK_VERSION: {$_server['HTTP_X_ESP8266_SDK_VERSION']}\n
HTTP_X_ESP8266_STA_MAC: {$_SERVER['HTTP_X_ESP8266_STA_MAC']}\n
HTTP_X_ESP8266_VERSION: {$_SERVER['HTTP_X_ESP8266_VERSION']}\n
HTTP_X_ESP8266_SKETCH_MD5: {$_SERVER['HTTP_X_ESP8266_SKETCH_MD5']}\n
localmd5: $localBinaryMD5\n
check_header('HTTP_X_ESP8266_SDK_VERSION'): $v1\n\n";

if($_SERVER["HTTP_X_ESP8266_SKETCH_MD5"] != md5_file($localBinary)) {
echo "versions do not match - updating\n";
sendFile($localBinary);
} else {
echo "versions match - no action required\n";
header($_SERVER["SERVER_PROTOCOL"].' 304 Not Modified', true, 304);
}
header($_SERVER["SERVER_PROTOCOL"].' 500 no version for ESP MAC', true, 500);
echo "End of script\n";

?>
```

Debug Messages

This is a sample of the TCP stream between the ESP8266 and the server:

GET /index.php HTTP/1.0
Host: 192.168.2.110
User-Agent: ESP8266-http-Update
Connection: close
x-ESP8266-STA-MAC: 5C:CF:7F:B0:F2:14
x-ESP8266-AP-MAC: 5E:CF:7F:B0:F2:14
x-ESP8266-free-space: 778240
x-ESP8266-sketch-size: 269552
x-ESP8266-sketch-md5: 0b80225ec75c2ed95ecbecd227e53e38
x-ESP8266-chip-size: 4194304
x-ESP8266-sdk-version: 2.0.0(656edbf)
x-ESP8266-mode: sketch
x-ESP8266-version: httpUpdateDev.ino.nodemcu

HTTP/1.1 200 OK
Date: Sat, 07 Oct 2017 11:41:14 GMT
Server: Apache/2.2.29 (Unix) mod_wsgi/3.5 Python/2.7.10 PHP/5.6.10 mod_ssl/2.2.29 OpenSSL/0.9.8zh DAV/2 mod_fastcgi/2.4.6 mod_perl/2.0.9 Perl/v5.22.0
X-Powered-By: PHP/5.6.10
Content-Length: 520
Connection: close
Content-Type: text/plain; charset=utf8

PHP script starts
User agent test okay
Headers tested okay
MAC Database defined
MAC address found in db
File name requested: ./bin/httpUpdateDev.ino.nodemcu.bin
Version check parameters:

HTTP_X_ESP8266_SDK_VERSION: 

HTTP_X_ESP8266_STA_MAC: 5C:CF:7F:B0:F2:14

HTTP_X_ESP8266_VERSION: httpUpdateDev.ino.nodemcu

HTTP_X_ESP8266_SKETCH_MD5: 0b80225ec75c2ed95ecbecd227e53e38

localmd5: 0b80225ec75c2ed95ecbecd227e53e38

check_header('HTTP_X_ESP8266_SDK_VERSION'): 1

versions match - no action required
End of script

Most helpful comment

Working version of PHP script follows:

<?php

header('Content-type: text/plain; charset=utf8', true);

//  Function to test existance of header value
function check_header($name, $value = false) {
    if(!isset($_SERVER[$name])) {
        return false;
    }
    if($value && $_SERVER[$name] != $value) {
        return false;
    }
    return true;
}

//  Function to send file to ESP8266
function sendFile($path) {
    header($_SERVER["SERVER_PROTOCOL"].' 200 OK', true, 200);
    header('Content-Type: application/octet-stream', true);
    header('Content-Disposition: attachment; filename='.basename($path));
    header('Content-Length: '.filesize($path), true);
    header('x-MD5: '.md5_file($path), true);
    readfile($path);
}

//  Test for correct user agent
if(!check_header('HTTP_USER_AGENT', 'ESP8266-http-Update')) {
    header($_SERVER["SERVER_PROTOCOL"].' 403 Forbidden', true, 403);
    echo "Invalid USER AGENT. This is only for ESP8266 updater!\n";
    exit();
}

//  Confirm existance of HTTP headers from ESP8266
if(
    !check_header('HTTP_X_ESP8266_STA_MAC') ||
    !check_header('HTTP_X_ESP8266_AP_MAC') ||
    !check_header('HTTP_X_ESP8266_FREE_SPACE') ||
    !check_header('HTTP_X_ESP8266_SKETCH_SIZE') ||
    !check_header('HTTP_X_ESP8266_SKETCH_MD5') ||
    !check_header('HTTP_X_ESP8266_CHIP_SIZE') ||
    !check_header('HTTP_X_ESP8266_SDK_VERSION')
) {
    header($_SERVER["SERVER_PROTOCOL"].' 403 Forbidden - Missing header value.', true, 403);
    exit();
}

//  Database associating ESP8266 MAC address with sketch file
$db = array(
    "18:FE:AA:AA:AA:AA" => "DOOR-7-g14f53a19",
    "5C:CF:7F:B0:F2:14" => "httpUpdateDev.ino.nodemcu",
    "18:FE:AA:AA:AA:BB" => "TEMP-1.0.0"
);

//  Confirm ESP8266 MAC addres in database
if(!isset($db[$_SERVER['HTTP_X_ESP8266_STA_MAC']])) {
    header($_SERVER["SERVER_PROTOCOL"].' 500 ESP MAC not configured for updates', true, 500);
    exit();
}

//  Build filename of version requested from database
$localBinary = "./bin/".$db[$_SERVER['HTTP_X_ESP8266_STA_MAC']].".bin";

// Check if version has been set and does not match, if not, check if
// MD5 hash between local binary and ESP8266 binary do not match if not.
// then no update has been found.

if  (($db[$_SERVER['HTTP_X_ESP8266_STA_MAC']] != $_SERVER['HTTP_X_ESP8266_VERSION']) ||     // if ESP8266 requests different file from database OR
    ($_SERVER["HTTP_X_ESP8266_SKETCH_MD5"] != md5_file($localBinary)))                      // is there a mismatch between MD5 ... then
    {
        sendFile($localBinary);
    } else {
        header($_SERVER["SERVER_PROTOCOL"].' 304 Not Modified - no update required', true, 304);
    }

?>

All 2 comments

After some debugging, this particular problem is traced to the "echo" commands in the PHP script. It seems they interfere with the header information returned from the server. However, removing them results in a different error, the "HTTP_UPDATE_FAILD Error (-104): Wrong HTTP code". This problem is caused by the last line of the PHP script:
header($_SERVER["SERVER_PROTOCOL"].' 500 no version for ESP MAC', true, 500);

Commenting out this line results expected behaviour. There are still a few problems with the UPDATE / NO-UPDATE logic. To be continued.

Working version of PHP script follows:

<?php

header('Content-type: text/plain; charset=utf8', true);

//  Function to test existance of header value
function check_header($name, $value = false) {
    if(!isset($_SERVER[$name])) {
        return false;
    }
    if($value && $_SERVER[$name] != $value) {
        return false;
    }
    return true;
}

//  Function to send file to ESP8266
function sendFile($path) {
    header($_SERVER["SERVER_PROTOCOL"].' 200 OK', true, 200);
    header('Content-Type: application/octet-stream', true);
    header('Content-Disposition: attachment; filename='.basename($path));
    header('Content-Length: '.filesize($path), true);
    header('x-MD5: '.md5_file($path), true);
    readfile($path);
}

//  Test for correct user agent
if(!check_header('HTTP_USER_AGENT', 'ESP8266-http-Update')) {
    header($_SERVER["SERVER_PROTOCOL"].' 403 Forbidden', true, 403);
    echo "Invalid USER AGENT. This is only for ESP8266 updater!\n";
    exit();
}

//  Confirm existance of HTTP headers from ESP8266
if(
    !check_header('HTTP_X_ESP8266_STA_MAC') ||
    !check_header('HTTP_X_ESP8266_AP_MAC') ||
    !check_header('HTTP_X_ESP8266_FREE_SPACE') ||
    !check_header('HTTP_X_ESP8266_SKETCH_SIZE') ||
    !check_header('HTTP_X_ESP8266_SKETCH_MD5') ||
    !check_header('HTTP_X_ESP8266_CHIP_SIZE') ||
    !check_header('HTTP_X_ESP8266_SDK_VERSION')
) {
    header($_SERVER["SERVER_PROTOCOL"].' 403 Forbidden - Missing header value.', true, 403);
    exit();
}

//  Database associating ESP8266 MAC address with sketch file
$db = array(
    "18:FE:AA:AA:AA:AA" => "DOOR-7-g14f53a19",
    "5C:CF:7F:B0:F2:14" => "httpUpdateDev.ino.nodemcu",
    "18:FE:AA:AA:AA:BB" => "TEMP-1.0.0"
);

//  Confirm ESP8266 MAC addres in database
if(!isset($db[$_SERVER['HTTP_X_ESP8266_STA_MAC']])) {
    header($_SERVER["SERVER_PROTOCOL"].' 500 ESP MAC not configured for updates', true, 500);
    exit();
}

//  Build filename of version requested from database
$localBinary = "./bin/".$db[$_SERVER['HTTP_X_ESP8266_STA_MAC']].".bin";

// Check if version has been set and does not match, if not, check if
// MD5 hash between local binary and ESP8266 binary do not match if not.
// then no update has been found.

if  (($db[$_SERVER['HTTP_X_ESP8266_STA_MAC']] != $_SERVER['HTTP_X_ESP8266_VERSION']) ||     // if ESP8266 requests different file from database OR
    ($_SERVER["HTTP_X_ESP8266_SKETCH_MD5"] != md5_file($localBinary)))                      // is there a mismatch between MD5 ... then
    {
        sendFile($localBinary);
    } else {
        header($_SERVER["SERVER_PROTOCOL"].' 304 Not Modified - no update required', true, 304);
    }

?>
Was this page helpful?
0 / 5 - 0 ratings

Related issues

eliabieri picture eliabieri  路  3Comments

tiestvangool picture tiestvangool  路  3Comments

gosewski picture gosewski  路  3Comments

hulkco picture hulkco  路  3Comments

Chagui- picture Chagui-  路  3Comments