[Search for users] [Overall Top Noters] [List of all Conferences] [Download this site]

Conference jamin::pathworks32

Title:Digital PATHWORKS 32
Moderator:SPELNK::curless
Created:Fri Nov 01 1996
Last Modified:Fri Jun 06 1997
Last Successful Update:Fri Jun 06 1997
Number of topics:337
Total number of notes:1612

305.0. "Decnet Socket App conversion ??" by ALFSS2::OLSEN_G (Real Men Go Wireless!) Mon May 19 1997 14:44

    Hi,
    
    I have a customer with some questions about converting his app to NT
    4.0 from 3.51 using the PW32 SDK. We have no one here that can answer
    his question. Could someone take a look at his lengthy description
    below and answer his questions?
    
    Thanks,
    
    Gary Olsen
    Atlanta CSC
    --------------------------------------------------
    
    
Subject: Converting a DECNET Socket Application from NT V3.51 to NT V4.0

I have an application that was developed under NT 3.51, Microsoft's C++ V4.1
compiler and Pathworks V4.1B. These applications are running on the Intel 
processor.

We have recently upgraded to NT version 4.0 and the C++ compiler version 5.0.
We also have purchased and upgraded to PATHWORKS 32 (our understanding is that 
this is needed for NT 4.0 support).

All our applications (C++) have upgraded easily from NT 3.51 to NT 4.0 / C++
V4.1 to C++ V5.0 with the exception of the DECNET applications.  When attempting
to compile the applications, several compiler errors are reported.

I have copied over the SDK include directories from the PATHWORKS 32 CD
(directory: \I386\PWSDK\INC32 and \I386\PWSDK\LIB32 ) and included these in my 
INCLUDE path / LIB path for C++.

Our application source file(s) were using a #define of: DNET_USE_WINSOCK to use
the NT WINSOCK format of the socket calls.  In searching the current Pathworks 
32 include files, this define does not seem to be used any longer.

I was using the NT socket calls such as: closesocket(), ioctlsocket() and 
the socket number defined as a data type of: "SOCKET" (per the WIN32 socket 
application programming manual).  

The compiler now complains that these are no longer valid function names.  In 
looking at the PATHWORKS 32 include files, it does not appear these are used 
(the sclose() and sioctl() names are used instead).

For NT socket applications (we also have several that use TCP/IP instead of
DECNET), the programming guide describes a requirement that the WSAStartup() 
must be called prior to using socket calls and the WSACleanup() should be used 
after sockets have been closed.  These functions worked OK under PATHWORKS 
V4.1B.  When including the prgpre.h file from the PW32 SDK, these calls are now
undefined (seems to be caused by your socket.h overriding the MS socket.h file)
 
Also, the WSAGetLastError() function (used to get error info) is also undefined.

I attempted to remove all of the MS WSA calls and convert all socket calls
back to function names (sioctl, sclose, etc) recognized by PATHWORKS 32.  I 
still get link errors becaues the _errorno is undefined.

Our application is object based.  We derive from several base classes that 
are using the standard socket calls and interface (which seem to have problems 
while compiling the DECNET sources).  The derived class has DECNET
specific handling thus to fully convert to the application to use the the
socket naming formats used within the Pathworks 32 CD would need quite a lot of 
re-work to several applications and BASE classes.

I am wondering if we are missing (or need to aquire) a Pathworks 32 CD for 
NT development in order for the applications to be upgraded to NT 4.0 (and C++ 
V5.0).  The include file (prgpre.h) seemed to be NT specific and
the include files I am now using seem to be DOS/WINDOWS (WINDOWS 95) 
specific.

Please advice as to what the best method of converting our applications to 
NT 4.0 using Pathworks.



PS:  While these applications are running under NT 4.0 on the Intel 
platform, we also need to convert our applications running on the DEC Alpha 
platform.  Do you know when the (Microsoft) C++ V5.0 for Alpha will be 
available?

T.RTitleUserPersonal
Name
DateLines
305.1SPELNK::curlessMon May 19 1997 14:5213
First... the customer should be converting over to Winsock 2.0, NOT PWSOCK,
as the include files they were using from PWv4.1b, coupled with the specific
define the do, maps the Winsock function in.

