Skip to content

Advanced Licensing Java Implementation #213

@jonthemonke

Description

@jonthemonke

Issue

In an attempt to wrap the Scichart Server Licensing shared object using java (JNA), I ended up with strange behavior when calling any function which returns char *. In Java, the returned pointer memory does not start at the correct offset which holds the string value and therefore invalid characters are returned.

Hypothesis

My guess, after evaluation, is that either the function is returning some std::string object, or that it is actually returning say str.c_str() where str is an std::string. The issue is that returning str.c_str() causes the reference to be dropped once it is out of scope, this means that a dangling pointer is returned. I ended up needing to wrap the function calls in another extern C layer to get the desired functionality in Java, see below.

scichart.h

#include<cstring>
#include <string>

namespace SciChart {
enum class SCRTLicenseType {
  /// Invalid but informs the user a trial is being requested.
  LICENSE_TYPE_NO_LICENSE = 0,
  /// Trial - Valid but with trial notices
  LICENSE_TYPE_TRIAL = 0x02,
  /// Community - Watermark but no expiry
  LICENSE_TYPE_COMMUNITY = 0x03,
  /// Full - Valid
  LICENSE_TYPE_FULL = 0x20,
  /// Full expired - For Non-perpetual (web)
  LICENSE_TYPE_FULL_EXPIRED = 0x04,
  /// Trial expired - Invalid
  LICENSE_TYPE_TRIAL_EXPIRED = 0x40,
  /// Subscription expired - build is after expiry date
  LICENSE_TYPE_SUBSCRIPTION_EXPIRED = 0x80,
  /// Invalid developer license - Invalid machine specific license
  LICENSE_TYPE_INVALID_DEVELOPER_LICENSE = 0x0F,
  /// License that requires server validation
  LICENSE_TYPE_REQUIRES_VALIDATION = 0x2F,
  /// Invalid license - Invalid runtime license
  LICENSE_TYPE_INVALID_LICENSE = 0xFF
};

namespace LicenseServer {

void ResetRuntimeLicense();

bool SetAssemblyName(const std::string &_assemblyName);

/// Sets the Runtime License ( narrow string version ).
/// Returns true passed license key is valid; otherwise false.
bool SetRuntimeLicenseKey(const std::string &_strKey);

/// Gets a type of the Runtime License.
SCRTLicenseType GetLicenseType();

/// Determines whether the Runtime License is valid.
bool CheckLicenseValid();

/// Gets the OrderId of the current license
std::string GetOrderId();

/// Gets the reason for the license failure
std::string GetLicenseErrors();

/// Decode and check challenge.  Generate response with encrypted expiry
std::string ValidateChallenge(const std::string &_challenge);

/// Dumps the information of the Runtime License to returned string.
std::string Dump();

} // namespace LicenseServer
} // namespace SciChart

#ifdef __cplusplus
extern "C" {
#endif
bool SciChartSCS_SetRuntimeLicenseKey(char* _strKey);
#ifdef __cplusplus
}
#endif

#ifdef __cplusplus
extern "C" {
#endif
char *SciChartSCS_GetLicenseErrors();
#ifdef __cplusplus
}
#endif

#ifdef __cplusplus
extern "C" {
#endif
char *SciChartSCS_ValidateChallenge(char* _challenge);
#ifdef __cplusplus
}
#endif

scichart.cpp

#include <string>
#include <cstring>
#include "scichart.h"

extern "C" {
bool SciChartSCS_SetRuntimeLicenseKey(char *_strKey) {
  using namespace std;
  return SciChart::LicenseServer::SetRuntimeLicenseKey(_strKey);
}
}

extern "C" {
char *SciChartSCS_GetLicenseErrors() {
  using namespace std;
  std::string val = SciChart::LicenseServer::GetLicenseErrors();

  char *ret = (char *)malloc(val.size() + 1);
  strcpy(ret, val.c_str());

  return ret;
}
}

extern "C" {
char *SciChartSCS_ValidateChallenge(char *_challenge) {
  using namespace std;
  std::string val = SciChart::LicenseServer::ValidateChallenge(_challenge);

  char *ret = (char *)malloc(val.size() + 1);
  strcpy(ret, val.c_str());

  return ret;
}
}

int main() { return 0; }

I then free the malloc on the Java side to get this to work. I believe that if the current shared object actually wrote it's c_str() to a native char* buffer then returned it, there would be no dangling pointer on the Java side and we would not need to to any additional wrapping.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions