Commit 126fed52 authored by Nikola Hardi's avatar Nikola Hardi Committed by Volodymyr Yurchenko
Browse files

Feature DNS resolv

parent 3a214844
Pipeline #899990 passed with stage
in 2 minutes and 28 seconds
......@@ -33,7 +33,11 @@ set(SRCS
TJAlienResult.cxx
TJAlienResultRewriter.cxx
TJAlienSAXHandler.cxx
TJAlienSystem.cxx)
TJAlienSystem.cxx
TJAlienCredentials.cxx
TJClientFile.cxx
TJAlienDNSResolver.cxx
)
string(REPLACE ".cxx" ".h" HDRS "${SRCS}")
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
include_directories(${LIBNAME} ${OPENSSL_INCLUDE_DIR})
......
......@@ -20,4 +20,7 @@
#pragma link C++ class TJAlienResultRewriter;
#pragma link C++ class TJAlienSAXHandler;
#pragma link C++ class TJAlienSystem;
#pragma link C++ class TJAlienCredentials;
#pragma link C++ class TJClientFile;
#pragma link C++ class TJAlienDNSResolver;
#endif
......@@ -19,6 +19,7 @@
#include "TJAlienJobStatus.h"
#include "TJAlienJobStatusList.h"
#include "TJAlienResultRewriter.h"
#include "TJAlienDNSResolver.h"
#include <sstream>
ClassImp(TJAlien)
......@@ -29,6 +30,8 @@ int TJAlien::writeable_flag = 0;
int TJAlien::receive_flag = 0;
std::string TJAlien::readBuffer = "";
using std::string;
//______________________________________________________________________________
TJAlien::TJAlien (const char* gridUrl, const char* uId, const char* passwd,
......@@ -73,120 +76,103 @@ TJAlien::~TJAlien()
//______________________________________________________________________________
void TJAlien::CreateConnection()
{
for (int i = 0; i < 5;)
{
// Clear flags
destroy_flag = 0;
connection_flag = 0;
writeable_flag = 0;
receive_flag = 0;
readBuffer = "";
// Load certificate
std::stringstream tokencert_s, tokenkey_s;
tokencert_s << tmpdir << "/tokencert_" << getuid() << ".pem";
tokenkey_s << tmpdir << "/tokenkey_" << getuid() << ".pem";
std::string tokencert = tokencert_s.str();
std::string tokenkey = tokenkey_s.str();
std::string tokencertpath = std::getenv("JALIEN_TOKEN_CERT") ? : tokencert;
std::string tokenkeypath = std::getenv("JALIEN_TOKEN_KEY") ? : tokenkey;
FILE *tokencertfile = NULL;
FILE *tokenkeyfile = NULL;
TJAlienCredentialsObject co;
TJAlienDNSResolver dns_jcentral(default_server, default_WSport);
string current_host;
clearFlags();
creds.loadCredentials();
if(creds.has(cJBOX_TOKEN)) {
co = creds.get(cJBOX_TOKEN);
} else if (creds.has(cFULL_GRID_CERT)) {
co = creds.get(cFULL_GRID_CERT);
} else {
return;
}
// Try to connect with token certificate if it exists
if ((tokencertfile = fopen(tokencertpath.c_str(), "r")) &&
(tokenkeyfile = fopen(tokenkeypath.c_str(), "r")) )
{
fclose(tokencertfile);
fclose(tokenkeyfile);
if(co.kind == cJBOX_TOKEN) {
ConnectJBox();
}
ConnectJBox(tokencertpath, tokenkeypath);
}
if(connection_flag) return;
// In not succeded, establish a connection with full user grid certificate
if (!connection_flag)
{
std::string usercert = sUsercert.Data()[0] != '\0' ? sUsercert.Data() : homedir + "/.globus/usercert.pem";
std::string userkey = sUserkey.Data()[0] != '\0' ? sUserkey.Data() : homedir + "/.globus/userkey.pem";
std::string usercertpath = std::getenv("X509_USER_CERT") ? : usercert;
std::string userkeypath = std::getenv("X509_USER_KEY") ? : userkey;
ConnectJBox(usercertpath, userkeypath);
}
for (int i = 0; i < dns_jcentral.lenght(); i++)
{
current_host = dns_jcentral.get_next_host();
ConnectJCentral(co.certpath, co.keypath, current_host);
if (connection_flag)
{
// If connected directly to JCentral, immediately ask for token
if (fHost == default_server)
Token("", false);
if(gDebug > 0) {
Info("TJAlien", "Successfully connected to %s", current_host.c_str());
}
Token("", false);
fUser = Whoami();
return;
}
else
{
Error("TJAlien", "Failed to connect to any server! Retrying in %d seconds...", ++i);
sleep(i);
Error("TJAlien", "Failed to connect to %s - retrying...", current_host.c_str());
sleep(1);
}
}
Error("TJAlien", "Failed to connect to any server! Giving up");
}
//______________________________________________________________________________
void TJAlien::ConnectJBox(std::string certpath, std::string keypath)
void TJAlien::clearFlags()
{
// Load token config file
char* cUserId = new char[10];
sprintf(cUserId, "%d", getuid());
char* jclientFileLocation = new char[100];
sprintf(jclientFileLocation, "%s%s%s", P_tmpdir, "/jclient_token_", cUserId);
// Read server:port from config file
// If successful, try to connect
if (ReadJClientFile(jclientFileLocation))
MakeWebsocketConnection(certpath, keypath);
destroy_flag = 0;
connection_flag = 0;
writeable_flag = 0;
receive_flag = 0;
readBuffer = "";
}
delete cUserId;
delete jclientFileLocation;
//______________________________________________________________________________
void TJAlien::ConnectJBox()
{
if(!creds.has(cJBOX_TOKEN)) {
return;
}
TJAlienCredentialsObject c = creds.get(cJBOX_TOKEN);
TJClientFile jcf;
if(jcf.isValid) {
MakeWebsocketConnection(c.certpath, c.keypath, (string)jcf.fHost, jcf.fWSPort);
} else {
Info("TJAlien", "The JClient file is not valid - not connecting to JBox!");
}
}
// Connection failed, try again with central server
if (!connection_flag)
{
if (gDebug > 1) Info("TJAlien", "Trying to connect to default server!");
fHost = default_server;
fPort = 8098;
fWSPort = 8097;
fUser = "";
fPw = "";
MakeWebsocketConnection(certpath, keypath);
}
void TJAlien::ConnectJCentral(string certpath, string keypath, string host)
{
if (gDebug > 1) Info("TJAlien", "Trying to connect to server %s", host.c_str());
MakeWebsocketConnection(certpath, keypath, host, default_WSport);
}
//______________________________________________________________________________
void TJAlien::MakeWebsocketConnection(std::string certpath, std::string keypath)
void TJAlien::MakeWebsocketConnection(string certpath, string keypath, string host, int WSPort)
{
// Create the connection to JBox using the parameters read from the token
// returns true if the connection was established
Info("TJAlien", "Connecting to Server %s:%d", fHost.Data(), fWSPort);
if(gDebug > 0) {
Info("TJAlien", "Connecting to Server %s:%d", host.c_str(), WSPort);
Info("TJAlien", "Using cert %s and %s", certpath.c_str(), keypath.c_str());
}
// Use this for debugging
//lws_set_log_level(1023, NULL);//LLL_DEBUG | LLL_INFO | LLL_ERR | LLL_NOTICE, NULL);
// lws_set_log_level(1023, NULL);//LLL_DEBUG | LLL_INFO | LLL_ERR | LLL_NOTICE, NULL);
lws_set_log_level(gDebug, NULL);
// Reset context variables
context = NULL;
wsi = NULL;
// Clear flags
destroy_flag = 0;
connection_flag = 0;
writeable_flag = 0;
receive_flag = 0;
clearFlags();
// libwebsockets variables
struct lws_client_connect_info connect_info;
......@@ -235,13 +221,13 @@ void TJAlien::MakeWebsocketConnection(std::string certpath, std::string keypath)
if (gDebug > 1)
Info("TJAlien", "context created");
connect_info.address = fHost;
connect_info.port = fWSPort;
connect_info.address = host.c_str();
connect_info.port = WSPort;
connect_info.path = "/websocket/json";
connect_info.context = context;
connect_info.ssl_connection = use_ssl;
connect_info.host = fHost;
connect_info.origin = fHost;
connect_info.host = host.c_str();
connect_info.origin = host.c_str();
connect_info.ietf_version_or_minus_one = -1;
connect_info.protocol = protocols[0].name;
connect_info.pwsi = &wsi;
......@@ -249,7 +235,9 @@ void TJAlien::MakeWebsocketConnection(std::string certpath, std::string keypath)
// Create wsi - WebSocket Instance
lws_client_connect_via_info(&connect_info);
if (wsi == NULL) {
Error("TJAlien", "WebSocket instance creation error");
if(gDebug > 0) {
Error("TJAlien", "WebSocket instance creation error");
}
return;
}
......@@ -391,118 +379,6 @@ TJAlienResult* TJAlien::GetCommandResult(json_object *json_response)
return gridResult;
}
//______________________________________________________________________________
Bool_t TJAlien::ReadJClientFile(const char* jclientFilePath)
{
// Reads the token generated by JBox to set the connection parameters
// Setting: fHost, fPort, fWSPort, fUser and fPW
// jclientFilePath: the token file
// returns
// - true if all connections paramenters are set
// - false for any error
std::ifstream jclientFile(jclientFilePath);
std::string fileLine;
Bool_t result = true;
if (jclientFile.is_open())
{
while (getline(jclientFile, fileLine))
{
if (gDebug > 1) Info("TJAlien", "Token file line: %s", fileLine.c_str());
TString sLine = fileLine;
TObjArray *arr = sLine.Tokenize("= ");
if (arr->GetEntries() == 2)
{
TObjString *a = (TObjString*) arr->At(0);
TObjString *b = (TObjString*) arr->At(1);
TString sKey = a->GetString();
TString sValue = b->GetString();
if (gDebug > 1) Info("TJAlien", "\"%s\" = \"%s\"", sKey.Data(), sValue.Data());
if (sKey.EqualTo("Host"))
{
fHost = sValue;
if (fHost == NULL || fHost.Length() == 0)
{
Error("TJAlien", "JAliEn connection host field empty");
result = false;
}
}
if (sKey.EqualTo("Port"))
{
fPort = sValue.Atoi();
}
if (sKey.EqualTo("WSPort"))
{
fWSPort = sValue.Atoi();
}
if (sKey.EqualTo("Home"))
{
fHome = sValue;
}
if (sKey.EqualTo("Usercert"))
{
sUsercert = sValue;
}
if (sKey.EqualTo("Userkey"))
{
sUserkey = sValue;
}
if (sKey.EqualTo("User"))
{
fUser = sValue;
if (fUser == NULL || fUser.Length() == 0)
{
if (gDebug > 1) Error("TJAlien", "JAliEn connection user field is empty");
result = false;
}
}
if (sKey.EqualTo("Passwd"))
{
fPw = sValue;
if (fPw == NULL || fPw.Length() == 0)
{
if (gDebug > 1) Error("TJAlien", "JAliEn connection password field is empty");
result = false;
}
}
}
else
{
if (gDebug > 1) Error("TJAlien", "jclient file does not have "
"the correct structure (%d)", arr->GetEntries());
result = false;
}
delete arr;
}
jclientFile.close();
}
else
{
if (gDebug > 1) Error("TJAlien", "Error while opening jclient file");
result = false;
}
return result;
}
//______________________________________________________________________________
void TJAlien::Stderr()
{
......@@ -671,7 +547,8 @@ void TJAlien::Token(Option_t* options, bool force_restart)
std::string userkey = sUserkey.Data()[0] != '\0' ? sUserkey.Data() : homedir + "/.globus/userkey.pem";
std::string usercertpath = std::getenv("X509_USER_CERT") ? : usercert.c_str();
std::string userkeypath = std::getenv("X509_USER_KEY") ? : userkey.c_str();
ConnectJBox(usercertpath, userkeypath);
// ConnectJBox(usercertpath, userkeypath);
ConnectJCentral(usercertpath, userkeypath);
if (!connection_flag)
{
Info("TJAlien", "TJAlien::Token failed to establish the connection to the server");
......
......@@ -79,6 +79,12 @@ typedef char int8_t;
#endif
#define UNUSED(x) (void)(x)
#define DEFAULT_JCENTRAL_SERVER "alice-jcentral.cern.ch"
#include "TJClientFile.h"
#include "TJAlienCredentials.h"
using std::string;
class TJAlien : public TGrid {
......@@ -95,15 +101,16 @@ private:
static std::string readBuffer;
std::string homedir; // local home directory
std::string tmpdir; // tmp directory
const int default_WSport = 8097;
const std::string default_server = "alice-jcentral.cern.ch";
Bool_t ReadJClientFile(const char* jclientFilePath);
const std::string default_server = DEFAULT_JCENTRAL_SERVER;
Bool_t WriteTokenFile();
static size_t WriteCallback(void *contents, size_t size, size_t nmemb);
void CreateConnection();
void ConnectJBox(std::string certpath, std::string keypath);
void MakeWebsocketConnection(std::string certpath, std::string keypath);
void ConnectJBox();
void ConnectJCentral(string certpath, string keypath, string host = DEFAULT_JCENTRAL_SERVER);
void MakeWebsocketConnection(string certpath, string keypath, string host, int WSPort);
// Format command to Json structure
json_object *CreateJsonCommand(TString *command, TList *options);
......@@ -134,6 +141,9 @@ private:
virtual TGridResult *OpenDataset(const char *lfn, const char *options = "");
const char* Whoami();
void clearFlags();
TJAlienCredentials creds;
public:
TJAlien(const char *gridUrl, const char *uId=0, const char *passwd=0,
......
#include "TJAlienCredentials.h"
#include <sstream>
#include <cstdlib>
#include <unistd.h>
string TJAlienCredentials::getTmpDir() {
string tmpdir;
if (getenv("TMPDIR") != NULL)
tmpdir = getenv("TMPDIR");
else if (getenv("TMP") != NULL)
tmpdir = getenv("TMP");
else if (getenv("TEMP") != NULL)
tmpdir = getenv("TEMP");
else
tmpdir = P_tmpdir;
return tmpdir;
}
string TJAlienCredentials::getHomeDir() {
string homedir;
if (getenv("HOME") != NULL)
homedir = getenv("HOME");
else
homedir = "~";
return homedir;
}
string TJAlienCredentials::getTokencertPath()
{
std::stringstream tokencert_s;
tokencert_s << tmpdir << "/tokencert_" << getuid() << ".pem";
std::string tokencert = tokencert_s.str();
std::string tokencertpath = std::getenv("JALIEN_TOKEN_CERT") ? : tokencert;
return tokencertpath;
}
string TJAlienCredentials::getTokenkeyPath()
{
std::stringstream tokenkey_s;
tokenkey_s << tmpdir << "/tokenkey_" << getuid() << ".pem";
std::string tokenkey = tokenkey_s.str();
std::string tokenkeypath = std::getenv("JALIEN_TOKEN_KEY") ? : tokenkey;
return tokenkeypath;
}
string TJAlienCredentials::getUsercertPath()
{
std::string usercert = jcf.sUsercert.Data()[0] != '\0' ? jcf.sUsercert.Data() : homedir + "/.globus/usercert.pem";
std::string usercertpath = std::getenv("X509_USER_CERT") ? : usercert;
return usercertpath;
}
string TJAlienCredentials::getUserkeyPath()
{
std::string userkey = jcf.sUserkey.Data()[0] != '\0' ? jcf.sUserkey.Data() : homedir + "/.globus/userkey.pem";
std::string userkeypath = std::getenv("X509_USER_KEY") ? : userkey;
return userkeypath;
}
TJAlienCredentials::TJAlienCredentials() {
tmpdir = getTmpDir();
homedir = getHomeDir();
loadCredentials();
}
void TJAlienCredentials::loadCredentials() {
found_credentials.clear();
loadTokenCertificate();
loadFullGridCertificate();
}
void TJAlienCredentials::loadTokenCertificate() {
TJAlienCredentialsObject token_credentials(getTokencertPath(), getTokenkeyPath(), cJBOX_TOKEN);
if(token_credentials.exists()) {
found_credentials[cJBOX_TOKEN] = token_credentials;
}
}
void TJAlienCredentials::loadFullGridCertificate() {
TJAlienCredentialsObject grid_certificate(getUsercertPath(), getUserkeyPath(), cFULL_GRID_CERT);
if(grid_certificate.exists()) {
found_credentials[cFULL_GRID_CERT] = grid_certificate;
}
}
bool TJAlienCredentials::has(CredentialsKind kind) {
return found_credentials.count(kind) == 1;
}
TJAlienCredentialsObject TJAlienCredentials::get(CredentialsKind kind) {
if(this->has(kind)) {
return found_credentials[kind];
}
}
// Author: Nikola Hardi 3/6/2019
#ifndef ROOT_TJAlienCredentials
#define ROOT_TJAlienCredentials
#include <string>
#include <map>
#include "TObject.h"
#include "TJClientFile.h"
using std::string;
using std::map;
enum CredentialsKind { cJBOX_TOKEN = 0,
cFULL_GRID_CERT,
cJOB_TOKEN,
cOTHER_TOKEN,
};
struct TJAlienCredentialsObject {
string certpath;
string keypath;
string source;
CredentialsKind kind;
TJAlienCredentialsObject() {}
TJAlienCredentialsObject(string certpath,
string keypath,
CredentialsKind kind = cOTHER_TOKEN,
string source = "")
{
this->certpath = certpath;
this->keypath = keypath;
this->kind = kind;
this->source = source;
};
bool exists() {
return fileExists(certpath) && fileExists(keypath);
};
private:
bool fileExists(string filename)
{
bool fileExists = false;
FILE *f = fopen(filename.c_str(), "r");
if (f != NULL )
{
fclose(f);
fileExists = true;
}
else
{
fileExists = false;
}
return fileExists;
}
};
class TJAlienCredentials : public TObject {
public:
TJAlienCredentials();
string getTmpDir();
string getHomeDir();
void loadCredentials();
bool has(CredentialsKind kind);
TJAlienCredentialsObject get(CredentialsKind kind);
private:
void loadTokenCertificate();
void loadFullGridCertificate();
string getUsercertPath();
string getUserkeyPath();
string getTokencertPath();
string getTokenkeyPath();
string tmpdir;
string homedir;
map<CredentialsKind, TJAlienCredentialsObject> found_credentials;
TJClientFile jcf;
ClassDef(TJAlienCredentials, 0)
};
#endif
#include "TJAlienDNSResolver.h"
using std::random_device;
TJAlienDNSResolver::TJAlienDNSResolver(string host, int port) {
this->host = host;
this->port = std::to_string(port);
reset();
}
string TJAlienDNSResolver::addr2string(const struct addrinfo *ai)
{
char dst[32];
const struct sockaddr *sa = ai->ai_addr;