blob: 0afdea662f4e0d9aedd918bd6a65f2223273d5ed [file] [log] [blame]
/*
*
* Copyright (c) 2013-2017 Nest Labs, Inc.
* All rights reserved.
*
* 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.
*/
/**
* @file
* This file implements a process to effect a functional test for
* the InetLayer Internet Protocol stack abstraction interfaces.
*
*/
#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS
#endif
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include "ToolCommon.h"
#include <SystemLayer/SystemTimer.h>
using namespace nl::Inet;
#define TOOL_NAME "TestInetLayer"
static bool HandleOption(const char *progName, OptionSet *optSet, int id, const char *name, const char *arg);
static bool HandleNonOptionArgs(const char *progName, int argc, char *argv[]);
static void StartTest();
static void DriveSend();
static void HandleConnectionComplete(TCPEndPoint *ep, INET_ERROR conErr);
static void HandleConnectionReceived(TCPEndPoint *listeningEP, TCPEndPoint *conEP, const IPAddress &peerAddr,
uint16_t peerPort);
static void HandleConnectionClosed(TCPEndPoint *ep, INET_ERROR err);
static void HandlePeerClose(TCPEndPoint *ep);
static void HandleDataSent(TCPEndPoint *ep, uint16_t len);
static void HandleDataReceived(TCPEndPoint *ep, PacketBuffer *data);
static void HandleAcceptError(TCPEndPoint *endPoint, INET_ERROR err);
static void HandleRawMessageReceived(RawEndPoint *endPoint, PacketBuffer *msg, IPAddress senderAddr);
static void HandleRawReceiveError(RawEndPoint *endPoint, INET_ERROR err, IPAddress senderAddr);
static void HandleUDPMessageReceived(UDPEndPoint *endPoint, PacketBuffer *msg, const IPPacketInfo *pktInfo);
static void HandleUDPReceiveError(UDPEndPoint *endPoint, INET_ERROR err, const IPPacketInfo *pktInfo);
static void HandleSendTimerComplete(System::Layer* aSystemLayer, void* aAppState, System::Error aError);
static PacketBuffer *MakeDataBuffer(int32_t len);
bool Listen = false;
const char *destHostName = NULL;
IPAddress DestAddr = IPAddress::Any;
bool IsTimeToSend = true;
int32_t SendInterval = 1000; // in ms
int32_t SendLength = 3200;
int32_t MaxSendLength = -1;
int32_t MinRcvLength = 0;
int32_t MaxRcvLength = -1;
int32_t TotalSendLength = 0;
int32_t TotalRcvLength = 0;
const char *IntfFilterName = NULL;
#if INET_CONFIG_ENABLE_IPV4
bool UseRaw4 = false;
#endif // INET_CONFIG_ENABLE_IPV4
bool UseRaw6 = false;
bool UseTCP = false;
TCPEndPoint *TCPEP = NULL;
TCPEndPoint *ListenEP = NULL;
UDPEndPoint *UDPEP = NULL;
RawEndPoint *Raw4EP = NULL;
RawEndPoint *Raw6EP = NULL;
static OptionDef gToolOptionDefs[] =
{
{ "intf-filter", kArgumentRequired, 'F' },
{ "length", kArgumentRequired, 'l' },
{ "max-receive", kArgumentRequired, 'r' },
{ "max-send", kArgumentRequired, 's' },
{ "interval", kArgumentRequired, 'i' },
{ "listen", kNoArgument, 'L' },
#if INET_CONFIG_ENABLE_IPV4
{ "raw4", kNoArgument, '4' },
#endif // INET_CONFIG_ENABLE_IPV4
{ "raw6", kNoArgument, '6' },
{ "tcp", kNoArgument, 't' },
{ NULL }
};
static const char *gToolOptionHelp =
" -F, --intf-filter <interface-name>\n"
" Name of the interface to filter traffic from/to.\n"
"\n"
" -l, --length <num>\n"
" Send specified number of bytes.\n"
"\n"
" -r, --max-receive <num>\n"
" Maximum bytes to receive per connection.\n"
"\n"
" -s, --max-send <num>\n"
" Maximum bytes to send per connection.\n"
"\n"
" -i, --interval <ms>\n"
" Send data at the specified interval in milliseconds.\n"
"\n"
" -L, --listen\n"
" Listen for incoming data.\n"
"\n"
#if INET_CONFIG_ENABLE_IPV4
" -4, --raw4\n"
" Use Raw IPv4. Defaults to using UDP.\n"
"\n"
#endif // INET_CONFIG_ENABLE_IPV4
" -6, --raw6\n"
" Use Raw IPv6. Defaults to using UDP.\n"
"\n"
" -t, --tcp\n"
" Use TCP. Defaults to using UDP.\n"
"\n";
static OptionSet gToolOptions =
{
HandleOption,
gToolOptionDefs,
"GENERAL OPTIONS",
gToolOptionHelp
};
static HelpOptions gHelpOptions(
TOOL_NAME,
"Usage: " TOOL_NAME " <options> <src-node-addr> <dest-node-addr>\n"
" " TOOL_NAME " <options> <src-node-addr> --listen\n",
WEAVE_VERSION_STRING "\n" WEAVE_TOOL_COPYRIGHT
);
static OptionSet *gToolOptionSets[] =
{
&gToolOptions,
&gNetworkOptions,
&gFaultInjectionOptions,
&gHelpOptions,
NULL
};
#if INET_CONFIG_ENABLE_DNS_RESOLVER
static bool DNSResolutionComplete = false;
static void HandleDNSResolveComplete(void *appState, INET_ERROR err, uint8_t addrCount, IPAddress *addrArray);
#endif // INET_CONFIG_ENABLE_DNS_RESOLVER
int main(int argc, char *argv[])
{
SetSignalHandler(DoneOnHandleSIGUSR1);
if (argc == 1)
{
gHelpOptions.PrintBriefUsage(stderr);
exit(EXIT_FAILURE);
}
if (!ParseArgsFromEnvVar(TOOL_NAME, TOOL_OPTIONS_ENV_VAR_NAME, gToolOptionSets, NULL, true) ||
!ParseArgs(TOOL_NAME, argc, argv, gToolOptionSets, HandleNonOptionArgs))
{
exit(EXIT_FAILURE);
}
InitSystemLayer();
InitNetwork();
StartTest();
while (!Done)
{
struct timeval sleepTime;
sleepTime.tv_sec = 0;
sleepTime.tv_usec = 10000;
ServiceNetwork(sleepTime);
}
if (TCPEP)
TCPEP->Shutdown();
if (ListenEP)
ListenEP->Shutdown();
Inet.Shutdown();
return EXIT_SUCCESS;
}
bool HandleOption(const char *progName, OptionSet *optSet, int id, const char *name, const char *arg)
{
switch (id)
{
#if INET_CONFIG_ENABLE_IPV4
case '4':
UseRaw4 = true;
break;
#endif // INET_CONFIG_ENABLE_IPV4
case '6':
UseRaw6 = true;
break;
case 't':
UseTCP = true;
break;
case 'L':
Listen = true;
break;
case 'l':
if (!ParseInt(arg, SendLength) || SendLength < 0 || SendLength > UINT16_MAX)
{
PrintArgError("%s: Invalid value specified for data length: %s\n", progName, arg);
return false;
}
break;
case 'r':
if (!ParseInt(arg, MaxRcvLength) || MaxRcvLength < 0)
{
PrintArgError("%s: Invalid value specified for max receive: %s\n", progName, arg);
return false;
}
break;
case 's':
if (!ParseInt(arg, MaxSendLength) || MaxSendLength < 0)
{
PrintArgError("%s: Invalid value specified for max send: %s\n", progName, arg);
return false;
}
break;
case 'i':
if (!ParseInt(arg, SendInterval) || SendInterval < 0 || SendInterval > INT32_MAX)
{
PrintArgError("%s: Invalid value specified for send interval: %s\n", progName, arg);
return false;
}
break;
case 'F':
IntfFilterName = arg;
break;
default:
PrintArgError("%s: INTERNAL ERROR: Unhandled option: %s\n", progName, name);
return false;
}
return true;
}
bool HandleNonOptionArgs(const char *progName, int argc, char *argv[])
{
if (!Listen)
{
if (argc == 0)
{
PrintArgError("%s: Please specify a destination name or address\n", progName);
return false;
}
destHostName = argv[0];
argc--; argv++;
}
else
{
// If listening and a send length wasn't explicitly specified, then don't send anything.
// NOTE: this only applies when using TCP.
if (MaxSendLength == -1)
MaxSendLength = 0;
}
if (argc > 0)
{
PrintArgError("%s: TestInetLayer: Unexpected argument: %s\n", progName, argv[0]);
return false;
}
return true;
}
#define NUM_ICMP6_FILTER_TYPES 2
uint8_t ICMP6Types[NUM_ICMP6_FILTER_TYPES] =
{ 128, 129 }; //Echo Request, Echo Reply
//#define NUM_ICMP6_FILTER_TYPES 1
//uint8_t ICMP6Types[NUM_ICMP6_FILTER_TYPES] = {255}; //Reserved for expansion of ICMPv6 informational messages
void StartTest()
{
INET_ERROR err;
IsTimeToSend = (MaxSendLength != 0);
if (UseRaw6)
{
printf("UseRaw6, if: %s (WEAVE_SYSTEM_CONFIG_USE_LWIP: %d)\n", IntfFilterName, WEAVE_SYSTEM_CONFIG_USE_LWIP);
err = Inet.NewRawEndPoint(kIPVersion_6, kIPProtocol_ICMPv6, &Raw6EP);
FAIL_ERROR(err, "InetLayer::NewRawEndPoint (IPv6) failed");
if (IntfFilterName != NULL)
{
InterfaceId intfId;
err = InterfaceNameToId(IntfFilterName, intfId);
FAIL_ERROR(err, "InterfaceNameToId failed");
err = Raw6EP->BindInterface(intfId);
FAIL_ERROR(err, "RawEndPoint::BindInterface (IPv6) failed");
}
Raw6EP->OnMessageReceived = HandleRawMessageReceived;
Raw6EP->OnReceiveError = HandleRawReceiveError;
}
#if INET_CONFIG_ENABLE_IPV4
else if (UseRaw4)
{
err = Inet.NewRawEndPoint(kIPVersion_4, kIPProtocol_ICMPv4, &Raw4EP);
FAIL_ERROR(err, "InetLayer::NewRawEndPoint (IPv4) failed");
if (IntfFilterName != NULL)
{
InterfaceId intfId;
err = InterfaceNameToId(IntfFilterName, intfId);
FAIL_ERROR(err, "InterfaceNameToId failed");
err = Raw4EP->BindInterface(intfId);
FAIL_ERROR(err, "RawEndPoint::BindInterface (IPv4) failed");
}
Raw4EP->OnMessageReceived = HandleRawMessageReceived;
Raw4EP->OnReceiveError = HandleRawReceiveError;
}
#endif // INET_CONFIG_ENABLE_IPV4
else if (!UseTCP)
{
err = Inet.NewUDPEndPoint(&UDPEP);
FAIL_ERROR(err, "InetLayer::NewUDPEndPoint failed");
if (IntfFilterName != NULL)
{
InterfaceId intfId;
err = InterfaceNameToId(IntfFilterName, intfId);
FAIL_ERROR(err, "InterfaceNameToId failed");
err = UDPEP->BindInterface(kIPAddressType_IPv6, intfId);
FAIL_ERROR(err, "RawEndPoint::BindInterface (IPv4) failed");
}
UDPEP->OnMessageReceived = HandleUDPMessageReceived;
UDPEP->OnReceiveError = HandleUDPReceiveError;
}
if (Listen)
{
if (UseRaw6)
{
err = Raw6EP->Bind(kIPAddressType_IPv6, gNetworkOptions.LocalIPv6Addr);
FAIL_ERROR(err, "RawEndPoint::Bind (IPv6) failed");
if (NUM_ICMP6_FILTER_TYPES == 1)
printf("NumICMP6Types: %d: [0]: %d\n", NUM_ICMP6_FILTER_TYPES, ICMP6Types[0]);
if (NUM_ICMP6_FILTER_TYPES == 2)
printf("NumICMP6Types: %d: [0]: %d, [1]: %d\n", NUM_ICMP6_FILTER_TYPES, ICMP6Types[0], ICMP6Types[1]);
err = Raw6EP->SetICMPFilter(NUM_ICMP6_FILTER_TYPES, ICMP6Types);
FAIL_ERROR(err, "RawEndPoint::SetICMPFilter (IPv6) failed");
err = Raw6EP->Listen();
FAIL_ERROR(err, "RawEndPoint::Listen (IPv6) failed");
}
#if INET_CONFIG_ENABLE_IPV4
else if (UseRaw4)
{
err = Raw4EP->Bind(kIPAddressType_IPv4, gNetworkOptions.LocalIPv4Addr);
FAIL_ERROR(err, "RawEndPoint::Bind (IPv4) failed");
err = Raw4EP->Listen();
FAIL_ERROR(err, "RawEndPoint::Listen (IPv4) failed");
}
#endif // INET_CONFIG_ENABLE_IPV4
else if (UseTCP)
{
err = Inet.NewTCPEndPoint(&ListenEP);
FAIL_ERROR(err, "InetLayer::NewTCPEndPoint failed");
ListenEP->OnConnectionReceived = HandleConnectionReceived;
ListenEP->OnAcceptError = HandleAcceptError;
err = ListenEP->Bind(kIPAddressType_IPv6, IPAddress::Any, 4242, true);
FAIL_ERROR(err, "TCPEndPoint::Bind failed");
err = ListenEP->Listen(1);
FAIL_ERROR(err, "TCPEndPoint::Listen failed");
}
else
{
err = UDPEP->Bind(kIPAddressType_IPv6, IPAddress::Any, 4242);
FAIL_ERROR(err, "UDPEndPoint::Bind failed");
err = UDPEP->Listen();
FAIL_ERROR(err, "UDPEndPoint::Listen failed");
}
printf("Listening...\n");
}
DriveSend();
}
void DriveSend()
{
INET_ERROR err;
if (!IsTimeToSend)
return;
if (TotalSendLength == MaxSendLength) {
Inet.Shutdown();
Done = true;
return;
}
#if INET_CONFIG_ENABLE_DNS_RESOLVER
if (!DNSResolutionComplete && !Listen)
{
printf("Resolving destination name...\n");
err = Inet.ResolveHostAddress(destHostName, 1, &DestAddr, HandleDNSResolveComplete, NULL);
FAIL_ERROR(err, "InetLayer::ResolveHostAddress failed");
return;
}
#endif // INET_CONFIG_ENABLE_DNS_RESOLVER
if (UseTCP)
{
if (TCPEP == NULL)
{
if (Listen)
return;
err = Inet.NewTCPEndPoint(&TCPEP);
FAIL_ERROR(err, "InetLayer::NewTCPEndPoint failed");
TCPEP->OnConnectComplete = HandleConnectionComplete;
TCPEP->OnConnectionClosed = HandleConnectionClosed;
TCPEP->OnDataSent = HandleDataSent;
TCPEP->OnDataReceived = HandleDataReceived;
err = TCPEP->Connect(DestAddr, 4242);
FAIL_ERROR(err, "TCPEndPoint::Connect failed");
}
if (TCPEP->State != TCPEndPoint::kState_Connected && TCPEP->State != TCPEndPoint::kState_ReceiveShutdown)
return;
if (TCPEP->PendingSendLength() > 0)
return;
int32_t sendLen = SendLength;
if (MaxSendLength != -1)
{
int32_t remainingLen = MaxSendLength - TotalSendLength;
if (sendLen > remainingLen)
sendLen = remainingLen;
}
IsTimeToSend = false;
SystemLayer.StartTimer(SendInterval, HandleSendTimerComplete, NULL);
PacketBuffer *buf = MakeDataBuffer(sendLen);
if (buf == NULL)
{
printf("Failed to allocate PacketBuffer\n");
return;
}
sendLen = buf->DataLength();
err = TCPEP->Send(buf);
if (err != INET_ERROR_CONNECTION_ABORTED)
FAIL_ERROR(err, "TCPEndPoint::Send failed");
TotalSendLength += sendLen;
if (MaxSendLength != -1 && TotalSendLength == MaxSendLength)
{
printf("Closing connection\n");
err = TCPEP->Close();
FAIL_ERROR(err, "TCPEndPoint::Close failed");
printf("Freeing end point\n");
TCPEP->Free();
TCPEP = NULL;
}
}
else if (!Listen)
{
int32_t sendLen = SendLength;
if (MaxSendLength != -1)
{
int32_t remainingLen = MaxSendLength - TotalSendLength;
if (sendLen > remainingLen)
sendLen = remainingLen;
}
IsTimeToSend = false;
SystemLayer.StartTimer(SendInterval, HandleSendTimerComplete, NULL);
PacketBuffer *buf = MakeDataBuffer(sendLen);
if (buf == NULL)
{
printf("Failed to allocate PacketBuffer\n");
return;
}
if (UseRaw6)
{
uint8_t *p = buf->Start();
*p = ICMP6Types[0]; // change ICMPv6 type to be consistent with the filter
err = Raw6EP->SendTo(DestAddr, buf);
FAIL_ERROR(err, "RawEndPoint::SendTo (IPv6) failed");
}
#if INET_CONFIG_ENABLE_IPV4
else if (UseRaw4)
{
err = Raw4EP->SendTo(DestAddr, buf);
FAIL_ERROR(err, "RawEndPoint::SendTo (IPv4) failed");
}
#endif // INET_CONFIG_ENABLE_IPV4
else if (!UseTCP)
{
err = UDPEP->SendTo(DestAddr, 4242, buf);
FAIL_ERROR(err, "UDPEndPoint::SendTo failed");
}
TotalSendLength += sendLen;
}
}
#if INET_CONFIG_ENABLE_DNS_RESOLVER
void HandleDNSResolveComplete(void *appState, INET_ERROR err, uint8_t addrCount, IPAddress *addrArray)
{
DNSResolutionComplete = true;
FAIL_ERROR(err, "DNS name resolution failed");
if (addrCount > 0)
{
char destAddrStr[64];
DestAddr.ToString(destAddrStr, sizeof(destAddrStr));
printf("DNS name resolution complete: %s\n", destAddrStr);
}
else
printf("DNS name resolution return no addresses\n");
DriveSend();
}
#endif // INET_CONFIG_ENABLE_DNS_RESOLVER
void HandleConnectionComplete(TCPEndPoint *ep, INET_ERROR conErr)
{
INET_ERROR err;
IPAddress peerAddr;
uint16_t peerPort;
if (conErr == WEAVE_NO_ERROR)
{
err = ep->GetPeerInfo(&peerAddr, &peerPort);
FAIL_ERROR(err, "TCPEndPoint::GetPeerInfo failed");
char peerAddrStr[64];
peerAddr.ToString(peerAddrStr, sizeof(peerAddrStr));
printf("Connection established to %s:%ld\n", peerAddrStr, (long) peerPort);
TotalSendLength = 0;
TotalRcvLength = 0;
if (TCPEP->PendingReceiveLength() == 0)
TCPEP->PutBackReceivedData(NULL);
TCPEP->DisableReceive();
TCPEP->EnableKeepAlive(10, 100);
TCPEP->DisableKeepAlive();
TCPEP->EnableReceive();
DriveSend();
}
else
{
printf("Connection FAILED: %s\n", ErrorStr(conErr));
ep->Free();
ep= NULL;
IsTimeToSend = false;
SystemLayer.CancelTimer(HandleSendTimerComplete, NULL);
SystemLayer.StartTimer(SendInterval, HandleSendTimerComplete, NULL);
}
}
void HandleConnectionReceived(TCPEndPoint *listeningEP, TCPEndPoint *conEP, const IPAddress &peerAddr, uint16_t peerPort)
{
char peerAddrStr[64];
peerAddr.ToString(peerAddrStr, sizeof(peerAddrStr));
printf("Accepted connection from %s, port %ld\n", peerAddrStr, (long) peerPort);
conEP->OnConnectComplete = HandleConnectionComplete;
conEP->OnConnectionClosed = HandleConnectionClosed;
conEP->OnDataSent = HandleDataSent;
conEP->OnDataReceived = HandleDataReceived;
TCPEP = conEP;
TotalSendLength = 0;
TotalRcvLength = 0;
DriveSend();
}
void HandleConnectionClosed(TCPEndPoint *ep, INET_ERROR err)
{
if (err == WEAVE_NO_ERROR)
printf("Connection closed\n");
else
printf("Connection closed with error: %s\n", ErrorStr(err));
printf("Freeing end point\n");
ep->Free();
if (ep == TCPEP)
{
TCPEP = NULL;
DriveSend();
}
}
void HandlePeerClose(TCPEndPoint *ep)
{
printf("HandlePeerClose\n");
(void)HandlePeerClose;
}
void HandleDataSent(TCPEndPoint *ep, uint16_t len)
{
printf("Data sent: %ld\n", (long) len);
if (ep == TCPEP)
DriveSend();
}
void HandleDataReceived(TCPEndPoint *ep, PacketBuffer *data)
{
INET_ERROR err;
if (data->TotalLength() < MinRcvLength && ep->State == TCPEndPoint::kState_Connected)
{
err = ep->PutBackReceivedData(data);
FAIL_ERROR(err, "TCPEndPoint::PutBackReceivedData failed");
return;
}
for (PacketBuffer *buf = data; buf; buf = buf->Next())
{
printf("Data received (%ld bytes)\n", (long) buf->DataLength());
uint8_t *p = buf->Start();
for (uint16_t i = 0; i < buf->DataLength(); i++, p++, TotalRcvLength++)
if (*p != (uint8_t) TotalRcvLength)
{
printf("Bad data value, offset %d\n", (int) i);
exit(-1);
}
printf("Total received data length: %d bytes\n", TotalRcvLength);
}
err = ep->AckReceive(data->TotalLength());
FAIL_ERROR(err, "TCPEndPoint::AckReceive failed");
PacketBuffer::Free(data);
if (MaxRcvLength != -1 && TotalRcvLength >= MaxRcvLength)
{
printf("Closing connection\n");
err = ep->Close();
FAIL_ERROR(err, "TCPEndPoint::Close failed");
printf("Freeing end point\n");
ep->Free();
if (ep == TCPEP)
TCPEP = NULL;
TotalRcvLength = 0;
}
}
void HandleAcceptError(TCPEndPoint *endPoint, INET_ERROR err)
{
printf("Accept error: %s\n", ErrorStr(err));
}
void HandleRawMessageReceived(RawEndPoint *endPoint, PacketBuffer *msg, IPAddress senderAddr)
{
char senderAddrStr[64];
senderAddr.ToString(senderAddrStr, sizeof(senderAddrStr));
printf("Raw message received from %s (%ld bytes)\n", senderAddrStr, (long) msg->DataLength());
TotalRcvLength += msg->DataLength();
printf("Total received data length: %d bytes\n", TotalRcvLength);
PacketBuffer::Free(msg);
}
void HandleRawReceiveError(RawEndPoint *endPoint, INET_ERROR err, IPAddress senderAddr)
{
char senderAddrStr[64];
senderAddr.ToString(senderAddrStr, sizeof(senderAddrStr));
printf("Raw receive error (%s): %s\n", senderAddrStr, ErrorStr(err));
}
void HandleUDPMessageReceived(UDPEndPoint *endPoint, PacketBuffer *msg, const IPPacketInfo *pktInfo)
{
char senderAddrStr[64];
pktInfo->SrcAddress.ToString(senderAddrStr, sizeof(senderAddrStr));
for (PacketBuffer *buf = msg; buf; buf = buf->Next())
{
printf("UDP message received from %s, port %ld (%ld bytes)\n", senderAddrStr, (long) pktInfo->SrcPort,
(long) msg->DataLength());
uint8_t *p = buf->Start();
for (uint16_t i = 0; i < buf->DataLength(); i++, p++, TotalRcvLength++)
if (*p != (uint8_t) TotalRcvLength)
{
printf("Bad data value, offset %d\n", (int) i);
exit(-1);
}
printf("Total received data length: %d bytes\n", TotalRcvLength);
}
PacketBuffer::Free(msg);
}
void HandleUDPReceiveError(UDPEndPoint *endPoint, INET_ERROR err, const IPPacketInfo *pktInfo)
{
char senderAddrStr[64];
uint16_t senderPort;
if (pktInfo != NULL)
{
pktInfo->SrcAddress.ToString(senderAddrStr, sizeof(senderAddrStr));
senderPort = pktInfo->SrcPort;
}
else
{
strcpy(senderAddrStr, "(unknown)");
senderPort = 0;
}
printf("UDP receive error (%s, port %ld): %s\n", senderAddrStr, (long) senderPort, ErrorStr(err));
}
void HandleSendTimerComplete(System::Layer* aSystemLayer, void* aAppState, System::Error aError)
{
FAIL_ERROR(aError, "Send timer completed with error");
IsTimeToSend = true;
DriveSend();
}
PacketBuffer *MakeDataBuffer(int32_t desiredLen)
{
PacketBuffer *buf;
buf = PacketBuffer::New();
if (buf == NULL)
return NULL;
if (desiredLen > buf->MaxDataLength())
desiredLen = buf->MaxDataLength();
char *p = (char *) buf->Start();
for (uint16_t i = 0; i < desiredLen; i++, p++)
*p = (uint8_t) (TotalSendLength + i);
buf->SetDataLength(desiredLen);
return buf;
}