mirror of https://github.com/FOME-Tech/openblt.git
Refs #318. Added TCP/IP support to LibOpenBLT and BootCommander.
git-svn-id: https://svn.code.sf.net/p/openblt/code/trunk@388 5dc33758-31d5-4daf-9ae8-b24bf3d40d73
This commit is contained in:
parent
159f00f0b3
commit
2327d92c65
Binary file not shown.
|
@ -169,10 +169,6 @@ int main(int argc, char const * const argv[])
|
||||||
if ( (appSessionSettings == NULL) || (!appTransportSettingsOkay) ||
|
if ( (appSessionSettings == NULL) || (!appTransportSettingsOkay) ||
|
||||||
(appFirmwareFile == NULL) )
|
(appFirmwareFile == NULL) )
|
||||||
{
|
{
|
||||||
/* Display program info */
|
|
||||||
DisplayProgramInfo();
|
|
||||||
/* Display program usage. */
|
|
||||||
DisplayProgramUsage();
|
|
||||||
/* Set error code. */
|
/* Set error code. */
|
||||||
result = RESULT_ERROR_COMMANDLINE;
|
result = RESULT_ERROR_COMMANDLINE;
|
||||||
}
|
}
|
||||||
|
@ -460,6 +456,7 @@ static void DisplayProgramUsage(void)
|
||||||
printf(" xcp_rs232 (default) -> XCP on RS232.\n");
|
printf(" xcp_rs232 (default) -> XCP on RS232.\n");
|
||||||
printf(" xcp_can -> XCP on CAN.\n");
|
printf(" xcp_can -> XCP on CAN.\n");
|
||||||
printf(" xcp_usb -> XCP on USB.\n");
|
printf(" xcp_usb -> XCP on USB.\n");
|
||||||
|
printf(" xcp_net -> XCP on TCP/IP.\n");
|
||||||
printf("\n");
|
printf("\n");
|
||||||
printf("XCP version 1.0 settings (xcp):\n");
|
printf("XCP version 1.0 settings (xcp):\n");
|
||||||
printf(" -t1=[timeout] Command response timeout in milliseconds as a 16-bit\n");
|
printf(" -t1=[timeout] Command response timeout in milliseconds as a 16-bit\n");
|
||||||
|
@ -511,6 +508,12 @@ static void DisplayProgramUsage(void)
|
||||||
printf("XCP on USB settings (xcp_usb):\n");
|
printf("XCP on USB settings (xcp_usb):\n");
|
||||||
printf(" No additional settings needed.\n");
|
printf(" No additional settings needed.\n");
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
printf("XCP on TCP/IP settings (xcp_net):\n");
|
||||||
|
printf(" -a=[value] The IP address or hostname of the target to connect to.\n");
|
||||||
|
printf(" For example 192.168.178.23 (Mandatory).\n");
|
||||||
|
printf(" -p=[value] The TCP port number to use, as a 16-bit value (Default\n");
|
||||||
|
printf(" = 1000).\n");
|
||||||
|
printf("\n");
|
||||||
printf("Program settings:\n");
|
printf("Program settings:\n");
|
||||||
printf(" -sm Silent mode switch. When specified, only minimal\n");
|
printf(" -sm Silent mode switch. When specified, only minimal\n");
|
||||||
printf(" information is written to the output (Optional).\n");
|
printf(" information is written to the output (Optional).\n");
|
||||||
|
@ -606,6 +609,9 @@ static void DisplayTransportInfo(uint32_t transportType, void const * transportS
|
||||||
case BLT_TRANSPORT_XCP_V10_USB:
|
case BLT_TRANSPORT_XCP_V10_USB:
|
||||||
printf("XCP on USB\n");
|
printf("XCP on USB\n");
|
||||||
break;
|
break;
|
||||||
|
case BLT_TRANSPORT_XCP_V10_NET:
|
||||||
|
printf("XCP on TCP/IP\n");
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
printf("Unknown\n");
|
printf("Unknown\n");
|
||||||
break;
|
break;
|
||||||
|
@ -688,6 +694,34 @@ static void DisplayTransportInfo(uint32_t transportType, void const * transportS
|
||||||
printf(" -> No additional settings required.\n");
|
printf(" -> No additional settings required.\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case BLT_TRANSPORT_XCP_V10_NET:
|
||||||
|
{
|
||||||
|
/* Check settings pointer. */
|
||||||
|
assert(transportSettings);
|
||||||
|
if (transportSettings == NULL) /*lint !e774 */
|
||||||
|
{
|
||||||
|
/* No valid settings present. */
|
||||||
|
printf(" -> Invalid settings specified\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tBltTransportSettingsXcpV10Net * xcpNetSettings =
|
||||||
|
(tBltTransportSettingsXcpV10Net *)transportSettings;
|
||||||
|
|
||||||
|
/* Output the settings to the user. */
|
||||||
|
printf(" -> Address: ");
|
||||||
|
if (xcpNetSettings->address != NULL)
|
||||||
|
{
|
||||||
|
printf("%s\n", xcpNetSettings->address);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("Unknown\n");
|
||||||
|
}
|
||||||
|
printf(" -> Port: %hu \n", xcpNetSettings->port);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
printf(" -> No settings specified\n");
|
printf(" -> No settings specified\n");
|
||||||
break;
|
break;
|
||||||
|
@ -974,7 +1008,8 @@ static uint32_t ExtractTransportTypeFromCommandLine(int argc, char const * const
|
||||||
{
|
{
|
||||||
{ .name = "xcp_rs232", .value = BLT_TRANSPORT_XCP_V10_RS232 },
|
{ .name = "xcp_rs232", .value = BLT_TRANSPORT_XCP_V10_RS232 },
|
||||||
{ .name = "xcp_can", .value = BLT_TRANSPORT_XCP_V10_CAN },
|
{ .name = "xcp_can", .value = BLT_TRANSPORT_XCP_V10_CAN },
|
||||||
{ .name = "xcp_usb", .value = BLT_TRANSPORT_XCP_V10_USB }
|
{ .name = "xcp_usb", .value = BLT_TRANSPORT_XCP_V10_USB },
|
||||||
|
{ .name = "xcp_net", .value = BLT_TRANSPORT_XCP_V10_NET }
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Set the default transport type in case nothing was specified on the command line. */
|
/* Set the default transport type in case nothing was specified on the command line. */
|
||||||
|
@ -1182,6 +1217,49 @@ static void * ExtractTransportSettingsFromCommandLine(int argc,
|
||||||
* layer.
|
* layer.
|
||||||
*/
|
*/
|
||||||
break;
|
break;
|
||||||
|
/* -------------------------- XCP on TCP/IP ---------------------------------- */
|
||||||
|
case BLT_TRANSPORT_XCP_V10_NET:
|
||||||
|
/* The following transport layer specific command line parameters are supported:
|
||||||
|
* -a=[value] -> The IP address or hostname of the target to connect to.
|
||||||
|
* -p=[value] -> The TCP port number to use.
|
||||||
|
*/
|
||||||
|
/* Allocate memory for storing the settings and check the result. */
|
||||||
|
result = malloc(sizeof(tBltTransportSettingsXcpV10Net));
|
||||||
|
assert(result != NULL);
|
||||||
|
if (result != NULL) /*lint !e774 */
|
||||||
|
{
|
||||||
|
/* Create typed pointer for easy reading. */
|
||||||
|
tBltTransportSettingsXcpV10Net * netSettings =
|
||||||
|
(tBltTransportSettingsXcpV10Net *)result;
|
||||||
|
/* Set default values. */
|
||||||
|
netSettings->address = NULL;
|
||||||
|
netSettings->port = 1000;
|
||||||
|
/* Loop through all the command line parameters, just skip the 1st one because
|
||||||
|
* this is the name of the program, which we are not interested in.
|
||||||
|
*/
|
||||||
|
for (paramIdx = 1; paramIdx < argc; paramIdx++)
|
||||||
|
{
|
||||||
|
/* Is this the -a=[name] parameter? */
|
||||||
|
if ( (strstr(argv[paramIdx], "-a=") != NULL) &&
|
||||||
|
(strlen(argv[paramIdx]) > 3) )
|
||||||
|
{
|
||||||
|
/* Store the pointer to the network address. */
|
||||||
|
netSettings->address = &argv[paramIdx][3];
|
||||||
|
/* Continue with next loop iteration. */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* Is this the -p=[value] parameter? */
|
||||||
|
if ( (strstr(argv[paramIdx], "-p=") != NULL) &&
|
||||||
|
(strlen(argv[paramIdx]) > 3) )
|
||||||
|
{
|
||||||
|
/* Extract the port value. */
|
||||||
|
sscanf(&argv[paramIdx][3], "%hu", &(netSettings->port));
|
||||||
|
/* Continue with next loop iteration. */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
/* -------------------------- Unknown ------------------------------------------ */
|
/* -------------------------- Unknown ------------------------------------------ */
|
||||||
default:
|
default:
|
||||||
/* Noting to extract. */
|
/* Noting to extract. */
|
||||||
|
|
|
@ -145,7 +145,8 @@ set(
|
||||||
# "make openblt_static" to individually build the static library.
|
# "make openblt_static" to individually build the static library.
|
||||||
# Note that when you link your own application to the static library of LibOpenBLT under
|
# Note that when you link your own application to the static library of LibOpenBLT under
|
||||||
# Unix, you need to also link the LibUsb and LibDL libraries by adding usb-1.0 and dl to
|
# Unix, you need to also link the LibUsb and LibDL libraries by adding usb-1.0 and dl to
|
||||||
# the linker library dependencies.
|
# the linker library dependencies. Under Windows, you need to also link the Winsock
|
||||||
|
# library by adding ws2_32 to the linker library dependencies.
|
||||||
if(BUILD_STATIC)
|
if(BUILD_STATIC)
|
||||||
add_library(openblt_static STATIC ${LIB_SRCS})
|
add_library(openblt_static STATIC ${LIB_SRCS})
|
||||||
SET_TARGET_PROPERTIES(openblt_static PROPERTIES OUTPUT_NAME openblt CLEAN_DIRECT_OUTPUT 1)
|
SET_TARGET_PROPERTIES(openblt_static PROPERTIES OUTPUT_NAME openblt CLEAN_DIRECT_OUTPUT 1)
|
||||||
|
@ -175,6 +176,8 @@ if(BUILD_SHARED)
|
||||||
else()
|
else()
|
||||||
SET_TARGET_PROPERTIES(openblt_shared PROPERTIES OUTPUT_NAME openblt CLEAN_DIRECT_OUTPUT 1)
|
SET_TARGET_PROPERTIES(openblt_shared PROPERTIES OUTPUT_NAME openblt CLEAN_DIRECT_OUTPUT 1)
|
||||||
endif()
|
endif()
|
||||||
|
# Link the Winsock library
|
||||||
|
target_link_libraries(openblt_shared ws2_32)
|
||||||
endif(BUILD_SHARED)
|
endif(BUILD_SHARED)
|
||||||
|
|
||||||
# Only generate the PC-lint taget if the option is enabled. Use "make openblt_LINT" to
|
# Only generate the PC-lint taget if the option is enabled. Use "make openblt_LINT" to
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
/************************************************************************************//**
|
||||||
|
* \file netaccess.h
|
||||||
|
* \brief TCP/IP network access header file.
|
||||||
|
* \ingroup NetAccess
|
||||||
|
* \internal
|
||||||
|
*----------------------------------------------------------------------------------------
|
||||||
|
* C O P Y R I G H T
|
||||||
|
*----------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) 2017 by Feaser http://www.feaser.com All rights reserved
|
||||||
|
*
|
||||||
|
*----------------------------------------------------------------------------------------
|
||||||
|
* L I C E N S E
|
||||||
|
*----------------------------------------------------------------------------------------
|
||||||
|
* This file is part of OpenBLT. OpenBLT is free software: you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation, either version 3 of the License, or (at your option) any later
|
||||||
|
* version.
|
||||||
|
*
|
||||||
|
* OpenBLT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||||
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE. See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You have received a copy of the GNU General Public License along with OpenBLT. It
|
||||||
|
* should be located in ".\Doc\license.html". If not, contact Feaser to obtain a copy.
|
||||||
|
*
|
||||||
|
* \endinternal
|
||||||
|
****************************************************************************************/
|
||||||
|
/************************************************************************************//**
|
||||||
|
* \defgroup NetAccess TCP/IP Network Access
|
||||||
|
* \brief This module implements a generic TCP/IP network access client driver.
|
||||||
|
* \ingroup Session
|
||||||
|
****************************************************************************************/
|
||||||
|
#ifndef NETACCESS_H
|
||||||
|
#define NETACCESS_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/****************************************************************************************
|
||||||
|
* Function prototypes
|
||||||
|
****************************************************************************************/
|
||||||
|
void NetAccessInit(void);
|
||||||
|
void NetAccessTerminate(void);
|
||||||
|
bool NetAccessConnect(char const * address, uint16_t port);
|
||||||
|
void NetAccessDisconnect(void);
|
||||||
|
bool NetAccessSend(uint8_t const * data, uint32_t length);
|
||||||
|
bool NetAccessReceive(uint8_t * data, uint32_t * length, uint32_t timeout);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* NETACCESS_H */
|
||||||
|
/********************************* end of netaccess.h **********************************/
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
#include "xcptpuart.h" /* XCP UART transport layer */
|
#include "xcptpuart.h" /* XCP UART transport layer */
|
||||||
#include "xcptpcan.h" /* XCP CAN transport layer */
|
#include "xcptpcan.h" /* XCP CAN transport layer */
|
||||||
#include "xcptpusb.h" /* XCP USB transport layer */
|
#include "xcptpusb.h" /* XCP USB transport layer */
|
||||||
|
#include "xcptpnet.h" /* XCP TCP/IP transport layer */
|
||||||
|
|
||||||
|
|
||||||
/****************************************************************************************
|
/****************************************************************************************
|
||||||
|
@ -119,7 +120,8 @@ LIBOPENBLT_EXPORT void BltSessionInit(uint32_t sessionType,
|
||||||
assert(sessionType == BLT_SESSION_XCP_V10);
|
assert(sessionType == BLT_SESSION_XCP_V10);
|
||||||
assert( (transportType == BLT_TRANSPORT_XCP_V10_RS232) || \
|
assert( (transportType == BLT_TRANSPORT_XCP_V10_RS232) || \
|
||||||
(transportType == BLT_TRANSPORT_XCP_V10_CAN) || \
|
(transportType == BLT_TRANSPORT_XCP_V10_CAN) || \
|
||||||
(transportType == BLT_TRANSPORT_XCP_V10_USB) );
|
(transportType == BLT_TRANSPORT_XCP_V10_USB) || \
|
||||||
|
(transportType == BLT_TRANSPORT_XCP_V10_NET) );
|
||||||
|
|
||||||
/* Initialize the correct session. */
|
/* Initialize the correct session. */
|
||||||
if (sessionType == BLT_SESSION_XCP_V10) /*lint !e774 */
|
if (sessionType == BLT_SESSION_XCP_V10) /*lint !e774 */
|
||||||
|
@ -207,6 +209,32 @@ LIBOPENBLT_EXPORT void BltSessionInit(uint32_t sessionType,
|
||||||
/* Link the transport layer to the XCP loader settings. */
|
/* Link the transport layer to the XCP loader settings. */
|
||||||
xcpLoaderSettings.transport = XcpTpUsbGetTransport();
|
xcpLoaderSettings.transport = XcpTpUsbGetTransport();
|
||||||
}
|
}
|
||||||
|
else if (transportType == BLT_TRANSPORT_XCP_V10_NET)
|
||||||
|
{
|
||||||
|
/* Verify transportSettings parameters because the XCP NET transport layer
|
||||||
|
* requires them.
|
||||||
|
*/
|
||||||
|
assert(transportSettings != NULL);
|
||||||
|
/* Only continue if the transportSettings parameter is valid. */
|
||||||
|
if (transportSettings != NULL) /*lint !e774 */
|
||||||
|
{
|
||||||
|
/* Cast transport settings to the correct type. */
|
||||||
|
tBltTransportSettingsXcpV10Net * bltTransportSettingsXcpV10NetPtr;
|
||||||
|
bltTransportSettingsXcpV10NetPtr =
|
||||||
|
(tBltTransportSettingsXcpV10Net * )transportSettings;
|
||||||
|
/* Convert transport settings to the format supported by the XCP NET transport
|
||||||
|
* layer. It was made static to make sure it doesn't get out of scope when
|
||||||
|
* used in xcpLoaderSettings.
|
||||||
|
*/
|
||||||
|
static tXcpTpNetSettings xcpTpNetSettings;
|
||||||
|
xcpTpNetSettings.address = bltTransportSettingsXcpV10NetPtr->address;
|
||||||
|
xcpTpNetSettings.port = bltTransportSettingsXcpV10NetPtr->port;
|
||||||
|
/* Store transport layer settings in the XCP loader settings. */
|
||||||
|
xcpLoaderSettings.transportSettings = &xcpTpNetSettings;
|
||||||
|
/* Link the transport layer to the XCP loader settings. */
|
||||||
|
xcpLoaderSettings.transport = XcpTpNetGetTransport();
|
||||||
|
}
|
||||||
|
}
|
||||||
/* Perform actual session initialization. */
|
/* Perform actual session initialization. */
|
||||||
SessionInit(XcpLoaderGetProtocol(), &xcpLoaderSettings);
|
SessionInit(XcpLoaderGetProtocol(), &xcpLoaderSettings);
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,6 +108,11 @@ LIBOPENBLT_EXPORT char const * BltVersionGetString(void);
|
||||||
*/
|
*/
|
||||||
#define BLT_TRANSPORT_XCP_V10_USB ((uint32_t)2u)
|
#define BLT_TRANSPORT_XCP_V10_USB ((uint32_t)2u)
|
||||||
|
|
||||||
|
/** \brief Transport layer for the XCP v1.0 protocol that uses TCP/IP for data
|
||||||
|
* exchange.
|
||||||
|
*/
|
||||||
|
#define BLT_TRANSPORT_XCP_V10_NET ((uint32_t)3u)
|
||||||
|
|
||||||
|
|
||||||
/****************************************************************************************
|
/****************************************************************************************
|
||||||
* Type definitions
|
* Type definitions
|
||||||
|
@ -160,6 +165,17 @@ typedef struct t_blt_transport_settings_xcp_v10_can
|
||||||
uint32_t useExtended; /**< Boolean to configure 29-bit CAN identifiers. */
|
uint32_t useExtended; /**< Boolean to configure 29-bit CAN identifiers. */
|
||||||
} tBltTransportSettingsXcpV10Can;
|
} tBltTransportSettingsXcpV10Can;
|
||||||
|
|
||||||
|
/** \brief Structure layout of the XCP version 1.0 RS232 transport layer settings. The
|
||||||
|
* portName field is platform dependent. On Linux based systems this should be
|
||||||
|
* the filename of the tty-device, such as "/dev/tty0". On Windows based systems
|
||||||
|
* it should be the name of the COM-port, such as "COM1".
|
||||||
|
*/
|
||||||
|
typedef struct t_blt_transport_settings_xcp_v10_net
|
||||||
|
{
|
||||||
|
char const * address; /**< Target IP-address or hostname on the network. */
|
||||||
|
uint16_t port; /**< TCP port to use. */
|
||||||
|
} tBltTransportSettingsXcpV10Net;
|
||||||
|
|
||||||
|
|
||||||
/****************************************************************************************
|
/****************************************************************************************
|
||||||
* Function prototypes
|
* Function prototypes
|
||||||
|
|
|
@ -0,0 +1,332 @@
|
||||||
|
/************************************************************************************//**
|
||||||
|
* \file port/linux/netaccess.c
|
||||||
|
* \brief TCP/IP network access source file.
|
||||||
|
* \ingroup NetAccess
|
||||||
|
* \internal
|
||||||
|
*----------------------------------------------------------------------------------------
|
||||||
|
* C O P Y R I G H T
|
||||||
|
*----------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) 2017 by Feaser http://www.feaser.com All rights reserved
|
||||||
|
*
|
||||||
|
*----------------------------------------------------------------------------------------
|
||||||
|
* L I C E N S E
|
||||||
|
*----------------------------------------------------------------------------------------
|
||||||
|
* This file is part of OpenBLT. OpenBLT is free software: you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation, either version 3 of the License, or (at your option) any later
|
||||||
|
* version.
|
||||||
|
*
|
||||||
|
* OpenBLT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||||
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE. See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You have received a copy of the GNU General Public License along with OpenBLT. It
|
||||||
|
* should be located in ".\Doc\license.html". If not, contact Feaser to obtain a copy.
|
||||||
|
*
|
||||||
|
* \endinternal
|
||||||
|
****************************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************************
|
||||||
|
* Include files
|
||||||
|
****************************************************************************************/
|
||||||
|
#include <assert.h> /* for assertions */
|
||||||
|
#include <stdint.h> /* for standard integer types */
|
||||||
|
#include <stddef.h> /* for NULL declaration */
|
||||||
|
#include <stdbool.h> /* for boolean type */
|
||||||
|
#include <string.h> /* for string utilities */
|
||||||
|
#include <unistd.h> /* for close */
|
||||||
|
#include <sys/socket.h> /* for socket */
|
||||||
|
#include <arpa/inet.h> /* for inet_addr */
|
||||||
|
#include <netdb.h> /* for hostent */
|
||||||
|
#include "netaccess.h" /* TCP/IP network access module */
|
||||||
|
|
||||||
|
|
||||||
|
/****************************************************************************************
|
||||||
|
* Macro definitions
|
||||||
|
****************************************************************************************/
|
||||||
|
/** \brief Constant value that indicates that the network socket is invalid. */
|
||||||
|
#define NETACCESS_INVALID_SOCKET (-1)
|
||||||
|
|
||||||
|
|
||||||
|
/****************************************************************************************
|
||||||
|
* Local data declarations
|
||||||
|
****************************************************************************************/
|
||||||
|
/** \brief The socket that is used as an endpoint for the TCP/IP network
|
||||||
|
* communication.
|
||||||
|
*/
|
||||||
|
static int netAccessSocket;
|
||||||
|
|
||||||
|
|
||||||
|
/************************************************************************************//**
|
||||||
|
** \brief Initializes the network access module.
|
||||||
|
**
|
||||||
|
****************************************************************************************/
|
||||||
|
void NetAccessInit(void)
|
||||||
|
{
|
||||||
|
/* Invalidate the socket. */
|
||||||
|
netAccessSocket = NETACCESS_INVALID_SOCKET;
|
||||||
|
} /*** end of NetAccessInit ***/
|
||||||
|
|
||||||
|
|
||||||
|
/************************************************************************************//**
|
||||||
|
** \brief Terminates the network access module.
|
||||||
|
**
|
||||||
|
****************************************************************************************/
|
||||||
|
void NetAccessTerminate(void)
|
||||||
|
{
|
||||||
|
/* Make sure to disconnect form the server. */
|
||||||
|
NetAccessDisconnect();
|
||||||
|
} /*** end of NetAccessTerminate ***/
|
||||||
|
|
||||||
|
|
||||||
|
/************************************************************************************//**
|
||||||
|
** \brief Connects to the TCP/IP server at the specified address and the given port.
|
||||||
|
** \param address The address of the server. This can be a hostname (such as
|
||||||
|
** mydomain.com) or an IP address (such as 127.0.0.1).
|
||||||
|
** \param port The port number on the server to connect to.
|
||||||
|
** \return True if successful, false otherwise.
|
||||||
|
**
|
||||||
|
****************************************************************************************/
|
||||||
|
bool NetAccessConnect(char const * address, uint16_t port)
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
struct addrinfo hints = { 0 };
|
||||||
|
struct addrinfo * serverinfo = NULL;
|
||||||
|
struct sockaddr_in serverIPv4 = { 0 };
|
||||||
|
struct sockaddr_in6 serverIPv6 = { 0 };
|
||||||
|
bool serverIPv4found = false;
|
||||||
|
bool serverIPv6found = false;
|
||||||
|
|
||||||
|
/* Check parameters. */
|
||||||
|
assert(address != NULL);
|
||||||
|
assert(port > 0);
|
||||||
|
|
||||||
|
/* Start by invalidating the socket. */
|
||||||
|
netAccessSocket = NETACCESS_INVALID_SOCKET;
|
||||||
|
|
||||||
|
/* Only continue with valid parameters. */
|
||||||
|
if ( (address != NULL) && (port > 0) ) /*lint !e774 */
|
||||||
|
{
|
||||||
|
/* Set result to true and only reset it to false upon detection of a problem. */
|
||||||
|
result = true;
|
||||||
|
|
||||||
|
/* Initialize hints structure to aid in hostname resolving. Note that AF_UNSPEC is
|
||||||
|
* used to support both IPv4 and IPv6.
|
||||||
|
*/
|
||||||
|
hints.ai_family = AF_UNSPEC;
|
||||||
|
hints.ai_socktype = (int)SOCK_STREAM;
|
||||||
|
hints.ai_flags |= AI_CANONNAME;
|
||||||
|
|
||||||
|
/* Attempt to resolve the hostname. This converts the hostname to an IP address, if
|
||||||
|
* it wasn't already an IP address.
|
||||||
|
*/
|
||||||
|
if (getaddrinfo(address, NULL, &hints, &serverinfo) != 0)
|
||||||
|
{
|
||||||
|
/* Could not resolve the hostname. */
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
/* Sanity check on the pointer that should now be initialized and contain data. */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (serverinfo == NULL)
|
||||||
|
{
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* The serverinfo pointer now points to an array with results of the hostname
|
||||||
|
* resolving. We only need one, so grab the first valid one. Prefer IPv4 over IPv6.
|
||||||
|
*/
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
/* Point to the first entry. */
|
||||||
|
struct addrinfo * entry = serverinfo;
|
||||||
|
/* Loop over the entries until a valid one was found. */
|
||||||
|
while (entry != NULL)
|
||||||
|
{
|
||||||
|
/* Does this entry contain an IPv4 address? */
|
||||||
|
if (entry->ai_family == AF_INET)
|
||||||
|
{
|
||||||
|
/* Copy this one for later usage. */
|
||||||
|
memcpy (&serverIPv4, entry->ai_addr, entry->ai_addrlen);
|
||||||
|
serverIPv4.sin_family = AF_INET;
|
||||||
|
serverIPv4.sin_port = htons(port);
|
||||||
|
/* Set flag so we know which socket address variable to use later on. */
|
||||||
|
serverIPv4found = true;
|
||||||
|
/* No need to go over the other entries, since we found a valid one. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* Does this entry contain an IPv6 address? */
|
||||||
|
if (entry->ai_family == AF_INET6)
|
||||||
|
{
|
||||||
|
/* Copy this one for later usage. */
|
||||||
|
memcpy (&serverIPv6, entry->ai_addr, entry->ai_addrlen);
|
||||||
|
serverIPv6.sin6_family = AF_INET6;
|
||||||
|
serverIPv6.sin6_port = htons(port);
|
||||||
|
/* Set flag so we know which socket address variable to use later on. */
|
||||||
|
serverIPv6found = true;
|
||||||
|
/* No need to go over the other entries, since we found a valid one. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* Move on to the next one. */
|
||||||
|
entry = entry->ai_next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Check that a valid entry was found. */
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
if ( (!serverIPv4found) && (!serverIPv6found) )
|
||||||
|
{
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Create the socket. */
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
/* Create the socket based on the family type. */
|
||||||
|
if (serverIPv4found)
|
||||||
|
{
|
||||||
|
netAccessSocket = socket(serverIPv4.sin_family, (int)SOCK_STREAM, IPPROTO_TCP);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
netAccessSocket = socket(serverIPv6.sin6_family, (int)SOCK_STREAM, IPPROTO_TCP);
|
||||||
|
}
|
||||||
|
/* Check the socket. */
|
||||||
|
if (netAccessSocket < 0)
|
||||||
|
{
|
||||||
|
/* Could not create the socket. */
|
||||||
|
netAccessSocket = NETACCESS_INVALID_SOCKET;
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Connect the socket. */
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
/* Get the socket address pointer based on the family type. */
|
||||||
|
struct sockaddr * server_address;
|
||||||
|
if (serverIPv4found)
|
||||||
|
{
|
||||||
|
server_address = (struct sockaddr *)&serverIPv4; /*lint !e740 */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
server_address = (struct sockaddr *)&serverIPv6; /*lint !e740 */
|
||||||
|
}
|
||||||
|
/* Attempt to connect. */
|
||||||
|
if (connect(netAccessSocket, server_address, sizeof(struct sockaddr)) < 0)
|
||||||
|
{
|
||||||
|
/* Could not connect. Close the socket and negate result value. */
|
||||||
|
close(netAccessSocket);
|
||||||
|
netAccessSocket = NETACCESS_INVALID_SOCKET;
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Give the result back to the caller. */
|
||||||
|
return result;
|
||||||
|
} /*** end of NetAccessConnect ***/
|
||||||
|
|
||||||
|
|
||||||
|
/************************************************************************************//**
|
||||||
|
** \brief Disconnects from the TCP/IP server.
|
||||||
|
**
|
||||||
|
****************************************************************************************/
|
||||||
|
void NetAccessDisconnect(void)
|
||||||
|
{
|
||||||
|
/* Close the socket if it is open. */
|
||||||
|
if (netAccessSocket >= 0)
|
||||||
|
{
|
||||||
|
close(netAccessSocket);
|
||||||
|
netAccessSocket = NETACCESS_INVALID_SOCKET;
|
||||||
|
}
|
||||||
|
} /*** end of NetAccessDisconnect ***/
|
||||||
|
|
||||||
|
|
||||||
|
/************************************************************************************//**
|
||||||
|
** \brief Sends data to the TCP/IP server.
|
||||||
|
** \param data Pointer to byte array with data to send.
|
||||||
|
** \param length Number of bytes to send.
|
||||||
|
** \return True if successful, false otherwise.
|
||||||
|
**
|
||||||
|
****************************************************************************************/
|
||||||
|
bool NetAccessSend(uint8_t const * data, uint32_t length)
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
|
||||||
|
/* Check parameters. */
|
||||||
|
assert(data != NULL);
|
||||||
|
assert(length > 0);
|
||||||
|
|
||||||
|
/* Only continue with valid parameters. */
|
||||||
|
if ( (data != NULL) && (length > 0) ) /*lint !e774 */
|
||||||
|
{
|
||||||
|
/* Only continue with a valid socket. */
|
||||||
|
if (netAccessSocket >= 0)
|
||||||
|
{
|
||||||
|
/* Attempt to send the data. */
|
||||||
|
if (send(netAccessSocket, data, length, 0) >= 0)
|
||||||
|
{
|
||||||
|
/* Successfully send the data. */
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Give the result back to the caller. */
|
||||||
|
return result;
|
||||||
|
} /*** end of NetAccessSend ***/
|
||||||
|
|
||||||
|
|
||||||
|
/************************************************************************************//**
|
||||||
|
** \brief Receives data from the TCP/IP server in a blocking manner.
|
||||||
|
** \param data Pointer to byte array to store the received data.
|
||||||
|
** \param length Holds the max number of bytes that can be stored into the byte
|
||||||
|
** array. This function also overwrites this value with the number of bytes
|
||||||
|
** that were actually received.
|
||||||
|
** \param timeout Timeout in milliseconds for the data reception.
|
||||||
|
** \return True if successful, false otherwise.
|
||||||
|
**
|
||||||
|
****************************************************************************************/
|
||||||
|
bool NetAccessReceive(uint8_t * data, uint32_t * length, uint32_t timeout)
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
struct timeval tv;
|
||||||
|
ssize_t receivedLen;
|
||||||
|
|
||||||
|
/* Check parameters. */
|
||||||
|
assert(data != NULL);
|
||||||
|
assert(length != NULL);
|
||||||
|
assert(timeout > 0);
|
||||||
|
|
||||||
|
/* Only continue with valid parameters. */
|
||||||
|
if ( (data != NULL) && (length != NULL) && (timeout > 0) ) /*lint !e774 */
|
||||||
|
{
|
||||||
|
/* Only continue with a valid socket. */
|
||||||
|
if (netAccessSocket >= 0)
|
||||||
|
{
|
||||||
|
/* Configure the timeout for the receive operation. */
|
||||||
|
tv.tv_sec = (__time_t)(timeout / 1000u);
|
||||||
|
tv.tv_usec = (timeout % 1000u) * 1000u;
|
||||||
|
if (setsockopt(netAccessSocket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(struct timeval)) >= 0)
|
||||||
|
{
|
||||||
|
/* Attempt to receive data. */
|
||||||
|
receivedLen = recv(netAccessSocket, data, *length, 0);
|
||||||
|
/* Process the result. Everything < 0 indicate that an error occured. A value of
|
||||||
|
* zero is also treated as an error, since data was expected.
|
||||||
|
*/
|
||||||
|
if (receivedLen > 0)
|
||||||
|
{
|
||||||
|
/* Store the number of received bytes. */
|
||||||
|
*length = (uint32_t)receivedLen;
|
||||||
|
/* Successfully received data. */
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Give the result back to the caller. */
|
||||||
|
return result;
|
||||||
|
} /*** end of NetAccessReceive ***/
|
||||||
|
|
||||||
|
|
||||||
|
/*********************************** end of netaccess.c ********************************/
|
||||||
|
|
|
@ -0,0 +1,349 @@
|
||||||
|
/************************************************************************************//**
|
||||||
|
* \file port/windows/netaccess.c
|
||||||
|
* \brief TCP/IP network access source file.
|
||||||
|
* \ingroup NetAccess
|
||||||
|
* \internal
|
||||||
|
*----------------------------------------------------------------------------------------
|
||||||
|
* C O P Y R I G H T
|
||||||
|
*----------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) 2017 by Feaser http://www.feaser.com All rights reserved
|
||||||
|
*
|
||||||
|
*----------------------------------------------------------------------------------------
|
||||||
|
* L I C E N S E
|
||||||
|
*----------------------------------------------------------------------------------------
|
||||||
|
* This file is part of OpenBLT. OpenBLT is free software: you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation, either version 3 of the License, or (at your option) any later
|
||||||
|
* version.
|
||||||
|
*
|
||||||
|
* OpenBLT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||||
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE. See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You have received a copy of the GNU General Public License along with OpenBLT. It
|
||||||
|
* should be located in ".\Doc\license.html". If not, contact Feaser to obtain a copy.
|
||||||
|
*
|
||||||
|
* \endinternal
|
||||||
|
****************************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************************
|
||||||
|
* Include files
|
||||||
|
****************************************************************************************/
|
||||||
|
#include <assert.h> /* for assertions */
|
||||||
|
#include <stdint.h> /* for standard integer types */
|
||||||
|
#include <stddef.h> /* for NULL declaration */
|
||||||
|
#include <stdbool.h> /* for boolean type */
|
||||||
|
#include <winsock2.h> /* for WinSock2 definitions */
|
||||||
|
#include <ws2tcpip.h> /* for WinSock2 TCP/IP protocol extensions */
|
||||||
|
#include "netaccess.h" /* TCP/IP network access module */
|
||||||
|
|
||||||
|
|
||||||
|
/****************************************************************************************
|
||||||
|
* Local data declarations
|
||||||
|
****************************************************************************************/
|
||||||
|
/** \brief Boolean flag to keep track if the Winsock library is initialized. */
|
||||||
|
static bool winsockInitialized;
|
||||||
|
|
||||||
|
/** \brief The socket that is used as an endpoint for the TCP/IP network
|
||||||
|
* communication.
|
||||||
|
*/
|
||||||
|
static SOCKET netAccessSocket;
|
||||||
|
|
||||||
|
|
||||||
|
/************************************************************************************//**
|
||||||
|
** \brief Initializes the network access module.
|
||||||
|
**
|
||||||
|
****************************************************************************************/
|
||||||
|
void NetAccessInit(void)
|
||||||
|
{
|
||||||
|
WSADATA wsa;
|
||||||
|
|
||||||
|
/* Invalidate the socket. */
|
||||||
|
netAccessSocket = INVALID_SOCKET;
|
||||||
|
|
||||||
|
/* Init locals. */
|
||||||
|
winsockInitialized = false;
|
||||||
|
|
||||||
|
/* Attempt to initialize the Winsock library. */
|
||||||
|
if (WSAStartup(MAKEWORD(2,2),&wsa) == 0)
|
||||||
|
{
|
||||||
|
/* Update flag. */
|
||||||
|
winsockInitialized = true;
|
||||||
|
}
|
||||||
|
} /*** end of NetAccessInit ***/
|
||||||
|
|
||||||
|
|
||||||
|
/************************************************************************************//**
|
||||||
|
** \brief Terminates the network access module.
|
||||||
|
**
|
||||||
|
****************************************************************************************/
|
||||||
|
void NetAccessTerminate(void)
|
||||||
|
{
|
||||||
|
/* Make sure to disconnect form the server. */
|
||||||
|
NetAccessDisconnect();
|
||||||
|
|
||||||
|
/* Cleanup the Winsock library, if it was initialized. */
|
||||||
|
if (winsockInitialized)
|
||||||
|
{
|
||||||
|
/* Update flag. */
|
||||||
|
winsockInitialized = false;
|
||||||
|
/* Free Winsock resources. */
|
||||||
|
(void)WSACleanup();
|
||||||
|
}
|
||||||
|
} /*** end of NetAccessTerminate ***/
|
||||||
|
|
||||||
|
|
||||||
|
/************************************************************************************//**
|
||||||
|
** \brief Connects to the TCP/IP server at the specified address and the given port.
|
||||||
|
** \param address The address of the server. This can be a hostname (such as
|
||||||
|
** mydomain.com) or an IP address (such as 127.0.0.1).
|
||||||
|
** \param port The port number on the server to connect to.
|
||||||
|
** \return True if successful, false otherwise.
|
||||||
|
**
|
||||||
|
****************************************************************************************/
|
||||||
|
bool NetAccessConnect(char const * address, uint16_t port)
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
struct addrinfo hints = { 0 };
|
||||||
|
struct addrinfo * serverinfo = NULL;
|
||||||
|
struct sockaddr_in serverIPv4 = { 0 };
|
||||||
|
struct sockaddr_in6 serverIPv6 = { 0 };
|
||||||
|
bool serverIPv4found = false;
|
||||||
|
bool serverIPv6found = false;
|
||||||
|
|
||||||
|
/* Check parameters. */
|
||||||
|
assert(address != NULL);
|
||||||
|
assert(port > 0);
|
||||||
|
|
||||||
|
/* Start by invalidating the socket. */
|
||||||
|
netAccessSocket = INVALID_SOCKET;
|
||||||
|
|
||||||
|
/* Only continue with valid parameters and an initialized Winsock. */
|
||||||
|
if ( (address != NULL) && (port > 0) && (winsockInitialized) ) /*lint !e774 */
|
||||||
|
{
|
||||||
|
/* Set result to true and only reset it to false upon detection of a problem. */
|
||||||
|
result = true;
|
||||||
|
|
||||||
|
/* Initialize hints structure to aid in hostname resolving. Note that AF_UNSPEC is
|
||||||
|
* used to support both IPv4 and IPv6.
|
||||||
|
*/
|
||||||
|
hints.ai_family = AF_UNSPEC;
|
||||||
|
hints.ai_socktype = (int)SOCK_STREAM;
|
||||||
|
hints.ai_flags |= AI_CANONNAME;
|
||||||
|
|
||||||
|
/* Attempt to resolve the hostname. This converts the hostname to an IP address, if
|
||||||
|
* it wasn't already an IP address.
|
||||||
|
*/
|
||||||
|
if (getaddrinfo(address, NULL, &hints, &serverinfo) != 0)
|
||||||
|
{
|
||||||
|
/* Could not resolve the hostname. */
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
/* Sanity check on the pointer that should now be initialized and contain data. */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (serverinfo == NULL)
|
||||||
|
{
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* The serverinfo pointer now points to an array with results of the hostname
|
||||||
|
* resolving. We only need one, so grab the first valid one. Prefer IPv4 over IPv6.
|
||||||
|
*/
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
/* Point to the first entry. */
|
||||||
|
struct addrinfo * entry = serverinfo;
|
||||||
|
/* Loop over the entries until a valid one was found. */
|
||||||
|
while (entry != NULL)
|
||||||
|
{
|
||||||
|
/* Does this entry contain an IPv4 address? */
|
||||||
|
if (entry->ai_family == AF_INET)
|
||||||
|
{
|
||||||
|
/* Copy this one for later usage. */
|
||||||
|
memcpy (&serverIPv4, entry->ai_addr, entry->ai_addrlen);
|
||||||
|
serverIPv4.sin_family = AF_INET;
|
||||||
|
serverIPv4.sin_port = htons(port);
|
||||||
|
/* Set flag so we know which socket address variable to use later on. */
|
||||||
|
serverIPv4found = true;
|
||||||
|
/* No need to go over the other entries, since we found a valid one. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* Does this entry contain an IPv6 address? */
|
||||||
|
if (entry->ai_family == AF_INET6)
|
||||||
|
{
|
||||||
|
/* Copy this one for later usage. */
|
||||||
|
memcpy (&serverIPv6, entry->ai_addr, entry->ai_addrlen);
|
||||||
|
serverIPv6.sin6_family = AF_INET6;
|
||||||
|
serverIPv6.sin6_port = htons(port);
|
||||||
|
/* Set flag so we know which socket address variable to use later on. */
|
||||||
|
serverIPv6found = true;
|
||||||
|
/* No need to go over the other entries, since we found a valid one. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* Move on to the next one. */
|
||||||
|
entry = entry->ai_next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Check that a valid entry was found. */
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
if ( (!serverIPv4found) && (!serverIPv6found) )
|
||||||
|
{
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Create the socket. */
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
/* Create the socket based on the family type. */
|
||||||
|
if (serverIPv4found)
|
||||||
|
{
|
||||||
|
netAccessSocket = socket(serverIPv4.sin_family, (int)SOCK_STREAM, (int)IPPROTO_TCP);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
netAccessSocket = socket(serverIPv6.sin6_family, (int)SOCK_STREAM, (int)IPPROTO_TCP);
|
||||||
|
}
|
||||||
|
/* Check the socket. */
|
||||||
|
if (netAccessSocket == INVALID_SOCKET)
|
||||||
|
{
|
||||||
|
/* Could not create the socket. */
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Connect the socket. */
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
/* Get the socket address pointer based on the family type. */
|
||||||
|
struct sockaddr * server_address;
|
||||||
|
if (serverIPv4found)
|
||||||
|
{
|
||||||
|
server_address = (struct sockaddr *)&serverIPv4; /*lint !e740 */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
server_address = (struct sockaddr *)&serverIPv6; /*lint !e740 */
|
||||||
|
}
|
||||||
|
/* Attempt to connect. */
|
||||||
|
if (connect(netAccessSocket, server_address, sizeof(struct sockaddr)) != 0)
|
||||||
|
{
|
||||||
|
/* Could not connect. Close the socket and negate result value. */
|
||||||
|
(void)closesocket(netAccessSocket);
|
||||||
|
netAccessSocket = INVALID_SOCKET;
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Give the result back to the caller. */
|
||||||
|
return result;
|
||||||
|
} /*** end of NetAccessConnect ***/
|
||||||
|
|
||||||
|
|
||||||
|
/************************************************************************************//**
|
||||||
|
** \brief Disconnects from the TCP/IP server.
|
||||||
|
**
|
||||||
|
****************************************************************************************/
|
||||||
|
void NetAccessDisconnect(void)
|
||||||
|
{
|
||||||
|
/* Only perform disconnect with an initialized Winsock. */
|
||||||
|
if (winsockInitialized)
|
||||||
|
{
|
||||||
|
/* Close the socket if it is open. */
|
||||||
|
if (netAccessSocket != INVALID_SOCKET)
|
||||||
|
{
|
||||||
|
(void)closesocket(netAccessSocket);
|
||||||
|
netAccessSocket = INVALID_SOCKET;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} /*** end of NetAccessDisconnect ***/
|
||||||
|
|
||||||
|
|
||||||
|
/************************************************************************************//**
|
||||||
|
** \brief Sends data to the TCP/IP server.
|
||||||
|
** \param data Pointer to byte array with data to send.
|
||||||
|
** \param length Number of bytes to send.
|
||||||
|
** \return True if successful, false otherwise.
|
||||||
|
**
|
||||||
|
****************************************************************************************/
|
||||||
|
bool NetAccessSend(uint8_t const * data, uint32_t length)
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
|
||||||
|
/* Check parameters. */
|
||||||
|
assert(data != NULL);
|
||||||
|
assert(length > 0);
|
||||||
|
|
||||||
|
/* Only continue with valid parameters and an initialized Winsock. */
|
||||||
|
if ( (data != NULL) && (length > 0) && (winsockInitialized) ) /*lint !e774 */
|
||||||
|
{
|
||||||
|
/* Only continue with a valid socket. */
|
||||||
|
if (netAccessSocket != INVALID_SOCKET)
|
||||||
|
{
|
||||||
|
/* Attempt to send the data. */
|
||||||
|
if (send(netAccessSocket, (char const *)data, (int)length, 0) != SOCKET_ERROR)
|
||||||
|
{
|
||||||
|
/* Successfully send the data. */
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Give the result back to the caller. */
|
||||||
|
return result;
|
||||||
|
} /*** end of NetAccessSend ***/
|
||||||
|
|
||||||
|
|
||||||
|
/************************************************************************************//**
|
||||||
|
** \brief Receives data from the TCP/IP server in a blocking manner.
|
||||||
|
** \param data Pointer to byte array to store the received data.
|
||||||
|
** \param length Holds the max number of bytes that can be stored into the byte
|
||||||
|
** array. This function also overwrites this value with the number of bytes
|
||||||
|
** that were actually received.
|
||||||
|
** \param timeout Timeout in milliseconds for the data reception.
|
||||||
|
** \return True if successful, false otherwise.
|
||||||
|
**
|
||||||
|
****************************************************************************************/
|
||||||
|
bool NetAccessReceive(uint8_t * data, uint32_t * length, uint32_t timeout)
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
int tv;
|
||||||
|
int receivedLen;
|
||||||
|
|
||||||
|
/* Check parameters. */
|
||||||
|
assert(data != NULL);
|
||||||
|
assert(length != NULL);
|
||||||
|
assert(timeout > 0);
|
||||||
|
|
||||||
|
/* Only continue with valid parameters and an initialized Winsock. */
|
||||||
|
if ( (data != NULL) && (length != NULL) && (timeout > 0) &&
|
||||||
|
(winsockInitialized) ) /*lint !e774 */
|
||||||
|
{
|
||||||
|
/* Only continue with a valid socket. */
|
||||||
|
if (netAccessSocket != INVALID_SOCKET)
|
||||||
|
{
|
||||||
|
/* Configure the timeout for the receive operation. */
|
||||||
|
tv = (int)timeout;
|
||||||
|
if (setsockopt(netAccessSocket, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(int)) != SOCKET_ERROR)
|
||||||
|
{
|
||||||
|
/* Attempt to receive data. */
|
||||||
|
receivedLen = recv(netAccessSocket, (char *)data, (int)*length, 0);
|
||||||
|
/* Process the result. Everything < 0 indicate that an error occured. A value of
|
||||||
|
* zero is also treated as an error, since data was expected.
|
||||||
|
*/
|
||||||
|
if ((receivedLen != SOCKET_ERROR) && (receivedLen > 0))
|
||||||
|
{
|
||||||
|
/* Store the number of received bytes. */
|
||||||
|
*length = (uint32_t)receivedLen;
|
||||||
|
/* Successfully received data. */
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Give the result back to the caller. */
|
||||||
|
return result;
|
||||||
|
} /*** end of NetAccessReceive ***/
|
||||||
|
|
||||||
|
|
||||||
|
/*********************************** end of netaccess.c ********************************/
|
||||||
|
|
|
@ -0,0 +1,291 @@
|
||||||
|
/************************************************************************************//**
|
||||||
|
* \file xcptpnet.c
|
||||||
|
* \brief XCP TCP/IP transport layer source file.
|
||||||
|
* \ingroup XcpTpNet
|
||||||
|
* \internal
|
||||||
|
*----------------------------------------------------------------------------------------
|
||||||
|
* C O P Y R I G H T
|
||||||
|
*----------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) 2017 by Feaser http://www.feaser.com All rights reserved
|
||||||
|
*
|
||||||
|
*----------------------------------------------------------------------------------------
|
||||||
|
* L I C E N S E
|
||||||
|
*----------------------------------------------------------------------------------------
|
||||||
|
* This file is part of OpenBLT. OpenBLT is free software: you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation, either version 3 of the License, or (at your option) any later
|
||||||
|
* version.
|
||||||
|
*
|
||||||
|
* OpenBLT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||||
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE. See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You have received a copy of the GNU General Public License along with OpenBLT. It
|
||||||
|
* should be located in ".\Doc\license.html". If not, contact Feaser to obtain a copy.
|
||||||
|
*
|
||||||
|
* \endinternal
|
||||||
|
****************************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************************
|
||||||
|
* Include files
|
||||||
|
****************************************************************************************/
|
||||||
|
#include <assert.h> /* for assertions */
|
||||||
|
#include <stdint.h> /* for standard integer types */
|
||||||
|
#include <stddef.h> /* for NULL declaration */
|
||||||
|
#include <stdbool.h> /* for boolean type */
|
||||||
|
#include <stdlib.h> /* for standard library */
|
||||||
|
#include <string.h> /* for string library */
|
||||||
|
#include "session.h" /* Communication session module */
|
||||||
|
#include "xcploader.h" /* XCP loader module */
|
||||||
|
#include "xcptpnet.h" /* XCP TCP/IP transport layer */
|
||||||
|
#include "netaccess.h" /* TCP/IP network access module */
|
||||||
|
|
||||||
|
|
||||||
|
/****************************************************************************************
|
||||||
|
* Function prototypes
|
||||||
|
****************************************************************************************/
|
||||||
|
static void XcpTpNetInit(void const * settings);
|
||||||
|
static void XcpTpNetTerminate(void);
|
||||||
|
static bool XcpTpNetConnect(void);
|
||||||
|
static void XcpTpNetDisconnect(void);
|
||||||
|
static bool XcpTpNetSendPacket(tXcpTransportPacket const * txPacket,
|
||||||
|
tXcpTransportPacket * rxPacket, uint16_t timeout);
|
||||||
|
|
||||||
|
|
||||||
|
/****************************************************************************************
|
||||||
|
* Local constant declarations
|
||||||
|
****************************************************************************************/
|
||||||
|
/** \brief XCP transport layer structure filled with TCP/IP specifics. */
|
||||||
|
static const tXcpTransport netTransport =
|
||||||
|
{
|
||||||
|
XcpTpNetInit,
|
||||||
|
XcpTpNetTerminate,
|
||||||
|
XcpTpNetConnect,
|
||||||
|
XcpTpNetDisconnect,
|
||||||
|
XcpTpNetSendPacket
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/****************************************************************************************
|
||||||
|
* Local data declarations
|
||||||
|
****************************************************************************************/
|
||||||
|
/** \brief The settings to use in this transport layer. */
|
||||||
|
static tXcpTpNetSettings tpNetSettings;
|
||||||
|
|
||||||
|
/** \brief Command receive object (CRO) counter. This counter starts at 1 with each new
|
||||||
|
* connection and is sent with each command packet. The counter gets incremented
|
||||||
|
* for each command packet, allowing the server to determine the correct order
|
||||||
|
* for the received commands.
|
||||||
|
*/
|
||||||
|
static uint32_t tpNetCroCounter;
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************************//**
|
||||||
|
** \brief Obtains a pointer to the transport layer structure, so that it can be
|
||||||
|
** linked to the XCP protocol module.
|
||||||
|
** \return Pointer to transport layer structure.
|
||||||
|
**
|
||||||
|
****************************************************************************************/
|
||||||
|
tXcpTransport const * XcpTpNetGetTransport(void)
|
||||||
|
{
|
||||||
|
return &netTransport;
|
||||||
|
} /*** end of XcpTpNetGetTransport ***/
|
||||||
|
|
||||||
|
|
||||||
|
/************************************************************************************//**
|
||||||
|
** \brief Initializes the transport layer.
|
||||||
|
** \param settings Pointer to settings structure.
|
||||||
|
** \return None.
|
||||||
|
**
|
||||||
|
****************************************************************************************/
|
||||||
|
static void XcpTpNetInit(void const * settings)
|
||||||
|
{
|
||||||
|
char * netAddress;
|
||||||
|
|
||||||
|
/* Reset transport layer settings. */
|
||||||
|
tpNetSettings.address = NULL;
|
||||||
|
tpNetSettings.port = 0;
|
||||||
|
|
||||||
|
/* Check parameters. */
|
||||||
|
assert(settings != NULL);
|
||||||
|
|
||||||
|
/* Only continue with valid parameters. */
|
||||||
|
if (settings != NULL) /*lint !e774 */
|
||||||
|
{
|
||||||
|
/* Shallow copy the transport layer settings for layer usage. */
|
||||||
|
tpNetSettings = *((tXcpTpNetSettings *)settings);
|
||||||
|
/* The address is a pointer and it is not guaranteed that it stays valid so we need
|
||||||
|
* to deep copy this one. note the +1 for '\0' in malloc.
|
||||||
|
*/
|
||||||
|
assert(((tXcpTpNetSettings *)settings)->address != NULL);
|
||||||
|
if (((tXcpTpNetSettings *)settings)->address != NULL) /*lint !e774 */
|
||||||
|
{
|
||||||
|
netAddress = malloc(strlen(((tXcpTpNetSettings *)settings)->address) + 1);
|
||||||
|
assert(netAddress != NULL);
|
||||||
|
if (netAddress != NULL) /*lint !e774 */
|
||||||
|
{
|
||||||
|
strcpy(netAddress, ((tXcpTpNetSettings *)settings)->address);
|
||||||
|
tpNetSettings.address = netAddress;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Initialize the network access module. */
|
||||||
|
NetAccessInit();
|
||||||
|
} /*** end of XcpTpNetInit ***/
|
||||||
|
|
||||||
|
|
||||||
|
/************************************************************************************//**
|
||||||
|
** \brief Terminates the transport layer.
|
||||||
|
**
|
||||||
|
****************************************************************************************/
|
||||||
|
static void XcpTpNetTerminate(void)
|
||||||
|
{
|
||||||
|
/* Terminate the network access module. */
|
||||||
|
NetAccessTerminate();
|
||||||
|
/* Release memory that was allocated for storing the network address. */
|
||||||
|
if (tpNetSettings.address != NULL)
|
||||||
|
{
|
||||||
|
free((char *)tpNetSettings.address);
|
||||||
|
}
|
||||||
|
/* Reset transport layer settings. */
|
||||||
|
tpNetSettings.address = NULL;
|
||||||
|
tpNetSettings.port = 0;
|
||||||
|
} /*** end of XcpTpNetTerminate ***/
|
||||||
|
|
||||||
|
|
||||||
|
/************************************************************************************//**
|
||||||
|
** \brief Connects to the transport layer.
|
||||||
|
** \return True is connected, false otherwise.
|
||||||
|
**
|
||||||
|
****************************************************************************************/
|
||||||
|
static bool XcpTpNetConnect(void)
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
|
||||||
|
/* Check transport layer settings. */
|
||||||
|
assert(tpNetSettings.address != NULL);
|
||||||
|
assert(tpNetSettings.port != 0);
|
||||||
|
|
||||||
|
/* Initialize the CRO counter. */
|
||||||
|
tpNetCroCounter = 1;
|
||||||
|
|
||||||
|
/* Only continue if the transport layer settings are valid. */
|
||||||
|
if ( (tpNetSettings.address != NULL) && (tpNetSettings.port != 0) ) /*lint !e774 */
|
||||||
|
{
|
||||||
|
/* Connect via the network access module. */
|
||||||
|
result = NetAccessConnect(tpNetSettings.address, tpNetSettings.port);
|
||||||
|
}
|
||||||
|
/* Give the result back to the caller. */
|
||||||
|
return result;
|
||||||
|
} /*** end of XcpTpNetConnect ***/
|
||||||
|
|
||||||
|
|
||||||
|
/************************************************************************************//**
|
||||||
|
** \brief Disconnects from the transport layer.
|
||||||
|
**
|
||||||
|
****************************************************************************************/
|
||||||
|
static void XcpTpNetDisconnect(void)
|
||||||
|
{
|
||||||
|
/* Disconnect via the network access module. */
|
||||||
|
NetAccessDisconnect();
|
||||||
|
} /*** end of XcpTpNetDisconnect ***/
|
||||||
|
|
||||||
|
|
||||||
|
/************************************************************************************//**
|
||||||
|
** \brief Transmits an XCP packet on the transport layer and attempts to receive the
|
||||||
|
** response packet within the specified timeout.
|
||||||
|
** \param txPacket Pointer to the packet to transmit.
|
||||||
|
** \param rxPacket Pointer where the received packet info is stored.
|
||||||
|
** \param timeout Maximum time in milliseconds to wait for the reception of the
|
||||||
|
** response packet.
|
||||||
|
** \return True is successful and a response packet was received, false otherwise.
|
||||||
|
**
|
||||||
|
****************************************************************************************/
|
||||||
|
static bool XcpTpNetSendPacket(tXcpTransportPacket const * txPacket,
|
||||||
|
tXcpTransportPacket * rxPacket, uint16_t timeout)
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
uint16_t byteIdx;
|
||||||
|
/* netBuffer is static to lower the stack load. +4 because the CRO counter value is
|
||||||
|
* added at the start of the packet.
|
||||||
|
*/
|
||||||
|
static uint8_t netBuffer[XCPLOADER_PACKET_SIZE_MAX + 4];
|
||||||
|
|
||||||
|
/* Check parameters. */
|
||||||
|
assert(txPacket != NULL);
|
||||||
|
assert(rxPacket != NULL);
|
||||||
|
|
||||||
|
/* Only continue with valid parameters. */
|
||||||
|
if ( (txPacket != NULL) && (rxPacket != NULL) ) /*lint !e774 */
|
||||||
|
{
|
||||||
|
/* Set result value to okay and only change it from now on if an error occurred. */
|
||||||
|
result = true;
|
||||||
|
/* Prepare the XCP packet for transmission via TCP/IP. This is basically the same
|
||||||
|
* as the XCP packet data but just the CRO counter of the packet is added to the
|
||||||
|
* first four bytes.
|
||||||
|
*/
|
||||||
|
netBuffer[0] = (uint8_t)tpNetCroCounter;
|
||||||
|
netBuffer[1] = (uint8_t)(tpNetCroCounter >> 8);
|
||||||
|
netBuffer[2] = (uint8_t)(tpNetCroCounter >> 16);
|
||||||
|
netBuffer[3] = (uint8_t)(tpNetCroCounter >> 24);
|
||||||
|
/* Increment the CRO counter for the next packet. */
|
||||||
|
tpNetCroCounter++;
|
||||||
|
/* Copy the actual packet data. */
|
||||||
|
for (byteIdx=0; byteIdx<txPacket->len; byteIdx++)
|
||||||
|
{
|
||||||
|
netBuffer[byteIdx + 4] = txPacket->data[byteIdx];
|
||||||
|
}
|
||||||
|
/* Send the packet. */
|
||||||
|
if (!NetAccessSend(netBuffer, txPacket->len + 4))
|
||||||
|
{
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Only continue if the packet was successfully sent. */
|
||||||
|
uint32_t netRxLength = 0;
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
/* Reset the length of the received packet data. */
|
||||||
|
rxPacket->len = 0;
|
||||||
|
/* Set the maximum allowed length of the response packet. */
|
||||||
|
netRxLength = sizeof(netBuffer)/sizeof(netBuffer[0]);
|
||||||
|
/* Attempt to receive the response within the specified timeout. */
|
||||||
|
if (!NetAccessReceive(netBuffer, &netRxLength, timeout))
|
||||||
|
{
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Only continue if a response packet was received. */
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
/* Validate the response length. It must at least have a DTO counter (32-bits) and
|
||||||
|
* one byte in the response data. It can also not be longer than the maximum
|
||||||
|
* allowed size, based on the size of the buffer.
|
||||||
|
*/
|
||||||
|
if ( (netRxLength < 5) ||
|
||||||
|
(netRxLength > (sizeof(netBuffer)/sizeof(netBuffer[0]))) )
|
||||||
|
{
|
||||||
|
/* Invalid length. */
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Only continue if the response packet has a valid length. */
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
/* The first four bytes contain a DTO counter in which we are not really
|
||||||
|
* interested.
|
||||||
|
*/
|
||||||
|
rxPacket->len = (uint8_t)(netRxLength - 4);
|
||||||
|
/* Copy the received packet data. */
|
||||||
|
for (byteIdx=0; byteIdx<rxPacket->len; byteIdx++)
|
||||||
|
{
|
||||||
|
rxPacket->data[byteIdx] = netBuffer[byteIdx + 4];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Give the result back to the caller. */
|
||||||
|
return result;
|
||||||
|
} /*** end of XcpTpNetSendPacket ***/
|
||||||
|
|
||||||
|
|
||||||
|
/*********************************** end of xcptpnet.c *********************************/
|
|
@ -0,0 +1,63 @@
|
||||||
|
/************************************************************************************//**
|
||||||
|
* \file xcptpnet.h
|
||||||
|
* \brief XCP TCP/IP transport layer header file.
|
||||||
|
* \ingroup XcpTpNet
|
||||||
|
* \internal
|
||||||
|
*----------------------------------------------------------------------------------------
|
||||||
|
* C O P Y R I G H T
|
||||||
|
*----------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) 2017 by Feaser http://www.feaser.com All rights reserved
|
||||||
|
*
|
||||||
|
*----------------------------------------------------------------------------------------
|
||||||
|
* L I C E N S E
|
||||||
|
*----------------------------------------------------------------------------------------
|
||||||
|
* This file is part of OpenBLT. OpenBLT is free software: you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation, either version 3 of the License, or (at your option) any later
|
||||||
|
* version.
|
||||||
|
*
|
||||||
|
* OpenBLT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||||
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE. See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You have received a copy of the GNU General Public License along with OpenBLT. It
|
||||||
|
* should be located in ".\Doc\license.html". If not, contact Feaser to obtain a copy.
|
||||||
|
*
|
||||||
|
* \endinternal
|
||||||
|
****************************************************************************************/
|
||||||
|
/************************************************************************************//**
|
||||||
|
* \defgroup XcpTpNet XCP TCP/IP transport layer
|
||||||
|
* \brief This module implements the XCP transport layer for TCP/IP.
|
||||||
|
* \ingroup XcpLoader
|
||||||
|
****************************************************************************************/
|
||||||
|
#ifndef XCPTPNET_H
|
||||||
|
#define XCPTPNET_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/****************************************************************************************
|
||||||
|
* Type definitions
|
||||||
|
****************************************************************************************/
|
||||||
|
/** \brief Layout of structure with settings specific to the XCP transport layer module
|
||||||
|
* for TCP/IP.
|
||||||
|
*/
|
||||||
|
typedef struct t_xcp_tp_net_settings
|
||||||
|
{
|
||||||
|
char const * address; /**< Target IP-address or hostname on the network. */
|
||||||
|
uint16_t port; /**< TCP port to use. */
|
||||||
|
} tXcpTpNetSettings;
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************************
|
||||||
|
* Function prototypes
|
||||||
|
****************************************************************************************/
|
||||||
|
tXcpTransport const * XcpTpNetGetTransport(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* XCPTPNET_H */
|
||||||
|
/*********************************** end of xcptpnet.h *********************************/
|
|
@ -227,7 +227,7 @@ static bool XcpTpUartSendPacket(tXcpTransportPacket const * txPacket,
|
||||||
bool result = false;
|
bool result = false;
|
||||||
uint16_t byteIdx;
|
uint16_t byteIdx;
|
||||||
/* uartBuffer is static to lower the stack load. +1 because the first byte for an XCP
|
/* uartBuffer is static to lower the stack load. +1 because the first byte for an XCP
|
||||||
* packet on the UART transport layer contains the packet lenght.
|
* packet on the UART transport layer contains the packet length.
|
||||||
*/
|
*/
|
||||||
static uint8_t uartBuffer[XCPLOADER_PACKET_SIZE_MAX + 1];
|
static uint8_t uartBuffer[XCPLOADER_PACKET_SIZE_MAX + 1];
|
||||||
uint32_t responseTimeoutTime = 0;
|
uint32_t responseTimeoutTime = 0;
|
||||||
|
|
Binary file not shown.
Loading…
Reference in New Issue