So... some steps:

1) remove the define
2) include WS2DNET.H

Recompile,.

Jeff
305.2exampleSPELNK::curlessMon May 19 1997 14:55911
This is an example of some winsock related code... there are
samples on the SDK.

Jeff

///////////////////////////////////////////////////////////////////////////////
//
//    Copyright (c) 1997
//    by DIGITAL Equipment Corporation, Maynard, Mass.
//    All Rights Reserved.
//
//    This software is furnished under a license and may be used and  copied
//    only  in  accordance  with  the  terms  of  such  license and with the
//    inclusion of the above copyright notice.  This software or  any  other
//    copies  thereof may not be provided or otherwise made available to any
//    other person.  No title to and ownership of  the  software  is  hereby
//    transferred.
//
//    The information in this software is subject to change  without  notice
//    and  should  not  be  construed  as  a commitment by DIGITAL Equipment
//    Corporation.
//
//    DIGITAL assumes no responsibility for the use or  reliability  of  its
//    software on equipment which is not supplied by DIGITAL.
//
//    Author:	Jeff Curless
//    File:	    DECnet.cpp
//    Date:	    9703.29
//
///////////////////////////////////////////////////////////////////////////////

#include "common.h"
#include "decnet.h"
#include "ws2dnet.h"

///////////////////////////////////////////////////////////////////////////////
//
// Force the linker to add the proper library for this module
// 
///////////////////////////////////////////////////////////////////////////////

#pragma comment(lib,"wsock32.lib")

typedef LPNODEENTF (GETNODEBYNAME)(char *Node);
typedef GETNODEBYNAME * LPMYGETNODEBYNAME;

///////////////////////////////////////////////////////////////////////////////
//
//  CDECnetConn    - Constructor
//
//  Constructor for the socket object.  This constructor does not have much
//  to do, other than initialize fields.
//
//  Warning: This constructor allocates memory, this is not normally 
//  acceptable, however if the allocation fails, nothing else will work so
//  it might be okay.  The WSADATA structure is allocated here, instead of
//  a static alloc as part of the object, so that the required includes for
//  this object do NOT REQUIRE the WinSock.h socket library include file, 
//  which will conflict with the DECnet one.
//
///////////////////////////////////////////////////////////////////////////////

CDECnetConn::CDECnetConn()
{
    m_ulReference  = 1;
    m_bInitialized = FALSE;

    //
    // No connection yet, initialize socket to an invalid value
    //
    m_sSocket   = INVALID_SOCKET;
    m_sSktError = 0;

    //
    // Haven't connected yet
    //
    m_bConnected = FALSE;

    //
    // Setup other members
    //
    m_lpszNode     = NULL;
    m_lpszUsername = NULL;
    m_lpszPassword = NULL;

    //
    // Clear all counters and such
    //
    memset( &m_Status, '\0', sizeof(STATUSREC));
    m_Status.Size = sizeof(STATUSREC);

    //
    // Initialize critical section
    //
    InitializeCriticalSection(&m_CS);

    //
    // Make sure that the Windows Socket interface is started.  Currently we will
    // reqeust version 1.1, however this needs to be looked at so that we request
    // a minimum of 1.1, but will use newer versions.  If the allocation of the
    // wsa data failes, then we will not initialize, and TCP/IP will not be
    // functional at this time.
    //
    m_wsaData = new unsigned char [sizeof(WSADATA)];
    if( m_wsaData != NULL ){
        m_wVersionRequested = MAKEWORD(1, 1);
        WSAStartup(m_wVersionRequested, (WSADATA *)m_wsaData);
        }

}

///////////////////////////////////////////////////////////////////////////////
//
//  ~CDECnetConn   - Destructor
//
//  Destructor for the socket object.  If the connection is still established,
//  make sure the connection is torn down.
//
///////////////////////////////////////////////////////////////////////////////

CDECnetConn::~CDECnetConn()
{
    //
    // If the socket was used, and appears to be connected, disconnect it.
    // The socket is always -1 if not connected so...
    //
    if( m_sSocket != -1 ){
        Disconnect();
        }

    //
    // Now, for all the other resources, nuke 'em
    //
    if( m_lpszNode    != NULL ) delete m_lpszNode;
    if( m_lpszUsername!= NULL ) delete m_lpszUsername;
    if( m_lpszPassword!= NULL ) delete m_lpszPassword;

    //
    // Release critical section
    //
    DeleteCriticalSection(&m_CS);

    //
    // Shutdown the Windows Socket interface, or at least the interface
    // we requested
    //
    WSACleanup();

    //
    // Release the memory associated with the Windows Socket interface
    //
    if( m_wsaData != NULL )
        delete m_wsaData;
}

///////////////////////////////////////////////////////////////////////////////
//
//  IUnknown Interface...
//
//  The IUnknown Interface provides object management functions from the OLE2
//  component object model.  The primary purpose of this interface is to keep
//  track of references to objects.  Since all extension objects inherit from
//  this interface, all extension interfaces include the three IUnknown methods
//  in addition to their own methods.
//
//  QueryInterface  (IUnknown Interface)
//  
//  Returns a pointer in lppUnk to the interface riid on the object.
//
//  Parameters:
//      lpiid       - Input parameter Interface reference identifier
//      lppUnk      - Output Parameter, pointing to an interface specified by
//                    lpiid if available.
//
//  Return Values:
//      E_NOINTERFACE   - The interface is not supported by the object
//      E_INVALIDARG    - An argument is invalid.
//
///////////////////////////////////////////////////////////////////////////////

STDMETHODIMP
CDECnetConn::QueryInterface( REFIID riid, LPVOID FAR *ppvObj)
{
    SCODE   hResult;
    LPVOID  pObject;

    //
    // Verify that we can return the pointer to an object
    //
    if( ppvObj == NULL ){
        hResult = E_NOINTERFACE;
        }
    
    //
    // Setup for Success, and clear out the Pointer to the object
    // pointer.  This will prevent any and all false access to an
    // object.
    //
    *ppvObj = NULL;
    hResult = S_OK;
    pObject = NULL;

    if( IsEqualIID(riid, IID_IUnknown) ){
        //
        // IUNKNOWN type must be of the root exchange extension object
        //
        pObject = (LPVOID)this;
        }
    else if( IsEqualIID(riid, IID_IPWConnect) ){
        pObject = (LPVOID)this;
        }
    else{
        //
        // Anything, and everything else is not supported.
        //
        hResult = E_NOINTERFACE;
        }

    //
    //  if we made some sort of assignment, return the pointer.  Also,
    //  since someone is referencing this item (again) generate an additional
    //  reference.
    //
    if( pObject != NULL ){
        *ppvObj = pObject;
        ((LPUNKNOWN)*ppvObj)->AddRef();
        }

    return hResult;
}

///////////////////////////////////////////////////////////////////////////////
//
//  AddRef  (IUnknown Interface)
//
//  Increments the reference count of an object
//
//  Comments:
//  
//  This method increments the reference count of an object and is typically
//  used when a copy will be made if the interface pointer.
//
///////////////////////////////////////////////////////////////////////////////

STDMETHODIMP_(ULONG)
CDECnetConn::AddRef()
{
    m_ulReference++;
    return m_ulReference;
}

///////////////////////////////////////////////////////////////////////////////
//
//  Release (IUnknown Interface)
//
//  Closes an object and decrements the reference count.
//
//  Comments:
//
//  This method decrements the reference count of an object and is typically
//  used when the interface pointer is no longer needed.  When the reference
//  count reaches zero, the object should free itself.
//
///////////////////////////////////////////////////////////////////////////////

STDMETHODIMP_(ULONG)
CDECnetConn::Release()
{
    m_ulReference--;

    if( m_ulReference <= 0 ){
        //
        // Reference count is down, nuke the object bunky!
        //
        delete this;
        return  0;
        }

    //
    // Tell the folks at home how many references are left
    //
    return m_ulReference;
}

///////////////////////////////////////////////////////////////////////////////
//
//  Connect
//
//  This function performs a connection to an object over TCP/IP.
//
//  Parameters:
//      lpszNode        - The name of the remote node to connect to
//      lpszUser        - The username to use to establish the connection
//      lpszPassword    - The password to use when establishing the connection
//
//  Returns:
//      TRUE            - The connection was made
//      FALSE           - No connection was made
//
//
///////////////////////////////////////////////////////////////////////////////

STDMETHODIMP_(BOOL)
CDECnetConn::Connect(const char *lpszNode,
                     const char *lpszUser,
                     const char *lpszPassword)
{
    //
    // Validate Parameters
    //
    if( (lpszNode == NULL) || (lpszUser == NULL) ||(lpszPassword == NULL) ){
        return FALSE;
        }

    //
    // Verify that no connection has been established, just in case
    // as we do not want to have extra sockets lingering around
    // 
    if( m_sSocket != -1 ){
        Disconnect();
        m_sSocket = INVALID_SOCKET;
        }

    //
    // Copy the connect info
    // 
    SafeStrDup( &m_lpszNode, lpszNode );
    SafeStrDup( &m_lpszUsername, lpszUser);
    SafeStrDup( &m_lpszPassword, lpszPassword );
    //
    // Go make the connection
    //
    m_sSktError = 0;
    if( !DoConnect( m_lpszNode, m_lpszUsername, m_lpszPassword ) ){
        return FALSE;
        }

    m_bConnected = TRUE;
      
    return TRUE;
}


///////////////////////////////////////////////////////////////////////////////
//
//  Reconnect
//
//  This function handles a reconnect to the remote node.  This function relies
//  on a previously established connection having been made.
//
//  Parameters:
//      None
//
//  Returns:
//      TRUE        - Reconnection worked
//      FALSE       - Could not reconnect
//
//  This function relies on the m_bConnected Flag to determine if a connection
//  has been made.  If a connection has been made, it is assumed that the
//  m_lpszConnect string is still valid.
//
///////////////////////////////////////////////////////////////////////////////

STDMETHODIMP_(BOOL)
CDECnetConn::Reconnect(void)
{
    DebugMessage(("CDECnetConn::Reconnect requested"));
    //
    // Does/Did a connection exist?
    //
    if( !m_bConnected ) return FALSE;
    
    //
    // Keep track of the reconnects
    //
    m_Status.Reconnects++;

    //
    // Is there an outstanding connection that needs to be closed off?  This
    // might be the case if one of the read/write functions reported and error
    // on the socket, and no one cleaned it up yet.
    // 
    if( m_sSocket != -1 ){
        Disconnect();
        }

    //
    // Socket was cleaned up, attemp reconnect now
    //
    m_sSktError = 0;
    if( DoConnect( m_lpszNode, m_lpszUsername, m_lpszPassword ) ){
        return TRUE;
        }
    return FALSE;
}

///////////////////////////////////////////////////////////////////////////////
//
//  Disconnect
//
//  This function is responsible for disconnecting the current connection,
//  if there is one.  House keeping is performed, and the member variable
//  Socket is set to -1 (an invalid socket number).
//
//  Parameters
//      None
//
//  Returns
//      TRUE     - if the connection was shutdown
//      FALSE    - if the connection was not shutdown properly.
//
///////////////////////////////////////////////////////////////////////////////

STDMETHODIMP_(BOOL)
CDECnetConn::Disconnect(void)
{
    BOOL  Result;

    Result = TRUE;
    if( m_sSocket != -1 ){
        //
        // Have a socket, close it down.  If the close fails, the socket
        // is really closed, but it might have ALREADY been closed, report
        // the error to the caller anyway.
        //
        // 2 - means disable sends & receives.
        //
        if( shutdown( m_sSocket, 2 ) ){
            m_sSktError = WSAGetLastError();
            Result = FALSE;
            }
        //
        // Close the socket, this will free resources allocated to it.
        //
        if( closesocket( m_sSocket ) ){
            m_sSktError = WSAGetLastError();
            Result = FALSE;
            }
        m_sSocket = INVALID_SOCKET;
        }

    return Result;
}

