How to connect iscsi target with special IP address(NIC) in C C++

i don’t know where goes my context!! No draft, no reversion, Oh no no.

I don’t want to write tooo much, just make it simple:

to connect to a iscsi target using special portal number (mapping to special host ip) uing MS iScsi Discovery API LoginIScsiTarget,

HRESULT WINAPI LoginIscsiTarget(
  _In_      PTCHAR TargetName,
  _In_      BOOLEAN IsInformationalSession,
  _In_opt_  PTCHAR InitiatorName,
  _In_opt_  ULONG InitiatorPortNumber,
  _In_opt_  PISCSI_TARGET_PORTAL TargetPortal,
  _In_opt_  ISCSI_SECURITY_FLAGS SecurityFlags,
  _In_opt_  PISCSI_TARGET_MAPPING Mappings,
  _In_opt_  PISCSI_LOGIN_OPTIONS LoginOptions,
  _In_opt_  ULONG KeySize,
  _In_opt_  PCHAR Key,
  _In_      BOOLEAN IsPersistent,
  _Out_     PISCSI_UNIQUE_SESSION_ID UniqueSessionId,
  _Out_     PISCSI_UNIQUE_CONNECTION_ID UniqueConnectionId
);

InitiatorName and InitiatorPortNumber specify which NIC you choose to connect to target, default value will using any possible routine to target. This document is about how to find out the mapping of the two parameters and the NIC ip address, using c/c++.

As all the samples on the internet i found, using WMI interface, by C#, power shell script or VBS, here i provide a method using C/C++ and VDS services. about VDS, check link here, it is more detail than MSDN. Base idea like this:

IVdsServiceLoader->LoadService(IVdsService)->QueryInterface(IVdsServiceIscsi)

->QueryInitiatorAdapters(IVdsIscsiInitiatorAdapter)->QueryInitiatorPortals(IVdsIscsiInitiatorPortal)

I think there is a bug for VDS iScsi interface, that is after VDS service starts, it will not update cached status of iScsi objects, when user change ip setting, install new NIC, DHCP, and so on. I did not found any solution for this, no refresh() or reenumerate() for IVdsServiceIScsi, ,so I have to restart VDS service completely before above process. Here is the code slice:

static HRESULT getInitiatorPortalInfo()
{
    HRESULT hr;
    IVdsServiceIscsi *pServiceIscsi = NULL;
    IVdsServiceInitialization* pServiceInitialization = NULL;
    IVdsService* pService = NULL;
    IVdsServiceLoader *pLoader = NULL;
    ULONG uFetched = 0;
    IUnknown* pUnknown = NULL;
    IEnumVdsObject *pInitiatorAdapters = NULL;

    // restart vds services....
    // I can't not refresh IVdsServiceIscsi cache... wtf
    // 
    DoStopSvc(_T("vds"));
    DoStartSvc(_T("vds"));

    hr = CoInitialize(NULL);
    if (FAILED(hr))
        return hr;

    hr = CoCreateInstance(CLSID_VdsLoader,
        NULL,
        CLSCTX_LOCAL_SERVER,
        IID_IVdsServiceLoader,
        (void **) &pLoader);
    if (FAILED(hr))  {
        return hr;
    }
    hr = pLoader->LoadService(NULL, &pService);
    if (FAILED(hr)) {
        goto EXIT;
    }
    hr = pService->QueryInterface(IID_IVdsServiceInitialization, 
                                 (void**)&pServiceInitialization);
    if (FAILED(hr)) {
        goto EXIT;
    }  
    hr = pServiceInitialization->Initialize(NULL);
    if (FAILED(hr)) {
        goto EXIT;
    }

    pService->WaitForServiceReady();
    
    hr = pService->QueryInterface(IID_IVdsServiceIscsi,
                                 (void**)&pServiceIscsi);
    if (FAILED(hr)) {
        goto EXIT;
    }
    // get adapters
    hr = pServiceIscsi->QueryInitiatorAdapters(&pInitiatorAdapters);
    if (FAILED(hr))
        goto EXIT;

    int i = 0;
    while (TRUE)
    {
        uFetched = 0;
        IVdsIscsiInitiatorAdapter *pVdsAdapter = NULL;
        hr = pInitiatorAdapters->Next(1, &pUnknown, &uFetched);
        if (FAILED(hr) || S_FALSE == hr) {
            break;
        }

        hr = pUnknown->QueryInterface(IID_IVdsIscsiInitiatorAdapter, 
                                      (void**)&pVdsAdapter);
        _SafeRelease(pUnknown);
        if (FAILED(hr))
            break;

        VDS_ISCSI_INITIATOR_ADAPTER_PROP prop;
        pVdsAdapter->GetProperties(&prop);

        // for each adapter, get initiator portal property
        IEnumVdsObject *pInitiatorPortals = NULL;
        hr = pVdsAdapter->QueryInitiatorPortals(&pInitiatorPortals);
        _SafeRelease(pVdsAdapter);
        if (FAILED(hr)) {
            if (prop.pwszName) {
                CoTaskMemFree(prop.pwszName);
            }
            continue;
        }

        // for each portal, get portal index and ip address, 
        while (TRUE)
        {
            uFetched = 0;
            IVdsIscsiInitiatorPortal* pPortal = NULL;
            hr = pInitiatorPortals->Next(1, &pUnknown, &uFetched);
            if (FAILED(hr) || S_FALSE == hr) {
                break;
            }

            hr = pUnknown->QueryInterface(
                   IID_IVdsIscsiInitiatorPortal, (void**)&pPortal);
            _SafeRelease(pUnknown);
            if (FAILED(hr))
                break;

            VDS_ISCSI_INITIATOR_PORTAL_PROP portal_prop;
            pPortal->GetProperties(&portal_prop);
            _SafeRelease(pPortal);
            if (prop.pwszName){
                // InitiatorName, should save it for login
            }
            g_Initiator[i].InitiatorPortNumber = 
                                           portal_prop.ulPortIndex;
            WCHAR buf[46];// max ipv6 len
            switch (portal_prop.address.type) {
            case VDS_IPT_IPV4:
                in_addr addr;
                addr.S_un.S_addr = portal_prop.address.ipv4Address;
                wcout << InetNtop(AF_INET, &addr, 
                                  buf, _countof(buf));
                break;
            case VDS_IPT_IPV6:
                in6_addr addr6;
                memcpy(addr6.u.Byte, 
                       portal_prop.address.ipv6Address, 16);
                wcout << InetNtop(AF_INET6, &addr6, 
                                  buf, _countof(buf));
                break;
            case VDS_IPT_TEXT:
                wcout << portal_prop.address.wszTextAddress;
                break;
            default:
                cout << "unknown format";
            }
            cout << endl;
        }
        if (prop.pwszName) {
            CoTaskMemFree(prop.pwszName);
        }
        _SafeRelease(pInitiatorPortals);

        if (FAILED(hr))
            break;
    }

    if (hr == S_FALSE)
        hr = S_OK;

EXIT:
    _SafeRelease(pInitiatorAdapters);
    _SafeRelease(pServiceIscsi);
    _SafeRelease(pServiceInitialization);
    _SafeRelease(pService);
    _SafeRelease(pUnknown);

    CoUninitialize();

    return hr;
}

The End

 

Advertisements
This entry was posted in tech and tagged . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s