blob: 09a00d85302bf94cb5ee9bf5a0073548adccd3c8 [file] [log] [blame]
/*
*
* Copyright (c) 2020 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "esp_event.h"
#include "esp_log.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "nvs_flash.h"
#include "tcpip_adapter.h"
#include <string.h>
#include <sys/param.h>
#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include <lwip/netdb.h>
#include <inet/IPAddress.h>
#include <inet/InetError.h>
#include <inet/InetLayer.h>
#include <inet/UDPEndPoint.h>
#include <platform/CHIPDeviceLayer.h>
#include <support/ErrorStr.h>
#include <system/SystemPacketBuffer.h>
#include "DataModelHandler.h"
#define PORT CONFIG_ECHO_PORT
static const char * TAG = "echo_server";
using namespace ::chip;
using namespace ::chip::Inet;
// UDP Endpoint Callbacks
static void echo(IPEndPointBasis * endpoint, System::PacketBuffer * buffer, const IPPacketInfo * packet_info)
{
bool status = endpoint != NULL && buffer != NULL && packet_info != NULL;
if (status)
{
char src_addr[INET_ADDRSTRLEN];
char dest_addr[INET_ADDRSTRLEN];
const size_t data_len = buffer->DataLength();
packet_info->SrcAddress.ToString(src_addr, sizeof(src_addr));
packet_info->DestAddress.ToString(dest_addr, sizeof(dest_addr));
ESP_LOGI(TAG, "UDP packet received from %s:%u to %s:%u (%zu bytes)", src_addr, packet_info->SrcPort, dest_addr,
packet_info->DestPort, static_cast<size_t>(data_len));
if (data_len > 0 && buffer->Start()[0] < 0x20)
{
// Non-ACII; assume it's a data model message.
HandleDataModelMessage(buffer);
return;
}
// attempt to print the incoming message
char msg_buffer[data_len + 1];
msg_buffer[data_len] = 0; // Null-terminate whatever we received and treat like a string...
memcpy(msg_buffer, buffer->Start(), data_len);
ESP_LOGI(TAG, "Client sent: \"%s\"", msg_buffer);
// Attempt to echo back
UDPEndPoint * udp_endpoint = static_cast<UDPEndPoint *>(endpoint);
INET_ERROR err = udp_endpoint->SendTo(packet_info->SrcAddress, packet_info->SrcPort, buffer);
if (err != INET_NO_ERROR)
{
ESP_LOGE(TAG, "Unable to echo back to client: %s", ErrorStr(err));
// Note the failure status
status = !status;
}
else
{
ESP_LOGI(TAG, "Echo sent");
}
}
if (!status)
{
ESP_LOGE(TAG, "Received data but couldn't process it...");
// SendTo calls Free on the buffer without an AddRef, if SendTo was not called, free the buffer.
if (buffer != NULL)
{
System::PacketBuffer::Free(buffer);
}
}
}
static void error(IPEndPointBasis * ep, INET_ERROR error, const IPPacketInfo * pi)
{
ESP_LOGE(TAG, "ERROR: %s\n Got UDP error", ErrorStr(error));
}
// The echo server assumes the platform's networking has been setup already
void startServer(UDPEndPoint * endpoint)
{
ESP_LOGI(TAG, "Trying to get Inet");
INET_ERROR err = DeviceLayer::InetLayer.NewUDPEndPoint(&endpoint);
if (err != INET_NO_ERROR)
{
ESP_LOGE(TAG, "ERROR: %s\n Couldn't create UDP Endpoint, server will not start.", ErrorStr(err));
return;
}
endpoint->OnMessageReceived = echo;
endpoint->OnReceiveError = error;
err = endpoint->Bind(kIPAddressType_IPv4, IPAddress::Any, PORT);
if (err != INET_NO_ERROR)
{
ESP_LOGE(TAG, "Socket unable to bind: Error %s", ErrorStr(err));
return;
}
err = endpoint->Listen();
if (err != INET_NO_ERROR)
{
ESP_LOGE(TAG, "Socket unable to Listen: Error %s", ErrorStr(err));
return;
}
ESP_LOGI(TAG, "Echo Server Listening on PORT:%d...", PORT);
}