client.cpp
Go to the documentation of this file.
00001 /******************************************************************************
00002  *   Copyright (C) 2014-2014 by Sintef Raufoss Manufacturing                  *
00003  *   olivier.roulet@gmail.com                  *
00004  *                                          *
00005  *   This library is free software; you can redistribute it and/or modify     *
00006  *   it under the terms of the GNU Lesser General Public License as          *
00007  *   published by the Free Software Foundation; version 3 of the License.     *
00008  *                                          *
00009  *   This library is distributed in the hope that it will be useful,          *
00010  *   but WITHOUT ANY WARRANTY; without even the implied warranty of          *
00011  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
00012  *   GNU Lesser General Public License for more details.              *
00013  *                                          *
00014  *   You should have received a copy of the GNU Lesser General Public License *
00015  *   along with this library; if not, write to the                  *
00016  *   Free Software Foundation, Inc.,                          *
00017  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.              *
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(); //close channel
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; //force the use of the enpoint the user wants, seems like servers often send wrong hostname
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       //const SessionData &session_data = response.Session;
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();//Do not leave any thread or connectino running
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(); //FIXME: check if we still need this
00284   }
00285 
00286   void UaClient::Abort()
00287   {
00288     KeepAlive.Stop();
00289 
00290     Server.reset(); //FIXME: check if we still need this
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     //return -1;
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 } // namespace OpcUa
00400 


ros_opcua_impl_freeopcua
Author(s): Denis Štogl
autogenerated on Sat Jun 8 2019 18:24:40