From f951ebc08e35c404724520d25d4c74743bf67d6d Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Thu, 13 Apr 2023 23:06:11 +0100 Subject: [PATCH] - Added function IedConnection_setLocalAddress to define local IP address and optionally local port of a client connection (LIB61850-378) --- dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs | 24 ++++++++++++++++- .../client_example1.c | 27 +++++++++++++++---- src/iec61850/client/ied_connection.c | 9 +++++++ src/iec61850/inc/iec61850_client.h | 11 ++++++++ src/mms/inc/iso_connection_parameters.h | 17 ++++++++++++ src/mms/iso_client/iso_client_connection.c | 11 +++++--- .../iso_common/iso_connection_parameters.c | 12 +++++++++ 7 files changed, 102 insertions(+), 9 deletions(-) diff --git a/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs b/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs index 4b45fe54..16d79a56 100644 --- a/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs +++ b/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs @@ -1,7 +1,7 @@ /* * IEC61850ClientAPI.cs * - * Copyright 2014-2021 Michael Zillgith + * Copyright 2014-2023 Michael Zillgith * * This file is part of libIEC61850. * @@ -437,6 +437,9 @@ namespace IEC61850 [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern void IedConnection_connect(IntPtr self, out int error, string hostname, int tcpPort); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void IedConnection_setLocalAddress(IntPtr self, string localIpAddress, int localPort); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern void IedConnection_abort(IntPtr self, out int error); @@ -894,6 +897,25 @@ namespace IEC61850 Connect(hostname, -1); } + /// + /// Set the local IP address and port to be used by the client + /// + /// the local IP address or hostname + /// the local TCP port to use. When 0 the OS will chose the TCP port to use. + public void SetLocalAddress(string localIpAddress, int localPort) + { + IedConnection_setLocalAddress(connection, localIpAddress, localPort); + } + + /// + /// Set the local IP address to be used by the client + /// + /// the local IP address or hostname + public void SetLocalAddress(string localIpAddress) + { + IedConnection_setLocalAddress(connection, localIpAddress, 0); + } + /// This exception is thrown if there is a connection or service error public ControlObject CreateControlObject(string objectReference) { diff --git a/examples/iec61850_client_example1/client_example1.c b/examples/iec61850_client_example1/client_example1.c index f84d37a0..6c9241f0 100644 --- a/examples/iec61850_client_example1/client_example1.c +++ b/examples/iec61850_client_example1/client_example1.c @@ -33,6 +33,9 @@ int main(int argc, char** argv) { char* hostname; int tcpPort = 102; + const char* localIp = NULL; + int localTcpPort = -1; + if (argc > 1) hostname = argv[1]; @@ -42,19 +45,34 @@ int main(int argc, char** argv) { if (argc > 2) tcpPort = atoi(argv[2]); + if (argc > 3) + localIp = argv[3]; + + if (argc > 4) + localTcpPort = atoi(argv[4]); + IedClientError error; IedConnection con = IedConnection_create(); + /* Optional bind to local IP address/interface */ + if (localIp) { + IedConnection_setLocalAddress(con, localIp, localTcpPort); + printf("Bound to Local Address: %s:%i\n", localIp, localTcpPort); + } + IedConnection_connect(con, &error, hostname, tcpPort); + printf("Connecting to %s:%i\n", hostname, tcpPort); - if (error == IED_ERROR_OK) { + if (error == IED_ERROR_OK) + { + printf("Connected\n"); /* read an analog measurement value from server */ MmsValue* value = IedConnection_readObject(con, &error, "simpleIOGenericIO/GGIO1.AnIn1.mag.f", IEC61850_FC_MX); - if (value != NULL) { - + if (value != NULL) + { if (MmsValue_getType(value) == MMS_FLOAT) { float fval = MmsValue_toFloat(value); printf("read float value: %f\n", fval); @@ -137,7 +155,6 @@ close_connection: } IedConnection_destroy(con); + return 0; } - - diff --git a/src/iec61850/client/ied_connection.c b/src/iec61850/client/ied_connection.c index b49a1fe7..bc581dea 100644 --- a/src/iec61850/client/ied_connection.c +++ b/src/iec61850/client/ied_connection.c @@ -651,6 +651,15 @@ IedConnection_tick(IedConnection self) return MmsConnection_tick(self->connection); } +void +IedConnection_setLocalAddress(IedConnection self, const char* localIpAddress, int localPort) +{ + MmsConnection connection = self->connection; + IsoConnectionParameters isoP = MmsConnection_getIsoConnectionParameters(connection); + + IsoConnectionParameters_setLocalTcpParameters(isoP, localIpAddress, localPort); +} + void IedConnection_setConnectTimeout(IedConnection self, uint32_t timeoutInMs) { diff --git a/src/iec61850/inc/iec61850_client.h b/src/iec61850/inc/iec61850_client.h index 852f2192..c3a174fe 100644 --- a/src/iec61850/inc/iec61850_client.h +++ b/src/iec61850/inc/iec61850_client.h @@ -231,6 +231,17 @@ IedConnection_createWithTlsSupport(TLSConfiguration tlsConfig); LIB61850_API void IedConnection_destroy(IedConnection self); +/** +* \brief Set the local IP address and port to be used by the client +* +* NOTE: This function is optional. When not used the OS decides what IP address and TCP port to use. +* +* \param self IedConnection instance +* \param localIpAddress the local IP address or hostname as C string +* \param localPort the local TCP port to use. When < 1 the OS will chose the TCP port to use. +*/ +LIB61850_API void +IedConnection_setLocalAddress(IedConnection self, const char* localIpAddress, int localPort); /** * \brief set the connect timeout in ms diff --git a/src/mms/inc/iso_connection_parameters.h b/src/mms/inc/iso_connection_parameters.h index cdd04bcb..3514f437 100644 --- a/src/mms/inc/iso_connection_parameters.h +++ b/src/mms/inc/iso_connection_parameters.h @@ -145,6 +145,9 @@ struct sIsoConnectionParameters const char* hostname; int tcpPort; + const char* localIpAddress; + int localTcpPort; + uint8_t remoteApTitle[10]; int remoteApTitleLen; int remoteAEQualifier; @@ -215,6 +218,20 @@ IsoConnectionParameters_setAcseAuthenticationParameter(IsoConnectionParameters s LIB61850_API void IsoConnectionParameters_setTcpParameters(IsoConnectionParameters self, const char* hostname, int tcpPort); +/** +* \brief Set Local TCP parameters (FOR LIBRARY INTERNAL USE) +* +* NOTE: This function used internally by the MMS Client library. When using the MMS or IEC 61850 API +* there should be no reason for the user to call this function +* +* \param self the IsoConnectionParameters instance +* \param localIpAddress the hostname of local IP address of the server +* \param localTcpPort the local TCP port number of the server +*/ +LIB61850_API void +IsoConnectionParameters_setLocalTcpParameters(IsoConnectionParameters self, const char* localIpAddress, int localTcpPort); + + /** * \brief set the remote AP-Title and AE-Qualifier * diff --git a/src/mms/iso_client/iso_client_connection.c b/src/mms/iso_client/iso_client_connection.c index cb58e98f..4f37176b 100644 --- a/src/mms/iso_client/iso_client_connection.c +++ b/src/mms/iso_client/iso_client_connection.c @@ -692,8 +692,13 @@ IsoClientConnection_associateAsync(IsoClientConnection self, uint32_t connectTim /* set timeout for connect */ self->nextReadTimeout = Hal_getTimeInMs() + connectTimeoutInMs; + /* Connect to Local Ip Address*/ + if (self->parameters->localIpAddress) { + Socket_bind(self->socket, self->parameters->localIpAddress, self->parameters->localTcpPort); + } + if (Socket_connectAsync(self->socket, self->parameters->hostname, self->parameters->tcpPort) == false) { - + Socket_destroy(self->socket); self->socket = NULL; @@ -704,9 +709,9 @@ IsoClientConnection_associateAsync(IsoClientConnection self, uint32_t connectTim success = false; } - + Semaphore_post(self->tickMutex); - + return success; } diff --git a/src/mms/iso_common/iso_connection_parameters.c b/src/mms/iso_common/iso_connection_parameters.c index 3fdf32c9..aa5334b3 100644 --- a/src/mms/iso_common/iso_connection_parameters.c +++ b/src/mms/iso_common/iso_connection_parameters.c @@ -104,6 +104,18 @@ IsoConnectionParameters_setTcpParameters(IsoConnectionParameters self, const cha self->tcpPort = tcpPort; } +void +IsoConnectionParameters_setLocalTcpParameters(IsoConnectionParameters self, const char* localIpAddress, int localTcpPort) +{ + if (self) { + if (localIpAddress) { + self->localIpAddress = strdup(localIpAddress); + self->localTcpPort = localTcpPort; + } + } +} + + void IsoConnectionParameters_setRemoteApTitle(IsoConnectionParameters self, const char* apTitle, int aeQualifier) {