Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <opc/ua/client/client.h>
00021
00022 #include <opc/common/uri_facade.h>
00023 #include <opc/ua/client/remote_connection.h>
00024 #include <opc/ua/services/services.h>
00025 #include <opc/ua/node.h>
00026 #include <opc/ua/protocol/string_utils.h>
00027
00028
00029 namespace OpcUa
00030 {
00031
00032 void KeepAliveThread::Start(Services::SharedPtr server, Node node, Duration period)
00033 {
00034 Server = server;
00035 NodeToRead = node;
00036 Period = period;
00037 Running = true;
00038 StopRequest = false;
00039 Thread = std::thread([this] { this->Run(); });
00040 }
00041
00042
00043 void KeepAliveThread::Run()
00044 {
00045 if (Debug) { std::cout << "KeepAliveThread | Starting." << std::endl; }
00046 while ( ! StopRequest )
00047 {
00048 if (Debug) { std::cout << "KeepAliveThread | Sleeping for: " << (int64_t) ( Period * 0.7 )<< std::endl; }
00049 std::unique_lock<std::mutex> lock(Mutex);
00050 std::cv_status status = Condition.wait_for(lock, std::chrono::milliseconds( (int64_t) ( Period * 0.7) ));
00051 if (status == std::cv_status::no_timeout )
00052 {
00053 break;
00054 }
00055 if (Debug) { std::cout << "KeepAliveThread | renewing secure channel " << std::endl; }
00056 OpenSecureChannelParameters params;
00057 params.ClientProtocolVersion = 0;
00058 params.RequestType = SecurityTokenRequestType::Renew;
00059 params.SecurityMode = MessageSecurityMode::None;
00060 params.ClientNonce = std::vector<uint8_t>(1, 0);
00061 params.RequestLifeTime = Period;
00062 OpenSecureChannelResponse response = Server->OpenSecureChannel(params);
00063 if ( (response.ChannelSecurityToken.RevisedLifetime < Period) && (response.ChannelSecurityToken.RevisedLifetime > 0) )
00064 {
00065 Period = response.ChannelSecurityToken.RevisedLifetime;
00066 }
00067
00068 if (Debug) { std::cout << "KeepAliveThread | read a variable from address space to keep session open " << std::endl; }
00069 NodeToRead.GetValue();
00070 }
00071 Running = false;
00072 if (Debug)
00073 {
00074 std::cout << "KeepAliveThread | Stopped" << std::endl;
00075 }
00076 }
00077
00078 void KeepAliveThread::Stop()
00079 {
00080 if (Debug) { std::cout << "KeepAliveThread | Stopping." << std::endl; }
00081 StopRequest = true;
00082 Condition.notify_all();
00083 try
00084 {
00085 Thread.join();
00086 }
00087 catch (std::system_error ex)
00088 {
00089 if (Debug) { std::cout << "KeepaliveThread | Exception thrown at attempt to join: " << ex.what() << std::endl; }
00090 }
00091 }
00092
00093 std::vector<EndpointDescription> UaClient::GetServerEndpoints(const std::string& endpoint)
00094 {
00095 const Common::Uri serverUri(endpoint);
00096 OpcUa::IOChannel::SharedPtr channel = OpcUa::Connect(serverUri.Host(), serverUri.Port());
00097
00098 OpcUa::SecureConnectionParams params;
00099 params.EndpointUrl = endpoint;
00100 params.SecurePolicy = "http://opcfoundation.org/UA/SecurityPolicy#None";
00101
00102 Server = OpcUa::CreateBinaryClient(channel, params, Debug);
00103
00104 OpenSecureChannel();
00105 std::vector<EndpointDescription> endpoints = UaClient::GetServerEndpoints();
00106 CloseSecureChannel();
00107
00108 Server.reset();
00109
00110 return endpoints;
00111 }
00112
00113 std::vector<EndpointDescription> UaClient::GetServerEndpoints()
00114 {
00115 GetEndpointsParameters filter;
00116 filter.EndpointUrl = Endpoint.EndpointUrl;
00117 filter.ProfileUris.push_back("http://opcfoundation.org/UA-Profile/Transport/uatcp-uasc-uabinary");
00118 filter.LocaleIds.push_back("http://opcfoundation.org/UA-Profile/Transport/uatcp-uasc-uabinary");
00119 std::vector<EndpointDescription> endpoints = Server->Endpoints()->GetEndpoints(filter);
00120
00121 return endpoints;
00122 }
00123
00124 EndpointDescription UaClient::SelectEndpoint(const std::string& endpoint)
00125 {
00126 std::vector<EndpointDescription> endpoints = GetServerEndpoints(endpoint);
00127 if (Debug) { std::cout << "UaClient | Going through server endpoints and selected one we support" << std::endl; }
00128 Common::Uri uri(endpoint);
00129 bool has_login = !uri.User().empty();
00130 for ( EndpointDescription ed : endpoints)
00131 {
00132 if (Debug) { std::cout << "UaClient | Examining endpoint: " << ed.EndpointUrl << " with security: " << ed.SecurityPolicyUri << std::endl; }
00133 if ( ed.SecurityPolicyUri == "http://opcfoundation.org/UA/SecurityPolicy#None")
00134 {
00135 if (Debug) { std::cout << "UaClient | Security policy is OK, now looking at user token" << std::endl; }
00136 if (ed.UserIdentityTokens.empty() )
00137 {
00138 if (Debug) { std::cout << "UaClient | Server does not use user token, OK" << std::endl; }
00139 return ed;
00140 }
00141 for ( UserTokenPolicy token : ed.UserIdentityTokens)
00142 {
00143 if (has_login)
00144 {
00145 if (token.TokenType == UserTokenType::UserName)
00146 {
00147 if (Debug) { std::cout << "UaClient | Endpoint selected " << std::endl; }
00148 return ed;
00149 }
00150 }
00151 else if (token.TokenType == UserTokenType::Anonymous)
00152 {
00153 if (Debug) { std::cout << "UaClient | Endpoint selected " << std::endl; }
00154 return ed;
00155 }
00156 }
00157 }
00158 }
00159 throw std::runtime_error("No supported endpoints found on server");
00160 }
00161
00162 void UaClient::Connect(const std::string& endpoint)
00163 {
00164 EndpointDescription endpointdesc = SelectEndpoint(endpoint);
00165 endpointdesc.EndpointUrl = endpoint;
00166 Connect(endpointdesc);
00167 }
00168
00169 void UaClient::Connect(const EndpointDescription& endpoint)
00170 {
00171 Endpoint = endpoint;
00172 const Common::Uri serverUri(Endpoint.EndpointUrl);
00173 OpcUa::IOChannel::SharedPtr channel = OpcUa::Connect(serverUri.Host(), serverUri.Port());
00174
00175 OpcUa::SecureConnectionParams params;
00176 params.EndpointUrl = Endpoint.EndpointUrl;
00177 params.SecurePolicy = "http://opcfoundation.org/UA/SecurityPolicy#None";
00178
00179 Server = OpcUa::CreateBinaryClient(channel, params, Debug);
00180
00181 OpenSecureChannel();
00182
00183
00184 if (Debug) { std::cout << "UaClient | Creating session ..." << std::endl; }
00185 OpcUa::RemoteSessionParameters session;
00186 session.ClientDescription.ApplicationUri = ApplicationUri;
00187 session.ClientDescription.ProductUri = ProductUri;
00188 session.ClientDescription.ApplicationName = LocalizedText(SessionName);
00189 session.ClientDescription.ApplicationType = OpcUa::ApplicationType::Client;
00190 session.SessionName = SessionName;
00191 session.EndpointUrl = endpoint.EndpointUrl;
00192 session.Timeout = DefaultTimeout;
00193 session.ServerURI = endpoint.Server.ApplicationUri;
00194
00195 CreateSessionResponse response = Server->CreateSession(session);
00196 CheckStatusCode(response.Header.ServiceResult);
00197 if (Debug) { std::cout << "UaClient | Create session OK" << std::endl; }
00198
00199 if (Debug) { std::cout << "UaClient | Activating session ..." << std::endl; }
00200 ActivateSessionParameters session_parameters;
00201 {
00202
00203 Common::Uri uri(session.EndpointUrl);
00204 std::string user = uri.User();
00205 std::string password = uri.Password();
00206 bool user_identify_token_found = false;
00207 session_parameters.ClientSignature.Algorithm = "http://www.w3.org/2000/09/xmldsig#rsa-sha1";
00208 for(auto ep : response.Parameters.ServerEndpoints) {
00209 if(ep.SecurityMode == MessageSecurityMode::None) {
00210 for(auto token : ep.UserIdentityTokens) {
00211 if(user.empty()) {
00212 if(token.TokenType == UserTokenType::Anonymous) {
00213 session_parameters.UserIdentityToken.setPolicyId(token.PolicyId);
00214 user_identify_token_found = true;
00215 break;
00216 }
00217 }
00218 else {
00219 if(token.TokenType == UserTokenType::UserName) {
00220 session_parameters.UserIdentityToken.setPolicyId(token.PolicyId);
00221 session_parameters.UserIdentityToken.setUser(user, password);
00222 user_identify_token_found = true;
00223 break;
00224 }
00225 }
00226 }
00227 }
00228 }
00229 if(!user_identify_token_found) {
00230 throw std::runtime_error("Cannot find suitable user identify token for session");
00231 }
00232 }
00233 ActivateSessionResponse aresponse = Server->ActivateSession(session_parameters);
00234 CheckStatusCode(aresponse.Header.ServiceResult);
00235 if (Debug) { std::cout << "UaClient | Activate session OK" << std::endl; }
00236
00237 if (response.Parameters.RevisedSessionTimeout > 0 && response.Parameters.RevisedSessionTimeout < DefaultTimeout )
00238 {
00239 DefaultTimeout = response.Parameters.RevisedSessionTimeout;
00240 }
00241 KeepAlive.Start(Server, Node(Server, ObjectId::Server_ServerStatus_State), DefaultTimeout);
00242 }
00243
00244 void UaClient::OpenSecureChannel()
00245 {
00246 OpenSecureChannelParameters channelparams;
00247 channelparams.ClientProtocolVersion = 0;
00248 channelparams.RequestType = SecurityTokenRequestType::Issue;
00249 channelparams.SecurityMode = MessageSecurityMode::None;
00250 channelparams.ClientNonce = std::vector<uint8_t>(1, 0);
00251 channelparams.RequestLifeTime = DefaultTimeout;
00252 const OpenSecureChannelResponse& response = Server->OpenSecureChannel(channelparams);
00253
00254 CheckStatusCode(response.Header.ServiceResult);
00255
00256 SecureChannelId = response.ChannelSecurityToken.SecureChannelId;
00257 if ( response.ChannelSecurityToken.RevisedLifetime > 0 )
00258 {
00259 DefaultTimeout = response.ChannelSecurityToken.RevisedLifetime;
00260 }
00261 }
00262
00263 void UaClient::CloseSecureChannel()
00264 {
00265 Server->CloseSecureChannel(SecureChannelId);
00266 }
00267
00268 UaClient::~UaClient()
00269 {
00270 Disconnect();
00271 }
00272
00273 void UaClient::Disconnect()
00274 {
00275 KeepAlive.Stop();
00276
00277 if ( Server )
00278 {
00279 CloseSessionResponse response = Server->CloseSession();
00280 if (Debug) { std::cout << "CloseSession response is " << ToString(response.Header.ServiceResult) << std::endl; }
00281 CloseSecureChannel();
00282 }
00283 Server.reset();
00284 }
00285
00286 void UaClient::Abort()
00287 {
00288 KeepAlive.Stop();
00289
00290 Server.reset();
00291 }
00292
00293 std::vector<std::string> UaClient::GetServerNamespaces()
00294 {
00295 if ( ! Server ) { throw std::runtime_error("Not connected");}
00296 Node namespacearray(Server, ObjectId::Server_NamespaceArray);
00297 return namespacearray.GetValue().As<std::vector<std::string>>();;
00298 }
00299
00300 uint32_t UaClient::GetNamespaceIndex(std::string uri)
00301 {
00302 if ( ! Server ) { throw std::runtime_error("Not connected");}
00303 Node namespacearray(Server, ObjectId::Server_NamespaceArray);
00304 std::vector<std::string> uris = namespacearray.GetValue().As<std::vector<std::string>>();;
00305 for ( uint32_t i=0; i<uris.size(); ++i)
00306 {
00307 if (uris[i] == uri )
00308 {
00309 return i;
00310 }
00311 }
00312 throw(std::runtime_error("Error namespace uri does not exists in server"));
00313
00314 }
00315
00316
00317 Node UaClient::GetNode(const std::string& nodeId) const
00318 {
00319 return Node(Server, ToNodeId(nodeId));
00320 }
00321
00322 Node UaClient::GetNode(const NodeId& nodeId) const
00323 {
00324 if ( ! Server ) { throw std::runtime_error("Not connected");}
00325 return Node(Server, nodeId);
00326 }
00327
00328 Node UaClient::GetRootNode() const
00329 {
00330 if ( ! Server ) { throw std::runtime_error("Not connected");}
00331 return Node(Server, OpcUa::ObjectId::RootFolder);
00332 }
00333
00334 Node UaClient::GetObjectsNode() const
00335 {
00336 if ( ! Server ) { throw std::runtime_error("Not connected");}
00337 return Node(Server, OpcUa::ObjectId::ObjectsFolder);
00338 }
00339
00340 Node UaClient::GetServerNode() const
00341 {
00342 if ( ! Server ) { throw std::runtime_error("Not connected");}
00343 return Node(Server, OpcUa::ObjectId::Server);
00344 }
00345
00346 void UaClient::DeleteNodes(std::vector<OpcUa::Node>& nodes, bool recursive)
00347 {
00348 if (recursive)
00349 {
00350 std::vector<OpcUa::Node> children = AddChilds(nodes);
00351 nodes.insert(nodes.end(), children.begin(), children.end());
00352 }
00353 if (Debug) { std::cout << "UaClient | Deleting nodes ..." << std::endl; }
00354 std::vector<OpcUa::DeleteNodesItem> nodesToDelete;
00355 nodesToDelete.resize(nodes.size());
00356 for (unsigned i = 0; i < nodes.size(); i++)
00357 {
00358 nodesToDelete[i].NodeId = nodes[i].GetId();
00359 nodesToDelete[i].DeleteTargetReferences = true;
00360 }
00361
00362 DeleteNodesResponse response = Server->DeleteNodes(nodesToDelete);
00363 for (std::vector<OpcUa::StatusCode>::iterator it = response.Results.begin(); it < response.Results.end(); it++)
00364 {
00365 CheckStatusCode(*it);
00366 }
00367 }
00368
00369 std::vector<OpcUa::Node> UaClient::AddChilds(std::vector<OpcUa::Node> nodes)
00370 {
00371 std::vector<OpcUa::Node> results;
00372 std::vector<OpcUa::Node> temp;
00373 for (std::vector<OpcUa::Node>::iterator it = nodes.begin(); it < nodes.end(); it++)
00374 {
00375 temp.clear();
00376 temp = it->GetChildren();
00377 if (!temp.empty())
00378 {
00379 results.insert(results.begin(), temp.begin(), temp.end());
00380 temp = AddChilds(temp);
00381 results.insert(results.begin(), temp.begin(), temp.end());
00382 }
00383 }
00384 return results;
00385 }
00386
00387 std::unique_ptr<Subscription> UaClient::CreateSubscription(unsigned int period, SubscriptionHandler& callback)
00388 {
00389 CreateSubscriptionParameters params;
00390 params.RequestedPublishingInterval = period;
00391
00392 return std::unique_ptr<Subscription>(new Subscription (Server, params, callback, Debug));
00393 }
00394
00395 ServerOperations UaClient::CreateServerOperations()
00396 {
00397 return std::move(ServerOperations(Server));
00398 }
00399 }
00400