///////////////////////////////////////////////////////////////////////////////
//
//  Status
//
//  This routine handles obtaining the status of transport, and connection.
//
//  Parameters:
//      iStatusFlag     - Used to determine the type of status to return,
//                        supported flags are:
//                        CONNECTION_STATUS - reports on connection status
//                        INSTALL_STATUS    - reports on transport availability
//                        TRANSPORT_STATUS  - Reports the last trasnport error
//  Returns:
//      iStatusFlag == INSTALL_STATUS
//          IS_TRANSPORT_AVAILABLE - Transport is available on workstation
//          IS_TRANSPORT_NOAVAIL   - Transport is not available
//
//      iStatusFlag == CONNECTION_STATUS
//          CS_CONNECTED           - Connection is up, and working
//          CS_NOTCONNECTED        - Connection is not up
//          CS_DISCONNECTED        - Connection was up, but somehow it was
//                                   terminated.
//
//      iStatusFlag == TRANSPORT_STATUS
//
//  STATUS_INVALIDFLAG  - iStatusFlag value is not supported.
//
///////////////////////////////////////////////////////////////////////////////

STDMETHODIMP_(long) 
CDECnetConn::Status(int iStatusFlag)
{
    long Result;
    unsigned long Length;

    switch( iStatusFlag ){
        case CONNECTION_STATUS:
            if( m_bConnected ){
                if( m_sSocket == -1 ){
                    Result = CS_DISCONNECTED;
                    }
                else if( ioctlsocket( m_sSocket, FIONREAD, &Length ) ){
                    m_sSktError = WSAGetLastError();
                    Result = CS_DISCONNECTED;
                    }
                else if( m_sSktError != 0 ){
                    Result = CS_ERRORSTATE;
                    m_sSktError = 0;
                    }
                else{
                    Result = CS_CONNECTED;
                    }
                }
            else{
                Result = CS_NOTCONNECTED;
                }
            break;
        case INSTALL_STATUS:
            //
            // Perform an Install Check for TCP/IP.
            //
            if( Installed() ){
                Result = IS_TRANSPORT_AVAILABLE;
                }
            else{
                Result = IS_TRANSPORT_NOTAVAIL;
                } 
            break;
        case TRANSPORT_STATUS:
            Result = GenTransError(AF_INET,m_sSktError);
            break;
        default:
            Result = STATUS_INVALIDFLAG;
            break;
        }
    return Result;
}


///////////////////////////////////////////////////////////////////////////////
//
//  Read
//
//  Read data from the socket.  The buffer supplied is filled with information
//  up to the length requested.  The actual amount of data read is returned, if
//  there is an error, a value less than zero is returned.
//
//  Parameters
//      lpBuffer        - Pointer to a buffer of information to read in
//      Length          - Length of buffer supplied in bytes
//
//  Returns:
//      Number of bytes received, or 0 if the other end terminiated.  Less
//      than zero if an error occurred.
//
///////////////////////////////////////////////////////////////////////////////

STDMETHODIMP_(long)
CDECnetConn::Read(unsigned char *lpBuffer, long Length)
{
    int Result;
    
    //
    // Validate parameters, if invalid, pretend that the socket
    // was disconnected at the remote end
    //
    if( lpBuffer == NULL ){
        return 0;
        }
        
    //
    // Obtain the data waiting on this socket
    //
    Result = recv( m_sSocket, (char *)lpBuffer, Length, 0 );
    if( Result <= 0 ){
        m_sSktError = WSAGetLastError();
        }

    //
    // Update counters
    //
    m_Status.BytesRead += Result;
    return Result;
}

///////////////////////////////////////////////////////////////////////////////
//
//  ReadAll
//
//
//  Parameters
//      lpBuffer        - Pointer to a buffer of information to read in
//      Length          - Length of buffer supplied in bytes
//
//  Returns:
//      Number of bytes received, or 0 if the other end terminiated.  Less
//      than zero if an error occurred.
//
///////////////////////////////////////////////////////////////////////////////

