Преглед изворни кода

Implemented UA_Client_getEndpoints function, relates to #313

Stasik0 пре 9 година
родитељ
комит
412bf6d64d
3 измењених фајлова са 101 додато и 10 уклоњено
  1. 25 1
      examples/client.c
  2. 12 0
      include/ua_client.h
  3. 64 9
      src/client/ua_client.c

+ 25 - 1
examples/client.c

@@ -21,7 +21,31 @@ static void handler_TheAnswerChanged(UA_UInt32 handle, UA_DataValue *value) {
 
 int main(int argc, char *argv[]) {
     UA_Client *client = UA_Client_new(UA_ClientConfig_standard, Logger_Stdout);
-    UA_StatusCode retval = UA_Client_connect(client, ClientNetworkLayerTCP_connect,
+
+    //listing endpoints
+    UA_EndpointDescription* endpointArray = NULL;
+    size_t endpointArraySize = 0;
+    UA_StatusCode retval = UA_client_getEndpoints(client, ClientNetworkLayerTCP_connect,
+            "opc.tcp://localhost:16664", &endpointArraySize, &endpointArray);
+
+    //freeing the endpointArray
+    if(retval != UA_STATUSCODE_GOOD) {
+        //cleanup array
+        UA_Array_delete(endpointArray,endpointArraySize, &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]);
+        UA_Client_delete(client);
+        return retval;
+    }
+
+    printf("%i endpoints found\n", (int)endpointArraySize);
+    for(size_t i=0;i<endpointArraySize;i++){
+        printf("URL of endpoint %i is %.*s\n", (int)i, (int)endpointArray[i].endpointUrl.length, endpointArray[i].endpointUrl.data);
+    }
+
+    //cleanup array of enpoints
+    UA_Array_delete(endpointArray,endpointArraySize, &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]);
+
+    //connect to a server
+    retval = UA_Client_connect(client, ClientNetworkLayerTCP_connect,
                                              "opc.tcp://localhost:16664");
 
     if(retval != UA_STATUSCODE_GOOD) {

+ 12 - 0
include/ua_client.h

@@ -55,6 +55,18 @@ void UA_EXPORT UA_Client_delete(UA_Client* client);
 typedef UA_Connection (*UA_ConnectClientConnection)(UA_ConnectionConfig localConf, const char *endpointUrl,
                                                     UA_Logger logger);
 
+/**
+ * Gets a list of endpoints of a server
+ * @param client to use
+ * @param connection function. You can use ClientNetworkLayerTCP_connect from examples/networklayer_tcp.h
+ * @param server url to connect (for example "opc.tcp://localhost:16664")
+ * @param endpointDescriptionsSize size of the array of endpoint descriptions
+ * @param endpointDescriptions array of endpoint descriptions that is allocated by the function (you need to free manually)
+ * @return Indicates whether the operation succeeded or returns an error code
+ */
+UA_StatusCode UA_EXPORT
+UA_client_getEndpoints(UA_Client *client, UA_ConnectClientConnection connectFunc,
+        const char *serverUrl, size_t* endpointDescriptionsSize, UA_EndpointDescription** endpointDescriptions);
 /**
  * start a connection to the selected server
  *

+ 64 - 9
src/client/ua_client.c

@@ -328,16 +328,18 @@ static UA_StatusCode ActivateSession(UA_Client *client) {
     return response.responseHeader.serviceResult; // not deleted
 }
 
-static UA_StatusCode EndpointsHandshake(UA_Client *client) {
+/**
+ * Gets a list of endpoints
+ * Memory is allocated for endpointDescription array
+ */
+static UA_StatusCode GetEndpoints(UA_Client *client, size_t* endpointDescriptionsSize, UA_EndpointDescription** endpointDescriptions) {
     UA_GetEndpointsRequest request;
     UA_GetEndpointsRequest_init(&request);
     request.requestHeader.authenticationToken = client->authenticationToken;
     request.requestHeader.timestamp = UA_DateTime_now();
     request.requestHeader.timeoutHint = 10000;
-    request.endpointUrl = client->endpointUrl;
-    UA_String profileUri = UA_STRING("http://opcfoundation.org/UA-Profile/Transport/uatcp-uasc-uabinary");
-    request.profileUris = &profileUri;
-    request.profileUrisSize = 1;
+    //no filter for endpoints
+    request.profileUrisSize = 0;
 
     UA_GetEndpointsResponse response;
     UA_GetEndpointsResponse_init(&response);
@@ -349,11 +351,32 @@ static UA_StatusCode EndpointsHandshake(UA_Client *client) {
         return response.responseHeader.serviceResult;
     }
 
+    *endpointDescriptionsSize = response.endpointsSize;
+    *endpointDescriptions = UA_Array_new(response.endpointsSize, &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]);
+    for(size_t i=0;i<response.endpointsSize;i++){
+        UA_EndpointDescription_copy(&response.endpoints[i], endpointDescriptions[i]);
+    }
+
+    UA_GetEndpointsResponse_deleteMembers(&response);
+
+    return response.responseHeader.serviceResult;
+}
+
+static UA_StatusCode EndpointsHandshake(UA_Client *client) {
+    UA_EndpointDescription* endpointArray = NULL;
+    size_t endpointArraySize = 0;
+    UA_StatusCode retval = GetEndpoints(client, &endpointArraySize, &endpointArray);
+
     UA_Boolean endpointFound = UA_FALSE;
     UA_Boolean tokenFound = UA_FALSE;
     UA_String securityNone = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#None");
-    for(size_t i = 0; i < response.endpointsSize; i++) {
-        UA_EndpointDescription* endpoint = &response.endpoints[i];
+    UA_String binaryTransport = UA_STRING("http://opcfoundation.org/UA-Profile/Transport/uatcp-uasc-uabinary");
+
+    for(size_t i = 0; i < endpointArraySize; i++) {
+        UA_EndpointDescription* endpoint = &endpointArray[i];
+        /* look out for binary transport endpoints */
+        if(!UA_String_equal(&endpoint->transportProfileUri, &binaryTransport))
+            continue;
         /* look out for an endpoint without security */
         if(!UA_String_equal(&endpoint->securityPolicyUri, &securityNone))
             continue;
@@ -370,7 +393,9 @@ static UA_StatusCode EndpointsHandshake(UA_Client *client) {
         }
     }
 
-    UA_GetEndpointsResponse_deleteMembers(&response);
+    //cleanup array
+    UA_Array_delete(endpointArray,endpointArraySize,&UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]);
+
     if(!endpointFound) {
         UA_LOG_ERROR(client->logger, UA_LOGCATEGORY_CLIENT, "No suitable endpoint found");
         return UA_STATUSCODE_BADINTERNALERROR;
@@ -379,7 +404,7 @@ static UA_StatusCode EndpointsHandshake(UA_Client *client) {
         UA_LOG_ERROR(client->logger, UA_LOGCATEGORY_CLIENT, "No anonymous token found");
         return UA_STATUSCODE_BADINTERNALERROR;
     }
-    return response.responseHeader.serviceResult;
+    return retval;
 }
 
 static UA_StatusCode SessionHandshake(UA_Client *client) {
@@ -471,6 +496,36 @@ static UA_StatusCode CloseSecureChannel(UA_Client *client) {
     return retval;
 }
 
+UA_StatusCode UA_client_getEndpoints(UA_Client *client, UA_ConnectClientConnection connectFunc,
+        const char *serverUrl, size_t* endpointDescriptionsSize, UA_EndpointDescription** endpointDescriptions) {
+    if(client->state == UA_CLIENTSTATE_CONNECTED)
+        return UA_STATUSCODE_GOOD;
+    if(client->state == UA_CLIENTSTATE_ERRORED) {
+        UA_Client_reset(client);
+    }
+
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+    client->connection = connectFunc(UA_ConnectionConfig_standard, serverUrl, client->logger);
+    if(client->connection.state != UA_CONNECTION_OPENING) {
+        retval = UA_STATUSCODE_BADCONNECTIONCLOSED;
+        goto cleanup;
+    }
+
+    client->connection.localConf = client->config.localConnectionConfig;
+    retval = HelAckHandshake(client);
+    if(retval == UA_STATUSCODE_GOOD)
+        retval = SecureChannelHandshake(client, UA_FALSE);
+    if(retval == UA_STATUSCODE_GOOD)
+        retval = GetEndpoints(client, endpointDescriptionsSize, endpointDescriptions);
+    //we always cleanup
+    cleanup:
+    retval = CloseSecureChannel(client);
+    client->state = UA_CLIENTSTATE_ERRORED;
+    //here the client is reset in its initial state
+    UA_Client_reset(client);
+    return retval;
+}
+
 UA_StatusCode UA_Client_connect(UA_Client *client, UA_ConnectClientConnection connectFunc,
                                 const char *endpointUrl) {
     if(client->state == UA_CLIENTSTATE_CONNECTED)