Feature/bip6 win32 debug enhancements (#212)
* Move win32 specific checks to bacport.h module * Create IPv6 snprintf function in bvlc6.c module * Improve BIP6 debug for win32 port Co-authored-by: Steve Karg <skarg@users.sourceforge.net>
This commit is contained in:
@@ -70,6 +70,12 @@ and globals in favor of more secure versions. */
|
|||||||
#endif
|
#endif
|
||||||
#include <sys/timeb.h>
|
#include <sys/timeb.h>
|
||||||
|
|
||||||
|
#if defined(__BORLANDC__) || defined(_WIN32)
|
||||||
|
/* seems to not be defined in time.h as specified by The Open Group */
|
||||||
|
/* difference from UTC and local standard time */
|
||||||
|
long int timezone;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#define inline __inline
|
#define inline __inline
|
||||||
#endif
|
#endif
|
||||||
@@ -79,6 +85,7 @@ and globals in favor of more secure versions. */
|
|||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#define strncasecmp(x, y, z) _strnicmp(x, y, z)
|
#define strncasecmp(x, y, z) _strnicmp(x, y, z)
|
||||||
|
#define snprintf _snprintf
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+33
-23
@@ -67,19 +67,21 @@ static bool BIP6_Debug = false;
|
|||||||
/**
|
/**
|
||||||
* @brief Print the IPv6 address with debug info
|
* @brief Print the IPv6 address with debug info
|
||||||
* @param str - debug info string
|
* @param str - debug info string
|
||||||
* @param addr - IPv4 address
|
* @param addr - IPv6 address
|
||||||
*/
|
*/
|
||||||
static void debug_print_ipv6(const char *str, const struct in6_addr *addr)
|
static void debug_print_ipv6(const char *str, const struct in6_addr *addr)
|
||||||
{
|
{
|
||||||
PRINTF("BIP6: %s "
|
#if PRINT_ENABLED
|
||||||
"%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%"
|
char addstr[40] = {};
|
||||||
"02x:%02x%02x\n",
|
BACNET_IP6_ADDRESS bip6_addr = {};
|
||||||
str, (int)addr->s6_addr[0], (int)addr->s6_addr[1],
|
|
||||||
(int)addr->s6_addr[2], (int)addr->s6_addr[3], (int)addr->s6_addr[4],
|
if (str && addr) {
|
||||||
(int)addr->s6_addr[5], (int)addr->s6_addr[6], (int)addr->s6_addr[7],
|
memcpy(&bip6_addr.address[0], &addr->s6_addr[0], IP6_ADDRESS_MAX);
|
||||||
(int)addr->s6_addr[8], (int)addr->s6_addr[9], (int)addr->s6_addr[10],
|
bvlc6_address_to_ascii(&bip6_addr, addstr,
|
||||||
(int)addr->s6_addr[11], (int)addr->s6_addr[12], (int)addr->s6_addr[13],
|
sizeof(addstr));
|
||||||
(int)addr->s6_addr[14], (int)addr->s6_addr[15]);
|
PRINTF("BIP6: %s %s\n", str, addstr);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -111,10 +113,10 @@ void bip6_set_interface(char *ifname)
|
|||||||
int i, RetVal;
|
int i, RetVal;
|
||||||
struct addrinfo Hints, *AddrInfo, *AI;
|
struct addrinfo Hints, *AddrInfo, *AI;
|
||||||
struct sockaddr_in6 *sin;
|
struct sockaddr_in6 *sin;
|
||||||
struct sockaddr_in6 server;
|
struct sockaddr_in6 server = {};
|
||||||
struct in6_addr broadcast_address;
|
struct in6_addr broadcast_address = {};
|
||||||
struct ipv6_mreq join_request;
|
struct ipv6_mreq join_request = {};
|
||||||
SOCKET ServSock[FD_SETSIZE];
|
SOCKET ServSock[FD_SETSIZE] = {};
|
||||||
char port[6] = "";
|
char port[6] = "";
|
||||||
int sockopt = 0;
|
int sockopt = 0;
|
||||||
|
|
||||||
@@ -126,12 +128,12 @@ void bip6_set_interface(char *ifname)
|
|||||||
// for that family.
|
// for that family.
|
||||||
//
|
//
|
||||||
memset(&Hints, 0, sizeof(Hints));
|
memset(&Hints, 0, sizeof(Hints));
|
||||||
Hints.ai_family = PF_INET6;
|
Hints.ai_family = AF_INET6;
|
||||||
Hints.ai_socktype = SOCK_DGRAM;
|
Hints.ai_socktype = SOCK_DGRAM;
|
||||||
Hints.ai_protocol = IPPROTO_UDP;
|
Hints.ai_protocol = IPPROTO_UDP;
|
||||||
Hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE;
|
Hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE;
|
||||||
snprintf(port, sizeof(port), "%u", BIP6_Addr.port);
|
snprintf(port, sizeof(port), "%u", BIP6_Addr.port);
|
||||||
PRINTF("BIP6: getaddrinfo - IPv6 address %s port %s\n", ifname, port);
|
PRINTF("BIP6: seeking IPv6 address %s port %s...\n", ifname, port);
|
||||||
RetVal = getaddrinfo(ifname, &port[0], &Hints, &AddrInfo);
|
RetVal = getaddrinfo(ifname, &port[0], &Hints, &AddrInfo);
|
||||||
if (RetVal != 0) {
|
if (RetVal != 0) {
|
||||||
fprintf(stderr, "BIP6: getaddrinfo failed with error %d: %s\n", RetVal,
|
fprintf(stderr, "BIP6: getaddrinfo failed with error %d: %s\n", RetVal,
|
||||||
@@ -139,6 +141,7 @@ void bip6_set_interface(char *ifname)
|
|||||||
WSACleanup();
|
WSACleanup();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
PRINTF("BIP6: getaddrinfo() succeeded!\n");
|
||||||
//
|
//
|
||||||
// Find the first matching address getaddrinfo returned so that
|
// Find the first matching address getaddrinfo returned so that
|
||||||
// we can create a new socket and bind that address to it,
|
// we can create a new socket and bind that address to it,
|
||||||
@@ -152,8 +155,8 @@ void bip6_set_interface(char *ifname)
|
|||||||
"use.\n");
|
"use.\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// only support PF_INET6.
|
// only support AF_INET6.
|
||||||
if (AI->ai_family != PF_INET6) {
|
if (AI->ai_family != AF_INET6) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// only support SOCK_DGRAM.
|
// only support SOCK_DGRAM.
|
||||||
@@ -164,13 +167,13 @@ void bip6_set_interface(char *ifname)
|
|||||||
if (AI->ai_protocol != IPPROTO_UDP) {
|
if (AI->ai_protocol != IPPROTO_UDP) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
BIP6_Socket = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
|
BIP6_Socket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
|
||||||
if (BIP6_Socket == INVALID_SOCKET) {
|
if (BIP6_Socket == INVALID_SOCKET) {
|
||||||
fprintf(stderr, "BIP6: socket() failed with error %d: %s\n",
|
fprintf(stderr, "BIP6: socket() failed with error %d: %s\n",
|
||||||
WSAGetLastError(), PrintError(WSAGetLastError()));
|
WSAGetLastError(), PrintError(WSAGetLastError()));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ((AI->ai_family == PF_INET6) && IN6_IS_ADDR_LINKLOCAL(AI->ai_addr) &&
|
if ((AI->ai_family == AF_INET6) && IN6_IS_ADDR_LINKLOCAL(AI->ai_addr) &&
|
||||||
(((SOCKADDR_IN6 *)(AI->ai_addr))->sin6_scope_id == 0)) {
|
(((SOCKADDR_IN6 *)(AI->ai_addr))->sin6_scope_id == 0)) {
|
||||||
fprintf(
|
fprintf(
|
||||||
stderr, "BIP6: IPv6 link local addresses needs a scope ID!\n");
|
stderr, "BIP6: IPv6 link local addresses needs a scope ID!\n");
|
||||||
@@ -183,6 +186,9 @@ void bip6_set_interface(char *ifname)
|
|||||||
if (RetVal < 0) {
|
if (RetVal < 0) {
|
||||||
closesocket(BIP6_Socket);
|
closesocket(BIP6_Socket);
|
||||||
BIP6_Socket = INVALID_SOCKET;
|
BIP6_Socket = INVALID_SOCKET;
|
||||||
|
fprintf(stderr,
|
||||||
|
"BIP6: setsockopt(SO_REUSEADDR) failed with error %d: %s\n",
|
||||||
|
WSAGetLastError(), PrintError(WSAGetLastError()));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/* allow us to send a broadcast */
|
/* allow us to send a broadcast */
|
||||||
@@ -219,7 +225,7 @@ void bip6_set_interface(char *ifname)
|
|||||||
// that clients know about in advance.
|
// that clients know about in advance.
|
||||||
//
|
//
|
||||||
memset(&server, 0, sizeof(server));
|
memset(&server, 0, sizeof(server));
|
||||||
server.sin6_family = PF_INET6;
|
server.sin6_family = AF_INET6;
|
||||||
server.sin6_port = htons(BIP6_Addr.port);
|
server.sin6_port = htons(BIP6_Addr.port);
|
||||||
server.sin6_addr = in6addr_any;
|
server.sin6_addr = in6addr_any;
|
||||||
if (bind(BIP6_Socket, (struct sockaddr *)&server, sizeof(server)) ==
|
if (bind(BIP6_Socket, (struct sockaddr *)&server, sizeof(server)) ==
|
||||||
@@ -238,6 +244,7 @@ void bip6_set_interface(char *ifname)
|
|||||||
ntohs(sin->sin6_addr.s6_addr16[5]),
|
ntohs(sin->sin6_addr.s6_addr16[5]),
|
||||||
ntohs(sin->sin6_addr.s6_addr16[6]),
|
ntohs(sin->sin6_addr.s6_addr16[6]),
|
||||||
ntohs(sin->sin6_addr.s6_addr16[7]));
|
ntohs(sin->sin6_addr.s6_addr16[7]));
|
||||||
|
debug_print_ipv6("bind() succeeded!", &sin->sin6_addr);
|
||||||
/* https://msdn.microsoft.com/en-us/library/windows/desktop/ms740496(v=vs.85).aspx
|
/* https://msdn.microsoft.com/en-us/library/windows/desktop/ms740496(v=vs.85).aspx
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
@@ -247,6 +254,9 @@ void bip6_set_interface(char *ifname)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
freeaddrinfo(AddrInfo);
|
freeaddrinfo(AddrInfo);
|
||||||
|
if (BIP6_Socket == INVALID_SOCKET) {
|
||||||
|
fprintf(stderr, "BIP6: AF_INET6 address not found getaddrinfo()\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -385,7 +395,7 @@ int bip6_send_mpdu(BACNET_IP6_ADDRESS *dest, uint8_t *mtu, uint16_t mtu_len)
|
|||||||
bvlc_dest.sin6_addr.s6_addr16[6] = htons(addr16[6]);
|
bvlc_dest.sin6_addr.s6_addr16[6] = htons(addr16[6]);
|
||||||
bvlc_dest.sin6_addr.s6_addr16[7] = htons(addr16[7]);
|
bvlc_dest.sin6_addr.s6_addr16[7] = htons(addr16[7]);
|
||||||
bvlc_dest.sin6_port = htons(dest->port);
|
bvlc_dest.sin6_port = htons(dest->port);
|
||||||
debug_print_ipv6("BIP6: Sending MPDU->", &bvlc_dest.sin6_addr);
|
debug_print_ipv6("Sending MPDU->", &bvlc_dest.sin6_addr);
|
||||||
/* Send the packet */
|
/* Send the packet */
|
||||||
return sendto(BIP6_Socket, (char *)mtu, mtu_len, 0,
|
return sendto(BIP6_Socket, (char *)mtu, mtu_len, 0,
|
||||||
(struct sockaddr *)&bvlc_dest, sizeof(bvlc_dest));
|
(struct sockaddr *)&bvlc_dest, sizeof(bvlc_dest));
|
||||||
@@ -497,7 +507,7 @@ uint16_t bip6_receive(
|
|||||||
void bip6_cleanup(void)
|
void bip6_cleanup(void)
|
||||||
{
|
{
|
||||||
if (BIP6_Socket != -1) {
|
if (BIP6_Socket != -1) {
|
||||||
close(BIP6_Socket);
|
closesocket(BIP6_Socket);
|
||||||
}
|
}
|
||||||
BIP6_Socket = -1;
|
BIP6_Socket = -1;
|
||||||
WSACleanup();
|
WSACleanup();
|
||||||
|
|||||||
@@ -54,10 +54,6 @@
|
|||||||
|
|
||||||
/** @file bacapp.c Utilities for the BACnet_Application_Data_Value */
|
/** @file bacapp.c Utilities for the BACnet_Application_Data_Value */
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
|
||||||
#define snprintf _snprintf
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** @brief Encode application data given by a pointer into the APDU.
|
/** @brief Encode application data given by a pointer into the APDU.
|
||||||
* Return the number encoded bytes.
|
* Return the number encoded bytes.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -62,12 +62,6 @@
|
|||||||
/* os specfic includes */
|
/* os specfic includes */
|
||||||
#include "bacnet/basic/sys/mstimer.h"
|
#include "bacnet/basic/sys/mstimer.h"
|
||||||
|
|
||||||
#if defined(__BORLANDC__) || defined(_WIN32)
|
|
||||||
/* seems to not be defined in time.h as specified by The Open Group */
|
|
||||||
/* difference from UTC and local standard time */
|
|
||||||
long int timezone;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* local forward and external prototypes */
|
/* local forward and external prototypes */
|
||||||
extern int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata);
|
extern int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata);
|
||||||
extern bool Device_Write_Property_Local(BACNET_WRITE_PROPERTY_DATA *wp_data);
|
extern bool Device_Write_Property_Local(BACNET_WRITE_PROPERTY_DATA *wp_data);
|
||||||
|
|||||||
@@ -34,6 +34,7 @@
|
|||||||
|
|
||||||
#include <stdint.h> /* for standard integer types uint8_t etc. */
|
#include <stdint.h> /* for standard integer types uint8_t etc. */
|
||||||
#include <stdbool.h> /* for the standard bool type. */
|
#include <stdbool.h> /* for the standard bool type. */
|
||||||
|
#include <stdio.h>
|
||||||
#include "bacnet/bacenum.h"
|
#include "bacnet/bacenum.h"
|
||||||
#include "bacnet/bacdcode.h"
|
#include "bacnet/bacdcode.h"
|
||||||
#include "bacnet/bacint.h"
|
#include "bacnet/bacint.h"
|
||||||
@@ -640,6 +641,96 @@ bool bvlc6_address_get(BACNET_IP6_ADDRESS *addr,
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Convert IPv6 Address from ASCII
|
||||||
|
*
|
||||||
|
* IPv6 addresses are represented as eight groups, separated by colons,
|
||||||
|
* of four hexadecimal digits.
|
||||||
|
*
|
||||||
|
* For convenience, an IPv6 address may be abbreviated to shorter notations
|
||||||
|
* by application of the following rules according to RFC 5952 [1]:
|
||||||
|
* - One or more leading zeros from any groups of hexadecimal digits
|
||||||
|
* are removed; this is usually done to either all or none of the
|
||||||
|
* leading zeros. For example, the group 0042 is converted to 42.
|
||||||
|
* - Consecutive sections of zeros are replaced with a double colon (::).
|
||||||
|
* The double colon may only be used once in an address, as multiple
|
||||||
|
* use would render the address indeterminate. RFC 5952 requires that
|
||||||
|
* a double colon not be used to denote an omitted single section of
|
||||||
|
* zeros.
|
||||||
|
*
|
||||||
|
* [1] https://www.rfc-editor.org/rfc/rfc5952
|
||||||
|
*
|
||||||
|
* Adapted from the uIP TCP/IP stack and the Contiki operating system.
|
||||||
|
* Thank you, Adam Dunkel, and the Swedish Institute of Computer Science.
|
||||||
|
*
|
||||||
|
* @param addr - B/IPv6 address that is parsed
|
||||||
|
* @param buf - B/IPv6 address in 16-bit ASCII hex compressed format
|
||||||
|
* @param buf_size - B/IPv6 address size in bytes
|
||||||
|
*
|
||||||
|
* @return the number of characters which would be generated for the given
|
||||||
|
* input, excluding the trailing null.
|
||||||
|
* @note buf and buf_size may be null and zero to return only the size
|
||||||
|
*/
|
||||||
|
int bvlc6_address_to_ascii(BACNET_IP6_ADDRESS *addr, char *buf,
|
||||||
|
size_t buf_size)
|
||||||
|
{
|
||||||
|
uint16_t a;
|
||||||
|
unsigned int i;
|
||||||
|
int f = 0;
|
||||||
|
int len = 0;
|
||||||
|
int n = 0;
|
||||||
|
|
||||||
|
if (!addr) {
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
if (!buf) {
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
for(i = 0; i < IP6_ADDRESS_MAX; i += 2) {
|
||||||
|
a = (addr->address[i] << 8) + addr->address[i + 1];
|
||||||
|
if ((a == 0) && (f >= 0)) {
|
||||||
|
if (f++ == 0) {
|
||||||
|
len = snprintf(buf, buf_size, "::");
|
||||||
|
if (buf) {
|
||||||
|
buf += len;
|
||||||
|
}
|
||||||
|
if (len > buf_size) {
|
||||||
|
buf_size = 0;
|
||||||
|
} else {
|
||||||
|
buf_size -= len;
|
||||||
|
}
|
||||||
|
n += len;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (f > 0) {
|
||||||
|
f = -1;
|
||||||
|
} else if (i > 0) {
|
||||||
|
len = snprintf(buf, buf_size, ":");
|
||||||
|
if (buf) {
|
||||||
|
buf += len;
|
||||||
|
}
|
||||||
|
if (len > buf_size) {
|
||||||
|
buf_size = 0;
|
||||||
|
} else {
|
||||||
|
buf_size -= len;
|
||||||
|
}
|
||||||
|
n += len;
|
||||||
|
}
|
||||||
|
len = snprintf(buf, buf_size, "%x", a);
|
||||||
|
if (buf) {
|
||||||
|
buf += len;
|
||||||
|
}
|
||||||
|
if (len > buf_size) {
|
||||||
|
buf_size = 0;
|
||||||
|
} else {
|
||||||
|
buf_size -= len;
|
||||||
|
}
|
||||||
|
n += len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/** Convert IPv6 Address from ASCII
|
/** Convert IPv6 Address from ASCII
|
||||||
*
|
*
|
||||||
* IPv6 addresses are represented as eight groups, separated by colons,
|
* IPv6 addresses are represented as eight groups, separated by colons,
|
||||||
@@ -672,7 +763,7 @@ bool bvlc6_address_from_ascii(BACNET_IP6_ADDRESS *addr, const char *addrstr)
|
|||||||
unsigned int i = 0;
|
unsigned int i = 0;
|
||||||
char c = 0;
|
char c = 0;
|
||||||
|
|
||||||
if (!addrstr) {
|
if (!addr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!addrstr) {
|
if (!addrstr) {
|
||||||
|
|||||||
@@ -180,6 +180,10 @@ extern "C" {
|
|||||||
bool bvlc6_address_different(
|
bool bvlc6_address_different(
|
||||||
BACNET_IP6_ADDRESS * dst,
|
BACNET_IP6_ADDRESS * dst,
|
||||||
BACNET_IP6_ADDRESS * src);
|
BACNET_IP6_ADDRESS * src);
|
||||||
|
|
||||||
|
BACNET_STACK_EXPORT
|
||||||
|
int bvlc6_address_to_ascii(BACNET_IP6_ADDRESS *addr, char *buf,
|
||||||
|
size_t buf_size);
|
||||||
BACNET_STACK_EXPORT
|
BACNET_STACK_EXPORT
|
||||||
bool bvlc6_address_from_ascii(
|
bool bvlc6_address_from_ascii(
|
||||||
BACNET_IP6_ADDRESS *addr,
|
BACNET_IP6_ADDRESS *addr,
|
||||||
|
|||||||
Reference in New Issue
Block a user