/*
* This code implements communication based on Miranda netlib library
*
* (c) majvan 2002-2004
*/
#include "..\stdafx.h"
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
BOOL SSLLoaded = FALSE;
HANDLE hNetlibUser = NULL;
void __stdcall SSL_DebugLog(const char *fmt, ...)
{
char str[4096];
va_list vararg;
va_start(vararg, fmt);
int tBytes = mir_vsnprintf(str, _countof(str), fmt, vararg);
if (tBytes == 0)
return;
if (tBytes > 0)
str[tBytes] = 0;
else
str[sizeof(str) - 1] = 0;
CallService(MS_NETLIB_LOG, (WPARAM)hNetlibUser, (LPARAM)str);
va_end(vararg);
}
HANDLE RegisterNLClient(const char *name)
{
static NETLIBUSER nlu = { 0 };
char desc[128];
mir_snprintf(desc, Translate("%s connection"), name);
#ifdef DEBUG_COMM
DebugLog(CommFile, "");
#endif
nlu.cbSize = sizeof(nlu);
nlu.flags = NUF_OUTGOING | NUF_HTTPCONNS;
nlu.szDescriptiveName = desc;
nlu.szSettingsModule = (char *)name;
hNetlibUser = (HANDLE)CallService(MS_NETLIB_REGISTERUSER, 0, (LPARAM)&nlu);
#ifdef DEBUG_COMM
if (NULL == hNetlibUser)
DebugLog(CommFile, "\n");
else
DebugLog(CommFile, "\n");
#endif
return hNetlibUser;
}
//Move connection to SSL
void CNLClient::SSLify() throw(DWORD)
{
#ifdef DEBUG_COMM
SSL_DebugLog("Staring SSL...");
#endif
int socket = CallService(MS_NETLIB_GETSOCKET, (WPARAM)hConnection, 0);
if (socket != INVALID_SOCKET) {
#ifdef DEBUG_COMM
SSL_DebugLog("Staring netlib core SSL");
#endif
if (CallService(MS_NETLIB_STARTSSL, (WPARAM)hConnection, 0)) {
#ifdef DEBUG_COMM
SSL_DebugLog("Netlib core SSL started");
#endif
isTLSed = true;
SSLLoaded = TRUE;
return;
}
}
//ssl could not be created
throw NetworkError = (DWORD)ESSL_CREATESSL;
}
//Connects to the server through the sock
//if not success, exception is throwed
void CNLClient::Connect(const char* servername, const int port) throw(DWORD)
{
NETLIBOPENCONNECTION nloc;
NetworkError = SystemError = 0;
isTLSed = false;
#ifdef DEBUG_COMM
DebugLog(CommFile, "\n");
#endif
try {
nloc.cbSize = sizeof(NETLIBOPENCONNECTION);
nloc.szHost = servername;
nloc.wPort = port;
nloc.flags = 0;
if (NULL == (hConnection = (HANDLE)CallService(MS_NETLIB_OPENCONNECTION, (WPARAM)hNetlibUser, (LPARAM)&nloc))) {
SystemError = WSAGetLastError();
throw NetworkError = (DWORD)ENL_CONNECT;
}
#ifdef DEBUG_COMM
DebugLog(CommFile, "\n");
#endif
return;
}
catch (...) {
#ifdef DEBUG_COMM
DebugLog(CommFile, "\n");
#endif
throw;
}
}
//Performs a simple query
// query- command to send
int CNLClient::LocalNetlib_Send(HANDLE hConn, const char *buf, int len, int flags)
{
if (isTLSed) {
#ifdef DEBUG_COMM
SSL_DebugLog("SSL send: %s", buf);
#endif
}
NETLIBBUFFER nlb = { (char*)buf,len,flags };
return CallService(MS_NETLIB_SEND, (WPARAM)hConn, (LPARAM)&nlb);
}
void CNLClient::Send(const char *query) throw(DWORD)
{
unsigned int Sent;
if (NULL == query)
return;
if (hConnection == NULL)
return;
#ifdef DEBUG_COMM
DebugLog(CommFile, "%s", query);
#endif
try {
if ((SOCKET_ERROR == (Sent = LocalNetlib_Send(hConnection, query, (int)mir_strlen(query), MSG_DUMPASTEXT))) || Sent != (unsigned int)mir_strlen(query)) {
SystemError = WSAGetLastError();
throw NetworkError = (DWORD)ENL_SEND;
}
#ifdef DEBUG_COMM
DebugLog(CommFile, "\n");
#endif
}
catch (...) {
#ifdef DEBUG_COMM
DebugLog(CommFile, "\n");
#endif
throw;
}
}
//Reads data from socket
// buf- buffer where to store max. buflen of received characters
// if buf is NULL, creates buffer of buflen size
// buf is NULL by default
//You need free() returned buffer, which can be allocated in this function
//if not success, exception is throwed
int CNLClient::LocalNetlib_Recv(HANDLE hConn, char *buf, int len, int flags)
{
NETLIBBUFFER nlb = { buf,len,flags };
int iReturn = CallService(MS_NETLIB_RECV, (WPARAM)hConn, (LPARAM)&nlb);
if (isTLSed) {
#ifdef DEBUG_COMM
SSL_DebugLog("SSL recv: %s", buf);
#endif
}
return iReturn;
}
char* CNLClient::Recv(char *buf, int buflen) throw(DWORD)
{
#ifdef DEBUG_COMM
DebugLog(CommFile, "");
#endif
try {
if (buf == NULL)
buf = (char *)malloc(sizeof(char)*(buflen + 1));
if (buf == NULL)
throw NetworkError = (DWORD)ENL_RECVALLOC;
if (!isTLSed) {
NETLIBSELECT nls;
memset(&nls, 0, sizeof(NETLIBSELECT));
nls.cbSize = sizeof(NETLIBSELECT);
nls.dwTimeout = 60000;
nls.hReadConns[0] = hConnection;
switch (CallService(MS_NETLIB_SELECT, 0, (LPARAM)&nls)) {
case SOCKET_ERROR:
free(buf);
SystemError = WSAGetLastError();
throw NetworkError = (DWORD)ENL_RECV;
case 0: // time out!
free(buf);
throw NetworkError = (DWORD)ENL_TIMEOUT;
}
}
memset(buf, 0, buflen);
if (SOCKET_ERROR == (Rcv = LocalNetlib_Recv(hConnection, buf, buflen, MSG_DUMPASTEXT))) {
free(buf);
SystemError = WSAGetLastError();
throw NetworkError = (DWORD)ENL_RECV;
}
if (!Rcv) {
free(buf);
SystemError = WSAGetLastError();
throw NetworkError = (DWORD)ENL_RECV;
}
#ifdef DEBUG_COMM
*(buf + Rcv) = 0; //end the buffer to write it to file
DebugLog(CommFile, "%s", buf);
DebugLog(CommFile, "\n");
#endif
return(buf);
}
catch (...) {
#ifdef DEBUG_COMM
DebugLog(CommFile, "\n");
#endif
throw;
}
}
//Closes netlib connection
void CNLClient::Disconnect()
{
Netlib_CloseHandle(hConnection);
hConnection = (HANDLE)NULL;
}
//Uninitializes netlib library
void UnregisterNLClient()
{
#ifdef DEBUG_COMM
DebugLog(CommFile, "");
#endif
Netlib_CloseHandle(hNetlibUser);
hNetlibUser = (HANDLE)NULL;
#ifdef DEBUG_COMM
DebugLog(CommFile, "\n");
#endif
}