| /* |
| * |
| * 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; |
| } |