You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
363 lines
7.5 KiB
363 lines
7.5 KiB
//--------------------------------------------------------------------------------------------
|
|
//
|
|
// Copyright (c) Microsoft Corporation, 1996
|
|
//
|
|
// Description:
|
|
//
|
|
// Microsoft Internet LDAP Client
|
|
//
|
|
//
|
|
// Authors:
|
|
//
|
|
// Umesh Madan
|
|
// Robert Carney 4/17/96 Created from ChatSock library.
|
|
// davidsan 04-25-96 hacked into tiny bits for my own devious purposes
|
|
//
|
|
//--------------------------------------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------------------------------------
|
|
//
|
|
// INCLUDES
|
|
//
|
|
//--------------------------------------------------------------------------------------------
|
|
#include "ldappch.h"
|
|
|
|
//--------------------------------------------------------------------------------------------
|
|
//
|
|
// PROTOTYPES
|
|
//
|
|
//--------------------------------------------------------------------------------------------
|
|
DWORD __stdcall DwReadThread(PVOID pvData);
|
|
|
|
//--------------------------------------------------------------------------------------------
|
|
//
|
|
// GLOBALS
|
|
//
|
|
//--------------------------------------------------------------------------------------------
|
|
BOOL g_fInitedWinsock = FALSE;
|
|
|
|
//--------------------------------------------------------------------------------------------
|
|
//
|
|
// FUNCTIONS
|
|
//
|
|
//--------------------------------------------------------------------------------------------
|
|
BOOL FInitSocketDLL()
|
|
{
|
|
WORD wVer;
|
|
WSADATA wsaData;
|
|
int err;
|
|
|
|
wVer = MAKEWORD(1, 1); // use Winsock 1.1
|
|
if (WSAStartup(wVer, &wsaData))
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void FreeSocketDLL()
|
|
{
|
|
WSACleanup();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------
|
|
//
|
|
// CLASSES
|
|
//
|
|
//--------------------------------------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------------------------------------
|
|
//
|
|
// CLdapWinsock
|
|
//
|
|
// Wrapper that implements a socket based connection.
|
|
//
|
|
//--------------------------------------------------------------------------------------------
|
|
|
|
CLdapWinsock::CLdapWinsock()
|
|
{
|
|
m_sc = INVALID_SOCKET;
|
|
m_pfnReceive = NULL;
|
|
m_pvCookie = NULL;
|
|
m_pbBuf = NULL;
|
|
m_cbBuf = 0;
|
|
m_cbBufMax = 0;
|
|
m_fConnected = FALSE;
|
|
m_hthread = NULL;
|
|
|
|
InitializeCriticalSection(&m_cs);
|
|
}
|
|
|
|
CLdapWinsock::~CLdapWinsock(void)
|
|
{
|
|
if (m_pbBuf)
|
|
delete [] m_pbBuf;
|
|
DeleteCriticalSection(&m_cs);
|
|
}
|
|
|
|
//
|
|
// Open a connection the named server, and connect to the port 'usPort' (host byte order)
|
|
// Can block
|
|
//
|
|
STDMETHODIMP
|
|
CLdapWinsock::HrConnect(PFNRECEIVEDATA pfnReceive, PVOID pvCookie, CHAR *szServer, USHORT usPort)
|
|
{
|
|
SOCKADDR_IN sin;
|
|
struct hostent *phe;
|
|
HRESULT hr;
|
|
|
|
if (!pfnReceive || !szServer || !usPort)
|
|
return E_INVALIDARG;
|
|
|
|
Assert(!m_pbBuf);
|
|
if (!m_pbBuf)
|
|
{
|
|
m_cbBufMax = CBBUFFERGROW;
|
|
m_pbBuf = new BYTE[m_cbBufMax];
|
|
m_cbBuf = 0;
|
|
if (!m_pbBuf)
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
FillMemory(&sin, 0, sizeof(sin));
|
|
sin.sin_family = AF_INET;
|
|
sin.sin_port = htons(usPort);
|
|
|
|
if (szServer[0] >= '1' && szServer[0] <= '9')
|
|
{
|
|
sin.sin_addr.s_addr = inet_addr(szServer);
|
|
if (sin.sin_addr.s_addr == INADDR_NONE)
|
|
{
|
|
delete [] m_pbBuf;
|
|
m_pbBuf = NULL;
|
|
return LDAP_E_HOSTNOTFOUND;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
phe = gethostbyname(szServer);
|
|
if (!phe)
|
|
{
|
|
delete [] m_pbBuf;
|
|
m_pbBuf = NULL;
|
|
return LDAP_E_HOSTNOTFOUND;
|
|
}
|
|
CopyMemory(&sin.sin_addr, phe->h_addr, phe->h_length);
|
|
}
|
|
|
|
::EnterCriticalSection(&m_cs);
|
|
if (m_fConnected)
|
|
this->HrDisconnect();
|
|
|
|
m_sc = socket(PF_INET, SOCK_STREAM, 0);
|
|
if (m_sc < 0)
|
|
{
|
|
delete [] m_pbBuf;
|
|
m_pbBuf = NULL;
|
|
::LeaveCriticalSection(&m_cs);
|
|
return LDAP_E_INVALIDSOCKET;
|
|
}
|
|
if (connect(m_sc, (struct sockaddr *)&sin, sizeof(sin)) < 0)
|
|
{
|
|
delete [] m_pbBuf;
|
|
m_pbBuf = NULL;
|
|
::LeaveCriticalSection(&m_cs);
|
|
return LDAP_E_CANTCONNECT;
|
|
}
|
|
|
|
hr = this->HrCreateReadThread();
|
|
if (SUCCEEDED(hr))
|
|
m_fConnected = TRUE;
|
|
else
|
|
{
|
|
delete [] m_pbBuf;
|
|
m_pbBuf = NULL;
|
|
}
|
|
::LeaveCriticalSection(&m_cs);
|
|
m_pfnReceive = pfnReceive;
|
|
m_pvCookie = pvCookie;
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CLdapWinsock::HrDisconnect()
|
|
{
|
|
HRESULT hr = NOERROR;
|
|
|
|
if (!m_fConnected)
|
|
return NOERROR;
|
|
|
|
::EnterCriticalSection(&m_cs);
|
|
m_fConnected = FALSE;
|
|
closesocket(m_sc);
|
|
::LeaveCriticalSection(&m_cs);
|
|
|
|
WaitForSingleObject(m_hthread, INFINITE);
|
|
|
|
::EnterCriticalSection(&m_cs);
|
|
delete [] m_pbBuf;
|
|
m_cbBuf = 0;
|
|
m_cbBufMax = 0;
|
|
m_pbBuf = NULL;
|
|
::LeaveCriticalSection(&m_cs);
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
CLdapWinsock::HrCreateReadThread()
|
|
{
|
|
HRESULT hr = NOERROR;
|
|
|
|
::EnterCriticalSection(&m_cs);
|
|
|
|
m_hthread = ::CreateThread(
|
|
NULL,
|
|
0,
|
|
::DwReadThread,
|
|
(LPVOID)this,
|
|
0,
|
|
&m_dwTid
|
|
);
|
|
if (!m_hthread)
|
|
hr = E_OUTOFMEMORY;
|
|
::LeaveCriticalSection(&m_cs);
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Write pvData out to the current socket/connection.
|
|
// can block
|
|
//
|
|
HRESULT
|
|
CLdapWinsock::HrSend(PVOID pv, int cb)
|
|
{
|
|
HRESULT hr = NOERROR;
|
|
|
|
if (!pv || cb <= 0)
|
|
return E_INVALIDARG;
|
|
|
|
if (send(m_sc, (const char *)pv, cb, 0) == SOCKET_ERROR)
|
|
hr = this->HrLastWinsockError();
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
CLdapWinsock::HrGrowBuffer()
|
|
{
|
|
BYTE *pb;
|
|
Assert(m_cbBufMax == m_cbBuf);
|
|
|
|
pb = new BYTE[m_cbBufMax + CBBUFFERGROW];
|
|
if (!pb)
|
|
return E_OUTOFMEMORY;
|
|
CopyMemory(pb, m_pbBuf, m_cbBuf);
|
|
delete [] m_pbBuf;
|
|
m_pbBuf = pb;
|
|
m_cbBufMax += CBBUFFERGROW;
|
|
return NOERROR;
|
|
}
|
|
|
|
void
|
|
CLdapWinsock::Receive(PVOID pv, int cb, int *pcbReceived)
|
|
{
|
|
if (m_pfnReceive)
|
|
m_pfnReceive(m_pvCookie, pv, cb, pcbReceived);
|
|
}
|
|
|
|
//$ TODO: Find a way to pass memory errors back to the API
|
|
DWORD
|
|
CLdapWinsock::DwReadThread()
|
|
{
|
|
int cbRead;
|
|
int cbLeft;
|
|
int cbReceived;
|
|
|
|
while (1)
|
|
{
|
|
// at the beginning of this loop: any unprocessed data is in m_pbBuf[0..m_cbBuf].
|
|
Assert(m_cbBuf <= m_cbBufMax);
|
|
if (m_cbBuf == m_cbBufMax)
|
|
{
|
|
if (FAILED(this->HrGrowBuffer()))
|
|
return 0xFFFFFFFF;
|
|
}
|
|
cbLeft = m_cbBufMax - m_cbBuf;
|
|
|
|
cbRead = recv(m_sc, (LPSTR)&(m_pbBuf[m_cbBuf]), cbLeft, 0);
|
|
if (cbRead == 0 || cbRead == SOCKET_ERROR)
|
|
return 0;
|
|
|
|
// note: i don't know why this is happening, but it is...
|
|
if (cbRead < 0)
|
|
return 0;
|
|
|
|
m_cbBuf += cbRead;
|
|
do
|
|
{
|
|
this->Receive(m_pbBuf, m_cbBuf, &cbReceived);
|
|
if (cbReceived)
|
|
{
|
|
m_cbBuf -= cbReceived;
|
|
CopyMemory(m_pbBuf, &m_pbBuf[cbReceived], m_cbBuf);
|
|
}
|
|
}
|
|
while (cbReceived && m_cbBuf);
|
|
}
|
|
}
|
|
|
|
HRESULT
|
|
CLdapWinsock::HrIsConnected(void)
|
|
{
|
|
return m_fConnected ? NOERROR : S_FALSE;
|
|
}
|
|
|
|
//$ TODO: Are there other errors that i need to handle here?
|
|
HRESULT
|
|
CLdapWinsock::HrLastWinsockError()
|
|
{
|
|
int idErr;
|
|
HRESULT hr = E_FAIL;
|
|
|
|
idErr = WSAGetLastError();
|
|
switch (idErr)
|
|
{
|
|
default:
|
|
break;
|
|
|
|
case WSANOTINITIALISED:
|
|
AssertSz(0,"socket not initialized!");
|
|
hr = E_FAIL;
|
|
break;
|
|
|
|
case WSAENETDOWN:
|
|
hr = LDAP_E_NETWORKDOWN;
|
|
break;
|
|
|
|
case WSAENETRESET:
|
|
hr = LDAP_E_LOSTCONNECTION;
|
|
break;
|
|
|
|
case WSAENOTCONN:
|
|
AssertSz(0,"Not connected!");
|
|
hr = E_FAIL;
|
|
break;
|
|
|
|
case WSAESHUTDOWN:
|
|
hr = LDAP_E_SOCKETCLOSED;
|
|
break;
|
|
|
|
case WSAECONNRESET:
|
|
hr = LDAP_E_HOSTDROPPED;
|
|
break;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
DWORD __stdcall DwReadThread(PVOID pvData)
|
|
{
|
|
PSOCK psock = (PSOCK)pvData;
|
|
|
|
Assert(pvData);
|
|
|
|
return psock->DwReadThread();
|
|
}
|