STDMETHODIMP_(long)
CDECnetConn::ReadAll(unsigned char *lpBuffer, long Length)
{
    int   Result;
    char *lpData;
    long  ulSize;

    //
    // Validate parameters, if invalid, pretend that the socket
    // was disconnected at the remote end
    //
    if( lpBuffer == NULL ){
        return -1;
        }
    
    lpData = (char *)lpBuffer;
    ulSize = Length;
    while( ulSize != 0 ){
        Result = recv( m_sSocket, lpData, ulSize, 0 );
        if( Result <= 0 ){
            m_sSktError = WSAGetLastError();
            return Result;
            }
        lpData             += Result;
        m_Status.BytesRead += Result;
        ulSize             -= Result;
        }

    return Length;
}

///////////////////////////////////////////////////////////////////////////////
//
//  Write
//
//  Write data to the socket.  The length of the buffer is passed in, and on
//  a successful write, the value returned from this function is the amount
//  of data actually written to the socket.
//
//  Parameters:
//      lpBuffer        - Buffer containing the data to be written
//      Length          - count of the number of bytes to write
//
//  Returns:
//      The number of bytes actually written, or a value less than 0 if
//      there is a problem with the write.
//  
//
///////////////////////////////////////////////////////////////////////////////

STDMETHODIMP_(long)
CDECnetConn::Write(const unsigned char *lpBuffer, long Length)
{
    int Result;
    
    //
    // Validate parameters, if NULL, report we sent zero bytes
    //
    if( lpBuffer == NULL )
        return 0;

    //
    // Write the data to the socket, report any problems reported by
    // the protocol stack.
    // 
    Result = send( m_sSocket, (const char *)lpBuffer, Length, 0 );
    if( (Result < 0) || (Result == SOCKET_ERROR) ){
        m_sSktError = WSAGetLastError();
        Result = 0;
        }

    //
    // Update counters
    //
    m_Status.BytesWritten += Result;

    return Result;
}

///////////////////////////////////////////////////////////////////////////////
//
//  GetNodeAddress
//
//  This routine obtains the address of a node, given the name.  Note that this
//  is done by calling into the DNETW dll, this is not a thread safe routine, so
//  we need to wrap it by one.
//
//  Parameters
//      lpcNode     - Pointer to a node name
//      Address     - pointer to the location used for storing the 16bit
//                    DECnet address of the remote node
//
//  Returns:
//      TRUE        - Address was obtained
//      FALSE       - Address could not be found
//
//  Remarks:
//      This routine MUST have a critical section, because it is not thread
//      save otherwise.
//
///////////////////////////////////////////////////////////////////////////////

BOOL
GetNodeAddress(const char *lpcNode,unsigned short *Address)
{
    HMODULE           hDNetw=NULL;
    LPMYGETNODEBYNAME lpgetnodebyname=NULL;
	LPNODEENTF        lpnodeentf=NULL;
    BOOL              bResult;


    bResult = FALSE;
    Begin
        //
        // Attempt to load the DLL
        //
        hDNetw = LoadLibrary( "DNETW.DLL" );
        ThrowError( hDNetw == NULL );

        //
        // Have DNETW, so... now get a reference to the getnodebyname function
        //
        lpgetnodebyname = (LPMYGETNODEBYNAME)GetProcAddress( hDNetw, "getnodebyname" );
        ThrowError( lpgetnodebyname == NULL );

        //
        // Get the node address by using the name
        //
        lpnodeentf = lpgetnodebyname((char *)lpcNode);
        ThrowError( lpnodeentf == NULL );

        // 
        // Have a valid node entity structure, so ... we can now use it!
        // this will only work for Phase IV addresses, not extended addresses
        //
        *Address = *((unsigned short *)lpnodeentf->n_addr);
        bResult = TRUE;
    End
        
    if( hDNetw != NULL ){
        FreeLibrary( hDNetw );
        }

    return bResult;
}

///////////////////////////////////////////////////////////////////////////////
//
//  DoConnect
//
//  This routine creates a socket, makes the connection, then performs the 
//  communications needed to get the rexecd daemon up and running, and have
//  it spawn the requested component.
//
//  Parameters
//      lpszNode        - Node name to connect to
//      lpszUserName    - username
//      lpszPassword    - password
//
//  Returns:
//      TRUE            - The connection was made
//      FALSE           - No connection made, m_sSktError contains the
//                        failure reason
//
///////////////////////////////////////////////////////////////////////////////

