Как получить доступ к интерфейсу CORBA без IDL или методов удаленного вызова с поздним связыванием
Мы использовали SAP "COM License Bridge" для доступа к их серверу лицензий и программного запроса аппаратного ключа системы (для повторного использования без собственного лицензирования). Это хорошо работало на версиях SAP Business One 2007A, 2007B и 8.8, но в 8.81 они, кажется, обновили свой интерфейс CORBA без обновления оболочки COM, потому что теперь мы получаем исключения из памяти при попытке вызвать функцию GetHardwareKey.
Поэтому я скачал IIOP.NET и начал пытаться написать свой собственный интерфейс. Мне никогда не нравилась эта оболочка COM. Но я столкнулся со своим старым врагом удаленного взаимодействия в.NET - невозможностью вызова удаленного метода без общего интерфейса, определенного как на сервере, так и на клиенте. Я попытался использовать компилятор IDL для CLS, включенный в IIOP.NET, но продолжаю получать ошибки о несовместимости интерфейса (SAP не предоставил файл IDL). Я не знаю, как IIOP и CORBA определяют, совместим ли интерфейс. Но я даже попытался отладить код IIOP.NET и заставить его выполнить метод, несмотря на несовместимость, но получил пустую строку вместо аппаратного ключа, который я хотел.
Мой следующий шаг - попытаться внедрить поддельный сервер лицензий и изучить запросы, поступающие от рабочего клиента, в надежде определить, как они должны выглядеть, но я не рассчитываю на большой успех, учитывая трудности, с которыми я столкнулся в вглядываясь во внутренности.NET удаленного взаимодействия уже.
Моя настоящая проблема заключается в том, как получить или сгенерировать аппаратный ключ SAP Business One, но вытекающие из этого вопросы:
- Как отразить или запросить информацию об интерфейсе CORBA? Я могу использовать метод list класса NamingContext для получения списка доступных объектов, но я не вижу, есть ли способ запросить доступные методы для объекта.
- Можно ли динамически вызывать методы удаленного взаимодействия.NET без интерфейса? Я вижу что-то под названием DII для динамического вызова CORBA, но я не вижу, как использовать это из IIOP.NET.
- Могу ли я вызвать методы удаленного взаимодействия.NET только с делегатом или неполным интерфейсом? Я попытался использовать динамическое ключевое слово, но он не смог вызвать метод для моего удаленного объекта MarshalByRef... Я думаю, он сказал, что метод не существует в моем экземпляре MarshalByRef или что-то в этом роде. Я только попробовал это через IIOP.NET, хотя (интересно, работает ли это для нормального удаленного взаимодействия.NET).
- Как создать или проверить экземпляры сообщений в платформе удаленного взаимодействия.NET?
- Могу ли я отправлять или получать удаленные сообщения напрямую, минуя прокси-серверы?
Редактировать: мне удалось заставить IIOP.NET / CORBA поверить, что у меня был совместимый интерфейс, применив атрибут RepositoryID:
[Ch.Elca.Iiop.Idl.InterfaceType(Ch.Elca.Iiop.Idl.IdlTypeInterface.ConcreteInterface)]
[Ch.Elca.Iiop.Idl.RepositoryID("IDL:LicenseInfo:1.0")]
public interface ILicenseInfo : Ch.Elca.Iiop.Idl.IIdlEntity
{
void GetHardwareKey(out string hwKey);
}
Но я все еще получаю пустой результат строки.
Редактировать 2: После еще нескольких экспериментов и отладки я обнаружил, что ответные сообщения содержат данные, которые я ищу, но не анализируются в значениях клиента должным образом, возможно, из-за моего неверного определения интерфейса. Надеясь, что отладка в обработке ответов поможет мне понять, как исправить мой интерфейс. Как ни странно, первое, что он анализирует из ответа, - это пустое значение в штучной упаковке, которое не подходит для параметра "out string".
Редактировать 3: я обнаружил, что мне нужно применить строковые атрибуты к параметрам, как это, чтобы предотвратить их обработку в виде значений в штучной упаковке:
void GetHardwareKey([StringValue(), WideChar(true)] out string hwKey);
Но, несмотря на атрибут Wide Char, я получаю ошибку по поводу того, что CodeSet не поддерживает WChar или что-то в этом роде. Я очень близок к тому, чтобы понять это.
Редактировать 4: я поставлен в тупик, как установить кодовый набор для WChar. Если я не установил его, я получаю сообщение об ошибке: "WChar Codeset либо не указан, либо не поддерживается". потому что сервер возвратил строку Unicode без переопределения набора символов по умолчанию. Я не могу найти способ переопределить это от клиента. Я пытался позвонить:
omg.org.CORBA.OrbServices.GetSingleton().OverrideDefaultCharSets(
CharSet.UTF8, WCharSet.UTF16);
Но это, похоже, не влияет на клиентскую часть. Пример кода показывает вызов этого на стороне сервера. Но я не писал сервер, поэтому я не могу это контролировать. Является ли мой единственный вариант переписать код IIOP.NET для моих собственных целей, чтобы заставить WCHar CodeSet по умолчанию вступить в силу?
2 ответа
После 3 дней отладки в IIOP для отслеживания его поведения и проверки данных, возвращаемых в ответе, я остановился на этом решении.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using omg.org.CosNaming;
using Ch.Elca.Iiop;
using Ch.Elca.Iiop.Services;
using System.Runtime.Remoting.Channels;
using Ch.Elca.Iiop.Idl;
[RepositoryID("IDL:LicenseInfo:1.0")]
public interface ILicenseInfo
{
Int32 GetHardwareKey([IdlSequence(0)] out byte[] hwKey);
Int32 GetInstallationNumberList([IdlSequence(0)] out byte[] instNum);
}
class Program
{
static void Main(string[] args)
{
IiopClientChannel channel = new IiopClientChannel();
ChannelServices.RegisterChannel(channel, false);
CorbaInit init = CorbaInit.GetInit();
NamingContext context = init.GetNameService("MYLICSRV", 30000);
NameComponent[] names = new NameComponent[] { new NameComponent("B1LicenseInfo") };
ILicenseInfo li = (ILicenseInfo)context.resolve(names);
byte[] hwKey;
byte[] instNum;
li.GetHardwareKey(out hwKey);
li.GetInstallationNumberList(out instNum);
Encoding encoding = new System.Text.UnicodeEncoding(false, false, true);
Console.WriteLine(encoding.GetString(hwKey));
Console.WriteLine(encoding.GetString(instNum));
}
}
Я временно также использовал это в попытке заставить IIOP вернуть мне правильные строки. Если бы мне пришло в голову, что я могу просто принять ответ в виде байтового массива и выполнить декодирование самостоятельно, я бы не потратил впустую половину времени, пытаясь понять, как заставить IIOP понять, как я хотел вернуть мою строку:
class MyOrbInitializer : omg.org.PortableInterceptor.ORBInitializer
{
public void post_init(omg.org.PortableInterceptor.ORBInitInfo info)
{
// Nothing to do
}
public void pre_init(omg.org.PortableInterceptor.ORBInitInfo info)
{
omg.org.IOP.Codec codec = info.codec_factory.create_codec(
new omg.org.IOP.Encoding(omg.org.IOP.ENCODING_CDR_ENCAPS.ConstVal, 1, 2));
Program.m_codec = codec;
}
}
class Program
{
public static omg.org.IOP.Codec m_codec;
static void Main(string[] args)
{
IOrbServices orb = OrbServices.GetSingleton();
orb.OverrideDefaultCharSets(CharSet.UTF8, WCharSet.UTF16);
orb.RegisterPortableInterceptorInitalizer(new MyOrbInitializer());
orb.CompleteInterceptorRegistration();
...
MarshalByRefObject objRef = context.resolve(names);
string origObjData = orb.object_to_string(objRef);
Ch.Elca.Iiop.CorbaObjRef.Ior iorObj = new Ch.Elca.Iiop.CorbaObjRef.Ior(origObjData);
CodeSetComponentData cscd = new CodeSetComponentData(
(int)Ch.Elca.Iiop.Services.CharSet.UTF8,
new int[] { (int)Ch.Elca.Iiop.Services.CharSet.UTF8 },
(int)Ch.Elca.Iiop.Services.WCharSet.UTF16,
new int[] { (int)Ch.Elca.Iiop.Services.WCharSet.UTF16 });
omg.org.IOP.TaggedComponent codesetcomp = new omg.org.IOP.TaggedComponent(
omg.org.IOP.TAG_CODE_SETS.ConstVal, m_codec.encode_value(cscd));
iorObj.Profiles[0].TaggedComponents.AddComponent(codesetcomp);
string newObjData = iorObj.ToString();
MarshalByRefObject newObj = (MarshalByRefObject)orb.string_to_object(newObjData);
ILicenseInfo li = (ILicenseInfo)newObj;
...
}
После выполнения этого большого количества кода у меня был объект, который определял бы WChar CodeSet, чтобы он правильно анализировал возвращаемые строки, избегая ошибки "WChar CodeSet либо не указан, либо не поддерживается". Но после всего этого порядок байтов в Юникоде тоже был обратным! И единственный способ исправить это, насколько я мог судить, - это переразобрать строку в байты и затем вернуться в строку Unicode. Но вот когда это пришло мне в голову, зачем даже спрашивать результат в виде строки!? Я мог бы просто взять байты напрямую и избежать такой сложности. Хотел бы я подумать об этом раньше.
SAP BO 882 //LicenseInterface.idl
typedef sequence<octet> LicenseFileData;
interface LicenseInfo
{
boolean IsUserLicensed(in wstring wstrUser, in wstring wstrModule, in wstring wstrInstallNo);
long GetHardwareKey(out wstring pbstrHK);
long GetInstallationNumberList(out wstring wbstrInstNum);
long GetSystemNumber(out wstring wbstrSysNum, in wstring wstrInstallNo);
long GetLicenseInfo(in wstring wstrModule, out long lNum, out long lAvailable, out long lStart, out long lEnd, in wstring wstrInstallNo);
long GetLoggedInUsers(out wstring wbstrLogUsers);
long StartLogging();
long StopLogging();
long GetLicenseNum(in wstring wstrKey, in wstring wstrInstallNo);
long GetLogFileName(out wstring wstrLogFileName);
boolean GetIsLogging();
long LoadLicenseFile (in LicenseFileData arg_licenseFileData);
boolean IsLicenseFileExist();
long ResetAllLicenses();
long GetVersion(out wstring sVersion);
//long DeleteLicenseFile (in wstring wstrInstallNo);
};
SBOLicense.idl
typedef sequence<octet> usBuffer;
enum LicenseClientUTFType {LIC_UTF16 , LIC_UTF32};
exception NotAuthenticated {};
exception UserNotConnected {};
interface LicenseServer
{
long SBOConnect (in usBuffer User, in usBuffer Company, in usBuffer PCName, out usBuffer SessionE, in long lDate, in usBuffer sInstallNo) raises(NotAuthenticated);
long AddOnGetLicense (in usBuffer Identifier, in usBuffer User, in usBuffer Company, in usBuffer PCName, out long plSessionID, out usBuffer SessionE, in long lDate, in usBuffer sInstallNo) raises(NotAuthenticated);
long PollSession (in usBuffer User, in usBuffer SIDs, out usBuffer RetE) raises(NotAuthenticated);
long SessionsInfo (in usBuffer User, in usBuffer SessionsInfo, out usBuffer SessionsInfoE, in long lDate) raises(NotAuthenticated);
long SessionVerify (in usBuffer User, in long lSessionID, out usBuffer pSessionIdE) raises(NotAuthenticated);
long CloseSession (in usBuffer User, in long lSessionId) raises(NotAuthenticated);
long LockServer (in usBuffer User, in long lSessionID) raises(NotAuthenticated);
long UnLockServer (in usBuffer User, in long lSessionID) raises(NotAuthenticated);
long GetUserLicenseInfo (in usBuffer User, out usBuffer pModules, out boolean pbIsConnected) raises(NotAuthenticated);
long GetAllModulesStatus (out usBuffer pModulesInfo) raises(NotAuthenticated);
long LoadLicenseFile (in usBuffer NewLicenseFile) raises(NotAuthenticated);
long GetHardwareKey (out usBuffer pHK) raises(NotAuthenticated);
long CreateIdentifier (in usBuffer Addon, out usBuffer pIdentifier, in usBuffer sInstallNo) raises(NotAuthenticated);
long GetAllUsersLicenseInfo(out usBuffer pUsersLicInfo) raises(NotAuthenticated);
long SetAllUsersLicenseInfo(in usBuffer User, in usBuffer UsersLicInfo, out usBuffer pConnectedUser) raises(NotAuthenticated,UserNotConnected);
long IsDevExist (in usBuffer sInstallNo);
long GetInstallationNumberList(out usBuffer pInstNum);
long GetSystemNumber (out usBuffer pSysNum, in usBuffer sInstallNo);
long GetFutureExpired(in long lFutureDate, out usBuffer pModules, in usBuffer sInstallNo);
long GetUserSessionsInfo(in usBuffer UserName,out usBuffer pRsltSessionsInfo);
long GetBIGSLicense (in usBuffer User, in usBuffer Company, in usBuffer PCName, in long lNum, out usBuffer pSessionsE, in long lDate, in usBuffer sInstallNo) raises(NotAuthenticated);
boolean IsLicenseFileExist();
long GetVersion(out usBuffer sVersion);
long ClearUserLicenses (in usBuffer User) raises(NotAuthenticated);
long UpdateUserLicenses (in usBuffer User, out usBuffer ModulesE, in long lDate, in long lSessionID, in usBuffer sCmpLocalization, in usBuffer sCmpVersion) raises(NotAuthenticated);
long RequestNamedLicenses (in usBuffer User, out usBuffer ModulesE, in long lDate, in long lSessionID, in usBuffer sCmpLocalization, in usBuffer sCmpVersion) raises(NotAuthenticated);
long IsLicenseConcurrent () raises(NotAuthenticated);
long GetLicenseFileGenInfo(in usBuffer sInstallNo, out usBuffer sLicGenInfo);
//long DeleteLicenseFile (in usBuffer sInstallNo) raises(NotAuthenticated);
long HandShake(in long algorithm, in usBuffer publicKey, out usBuffer sessionKey) raises(NotAuthenticated);
long GetCompanyDBCredentials(in long dbType, in usBuffer server, in usBuffer company, in usBuffer user, in usBuffer password, out usBuffer dbUser, out usBuffer dbPassword, out boolean useTrusted) raises(NotAuthenticated);
long GetDBCredentials(in long dbType, in usBuffer server, in usBuffer siteUser, in usBuffer password, out usBuffer dbUser, out usBuffer dbPassword, out boolean useTrusted) raises(NotAuthenticated);
long GetCompanyReadOnlyDBCredentials(in long dbType, in usBuffer server, in usBuffer company, in usBuffer user, in usBuffer password, out usBuffer dbUser, out usBuffer dbPassword) raises(NotAuthenticated);
long GetReadOnlyDBCredentials(in long dbType, in usBuffer server, in usBuffer siteUser, in usBuffer password, out usBuffer dbUser, out usBuffer dbPassword) raises(NotAuthenticated);
long GetListOfCompanies(in long dbType, in usBuffer server, in boolean refresh, out usBuffer listOfCompanies);
long GetCompanyEncryptionConfig(in long dbType, in usBuffer server, in usBuffer company, in usBuffer user, in usBuffer password, out long algorithm, out usBuffer keyId, out usBuffer key) raises(NotAuthenticated);
long GetEncryptionConfig(in usBuffer siteUser, in usBuffer password, out long algorithm, out usBuffer keyId, out usBuffer key) raises(NotAuthenticated);
long SetDBCredentials(in long dbType, in usBuffer server, in usBuffer siteUser, in usBuffer password, in usBuffer dbUser, in usBuffer dbPassword, in boolean useTrusted) raises(NotAuthenticated);
long RemoveDBCredentials(in long dbType, in usBuffer server, in usBuffer siteUser, in usBuffer password) raises(NotAuthenticated);
long GetServerVersion(in long dbType, in usBuffer server, out usBuffer version, in usBuffer commonDBName);
long SetReadOnlyDBCredentials(in long dbType, in usBuffer server, in usBuffer siteUser, in usBuffer password, in usBuffer dbUser, in usBuffer dbPassword) raises(NotAuthenticated);
long SetEncryptionAlghorithm(in usBuffer siteUser, in usBuffer password, in long algorithm) raises(NotAuthenticated);
long GenerateEncryptionKey(in usBuffer siteUser, in usBuffer password) raises(NotAuthenticated);
long GetServicesUserCredentials(in usBuffer siteUser, in usBuffer password, out usBuffer servicesUser, out usBuffer servicesPassword) raises(NotAuthenticated);
long ExportSecuritySettings(in usBuffer siteUser, in usBuffer password, out usBuffer xmlSettings) raises(NotAuthenticated);
long ImportSecuritySettings(in usBuffer siteUser, in usBuffer password, in usBuffer xmlSettings) raises(NotAuthenticated);
long GetListOfConfiguredServers(out usBuffer listOfServers);
long GetSiteUserName(out usBuffer siteUser);
long AuthenticateSiteUser(in usBuffer siteUser, in usBuffer password, out boolean result) raises(NotAuthenticated);
long AuthenticateServicesUser(in usBuffer siteUser, in usBuffer password, out boolean result) raises(NotAuthenticated);
long ChangeSiteUserPassword(in usBuffer siteUser, in usBuffer oldPassword, in usBuffer password) raises(NotAuthenticated);
long ChangeSiteUserPasswordByDB(in long dbType, in usBuffer server, in usBuffer dbUser, in usBuffer dbPassword, in usBuffer password) raises(NotAuthenticated);
long GetCompanyStaticKey(in long dbType, in usBuffer server, in usBuffer company, in usBuffer user, in usBuffer password, out usBuffer key) raises(NotAuthenticated);
long GetStaticKey(in usBuffer siteUser, in usBuffer password, out usBuffer key) raises(NotAuthenticated);
long GetEncryptionAlgorithm(out long algorithm);
long IsNTTrusted(in long dbType, in usBuffer server, out boolean isNTTrusted);
long IsDKeyUsed(out boolean result);
long ExportDKeys(in usBuffer siteUser, in usBuffer password, out usBuffer xmlDKeys) raises(NotAuthenticated);
long ImportDKeys(in usBuffer siteUser, in usBuffer password, in usBuffer xmlDKeys) raises(NotAuthenticated);
long GenerateDKey(in usBuffer siteUser, in usBuffer password, out usBuffer xmlDKeys) raises(NotAuthenticated);
long EnableDKey(in usBuffer siteUser, in usBuffer password, out usBuffer xmlDKeys) raises(NotAuthenticated);
long GetCompanyKeyAndKeyState(in long dbType, in usBuffer server, in usBuffer company, in usBuffer user, in usBuffer password, in usBuffer compKeyId, out long keyState, out usBuffer compKey)raises(NotAuthenticated);
long GetKeyAndKeyState(in usBuffer siteUser, in usBuffer password, in usBuffer compKeyId, out long keyState, out usBuffer compKey)raises(NotAuthenticated);
};
interface LicenseServerFactory
{
LicenseServer GetLicenseServer(in LicenseClientUTFType ClientUTFType);
};