pedroutil.cpp revision f4f76ab18b014c84d2b6abdd24fe5ac94dda22e5
/*
* Support classes for the Pedro mini-XMPP client
*
* Authors:
* Bob Jamison
*
* Copyright (C) 2005-2006 Bob Jamison
*
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include <stdarg.h>
#include "pedroutil.h"
#ifdef __WIN32__
#include <windows.h>
#else /* UNIX */
#include <netdb.h>
#include <unistd.h>
#include <pthread.h>
#endif /* UNIX */
#ifdef HAVE_SSL
#endif
namespace Pedro
{
//########################################################################
//########################################################################
//# B A S E 6 4
//########################################################################
//########################################################################
//#################
//# ENCODER
//#################
static char *base64encode =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
/**
* Writes the specified byte to the output buffer
*/
{
outBuf <<= 8;
bitCount += 8;
if (bitCount >= 24)
{
bitCount = 0;
outBuf = 0L;
}
}
/**
* Writes the specified string to the output buffer
*/
{
while (*str)
}
/**
* Writes the specified string to the output buffer
*/
{
while (len>0)
{
len--;
}
}
/**
* Writes the specified string to the output buffer
*/
{
}
/**
* Closes this output stream and releases any system resources
* associated with this stream.
*/
{
//get any last bytes (1 or 2) out of the buffer
if (bitCount == 16)
{
}
else if (bitCount == 8)
{
}
reset();
return ret;
}
{
return ret;
}
//#################
//# DECODER
//#################
static int base64decode[] =
{
/*00*/ -1, -1, -1, -1, -1, -1, -1, -1,
/*08*/ -1, -1, -1, -1, -1, -1, -1, -1,
/*10*/ -1, -1, -1, -1, -1, -1, -1, -1,
/*18*/ -1, -1, -1, -1, -1, -1, -1, -1,
/*20*/ -1, -1, -1, -1, -1, -1, -1, -1,
/*28*/ -1, -1, -1, 62, -1, -1, -1, 63,
/*30*/ 52, 53, 54, 55, 56, 57, 58, 59,
/*38*/ 60, 61, -1, -1, -1, -1, -1, -1,
/*40*/ -1, 0, 1, 2, 3, 4, 5, 6,
/*48*/ 7, 8, 9, 10, 11, 12, 13, 14,
/*50*/ 15, 16, 17, 18, 19, 20, 21, 22,
/*58*/ 23, 24, 25, -1, -1, -1, -1, -1,
/*60*/ -1, 26, 27, 28, 29, 30, 31, 32,
/*68*/ 33, 34, 35, 36, 37, 38, 39, 40,
/*70*/ 41, 42, 43, 44, 45, 46, 47, 48,
/*78*/ 49, 50, 51, -1, -1, -1, -1, -1
};
/**
* Appends one char to the decoder
*/
{
return;
{
}
else
{
//printf("char:%c %d\n", ch, byteVal);
if (byteVal < 0)
{
//Bad lookup value
}
}
if (inCount >=4 )
{
inCount = 0;
}
}
{
while (*str)
}
{
}
{
reset();
return ret;
}
{
return ret;
}
{
return buf;
}
//########################################################################
//########################################################################
//### S H A 1 H A S H I N G
//########################################################################
//########################################################################
{
}
static char *sha1hex = "0123456789abcdef";
{
unsigned char hashout[20];
for (int i=0 ; i<20 ; i++)
{
}
return ret;
}
{
lenW = 0;
sizeHi = 0;
sizeLo = 0;
// Initialize H with the magic constants (see FIPS180 for constants)
H[0] = 0x67452301L;
H[1] = 0xefcdab89L;
H[2] = 0x98badcfeL;
H[3] = 0x10325476L;
H[4] = 0xc3d2e1f0L;
for (int i = 0; i < 80; i++)
W[i] = 0;
}
{
// Read the data into W and process blocks as they get full
for (int i = 0; i < len; i++)
{
if ((++lenW) % 64 == 0)
{
hashblock();
lenW = 0;
}
sizeLo += 8;
}
}
{
unsigned char pad0x80 = 0x80;
unsigned char pad0x00 = 0x00;
unsigned char padlen[8];
// Pad with a binary 1 (e.g. 0x80), then zeroes, then length
while (lenW != 56)
// Output hash
for (int i = 0; i < 20; i++)
{
H[i / 4] <<= 8;
}
// Re-initialize the context (also zeroizes contents)
init();
}
{
for (int t = 16; t <= 79; t++)
unsigned long A = H[0];
unsigned long B = H[1];
unsigned long C = H[2];
unsigned long D = H[3];
unsigned long E = H[4];
unsigned long TEMP;
for (int t = 0; t <= 19; t++)
{
E + W[t] + 0x5a827999L) & 0xffffffffL;
}
for (int t = 20; t <= 39; t++)
{
E + W[t] + 0x6ed9eba1L) & 0xffffffffL;
}
for (int t = 40; t <= 59; t++)
{
E + W[t] + 0x8f1bbcdcL) & 0xffffffffL;
}
for (int t = 60; t <= 79; t++)
{
E + W[t] + 0xca62c1d6L) & 0xffffffffL;
}
H[0] += A;
H[1] += B;
H[2] += C;
H[3] += D;
H[4] += E;
}
//########################################################################
//########################################################################
//### M D 5 H A S H I N G
//########################################################################
//########################################################################
{
}
{
return ret;
}
/*
* Note: this code is harmless on little-endian machines.
*/
/*
static void byteReverse(unsigned char *buf, unsigned long longs)
{
do
{
unsigned long t = (unsigned long)
((unsigned) buf[3] << 8 | buf[2]) << 16 |
((unsigned) buf[1] << 8 | buf[0]);
*(unsigned long *) buf = t;
buf += 4;
} while (--longs);
}
*/
{
while (n--)
}
static void md5_memset(void *dest, char v, int n)
{
unsigned char *s = (unsigned char *)dest;
while (n--)
*s++ = v;
}
/**
* Initialize MD5 polynomials and storage
*/
{
buf[0] = 0x67452301;
bits[0] = 0;
bits[1] = 0;
}
/*
* Update context to reflect the concatenation of another buffer full
* of bytes.
*/
{
// Update bitcount
unsigned long t = bits[0];
//Bytes already in shsInfo->data
t = (t >> 3) & 0x3f;
// Handle any leading odd-sized chunks
if (t)
{
unsigned char *p = (unsigned char *) in + t;
t = 64 - t;
if (len < t)
{
return;
}
md5_memcpy(p, source, t);
//byteReverse(in, 16);
source += t;
len -= t;
}
// Process data in 64-byte chunks
while (len >= 64)
{
//byteReverse(in, 16);
source += 64;
len -= 64;
}
// Handle any remaining bytes of data.
}
/*
* Update context to reflect the concatenation of another string
*/
{
}
/*
* Update context to reflect the concatenation of a single character
*/
{
}
/*
* Final wrapup - pad to 64-byte boundary with the bit pattern
* 1 0* (64-bit count of bits processed, MSB-first)
*/
{
// Compute number of bytes mod 64
// Set the first char of padding to 0x80.
// This is safe since there is always at least one byte free
*p++ = 0x80;
// Bytes of padding needed to make 64 bytes
// Pad out to 56 mod 64
if (count < 8)
{
// Two lots of padding: Pad the first block to 64 bytes
md5_memset(p, 0, count);
//byteReverse(in, 16);
// Now fill the next block with 56 bytes
}
else
{
// Pad block to 56 bytes
}
//byteReverse(in, 14);
// Append length in bits and transform
//byteReverse((unsigned char *) buf, 4);
init(); // Security! ;-)
}
static char *md5hex = "0123456789abcdef";
{
unsigned char hashout[16];
for (int i=0 ; i<16 ; i++)
{
}
return ret;
}
//# The four core functions - F1 is optimized somewhat
// #define F1(x, y, z) (x & y | ~x & z)
#define F1(x, y, z) (z ^ (x & (y ^ z)))
#define F3(x, y, z) (x ^ y ^ z)
#define F4(x, y, z) (y ^ (x | ~z))
// ## This is the central step in the MD5 algorithm.
( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
/*
* The core of the MD5 algorithm, this alters an existing MD5 hash to
* reflect the addition of 16 longwords of new data. MD5Update blocks
* the data and converts bytes into longwords for this routine.
* @parm buf points to an array of 4 unsigned longs
* @parm in points to an array of 16 unsigned longs
*/
{
unsigned long a = buf[0];
unsigned long b = buf[1];
unsigned long c = buf[2];
unsigned long d = buf[3];
buf[0] += a;
buf[1] += b;
buf[2] += c;
buf[3] += d;
}
//########################################################################
//########################################################################
//### T H R E A D
//########################################################################
//########################################################################
#ifdef __WIN32__
{
return 0;
}
{
(LPVOID)this, 0, &dwThreadId);
//Make sure the thread is started before 'this' is deallocated
while (!started)
sleep(10);
}
{
}
#else /* UNIX */
void *PthreadThreadFunction(void *context)
{
return NULL;
}
{
PthreadThreadFunction, (void *)this);
if (ret != 0)
//Make sure the thread is started before 'this' is deallocated
while (!started)
sleep(10);
}
{
}
#endif
//########################################################################
//########################################################################
//### S O C K E T
//########################################################################
//########################################################################
//#########################################################################
//# U T I L I T Y
//#########################################################################
{
unsigned char *p = (unsigned char *)s;
while (n > 0)
{
*p++ = (unsigned char)0;
n--;
}
}
{
unsigned char *p = (unsigned char *)dest;
unsigned char *q = (unsigned char *)src;
while (n > 0)
{
*p++ = *q++;
n--;
}
}
//#########################################################################
//# T C P C O N N E C T I O N
//#########################################################################
{
init();
}
{
init();
}
#ifdef HAVE_SSL
{
//printf("########### LOCK\n");
{
errstr = "invalid mode";
goto err;
}
{
errstr = "type out of bounds";
goto err;
}
if (mode & CRYPTO_LOCK)
{
{
errstr = "already locked";
/* must not happen in a single-threaded program
* (would deadlock)
*/
goto err;
}
}
else if (mode & CRYPTO_UNLOCK)
{
{
errstr = "not locked";
goto err;
}
{
"CRYPTO_r_unlock on write lock" :
"CRYPTO_w_unlock on read lock";
}
}
else
{
errstr = "invalid mode";
goto err;
}
err:
if (errstr)
{
/* we cannot use bio_err here */
}
}
static unsigned long cryptoIdCallback()
{
#ifdef __WIN32__
unsigned long ret = (unsigned long) GetCurrentThreadId();
#else
unsigned long ret = (unsigned long) pthread_self();
#endif
return ret;
}
#endif
{
init();
}
static bool tcp_socket_inited = false;
{
if (!tcp_socket_inited)
{
#ifdef __WIN32__
#endif
#ifdef HAVE_SSL
if (libssl_is_present)
{
sslContext = NULL;
}
#endif
tcp_socket_inited = true;
}
sock = -1;
connected = false;
hostname = "";
portno = -1;
sslEnabled = false;
receiveTimeout = 0;
}
{
disconnect();
}
bool TcpSocket::isConnected()
{
return false;
return true;
}
bool TcpSocket::getHaveSSL()
{
#ifdef HAVE_SSL
if (libssl_is_present)
{
return true;
} else {
return false;
}
#else
return false;
#endif
}
{
sslEnabled = val;
}
bool TcpSocket::getEnableSSL()
{
return sslEnabled;
}
{
return connect();
}
#ifdef HAVE_SSL
/*
static int password_cb(char *buf, int bufLen, int rwflag, void *userdata)
{
char *password = "password";
if (bufLen < (int)(strlen(password)+1))
return 0;
strcpy(buf,password);
int ret = strlen(password);
return ret;
}
static void infoCallback(const SSL *ssl, int where, int ret)
{
switch (where)
{
case SSL_CB_ALERT:
{
printf("## %d SSL ALERT: %s\n", where, SSL_alert_desc_string_long(ret));
break;
}
default:
{
printf("## %d SSL: %s\n", where, SSL_state_string_long(ssl));
break;
}
}
}
*/
#endif
{
#ifndef HAVE_SSL
"SSL starttls() error: client not compiled with SSL enabled\n");
return false;
#else /*HAVE_SSL*/
if (!libssl_is_present)
{
"SSL starttls() error: the correct version of libssl was not found \n");
return false;
} else {
sslContext = NULL;
//SSL_METHOD *meth = SSLv23_method();
//SSL_METHOD *meth = SSLv3_client_method();
//SSL_CTX_set_info_callback(sslContext, infoCallback);
/**
* For now, let's accept all connections. Ignore this
* block of code
*
char *keyFile = "client.pem";
char *caList = "root.pem";
//# Load our keys and certificates
if (!(SSL_CTX_use_certificate_chain_file(sslContext, keyFile)))
{
fprintf(stderr, "Can't read certificate file\n");
disconnect();
return false;
}
SSL_CTX_set_default_passwd_cb(sslContext, password_cb);
if (!(SSL_CTX_use_PrivateKey_file(sslContext, keyFile, SSL_FILETYPE_PEM)))
{
fprintf(stderr, "Can't read key file\n");
disconnect();
return false;
}
//## Load the CAs we trust
if (!(SSL_CTX_load_verify_locations(sslContext, caList, 0)))
{
fprintf(stderr, "Can't read CA list\n");
disconnect();
return false;
}
*/
/* Connect the SSL socket */
if (ret == 0)
{
disconnect();
return false;
}
else if (ret < 0)
{
disconnect();
return false;
}
sslEnabled = true;
return true;
}
#endif /* HAVE_SSL */
}
{
{
return false;
}
if (portno<1)
{
return false;
}
if (sock < 0)
{
return false;
}
if (!server)
{
return false;
}
struct sockaddr_in serv_addr;
if (ret < 0)
{
return false;
}
if (sslEnabled)
{
if (!startTls())
return false;
}
connected = true;
return true;
}
bool TcpSocket::disconnect()
{
bool ret = true;
connected = false;
#ifdef HAVE_SSL
if (libssl_is_present)
{
if (sslEnabled)
{
if (sslStream)
{
int r = SSL_shutdown(sslStream);
switch(r)
{
case 1:
break; /* Success */
case 0:
case -1:
default:
//printf("Shutdown failed");
ret = false;
}
}
if (sslContext)
}
sslContext = NULL;
}
#endif /*HAVE_SSL*/
#ifdef __WIN32__
#else
#endif
sock = -1;
sslEnabled = false;
return ret;
}
{
return true;
}
/**
* For normal sockets, return the number of bytes waiting to be received.
* For SSL, just return >0 when something is ready to be read.
*/
{
if (!isConnected())
return -1;
long count = 0;
#ifdef __WIN32__
return -1;
#else
return -1;
#endif
if (count<=0 && sslEnabled)
{
#ifdef HAVE_SSL
if (libssl_is_present)
{
return SSL_pending(sslStream);
}
#endif
}
return count;
}
{
if (!isConnected())
{
return false;
}
unsigned char c = (unsigned char)ch;
if (sslEnabled)
{
#ifdef HAVE_SSL
if (libssl_is_present)
{
if (r<=0)
{
switch(SSL_get_error(sslStream, r))
{
default:
return -1;
}
}
}
#endif
}
else
{
//if (send(sock, &c, 1, 0) < 0)
{
return false;
}
}
return true;
}
{
if (!isConnected())
{
return false;
}
if (sslEnabled)
{
#ifdef HAVE_SSL
if (libssl_is_present)
{
if (r<=0)
{
switch(SSL_get_error(sslStream, r))
{
default:
return -1;
}
}
}
#endif
}
else
{
//if (send(sock, &c, 1, 0) < 0)
{
return false;
}
}
return true;
}
{
}
{
if (!isConnected())
return -1;
//We'll use this loop for timeouts, so that SSL and plain sockets
//will behave the same way
if (receiveTimeout > 0)
{
unsigned long tim = 0;
while (true)
{
if (avail > 0)
break;
if (tim >= receiveTimeout)
return -2;
tim += 20;
}
}
//check again
if (!isConnected())
return -1;
unsigned char ch;
if (sslEnabled)
{
#ifdef HAVE_SSL
if (libssl_is_present)
{
if (!sslStream)
return -1;
switch (err)
{
case SSL_ERROR_NONE:
break;
case SSL_ERROR_ZERO_RETURN:
return -1;
case SSL_ERROR_SYSCALL:
return -1;
default:
return -1;
}
}
#endif
}
else
{
{
disconnect();
return -1;
}
}
return (int)ch;
}
{
while (isConnected())
{
if (ch<0)
return ret;
return ret;
}
return ret;
}
} //namespace Pedro
//########################################################################
//# E N D O F F I L E
//########################################################################