BOOL
CDECnetConn::DoConnect(const char *lpszNode,
                       const char *lpszUsername,
                       const char *lpszPassword)
{
    SOCKADDRDN      sdn;
    BOOL            bResult;
    int             iResult;
    ACCESSDATADN    accessdata;

//
// Doing something that should NEVER be done... however, the only way to get
// DSO_CONACCESS is to include DN.H, and that will break my winsock includes
//
#define DSO_CONACCESS	3			/* set/get connect access data */

    //
    // Have several things to do, and all of them require cleanup if there
    // is a failure, so use a do-while loop, break if failure.  Cheap way
    // to do a try/catch mechanism.
    //
    m_sSktError = 0;
    m_sSocket   = INVALID_SOCKET;
    bResult     = FALSE;
    Begin
        //
        // Generate a socket, if unable to terminate with an error
        //
        m_sSocket = socket( AF_DECnet, SOCK_STREAM, DNPROTO_NSP );
        ThrowSocketError( m_sSocket == INVALID_SOCKET, m_sSktError );

        //
        // Have a socket, setup the required options with setsockopt
        //
        memset( &accessdata, '\0', sizeof(ACCESSDATADN));
        accessdata.acc_passl = SafeStrLen(lpszPassword);
        accessdata.acc_userl = SafeStrLen(lpszUsername);
        if( lpszPassword != NULL ){
            strncpy((char *)&accessdata.acc_pass[0],lpszPassword,DN_MAXACCL);
            }
        if( lpszUsername != NULL ){
            strncpy((char *)&accessdata.acc_user[0],lpszUsername,DN_MAXACCL);
            }

        iResult = setsockopt(m_sSocket,
                             DNPROTO_NSP,
                             DSO_CONACCESS,
                             (const char *)&accessdata,
                             sizeof(ACCESSDATADN));
        ThrowError( iResult != 0 );

        //
        // Fill in the SOCKADDRDN structure with the information we know about
        // the remote node.  The address was obtained above, the object number
        // is 0, as we want to launch a named service (PCSA$MAIL).
        //
        memset(&sdn,'\0',sizeof(SOCKADDRDN));
        sdn.sdn_family    = AF_DECnet;
        sdn.sdn_flags     = 0;
        sdn.sdn_objnum    = 0;
        sdn.sdn_objnamel  = 9;
        memcpy( sdn.sdn_objname, "PCSA$MAIL",sdn.sdn_objnamel);

        //
        // Perform a lookup of the DECnet node address from the
        // name requested.  This might take some time if the node
        // lookup is busted..
        //
	    sdn.sdn_nodeaddrl = sizeof(unsigned short);
        bResult = GetNodeAddress( lpszNode, (unsigned short*)&sdn.sdn_nodeaddr);
        ThrowError(bResult != TRUE);
        //
        // Have the Socket, and have the address setup, so make the
        // connection.
        //
        if( connect( m_sSocket, (const SOCKADDR *)&sdn, sizeof(SOCKADDRDN)) ){
            m_sSktError = WSAGetLastError();
            bResult = FALSE;
            break;
            }

        bResult = TRUE;
    End

    //
    // Perform cleanup if there was a socket error
    //
    if( !bResult || m_sSktError != 0 ){
        if( m_sSocket != -1 ){
            closesocket( m_sSocket );
            m_sSocket = INVALID_SOCKET;
            }
        bResult = FALSE;
        }

    return bResult;
}

///////////////////////////////////////////////////////////////////////////////
//
//  Installed
//
//  This function performs an install check on the DECnet stack.  They only
//  way I could figure out how to do this was to generate a socket for the
//  family type required, and see if it worked.
//
//  Returns:
//      TRUE    - DECnet is installed
//      FALSE   - DECnet is not installed
//
///////////////////////////////////////////////////////////////////////////////

BOOL
CDECnetConn::Installed( void )
{
    SOCKET Temp;
    
    Temp = socket( AF_DECnet, SOCK_STREAM, DNPROTO_NSP);
    if( INVALID_SOCKET == Temp ){
        return FALSE;
        }
    else{
        closesocket( Temp );
        return TRUE;
        }       
}

