//-------------------------------------------------------------------------------------------- // // 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(); }