///////////////////////////////////////////////////////////////////////////////
//
//  Counters
//
//  This routine returns the counters for this transport... those that make
//  sense that is... the number of transport switches is unknown at this level
//
//  Parameters
//
//  Returns
//
//  Remarks:
//
///////////////////////////////////////////////////////////////////////////////

STDMETHODIMP_(long)
CDECnetConn::Counters( LPSTATUSREC lpCounters )
{
    //
    // Validate parameters
    //
    if( (lpCounters == NULL) || (lpCounters->Size < sizeof(STATUSREC)) ){
        return PWC_INVALIDPARAM;
        }

    //
    // Transfer the counters into the location requested...
    // make sure we transfer the size of OUR record, not the size of
    // their record if it is larger
    //
    memcpy(lpCounters, &m_Status, sizeof(STATUSREC));

    return PWC_SUCCESS;    
}
305.3THANKS!ALFSS2::OLSEN_GReal Men Go Wireless!Mon May 19 1997 16:351
    
305.4Follow up Question...ALFSS2::OLSEN_GReal Men Go Wireless!Thu May 22 1997 15:4134
    
    
    
    
    
    Jeff,
    
    My customer has a follow up question. If you could address it, I would
    appreciate it.
    
    - Gary
    --------------------------------------------------------------------
     Using your examples to rework the code, I now have the following
    question..?
    
    scenario:
    
    I initiate the connection from the NT Digital Pathworks 32 machine, and
    receive a connection successful.  When I see the connect on the Pathworks
    DOS/WINDOWS 4.1 machine (it does connect) this machine locks up right away.
    
    Any ideas on an incompatibilty between these two versions..? Or any
    other ideas...?
    
    (We could only get the connect to work in "locking mode" and that is
    when this lockup of the dos/win pathworks system occurs).
    
    
    The originator is using the connect and the receiver is using an
    accept. The server accepts the connect but seems to lock up when it tries to
    send the next message.  Is there any decnet incompatibility between these 
    decnet versions, if not we'll look at the apps.
    
    
305.5Upgrade time?SPELNK::curlessThu May 22 1997 19:0512
Odd... sounds like a bug in PATHWORKS v4.0 DOS/Windows... there were several
dealing with DECnet (remember, that was the "old" DECnet, not the new DECnet
generated for PATHWORKS v5.0 and beyond).

If connections work to other nodes, and NOT v4.0 it must be a problem with
how v4.0 is expecting data to be received (there were several in this
area).

Can the customer upgrade the DOS/Windows clients?

Jeff
305.6NT - not DOS/WindowsALFSS2::OLSEN_GReal Men Go Wireless!Tue May 27 1997 15:388
    Jeff,
    
    This is PW/WNT 4.1b to Path32 and NT 3.51 to 4.0 - NOT pw dos/windows
    v4 to v5.
    
    Any other ideas - will this work?
    
    Gary
305.7Well, it does say DOS/WindowsSPELNK::curlessWed May 28 1997 12:1622
>     --------------------------------------------------------------------
>      Using your examples to rework the code, I now have the following
>     question..?
>     
>     scenario:
>     
>     I initiate the connection from the NT Digital Pathworks 32 machine, and
>     receive a connection successful.  When I see the connect on the Pathworks
>     DOS/WINDOWS 4.1 machine (it does connect) this machine locks up right
>     away.

Okay, I'm confused... where does it state NT v3.51/V4.0...

Please restate the problem with proper versions of:

1)  Something that works
2)  Something that does not work.

Thanks

Jeff

305.8oops!ALFSS2::OLSEN_GReal Men Go Wireless!Thu May 29 1997 11:3613
    Jeff,
    
    Sorry for the confusion - this is a DSNLINK call so it's hard to get it
    all together. The server with the app is NT 3.51 going to 4.0. The clients
    seem to be dos/win and pathworks 4.1.  Was working ok on 3.51 but when
    porting the app to 4.0 and pw/32, the 4.1 clients are having the
    problem.
    
    I will talk to her about upgrading the clients and see what happens.
    
    Thanks,
    
    Gary