summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: a4ff052)
raw | patch | inline | side by side (parent: a4ff052)
author | ishmal <ishmal@users.sourceforge.net> | |
Thu, 1 Jun 2006 09:01:07 +0000 (09:01 +0000) | ||
committer | ishmal <ishmal@users.sourceforge.net> | |
Thu, 1 Jun 2006 09:01:07 +0000 (09:01 +0000) |
src/pedro/Makefile.mingw | patch | blob | history | |
src/pedro/mingwenv.bat | patch | blob | history | |
src/pedro/pedrogui.cpp | patch | blob | history | |
src/pedro/pedrogui.h | patch | blob | history | |
src/pedro/pedroutil.cpp | [new file with mode: 0644] | patch | blob |
src/pedro/pedroutil.h | [new file with mode: 0644] | patch | blob |
src/pedro/pedroxmpp.cpp | patch | blob | history |
index 53b1d8e85889622425535b09752280c230ff21e3..f108c2c2feb9dff80eb30a198e92c2533f1faf03 100644 (file)
--- a/src/pedro/Makefile.mingw
+++ b/src/pedro/Makefile.mingw
-OBJ = \
-pedrodom.o \
-pedroxmpp.o \
-pedroconfig.o
+OBJ = \
+pedrodom.o \
+pedroxmpp.o \
+pedroconfig.o \
+pedroutil.o
+
GUIOBJ = \
pedrogui.o \
pedromain.o
+
TESTOBJ = \
work/test.o \
work/filesend.o \
diff --git a/src/pedro/mingwenv.bat b/src/pedro/mingwenv.bat
index 996566e7b3d37f7d2fc23ee07618ee56221c9470..f9ec1e7c51b33d0cdd22e5970560d3d56cb733b3 100644 (file)
--- a/src/pedro/mingwenv.bat
+++ b/src/pedro/mingwenv.bat
-set PATH=c:\mingw\bin;%PATH%\r
+set PATH=c:\mingw4\bin;%PATH%\r
set RM=del\r
diff --git a/src/pedro/pedrogui.cpp b/src/pedro/pedrogui.cpp
index 267e47ff9f5bc7032b0013fcd0530f84ac59a8f9..f785e7132591a5630e96c148026f68e594c83392 100644 (file)
--- a/src/pedro/pedrogui.cpp
+++ b/src/pedro/pedrogui.cpp
Glib::RefPtr<Gtk::ActionGroup> actionGroup = Gtk::ActionGroup::create();
actionGroup->add( Gtk::Action::create("MenuFile", "_File") );
actionGroup->add( Gtk::Action::create("Leave", Gtk::Stock::CANCEL),
- sigc::mem_fun(*this, &ChatWindow::leaveCallback) );
+ sigc::mem_fun(*this, &ChatWindow::leaveCallback) );
Glib::RefPtr<Gtk::UIManager> uiManager = Gtk::UIManager::create();
Glib::RefPtr<Gtk::ActionGroup> actionGroup = Gtk::ActionGroup::create();
actionGroup->add( Gtk::Action::create("MenuFile", "_File") );
actionGroup->add( Gtk::Action::create("Leave", Gtk::Stock::CANCEL),
- sigc::mem_fun(*this, &GroupChatWindow::leaveCallback) );
+ sigc::mem_fun(*this, &GroupChatWindow::leaveCallback) );
Glib::RefPtr<Gtk::UIManager> uiManager = Gtk::UIManager::create();
Glib::RefPtr<Gtk::ActionGroup> actionGroup = Gtk::ActionGroup::create();
actionGroup->add( Gtk::Action::create("MenuFile", "_File") );
actionGroup->add( Gtk::Action::create("Connect", Gtk::Stock::CONNECT, "Connect"),
- sigc::mem_fun(*this, &ConnectDialog::okCallback) );
+ sigc::mem_fun(*this, &ConnectDialog::okCallback) );
actionGroup->add( Gtk::Action::create("Cancel", Gtk::Stock::CANCEL, "Cancel"),
- sigc::mem_fun(*this, &ConnectDialog::cancelCallback) );
+ sigc::mem_fun(*this, &ConnectDialog::cancelCallback) );
Glib::RefPtr<Gtk::UIManager> uiManager = Gtk::UIManager::create();
+//#########################################################################
+//# C O N F I G D I A L O G
+//#########################################################################
+
+
+void ConfigDialog::okCallback()
+{
+ Glib::ustring pass = passField.get_text();
+ Glib::ustring newpass = newField.get_text();
+ Glib::ustring confpass = confField.get_text();
+ if ((pass.size() < 5 || pass.size() > 12 ) ||
+ (newpass.size() < 5 || newpass.size() > 12 ) ||
+ (confpass.size() < 5 || confpass.size()> 12 ))
+ {
+ Gtk::MessageDialog dlg(*this, "Password must be 5 to 12 characters",
+ false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
+ dlg.run();
+ }
+ else if (newpass != confpass)
+ {
+ Gtk::MessageDialog dlg(*this, "New password and confirmation do not match",
+ false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
+ dlg.run();
+ }
+ else
+ {
+ //response(Gtk::RESPONSE_OK);
+ hide();
+ }
+}
+
+void ConfigDialog::cancelCallback()
+{
+ //response(Gtk::RESPONSE_CANCEL);
+ hide();
+}
+
+void ConfigDialog::on_response(int response_id)
+{
+ if (response_id == Gtk::RESPONSE_OK)
+ okCallback();
+ else
+ cancelCallback();
+}
+
+bool ConfigDialog::doSetup()
+{
+ set_title("Change Password");
+ set_size_request(300,200);
+
+ Glib::RefPtr<Gtk::ActionGroup> actionGroup = Gtk::ActionGroup::create();
+ actionGroup->add( Gtk::Action::create("MenuFile", "_File") );
+ actionGroup->add( Gtk::Action::create("Change", Gtk::Stock::OK, "Change Password"),
+ sigc::mem_fun(*this, &ConfigDialog::okCallback) );
+ actionGroup->add( Gtk::Action::create("Cancel", Gtk::Stock::CANCEL, "Cancel"),
+ sigc::mem_fun(*this, &ConfigDialog::cancelCallback) );
+
+
+ Glib::RefPtr<Gtk::UIManager> uiManager = Gtk::UIManager::create();
+
+ uiManager->insert_action_group(actionGroup, 0);
+ add_accel_group(uiManager->get_accel_group());
+
+ Glib::ustring ui_info =
+ "<ui>"
+ " <menubar name='MenuBar'>"
+ " <menu action='MenuFile'>"
+ " <menuitem action='Change'/>"
+ " <separator/>"
+ " <menuitem action='Cancel'/>"
+ " </menu>"
+ " </menubar>"
+ "</ui>";
+
+ uiManager->add_ui_from_string(ui_info);
+ Gtk::Widget* pMenuBar = uiManager->get_widget("/MenuBar");
+ get_vbox()->pack_start(*pMenuBar, Gtk::PACK_SHRINK);
+
+ table.resize(3, 2);
+ get_vbox()->pack_start(table);
+
+ passLabel.set_text("Current Password");
+ table.attach(passLabel, 0, 1, 0, 1);
+ passField.set_visibility(false);
+ passField.set_text(parent.client.getPassword());
+ table.attach(passField, 1, 2, 0, 1);
+
+ newLabel.set_text("New Password");
+ table.attach(newLabel, 0, 1, 1, 2);
+ newField.set_visibility(false);
+ table.attach(newField, 1, 2, 1, 2);
+
+ confLabel.set_text("Confirm New Password");
+ table.attach(confLabel, 0, 1, 2, 3);
+ confField.set_visibility(false);
+ confField.signal_activate().connect(
+ sigc::mem_fun(*this, &ConfigDialog::okCallback) );
+ table.attach(confField, 1, 2, 2, 3);
+
+ add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
+ add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
+
+ show_all_children();
+
+ return true;
+}
+
//#########################################################################
//# P A S S W O R D D I A L O G
//#########################################################################
Glib::RefPtr<Gtk::ActionGroup> actionGroup = Gtk::ActionGroup::create();
actionGroup->add( Gtk::Action::create("MenuFile", "_File") );
actionGroup->add( Gtk::Action::create("Change", Gtk::Stock::OK, "Change Password"),
- sigc::mem_fun(*this, &PasswordDialog::okCallback) );
+ sigc::mem_fun(*this, &PasswordDialog::okCallback) );
actionGroup->add( Gtk::Action::create("Cancel", Gtk::Stock::CANCEL, "Cancel"),
- sigc::mem_fun(*this, &PasswordDialog::cancelCallback) );
+ sigc::mem_fun(*this, &PasswordDialog::cancelCallback) );
Glib::RefPtr<Gtk::UIManager> uiManager = Gtk::UIManager::create();
diff --git a/src/pedro/pedrogui.h b/src/pedro/pedrogui.h
index 3b25946d3eaa6291b3fb851a90df68a4e9cf008b..bd37d095d2d68901a9e917a773cff02d12d3e6f0 100644 (file)
--- a/src/pedro/pedrogui.h
+++ b/src/pedro/pedrogui.h
};
+
+
+//#########################################################################
+//# C O N F I G D I A L O G
+//#########################################################################
+
+class ConfigDialog : public Gtk::Dialog
+{
+public:
+
+ ConfigDialog (PedroGui &par) : parent(par)
+ { doSetup(); }
+
+ virtual ~ConfigDialog ()
+ {}
+
+ DOMString getPass()
+ { return passField.get_text(); }
+ DOMString getNewPass()
+ { return newField.get_text(); }
+ DOMString getConfirm()
+ { return confField.get_text(); }
+
+protected:
+
+ //Overloaded from Gtk::Dialog
+ virtual void on_response(int response_id);
+
+private:
+
+ void okCallback();
+ void cancelCallback();
+
+ bool doSetup();
+
+ Gtk::Table table;
+
+ Gtk::Label passLabel;
+ Gtk::Entry passField;
+ Gtk::Label newLabel;
+ Gtk::Entry newField;
+ Gtk::Label confLabel;
+ Gtk::Entry confField;
+
+ PedroGui &parent;
+};
+
+
//#########################################################################
//# P A S S W O R D D I A L O G
//#########################################################################
diff --git a/src/pedro/pedroutil.cpp b/src/pedro/pedroutil.cpp
--- /dev/null
+++ b/src/pedro/pedroutil.cpp
@@ -0,0 +1,1459 @@
+/*
+ * Support classes for the Pedro mini-XMPP client
+ *
+ * Authors:
+ * Bob Jamison
+ *
+ * Copyright (C) 2005-2006 Bob Jamison
+ *
+ * This library is free software; you can redistribute it and/or
+ * 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 <sys/stat.h>
+
+#include "pedroutil.h"
+
+
+
+#ifdef __WIN32__
+
+#include <windows.h>
+
+#else /* UNIX */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+
+#include <pthread.h>
+
+#endif /* UNIX */
+
+
+
+namespace Pedro
+{
+
+
+
+
+
+//########################################################################
+//########################################################################
+//# B A S E 6 4
+//########################################################################
+//########################################################################
+
+
+//#################
+//# ENCODER
+//#################
+
+
+static char *base64encode =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+
+
+/**
+ * Writes the specified byte to the output buffer
+ */
+void Base64Encoder::append(int ch)
+{
+ outBuf <<= 8;
+ outBuf |= (ch & 0xff);
+ bitCount += 8;
+ if (bitCount >= 24)
+ {
+ int indx = (int)((outBuf & 0x00fc0000L) >> 18);
+ int obyte = (int)base64encode[indx & 63];
+ buf.push_back(obyte);
+
+ indx = (int)((outBuf & 0x0003f000L) >> 12);
+ obyte = (int)base64encode[indx & 63];
+ buf.push_back(obyte);
+
+ indx = (int)((outBuf & 0x00000fc0L) >> 6);
+ obyte = (int)base64encode[indx & 63];
+ buf.push_back(obyte);
+
+ indx = (int)((outBuf & 0x0000003fL) );
+ obyte = (int)base64encode[indx & 63];
+ buf.push_back(obyte);
+
+ bitCount = 0;
+ outBuf = 0L;
+ }
+}
+
+/**
+ * Writes the specified string to the output buffer
+ */
+void Base64Encoder::append(char *str)
+{
+ while (*str)
+ append((int)*str++);
+}
+
+/**
+ * Writes the specified string to the output buffer
+ */
+void Base64Encoder::append(unsigned char *str, int len)
+{
+ while (len>0)
+ {
+ append((int)*str++);
+ len--;
+ }
+}
+
+/**
+ * Writes the specified string to the output buffer
+ */
+void Base64Encoder::append(const DOMString &str)
+{
+ append((char *)str.c_str());
+}
+
+/**
+ * Closes this output stream and releases any system resources
+ * associated with this stream.
+ */
+DOMString Base64Encoder::finish()
+{
+ //get any last bytes (1 or 2) out of the buffer
+ if (bitCount == 16)
+ {
+ outBuf <<= 2; //pad to make 18 bits
+
+ int indx = (int)((outBuf & 0x0003f000L) >> 12);
+ int obyte = (int)base64encode[indx & 63];
+ buf.push_back(obyte);
+
+ indx = (int)((outBuf & 0x00000fc0L) >> 6);
+ obyte = (int)base64encode[indx & 63];
+ buf.push_back(obyte);
+
+ indx = (int)((outBuf & 0x0000003fL) );
+ obyte = (int)base64encode[indx & 63];
+ buf.push_back(obyte);
+
+ buf.push_back('=');
+ }
+ else if (bitCount == 8)
+ {
+ outBuf <<= 4; //pad to make 12 bits
+
+ int indx = (int)((outBuf & 0x00000fc0L) >> 6);
+ int obyte = (int)base64encode[indx & 63];
+ buf.push_back(obyte);
+
+ indx = (int)((outBuf & 0x0000003fL) );
+ obyte = (int)base64encode[indx & 63];
+ buf.push_back(obyte);
+
+ buf.push_back('=');
+ buf.push_back('=');
+ }
+
+ DOMString ret = buf;
+ reset();
+ return ret;
+}
+
+
+DOMString Base64Encoder::encode(const DOMString &str)
+{
+ Base64Encoder encoder;
+ encoder.append(str);
+ DOMString ret = encoder.finish();
+ 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
+ */
+void Base64Decoder::append(int ch)
+{
+ if (isspace(ch))
+ return;
+ else if (ch == '=') //padding
+ {
+ inBytes[inCount++] = 0;
+ }
+ else
+ {
+ int byteVal = base64decode[ch & 0x7f];
+ //printf("char:%c %d\n", ch, byteVal);
+ if (byteVal < 0)
+ {
+ //Bad lookup value
+ }
+ inBytes[inCount++] = byteVal;
+ }
+
+ if (inCount >=4 )
+ {
+ unsigned char b0 = ((inBytes[0]<<2) & 0xfc) | ((inBytes[1]>>4) & 0x03);
+ unsigned char b1 = ((inBytes[1]<<4) & 0xf0) | ((inBytes[2]>>2) & 0x0f);
+ unsigned char b2 = ((inBytes[2]<<6) & 0xc0) | ((inBytes[3] ) & 0x3f);
+ buf.push_back(b0);
+ buf.push_back(b1);
+ buf.push_back(b2);
+ inCount = 0;
+ }
+
+}
+
+void Base64Decoder::append(char *str)
+{
+ while (*str)
+ append((int)*str++);
+}
+
+void Base64Decoder::append(const DOMString &str)
+{
+ append((char *)str.c_str());
+}
+
+std::vector<unsigned char> Base64Decoder::finish()
+{
+ std::vector<unsigned char> ret = buf;
+ reset();
+ return ret;
+}
+
+std::vector<unsigned char> Base64Decoder::decode(const DOMString &str)
+{
+ Base64Decoder decoder;
+ decoder.append(str);
+ std::vector<unsigned char> ret = decoder.finish();
+ return ret;
+}
+
+DOMString Base64Decoder::decodeToString(const DOMString &str)
+{
+ Base64Decoder decoder;
+ decoder.append(str);
+ std::vector<unsigned char> ret = decoder.finish();
+ DOMString buf;
+ for (unsigned int i=0 ; i<ret.size() ; i++)
+ buf.push_back(ret[i]);
+ return buf;
+}
+
+
+
+
+
+
+
+//########################################################################
+//########################################################################
+//### S H A 1 H A S H I N G
+//########################################################################
+//########################################################################
+
+
+
+
+void Sha1::hash(unsigned char *dataIn, int len, unsigned char *digest)
+{
+ Sha1 sha1;
+ sha1.append(dataIn, len);
+ sha1.finish(digest);
+}
+
+static char *sha1hex = "0123456789abcdef";
+
+DOMString Sha1::hashHex(unsigned char *dataIn, int len)
+{
+ unsigned char hashout[20];
+ hash(dataIn, len, hashout);
+ DOMString ret;
+ for (int i=0 ; i<20 ; i++)
+ {
+ unsigned char ch = hashout[i];
+ ret.push_back(sha1hex[ (ch>>4) & 15 ]);
+ ret.push_back(sha1hex[ ch & 15 ]);
+ }
+ return ret;
+}
+
+
+void Sha1::init()
+{
+
+ 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;
+}
+
+
+void Sha1::append(unsigned char *dataIn, int len)
+{
+ // Read the data into W and process blocks as they get full
+ for (int i = 0; i < len; i++)
+ {
+ W[lenW / 4] <<= 8;
+ W[lenW / 4] |= (unsigned long)dataIn[i];
+ if ((++lenW) % 64 == 0)
+ {
+ hashblock();
+ lenW = 0;
+ }
+ sizeLo += 8;
+ sizeHi += (sizeLo < 8);
+ }
+}
+
+
+void Sha1::finish(unsigned char hashout[20])
+{
+ unsigned char pad0x80 = 0x80;
+ unsigned char pad0x00 = 0x00;
+ unsigned char padlen[8];
+
+ // Pad with a binary 1 (e.g. 0x80), then zeroes, then length
+ padlen[0] = (unsigned char)((sizeHi >> 24) & 255);
+ padlen[1] = (unsigned char)((sizeHi >> 16) & 255);
+ padlen[2] = (unsigned char)((sizeHi >> 8) & 255);
+ padlen[3] = (unsigned char)((sizeHi >> 0) & 255);
+ padlen[4] = (unsigned char)((sizeLo >> 24) & 255);
+ padlen[5] = (unsigned char)((sizeLo >> 16) & 255);
+ padlen[6] = (unsigned char)((sizeLo >> 8) & 255);
+ padlen[7] = (unsigned char)((sizeLo >> 0) & 255);
+
+ append(&pad0x80, 1);
+
+ while (lenW != 56)
+ append(&pad0x00, 1);
+ append(padlen, 8);
+
+ // Output hash
+ for (int i = 0; i < 20; i++)
+ {
+ hashout[i] = (unsigned char)(H[i / 4] >> 24);
+ H[i / 4] <<= 8;
+ }
+
+ // Re-initialize the context (also zeroizes contents)
+ init();
+}
+
+
+#define SHA_ROTL(X,n) ((((X) << (n)) | ((X) >> (32-(n)))) & 0xffffffffL)
+
+void Sha1::hashblock()
+{
+
+ for (int t = 16; t <= 79; t++)
+ W[t] = SHA_ROTL(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16], 1);
+
+ 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++)
+ {
+ TEMP = (SHA_ROTL(A,5) + (((C^D)&B)^D) +
+ E + W[t] + 0x5a827999L) & 0xffffffffL;
+ E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP;
+ }
+ for (int t = 20; t <= 39; t++)
+ {
+ TEMP = (SHA_ROTL(A,5) + (B^C^D) +
+ E + W[t] + 0x6ed9eba1L) & 0xffffffffL;
+ E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP;
+ }
+ for (int t = 40; t <= 59; t++)
+ {
+ TEMP = (SHA_ROTL(A,5) + ((B&C)|(D&(B|C))) +
+ E + W[t] + 0x8f1bbcdcL) & 0xffffffffL;
+ E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP;
+ }
+ for (int t = 60; t <= 79; t++)
+ {
+ TEMP = (SHA_ROTL(A,5) + (B^C^D) +
+ E + W[t] + 0xca62c1d6L) & 0xffffffffL;
+ E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP;
+ }
+
+ 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
+//########################################################################
+//########################################################################
+
+
+
+
+
+void Md5::hash(unsigned char *dataIn, unsigned long len, unsigned char *digest)
+{
+ Md5 md5;
+ md5.append(dataIn, len);
+ md5.finish(digest);
+}
+
+DOMString Md5::hashHex(unsigned char *dataIn, unsigned long len)
+{
+ Md5 md5;
+ md5.append(dataIn, len);
+ DOMString ret = md5.finishHex();
+ 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);
+}
+*/
+
+static void md5_memcpy(void *dest, void *src, int n)
+{
+ unsigned char *s1 = (unsigned char *)dest;
+ unsigned char *s2 = (unsigned char *)src;
+ while (n--)
+ *s1++ = *s2++;
+}
+
+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
+ */
+void Md5::init()
+{
+ buf[0] = 0x67452301;
+ buf[1] = 0xefcdab89;
+ buf[2] = 0x98badcfe;
+ buf[3] = 0x10325476;
+
+ bits[0] = 0;
+ bits[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void Md5::append(unsigned char *source, unsigned long len)
+{
+
+ // Update bitcount
+ unsigned long t = bits[0];
+ if ((bits[0] = t + ((unsigned long) len << 3)) < t)
+ bits[1]++;// Carry from low to high
+ bits[1] += len >> 29;
+
+ //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)
+ {
+ md5_memcpy(p, source, len);
+ return;
+ }
+ md5_memcpy(p, source, t);
+ //byteReverse(in, 16);
+ transform(buf, (unsigned long *) in);
+ source += t;
+ len -= t;
+ }
+
+ // Process data in 64-byte chunks
+ while (len >= 64)
+ {
+ md5_memcpy(in, source, 64);
+ //byteReverse(in, 16);
+ transform(buf, (unsigned long *) in);
+ source += 64;
+ len -= 64;
+ }
+
+ // Handle any remaining bytes of data.
+ md5_memcpy(in, source, len);
+}
+
+/*
+ * Update context to reflect the concatenation of another string
+ */
+void Md5::append(const DOMString &str)
+{
+ append((unsigned char *)str.c_str(), str.size());
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void Md5::finish(unsigned char *digest)
+{
+ // Compute number of bytes mod 64
+ unsigned int count = (bits[0] >> 3) & 0x3F;
+
+ // Set the first char of padding to 0x80.
+ // This is safe since there is always at least one byte free
+ unsigned char *p = in + count;
+ *p++ = 0x80;
+
+ // Bytes of padding needed to make 64 bytes
+ count = 64 - 1 - count;
+
+ // 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);
+ transform(buf, (unsigned long *) in);
+
+ // Now fill the next block with 56 bytes
+ md5_memset(in, 0, 56);
+ }
+ else
+ {
+ // Pad block to 56 bytes
+ md5_memset(p, 0, count - 8);
+ }
+ //byteReverse(in, 14);
+
+ // Append length in bits and transform
+ ((unsigned long *) in)[14] = bits[0];
+ ((unsigned long *) in)[15] = bits[1];
+
+ transform(buf, (unsigned long *) in);
+ //byteReverse((unsigned char *) buf, 4);
+ md5_memcpy(digest, buf, 16);
+ init(); // Security! ;-)
+}
+
+static char *md5hex = "0123456789abcdef";
+
+DOMString Md5::finishHex()
+{
+ unsigned char hashout[16];
+ finish(hashout);
+ DOMString ret;
+ for (int i=0 ; i<16 ; i++)
+ {
+ unsigned char ch = hashout[i];
+ ret.push_back(md5hex[ (ch>>4) & 15 ]);
+ ret.push_back(md5hex[ ch & 15 ]);
+ }
+ 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 F2(x, y, z) F1(z, x, y)
+#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.
+#define MD5STEP(f, w, x, y, z, data, s) \
+ ( 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
+ */
+void Md5::transform(unsigned long *buf, unsigned long *in)
+{
+ unsigned long a = buf[0];
+ unsigned long b = buf[1];
+ unsigned long c = buf[2];
+ unsigned long d = buf[3];
+
+ MD5STEP(F1, a, b, c, d, in[ 0] + 0xd76aa478, 7);
+ MD5STEP(F1, d, a, b, c, in[ 1] + 0xe8c7b756, 12);
+ MD5STEP(F1, c, d, a, b, in[ 2] + 0x242070db, 17);
+ MD5STEP(F1, b, c, d, a, in[ 3] + 0xc1bdceee, 22);
+ MD5STEP(F1, a, b, c, d, in[ 4] + 0xf57c0faf, 7);
+ MD5STEP(F1, d, a, b, c, in[ 5] + 0x4787c62a, 12);
+ MD5STEP(F1, c, d, a, b, in[ 6] + 0xa8304613, 17);
+ MD5STEP(F1, b, c, d, a, in[ 7] + 0xfd469501, 22);
+ MD5STEP(F1, a, b, c, d, in[ 8] + 0x698098d8, 7);
+ MD5STEP(F1, d, a, b, c, in[ 9] + 0x8b44f7af, 12);
+ MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+ MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+ MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+ MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+ MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+ MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+ MD5STEP(F2, a, b, c, d, in[ 1] + 0xf61e2562, 5);
+ MD5STEP(F2, d, a, b, c, in[ 6] + 0xc040b340, 9);
+ MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+ MD5STEP(F2, b, c, d, a, in[ 0] + 0xe9b6c7aa, 20);
+ MD5STEP(F2, a, b, c, d, in[ 5] + 0xd62f105d, 5);
+ MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+ MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+ MD5STEP(F2, b, c, d, a, in[ 4] + 0xe7d3fbc8, 20);
+ MD5STEP(F2, a, b, c, d, in[ 9] + 0x21e1cde6, 5);
+ MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+ MD5STEP(F2, c, d, a, b, in[ 3] + 0xf4d50d87, 14);
+ MD5STEP(F2, b, c, d, a, in[ 8] + 0x455a14ed, 20);
+ MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+ MD5STEP(F2, d, a, b, c, in[ 2] + 0xfcefa3f8, 9);
+ MD5STEP(F2, c, d, a, b, in[ 7] + 0x676f02d9, 14);
+ MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+ MD5STEP(F3, a, b, c, d, in[ 5] + 0xfffa3942, 4);
+ MD5STEP(F3, d, a, b, c, in[ 8] + 0x8771f681, 11);
+ MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+ MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+ MD5STEP(F3, a, b, c, d, in[ 1] + 0xa4beea44, 4);
+ MD5STEP(F3, d, a, b, c, in[ 4] + 0x4bdecfa9, 11);
+ MD5STEP(F3, c, d, a, b, in[ 7] + 0xf6bb4b60, 16);
+ MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+ MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+ MD5STEP(F3, d, a, b, c, in[ 0] + 0xeaa127fa, 11);
+ MD5STEP(F3, c, d, a, b, in[ 3] + 0xd4ef3085, 16);
+ MD5STEP(F3, b, c, d, a, in[ 6] + 0x04881d05, 23);
+ MD5STEP(F3, a, b, c, d, in[ 9] + 0xd9d4d039, 4);
+ MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+ MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+ MD5STEP(F3, b, c, d, a, in[ 2] + 0xc4ac5665, 23);
+
+ MD5STEP(F4, a, b, c, d, in[ 0] + 0xf4292244, 6);
+ MD5STEP(F4, d, a, b, c, in[ 7] + 0x432aff97, 10);
+ MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+ MD5STEP(F4, b, c, d, a, in[ 5] + 0xfc93a039, 21);
+ MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+ MD5STEP(F4, d, a, b, c, in[ 3] + 0x8f0ccc92, 10);
+ MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+ MD5STEP(F4, b, c, d, a, in[ 1] + 0x85845dd1, 21);
+ MD5STEP(F4, a, b, c, d, in[ 8] + 0x6fa87e4f, 6);
+ MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+ MD5STEP(F4, c, d, a, b, in[ 6] + 0xa3014314, 15);
+ MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+ MD5STEP(F4, a, b, c, d, in[ 4] + 0xf7537e82, 6);
+ MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+ MD5STEP(F4, c, d, a, b, in[ 2] + 0x2ad7d2bb, 15);
+ MD5STEP(F4, b, c, d, a, in[ 9] + 0xeb86d391, 21);
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
+
+
+
+
+
+
+
+
+
+
+//########################################################################
+//########################################################################
+//### T H R E A D
+//########################################################################
+//########################################################################
+
+
+
+
+
+#ifdef __WIN32__
+
+
+static DWORD WINAPI WinThreadFunction(LPVOID context)
+{
+ Thread *thread = (Thread *)context;
+ thread->execute();
+ return 0;
+}
+
+
+void Thread::start()
+{
+ DWORD dwThreadId;
+ HANDLE hThread = CreateThread(NULL, 0, WinThreadFunction,
+ (LPVOID)this, 0, &dwThreadId);
+ //Make sure the thread is started before 'this' is deallocated
+ while (!started)
+ sleep(10);
+ CloseHandle(hThread);
+}
+
+void Thread::sleep(unsigned long millis)
+{
+ Sleep(millis);
+}
+
+#else /* UNIX */
+
+
+void *PthreadThreadFunction(void *context)
+{
+ Thread *thread = (Thread *)context;
+ thread->execute();
+ return NULL;
+}
+
+
+void Thread::start()
+{
+ pthread_t thread;
+
+ int ret = pthread_create(&thread, NULL,
+ PthreadThreadFunction, (void *)this);
+ if (ret != 0)
+ printf("Thread::start: thread creation failed: %s\n", strerror(ret));
+
+ //Make sure the thread is started before 'this' is deallocated
+ while (!started)
+ sleep(10);
+
+}
+
+void Thread::sleep(unsigned long millis)
+{
+ timespec requested;
+ requested.tv_sec = millis / 1000;
+ requested.tv_nsec = (millis % 1000 ) * 1000000L;
+ nanosleep(&requested, NULL);
+}
+
+#endif
+
+
+
+
+
+
+
+
+//########################################################################
+//########################################################################
+//### S O C K E T
+//########################################################################
+//########################################################################
+
+
+
+
+
+//#########################################################################
+//# U T I L I T Y
+//#########################################################################
+
+static void mybzero(void *s, size_t n)
+{
+ unsigned char *p = (unsigned char *)s;
+ while (n > 0)
+ {
+ *p++ = (unsigned char)0;
+ n--;
+ }
+}
+
+static void mybcopy(void *src, void *dest, size_t 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
+//#########################################################################
+
+TcpSocket::TcpSocket()
+{
+ init();
+}
+
+
+TcpSocket::TcpSocket(const char *hostnameArg, int port)
+{
+ init();
+ hostname = hostnameArg;
+ portno = port;
+}
+
+TcpSocket::TcpSocket(const std::string &hostnameArg, int port)
+{
+ init();
+ hostname = hostnameArg;
+ portno = port;
+}
+
+
+#ifdef HAVE_SSL
+
+static void cryptoLockCallback(int mode, int type, const char *file, int line)
+{
+ //printf("########### LOCK\n");
+ static int modes[CRYPTO_NUM_LOCKS]; /* = {0, 0, ... } */
+ const char *errstr = NULL;
+
+ int rw = mode & (CRYPTO_READ|CRYPTO_WRITE);
+ if (!((rw == CRYPTO_READ) || (rw == CRYPTO_WRITE)))
+ {
+ errstr = "invalid mode";
+ goto err;
+ }
+
+ if (type < 0 || type >= CRYPTO_NUM_LOCKS)
+ {
+ errstr = "type out of bounds";
+ goto err;
+ }
+
+ if (mode & CRYPTO_LOCK)
+ {
+ if (modes[type])
+ {
+ errstr = "already locked";
+ /* must not happen in a single-threaded program
+ * (would deadlock)
+ */
+ goto err;
+ }
+
+ modes[type] = rw;
+ }
+ else if (mode & CRYPTO_UNLOCK)
+ {
+ if (!modes[type])
+ {
+ errstr = "not locked";
+ goto err;
+ }
+
+ if (modes[type] != rw)
+ {
+ errstr = (rw == CRYPTO_READ) ?
+ "CRYPTO_r_unlock on write lock" :
+ "CRYPTO_w_unlock on read lock";
+ }
+
+ modes[type] = 0;
+ }
+ else
+ {
+ errstr = "invalid mode";
+ goto err;
+ }
+
+ err:
+ if (errstr)
+ {
+ /* we cannot use bio_err here */
+ fprintf(stderr, "openssl (lock_dbg_cb): %s (mode=%d, type=%d) at %s:%d\n",
+ errstr, mode, type, file, line);
+ }
+}
+
+static unsigned long cryptoIdCallback()
+{
+#ifdef __WIN32__
+ unsigned long ret = (unsigned long) GetCurrentThreadId();
+#else
+ unsigned long ret = (unsigned long) pthread_self();
+#endif
+ return ret;
+}
+
+#endif
+
+
+TcpSocket::TcpSocket(const TcpSocket &other)
+{
+ init();
+ sock = other.sock;
+ hostname = other.hostname;
+ portno = other.portno;
+}
+
+static bool tcp_socket_inited = false;
+
+void TcpSocket::init()
+{
+ if (!tcp_socket_inited)
+ {
+#ifdef __WIN32__
+ WORD wVersionRequested = MAKEWORD( 2, 2 );
+ WSADATA wsaData;
+ WSAStartup( wVersionRequested, &wsaData );
+#endif
+#ifdef HAVE_SSL
+ sslStream = NULL;
+ sslContext = NULL;
+ CRYPTO_set_locking_callback(cryptoLockCallback);
+ CRYPTO_set_id_callback(cryptoIdCallback);
+ SSL_library_init();
+ SSL_load_error_strings();
+#endif
+ tcp_socket_inited = true;
+ }
+ sock = -1;
+ connected = false;
+ hostname = "";
+ portno = -1;
+ sslEnabled = false;
+ receiveTimeout = 0;
+}
+
+TcpSocket::~TcpSocket()
+{
+ disconnect();
+}
+
+bool TcpSocket::isConnected()
+{
+ if (!connected || sock < 0)
+ return false;
+ return true;
+}
+
+void TcpSocket::enableSSL(bool val)
+{
+ sslEnabled = val;
+}
+
+bool TcpSocket::getEnableSSL()
+{
+ return sslEnabled;
+}
+
+
+bool TcpSocket::connect(const char *hostnameArg, int portnoArg)
+{
+ hostname = hostnameArg;
+ portno = portnoArg;
+ return connect();
+}
+
+bool TcpSocket::connect(const std::string &hostnameArg, int portnoArg)
+{
+ hostname = hostnameArg;
+ portno = portnoArg;
+ 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
+
+
+bool TcpSocket::startTls()
+{
+#ifdef HAVE_SSL
+ sslStream = NULL;
+ sslContext = NULL;
+
+ //SSL_METHOD *meth = SSLv23_method();
+ //SSL_METHOD *meth = SSLv3_client_method();
+ SSL_METHOD *meth = TLSv1_client_method();
+ sslContext = SSL_CTX_new(meth);
+ //SSL_CTX_set_info_callback(sslContext, infoCallback);
+
+#if 0
+ 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;
+ }
+#endif
+
+ /* Connect the SSL socket */
+ sslStream = SSL_new(sslContext);
+ SSL_set_fd(sslStream, sock);
+
+ int ret = SSL_connect(sslStream);
+ if (ret == 0)
+ {
+ fprintf(stderr, "SSL connection not successful\n");
+ disconnect();
+ return false;
+ }
+ else if (ret < 0)
+ {
+ int err = SSL_get_error(sslStream, ret);
+ fprintf(stderr, "SSL connect error %d\n", err);
+ disconnect();
+ return false;
+ }
+
+ sslEnabled = true;
+#endif /*HAVE_SSL*/
+ return true;
+}
+
+
+bool TcpSocket::connect()
+{
+ if (hostname.size()<1)
+ {
+ fprintf(stderr, "open: null hostname\n");
+ return false;
+ }
+
+ if (portno<1)
+ {
+ fprintf(stderr, "open: bad port number\n");
+ return false;
+ }
+
+ sock = socket(PF_INET, SOCK_STREAM, 0);
+ if (sock < 0)
+ {
+ fprintf(stderr, "open: error creating socket\n");
+ return false;
+ }
+
+ char *c_hostname = (char *)hostname.c_str();
+ struct hostent *server = gethostbyname(c_hostname);
+ if (!server)
+ {
+ fprintf(stderr, "open: could not locate host '%s'\n", c_hostname);
+ return false;
+ }
+
+ struct sockaddr_in serv_addr;
+ mybzero((char *) &serv_addr, sizeof(serv_addr));
+ serv_addr.sin_family = AF_INET;
+ mybcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr,
+ server->h_length);
+ serv_addr.sin_port = htons(portno);
+
+ int ret = ::connect(sock, (const sockaddr *)&serv_addr, sizeof(serv_addr));
+ if (ret < 0)
+ {
+ fprintf(stderr, "open: could not connect to host '%s'\n", c_hostname);
+ return false;
+ }
+
+ if (sslEnabled)
+ {
+ if (!startTls())
+ return false;
+ }
+ connected = true;
+ return true;
+}
+
+bool TcpSocket::disconnect()
+{
+ bool ret = true;
+ connected = false;
+#ifdef HAVE_SSL
+ 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;
+ }
+ SSL_free(sslStream);
+ }
+ if (sslContext)
+ SSL_CTX_free(sslContext);
+ }
+ sslStream = NULL;
+ sslContext = NULL;
+#endif /*HAVE_SSL*/
+
+#ifdef __WIN32__
+ closesocket(sock);
+#else
+ ::close(sock);
+#endif
+ sock = -1;
+ sslEnabled = false;
+
+ return ret;
+}
+
+
+
+bool TcpSocket::setReceiveTimeout(unsigned long millis)
+{
+ receiveTimeout = millis;
+ 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.
+ */
+long TcpSocket::available()
+{
+ if (!isConnected())
+ return -1;
+
+ long count = 0;
+#ifdef __WIN32__
+ if (ioctlsocket(sock, FIONREAD, (unsigned long *)&count) != 0)
+ return -1;
+#else
+ if (ioctl(sock, FIONREAD, &count) != 0)
+ return -1;
+#endif
+ if (count<=0 && sslEnabled)
+ {
+#ifdef HAVE_SSL
+ return SSL_pending(sslStream);
+#endif
+ }
+ return count;
+}
+
+
+
+bool TcpSocket::write(int ch)
+{
+ if (!isConnected())
+ {
+ fprintf(stderr, "write: socket closed\n");
+ return false;
+ }
+ unsigned char c = (unsigned char)ch;
+
+ if (sslEnabled)
+ {
+#ifdef HAVE_SSL
+ int r = SSL_write(sslStream, &c, 1);
+ if (r<=0)
+ {
+ switch(SSL_get_error(sslStream, r))
+ {
+ default:
+ fprintf(stderr, "SSL write problem");
+ return -1;
+ }
+ }
+#endif
+ }
+ else
+ {
+ if (send(sock, (const char *)&c, 1, 0) < 0)
+ //if (send(sock, &c, 1, 0) < 0)
+ {
+ fprintf(stderr, "write: could not send data\n");
+ return false;
+ }
+ }
+ return true;
+}
+
+bool TcpSocket::write(char *str)
+{
+ if (!isConnected())
+ {
+ fprintf(stderr, "write(str): socket closed\n");
+ return false;
+ }
+ int len = strlen(str);
+
+ if (sslEnabled)
+ {
+#ifdef HAVE_SSL
+ int r = SSL_write(sslStream, (unsigned char *)str, len);
+ if (r<=0)
+ {
+ switch(SSL_get_error(sslStream, r))
+ {
+ default:
+ fprintf(stderr, "SSL write problem");
+ return -1;
+ }
+ }
+#endif
+ }
+ else
+ {
+ if (send(sock, str, len, 0) < 0)
+ //if (send(sock, &c, 1, 0) < 0)
+ {
+ fprintf(stderr, "write: could not send data\n");
+ return false;
+ }
+ }
+ return true;
+}
+
+bool TcpSocket::write(const std::string &str)
+{
+ return write((char *)str.c_str());
+}
+
+int TcpSocket::read()
+{
+ 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)
+ {
+ int avail = available();
+ if (avail > 0)
+ break;
+ if (tim >= receiveTimeout)
+ return -2;
+ Thread::sleep(20);
+ tim += 20;
+ }
+ }
+
+ //check again
+ if (!isConnected())
+ return -1;
+
+ unsigned char ch;
+ if (sslEnabled)
+ {
+#ifdef HAVE_SSL
+ if (!sslStream)
+ return -1;
+ int r = SSL_read(sslStream, &ch, 1);
+ unsigned long err = SSL_get_error(sslStream, r);
+ switch (err)
+ {
+ case SSL_ERROR_NONE:
+ break;
+ case SSL_ERROR_ZERO_RETURN:
+ return -1;
+ case SSL_ERROR_SYSCALL:
+ fprintf(stderr, "SSL read problem(syscall) %s\n",
+ ERR_error_string(ERR_get_error(), NULL));
+ return -1;
+ default:
+ fprintf(stderr, "SSL read problem %s\n",
+ ERR_error_string(ERR_get_error(), NULL));
+ return -1;
+ }
+#endif
+ }
+ else
+ {
+ if (recv(sock, (char *)&ch, 1, 0) <= 0)
+ {
+ fprintf(stderr, "read: could not receive data\n");
+ disconnect();
+ return -1;
+ }
+ }
+ return (int)ch;
+}
+
+std::string TcpSocket::readLine()
+{
+ std::string ret;
+
+ while (isConnected())
+ {
+ int ch = read();
+ if (ch<0)
+ return ret;
+ if (ch=='\r' || ch=='\n')
+ return ret;
+ ret.push_back((char)ch);
+ }
+
+ return ret;
+}
+
+
+
+
+
+
+
+
+
+} //namespace Pedro
+//########################################################################
+//# E N D O F F I L E
+//########################################################################
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pedro/pedroutil.h b/src/pedro/pedroutil.h
--- /dev/null
+++ b/src/pedro/pedroutil.h
@@ -0,0 +1,493 @@
+#ifndef __PEDROUTIL_H__
+#define __PEDROUTIL_H__
+/*
+ * Support classes for the Pedro mini-XMPP client.
+ *
+ * Authors:
+ * Bob Jamison
+ *
+ * Copyright (C) 2006 Bob Jamison
+ *
+ * This library is free software; you can redistribute it and/or
+ * 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 <vector>
+
+#include <string>
+
+#include "pedrodom.h"
+
+
+#ifdef HAVE_SSL
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#endif
+
+
+
+namespace Pedro
+{
+
+
+
+
+//########################################################################
+//########################################################################
+//# B A S E 6 4
+//########################################################################
+//########################################################################
+
+
+//#################
+//# ENCODER
+//#################
+
+
+/**
+ * This class is for Base-64 encoding
+ */
+class Base64Encoder
+{
+
+public:
+
+ Base64Encoder()
+ {
+ reset();
+ }
+
+ virtual ~Base64Encoder()
+ {}
+
+ virtual void reset()
+ {
+ outBuf = 0L;
+ bitCount = 0;
+ buf = "";
+ }
+
+ virtual void append(int ch);
+
+ virtual void append(char *str);
+
+ virtual void append(unsigned char *str, int len);
+
+ virtual void append(const DOMString &str);
+
+ virtual DOMString finish();
+
+ static DOMString encode(const DOMString &str);
+
+
+private:
+
+
+ unsigned long outBuf;
+
+ int bitCount;
+
+ DOMString buf;
+
+};
+
+
+
+
+//#################
+//# DECODER
+//#################
+
+class Base64Decoder
+{
+public:
+ Base64Decoder()
+ {
+ reset();
+ }
+
+ virtual ~Base64Decoder()
+ {}
+
+ virtual void reset()
+ {
+ inCount = 0;
+ buf.clear();
+ }
+
+
+ virtual void append(int ch);
+
+ virtual void append(char *str);
+
+ virtual void append(const DOMString &str);
+
+ std::vector<unsigned char> finish();
+
+ static std::vector<unsigned char> decode(const DOMString &str);
+
+ static DOMString decodeToString(const DOMString &str);
+
+private:
+
+ int inBytes[4];
+ int inCount;
+ std::vector<unsigned char> buf;
+};
+
+
+
+
+//########################################################################
+//########################################################################
+//### S H A 1 H A S H I N G
+//########################################################################
+//########################################################################
+
+/**
+ *
+ */
+class Sha1
+{
+public:
+
+ /**
+ *
+ */
+ Sha1()
+ { init(); }
+
+ /**
+ *
+ */
+ virtual ~Sha1()
+ {}
+
+
+ /**
+ * Static convenience method. This would be the most commonly used
+ * version;
+ * @parm digest points to a bufer of 20 unsigned chars
+ */
+ static void hash(unsigned char *dataIn, int len, unsigned char *digest);
+
+ /**
+ * Static convenience method. This will fill a string with the hex
+ * codex string.
+ */
+ static DOMString hashHex(unsigned char *dataIn, int len);
+
+ /**
+ * Initialize the context (also zeroizes contents)
+ */
+ virtual void init();
+
+ /**
+ *
+ */
+ virtual void append(unsigned char *dataIn, int len);
+
+ /**
+ *
+ * @parm digest points to a bufer of 20 unsigned chars
+ */
+ virtual void finish(unsigned char *digest);
+
+
+private:
+
+ void hashblock();
+
+ unsigned long H[5];
+ unsigned long W[80];
+ unsigned long sizeHi,sizeLo;
+ int lenW;
+
+};
+
+
+
+
+
+//########################################################################
+//########################################################################
+//### M D 5 H A S H I N G
+//########################################################################
+//########################################################################
+
+/**
+ *
+ */
+class Md5
+{
+public:
+
+ /**
+ *
+ */
+ Md5()
+ { init(); }
+
+ /**
+ *
+ */
+ virtual ~Md5()
+ {}
+
+ /**
+ * Static convenience method.
+ * @parm digest points to an buffer of 16 unsigned chars
+ */
+ static void hash(unsigned char *dataIn,
+ unsigned long len, unsigned char *digest);
+
+ static DOMString hashHex(unsigned char *dataIn, unsigned long len);
+
+ /**
+ * Initialize the context (also zeroizes contents)
+ */
+ virtual void init();
+
+ /**
+ *
+ */
+ virtual void append(unsigned char *dataIn, unsigned long len);
+
+ /**
+ *
+ */
+ virtual void append(const DOMString &str);
+
+ /**
+ * Finalize and output the hash.
+ * @parm digest points to an buffer of 16 unsigned chars
+ */
+ virtual void finish(unsigned char *digest);
+
+
+ /**
+ * Same as above , but hex to an output String
+ */
+ virtual DOMString finishHex();
+
+private:
+
+ void transform(unsigned long *buf, unsigned long *in);
+
+ unsigned long buf[4];
+ unsigned long bits[2];
+ unsigned char in[64];
+
+};
+
+
+
+
+
+
+
+//########################################################################
+//########################################################################
+//### T H R E A D
+//########################################################################
+//########################################################################
+
+
+
+/**
+ * This is the interface for a delegate class which can
+ * be run by a Thread.
+ * Thread thread(runnable);
+ * thread.start();
+ */
+class Runnable
+{
+public:
+
+ Runnable()
+ {}
+ virtual ~Runnable()
+ {}
+
+ /**
+ * The method of a delegate class which can
+ * be run by a Thread. Thread is completed when this
+ * method is done.
+ */
+ virtual void run() = 0;
+
+};
+
+
+
+/**
+ * A simple wrapper of native threads in a portable class.
+ * It can be used either to execute its own run() method, or
+ * delegate to a Runnable class's run() method.
+ */
+class Thread
+{
+public:
+
+ /**
+ * Create a thread which will execute its own run() method.
+ */
+ Thread()
+ { runnable = NULL ; started = false; }
+
+ /**
+ * Create a thread which will run a Runnable class's run() method.
+ */
+ Thread(const Runnable &runner)
+ { runnable = (Runnable *)&runner; started = false; }
+
+ /**
+ * This does not kill a spawned thread.
+ */
+ virtual ~Thread()
+ {}
+
+ /**
+ * Static method to pause the current thread for a given
+ * number of milliseconds.
+ */
+ static void sleep(unsigned long millis);
+
+ /**
+ * This method will be executed if the Thread was created with
+ * no delegated Runnable class. The thread is completed when
+ * the method is done.
+ */
+ virtual void run()
+ {}
+
+ /**
+ * Starts the thread.
+ */
+ virtual void start();
+
+ /**
+ * Calls either this class's run() method, or that of a Runnable.
+ * A user would normally not call this directly.
+ */
+ virtual void execute()
+ {
+ started = true;
+ if (runnable)
+ runnable->run();
+ else
+ run();
+ }
+
+private:
+
+ Runnable *runnable;
+
+ bool started;
+
+};
+
+
+
+
+
+
+//########################################################################
+//########################################################################
+//### S O C K E T
+//########################################################################
+//########################################################################
+
+
+
+/**
+ * A socket wrapper that provides cross-platform capability, plus SSL
+ */
+class TcpSocket
+{
+public:
+
+ TcpSocket();
+
+ TcpSocket(const std::string &hostname, int port);
+
+ TcpSocket(const char *hostname, int port);
+
+ TcpSocket(const TcpSocket &other);
+
+ virtual ~TcpSocket();
+
+ bool isConnected();
+
+ void enableSSL(bool val);
+
+ bool getEnableSSL();
+
+ bool connect(const std::string &hostname, int portno);
+
+ bool connect(const char *hostname, int portno);
+
+ bool startTls();
+
+ bool connect();
+
+ bool disconnect();
+
+ bool setReceiveTimeout(unsigned long millis);
+
+ long available();
+
+ bool write(int ch);
+
+ bool write(char *str);
+
+ bool write(const std::string &str);
+
+ int read();
+
+ std::string readLine();
+
+private:
+ void init();
+
+ std::string hostname;
+ int portno;
+ int sock;
+ bool connected;
+
+ bool sslEnabled;
+
+ unsigned long receiveTimeout;
+
+#ifdef HAVE_SSL
+ SSL_CTX *sslContext;
+ SSL *sslStream;
+#endif
+
+};
+
+
+
+
+
+
+} //namespace Pedro
+
+#endif /* __PEDROUTIL_H__ */
+
+//########################################################################
+//# E N D O F F I L E
+//########################################################################
+
index 1f137850f353a22dbb2212e9f8bea9a62578aa36..30070c4347bab10308b0395f1173b393d852b953 100644 (file)
--- a/src/pedro/pedroxmpp.cpp
+++ b/src/pedro/pedroxmpp.cpp
#include "pedroxmpp.h"
#include "pedrodom.h"
+#include "pedroutil.h"
#include <map>
-#ifdef __WIN32__
-
-#include <windows.h>
-
-#else /* UNIX */
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netdb.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-
-#include <pthread.h>
-
-#endif /* UNIX */
-
-
-#ifdef HAVE_SSL
-#include <openssl/ssl.h>
-#include <openssl/err.h>
-#endif
namespace Pedro
{
-
-
-
-//########################################################################
-//########################################################################
-//# B A S E 6 4
-//########################################################################
-//########################################################################
-
-
-//#################
-//# ENCODER
-//#################
-
-
-static char *base64encode =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-
-/**
- * This class is for Base-64 encoding
- */
-class Base64Encoder
-{
-
-public:
-
- Base64Encoder()
- {
- reset();
- }
-
- virtual ~Base64Encoder()
- {}
-
- virtual void reset()
- {
- outBuf = 0L;
- bitCount = 0;
- buf = "";
- }
-
- virtual void append(int ch);
-
- virtual void append(char *str);
-
- virtual void append(unsigned char *str, int len);
-
- virtual void append(const DOMString &str);
-
- virtual DOMString finish();
-
- static DOMString encode(const DOMString &str);
-
-
-private:
-
-
- unsigned long outBuf;
-
- int bitCount;
-
- DOMString buf;
-
-};
-
-
-
-/**
- * Writes the specified byte to the output buffer
- */
-void Base64Encoder::append(int ch)
-{
- outBuf <<= 8;
- outBuf |= (ch & 0xff);
- bitCount += 8;
- if (bitCount >= 24)
- {
- int indx = (int)((outBuf & 0x00fc0000L) >> 18);
- int obyte = (int)base64encode[indx & 63];
- buf.push_back(obyte);
-
- indx = (int)((outBuf & 0x0003f000L) >> 12);
- obyte = (int)base64encode[indx & 63];
- buf.push_back(obyte);
-
- indx = (int)((outBuf & 0x00000fc0L) >> 6);
- obyte = (int)base64encode[indx & 63];
- buf.push_back(obyte);
-
- indx = (int)((outBuf & 0x0000003fL) );
- obyte = (int)base64encode[indx & 63];
- buf.push_back(obyte);
-
- bitCount = 0;
- outBuf = 0L;
- }
-}
-
-/**
- * Writes the specified string to the output buffer
- */
-void Base64Encoder::append(char *str)
-{
- while (*str)
- append((int)*str++);
-}
-
-/**
- * Writes the specified string to the output buffer
- */
-void Base64Encoder::append(unsigned char *str, int len)
-{
- while (len>0)
- {
- append((int)*str++);
- len--;
- }
-}
-
-/**
- * Writes the specified string to the output buffer
- */
-void Base64Encoder::append(const DOMString &str)
-{
- append((char *)str.c_str());
-}
-
-/**
- * Closes this output stream and releases any system resources
- * associated with this stream.
- */
-DOMString Base64Encoder::finish()
-{
- //get any last bytes (1 or 2) out of the buffer
- if (bitCount == 16)
- {
- outBuf <<= 2; //pad to make 18 bits
-
- int indx = (int)((outBuf & 0x0003f000L) >> 12);
- int obyte = (int)base64encode[indx & 63];
- buf.push_back(obyte);
-
- indx = (int)((outBuf & 0x00000fc0L) >> 6);
- obyte = (int)base64encode[indx & 63];
- buf.push_back(obyte);
-
- indx = (int)((outBuf & 0x0000003fL) );
- obyte = (int)base64encode[indx & 63];
- buf.push_back(obyte);
-
- buf.push_back('=');
- }
- else if (bitCount == 8)
- {
- outBuf <<= 4; //pad to make 12 bits
-
- int indx = (int)((outBuf & 0x00000fc0L) >> 6);
- int obyte = (int)base64encode[indx & 63];
- buf.push_back(obyte);
-
- indx = (int)((outBuf & 0x0000003fL) );
- obyte = (int)base64encode[indx & 63];
- buf.push_back(obyte);
-
- buf.push_back('=');
- buf.push_back('=');
- }
-
- DOMString ret = buf;
- reset();
- return ret;
-}
-
-
-DOMString Base64Encoder::encode(const DOMString &str)
-{
- Base64Encoder encoder;
- encoder.append(str);
- DOMString ret = encoder.finish();
- 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
-};
-
-class Base64Decoder
-{
-public:
- Base64Decoder()
- {
- reset();
- }
-
- virtual ~Base64Decoder()
- {}
-
- virtual void reset()
- {
- inCount = 0;
- buf.clear();
- }
-
-
- virtual void append(int ch);
-
- virtual void append(char *str);
-
- virtual void append(const DOMString &str);
-
- std::vector<unsigned char> finish();
-
- static std::vector<unsigned char> decode(const DOMString &str);
-
- static DOMString decodeToString(const DOMString &str);
-
-private:
-
- int inBytes[4];
- int inCount;
- std::vector<unsigned char> buf;
-};
-
-/**
- * Appends one char to the decoder
- */
-void Base64Decoder::append(int ch)
-{
- if (isspace(ch))
- return;
- else if (ch == '=') //padding
- {
- inBytes[inCount++] = 0;
- }
- else
- {
- int byteVal = base64decode[ch & 0x7f];
- //printf("char:%c %d\n", ch, byteVal);
- if (byteVal < 0)
- {
- //Bad lookup value
- }
- inBytes[inCount++] = byteVal;
- }
-
- if (inCount >=4 )
- {
- unsigned char b0 = ((inBytes[0]<<2) & 0xfc) | ((inBytes[1]>>4) & 0x03);
- unsigned char b1 = ((inBytes[1]<<4) & 0xf0) | ((inBytes[2]>>2) & 0x0f);
- unsigned char b2 = ((inBytes[2]<<6) & 0xc0) | ((inBytes[3] ) & 0x3f);
- buf.push_back(b0);
- buf.push_back(b1);
- buf.push_back(b2);
- inCount = 0;
- }
-
-}
-
-void Base64Decoder::append(char *str)
-{
- while (*str)
- append((int)*str++);
-}
-
-void Base64Decoder::append(const DOMString &str)
-{
- append((char *)str.c_str());
-}
-
-std::vector<unsigned char> Base64Decoder::finish()
-{
- std::vector<unsigned char> ret = buf;
- reset();
- return ret;
-}
-
-std::vector<unsigned char> Base64Decoder::decode(const DOMString &str)
-{
- Base64Decoder decoder;
- decoder.append(str);
- std::vector<unsigned char> ret = decoder.finish();
- return ret;
-}
-
-DOMString Base64Decoder::decodeToString(const DOMString &str)
-{
- Base64Decoder decoder;
- decoder.append(str);
- std::vector<unsigned char> ret = decoder.finish();
- DOMString buf;
- for (unsigned int i=0 ; i<ret.size() ; i++)
- buf.push_back(ret[i]);
- return buf;
-}
-
-
-
-
-
-
-
-//########################################################################
-//########################################################################
-//### S H A 1 H A S H I N G
-//########################################################################
-//########################################################################
-
-/**
- *
- */
-class Sha1
-{
-public:
-
- /**
- *
- */
- Sha1()
- { init(); }
-
- /**
- *
- */
- virtual ~Sha1()
- {}
-
-
- /**
- * Static convenience method. This would be the most commonly used
- * version;
- * @parm digest points to a bufer of 20 unsigned chars
- */
- static void hash(unsigned char *dataIn, int len, unsigned char *digest);
-
- /**
- * Static convenience method. This will fill a string with the hex
- * codex string.
- */
- static DOMString hashHex(unsigned char *dataIn, int len);
-
- /**
- * Initialize the context (also zeroizes contents)
- */
- virtual void init();
-
- /**
- *
- */
- virtual void append(unsigned char *dataIn, int len);
-
- /**
- *
- * @parm digest points to a bufer of 20 unsigned chars
- */
- virtual void finish(unsigned char *digest);
-
-
-private:
-
- void hashblock();
-
- unsigned long H[5];
- unsigned long W[80];
- unsigned long sizeHi,sizeLo;
- int lenW;
-
-};
-
-
-
-void Sha1::hash(unsigned char *dataIn, int len, unsigned char *digest)
-{
- Sha1 sha1;
- sha1.append(dataIn, len);
- sha1.finish(digest);
-}
-
-static char *sha1hex = "0123456789abcdef";
-
-DOMString Sha1::hashHex(unsigned char *dataIn, int len)
-{
- unsigned char hashout[20];
- hash(dataIn, len, hashout);
- DOMString ret;
- for (int i=0 ; i<20 ; i++)
- {
- unsigned char ch = hashout[i];
- ret.push_back(sha1hex[ (ch>>4) & 15 ]);
- ret.push_back(sha1hex[ ch & 15 ]);
- }
- return ret;
-}
-
-
-void Sha1::init()
-{
-
- 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;
-}
-
-
-void Sha1::append(unsigned char *dataIn, int len)
-{
- // Read the data into W and process blocks as they get full
- for (int i = 0; i < len; i++)
- {
- W[lenW / 4] <<= 8;
- W[lenW / 4] |= (unsigned long)dataIn[i];
- if ((++lenW) % 64 == 0)
- {
- hashblock();
- lenW = 0;
- }
- sizeLo += 8;
- sizeHi += (sizeLo < 8);
- }
-}
-
-
-void Sha1::finish(unsigned char hashout[20])
-{
- unsigned char pad0x80 = 0x80;
- unsigned char pad0x00 = 0x00;
- unsigned char padlen[8];
-
- // Pad with a binary 1 (e.g. 0x80), then zeroes, then length
- padlen[0] = (unsigned char)((sizeHi >> 24) & 255);
- padlen[1] = (unsigned char)((sizeHi >> 16) & 255);
- padlen[2] = (unsigned char)((sizeHi >> 8) & 255);
- padlen[3] = (unsigned char)((sizeHi >> 0) & 255);
- padlen[4] = (unsigned char)((sizeLo >> 24) & 255);
- padlen[5] = (unsigned char)((sizeLo >> 16) & 255);
- padlen[6] = (unsigned char)((sizeLo >> 8) & 255);
- padlen[7] = (unsigned char)((sizeLo >> 0) & 255);
-
- append(&pad0x80, 1);
-
- while (lenW != 56)
- append(&pad0x00, 1);
- append(padlen, 8);
-
- // Output hash
- for (int i = 0; i < 20; i++)
- {
- hashout[i] = (unsigned char)(H[i / 4] >> 24);
- H[i / 4] <<= 8;
- }
-
- // Re-initialize the context (also zeroizes contents)
- init();
-}
-
-
-#define SHA_ROTL(X,n) ((((X) << (n)) | ((X) >> (32-(n)))) & 0xffffffffL)
-
-void Sha1::hashblock()
-{
-
- for (int t = 16; t <= 79; t++)
- W[t] = SHA_ROTL(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16], 1);
-
- 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++)
- {
- TEMP = (SHA_ROTL(A,5) + (((C^D)&B)^D) +
- E + W[t] + 0x5a827999L) & 0xffffffffL;
- E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP;
- }
- for (int t = 20; t <= 39; t++)
- {
- TEMP = (SHA_ROTL(A,5) + (B^C^D) +
- E + W[t] + 0x6ed9eba1L) & 0xffffffffL;
- E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP;
- }
- for (int t = 40; t <= 59; t++)
- {
- TEMP = (SHA_ROTL(A,5) + ((B&C)|(D&(B|C))) +
- E + W[t] + 0x8f1bbcdcL) & 0xffffffffL;
- E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP;
- }
- for (int t = 60; t <= 79; t++)
- {
- TEMP = (SHA_ROTL(A,5) + (B^C^D) +
- E + W[t] + 0xca62c1d6L) & 0xffffffffL;
- E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP;
- }
-
- 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
-//########################################################################
-//########################################################################
-
-/**
- *
- */
-class Md5
-{
-public:
-
- /**
- *
- */
- Md5()
- { init(); }
-
- /**
- *
- */
- virtual ~Md5()
- {}
-
- /**
- * Static convenience method.
- * @parm digest points to an buffer of 16 unsigned chars
- */
- static void hash(unsigned char *dataIn,
- unsigned long len, unsigned char *digest);
-
- static DOMString hashHex(unsigned char *dataIn, unsigned long len);
-
- /**
- * Initialize the context (also zeroizes contents)
- */
- virtual void init();
-
- /**
- *
- */
- virtual void append(unsigned char *dataIn, unsigned long len);
-
- /**
- *
- */
- virtual void append(const DOMString &str);
-
- /**
- * Finalize and output the hash.
- * @parm digest points to an buffer of 16 unsigned chars
- */
- virtual void finish(unsigned char *digest);
-
-
- /**
- * Same as above , but hex to an output String
- */
- virtual DOMString finishHex();
-
-private:
-
- void transform(unsigned long *buf, unsigned long *in);
-
- unsigned long buf[4];
- unsigned long bits[2];
- unsigned char in[64];
-
-};
-
-
-
-
-void Md5::hash(unsigned char *dataIn, unsigned long len, unsigned char *digest)
-{
- Md5 md5;
- md5.append(dataIn, len);
- md5.finish(digest);
-}
-
-DOMString Md5::hashHex(unsigned char *dataIn, unsigned long len)
-{
- Md5 md5;
- md5.append(dataIn, len);
- DOMString ret = md5.finishHex();
- 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);
-}
-*/
-
-static void md5_memcpy(void *dest, void *src, int n)
-{
- unsigned char *s1 = (unsigned char *)dest;
- unsigned char *s2 = (unsigned char *)src;
- while (n--)
- *s1++ = *s2++;
-}
-
-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
- */
-void Md5::init()
-{
- buf[0] = 0x67452301;
- buf[1] = 0xefcdab89;
- buf[2] = 0x98badcfe;
- buf[3] = 0x10325476;
-
- bits[0] = 0;
- bits[1] = 0;
-}
-
-/*
- * Update context to reflect the concatenation of another buffer full
- * of bytes.
- */
-void Md5::append(unsigned char *source, unsigned long len)
-{
-
- // Update bitcount
- unsigned long t = bits[0];
- if ((bits[0] = t + ((unsigned long) len << 3)) < t)
- bits[1]++;// Carry from low to high
- bits[1] += len >> 29;
-
- //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)
- {
- md5_memcpy(p, source, len);
- return;
- }
- md5_memcpy(p, source, t);
- //byteReverse(in, 16);
- transform(buf, (unsigned long *) in);
- source += t;
- len -= t;
- }
-
- // Process data in 64-byte chunks
- while (len >= 64)
- {
- md5_memcpy(in, source, 64);
- //byteReverse(in, 16);
- transform(buf, (unsigned long *) in);
- source += 64;
- len -= 64;
- }
-
- // Handle any remaining bytes of data.
- md5_memcpy(in, source, len);
-}
-
-/*
- * Update context to reflect the concatenation of another string
- */
-void Md5::append(const DOMString &str)
-{
- append((unsigned char *)str.c_str(), str.size());
-}
-
-/*
- * Final wrapup - pad to 64-byte boundary with the bit pattern
- * 1 0* (64-bit count of bits processed, MSB-first)
- */
-void Md5::finish(unsigned char *digest)
-{
- // Compute number of bytes mod 64
- unsigned int count = (bits[0] >> 3) & 0x3F;
-
- // Set the first char of padding to 0x80.
- // This is safe since there is always at least one byte free
- unsigned char *p = in + count;
- *p++ = 0x80;
-
- // Bytes of padding needed to make 64 bytes
- count = 64 - 1 - count;
-
- // 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);
- transform(buf, (unsigned long *) in);
-
- // Now fill the next block with 56 bytes
- md5_memset(in, 0, 56);
- }
- else
- {
- // Pad block to 56 bytes
- md5_memset(p, 0, count - 8);
- }
- //byteReverse(in, 14);
-
- // Append length in bits and transform
- ((unsigned long *) in)[14] = bits[0];
- ((unsigned long *) in)[15] = bits[1];
-
- transform(buf, (unsigned long *) in);
- //byteReverse((unsigned char *) buf, 4);
- md5_memcpy(digest, buf, 16);
- init(); // Security! ;-)
-}
-
-static char *md5hex = "0123456789abcdef";
-
-DOMString Md5::finishHex()
-{
- unsigned char hashout[16];
- finish(hashout);
- DOMString ret;
- for (int i=0 ; i<16 ; i++)
- {
- unsigned char ch = hashout[i];
- ret.push_back(md5hex[ (ch>>4) & 15 ]);
- ret.push_back(md5hex[ ch & 15 ]);
- }
- 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 F2(x, y, z) F1(z, x, y)
-#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.
-#define MD5STEP(f, w, x, y, z, data, s) \
- ( 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
- */
-void Md5::transform(unsigned long *buf, unsigned long *in)
-{
- unsigned long a = buf[0];
- unsigned long b = buf[1];
- unsigned long c = buf[2];
- unsigned long d = buf[3];
-
- MD5STEP(F1, a, b, c, d, in[ 0] + 0xd76aa478, 7);
- MD5STEP(F1, d, a, b, c, in[ 1] + 0xe8c7b756, 12);
- MD5STEP(F1, c, d, a, b, in[ 2] + 0x242070db, 17);
- MD5STEP(F1, b, c, d, a, in[ 3] + 0xc1bdceee, 22);
- MD5STEP(F1, a, b, c, d, in[ 4] + 0xf57c0faf, 7);
- MD5STEP(F1, d, a, b, c, in[ 5] + 0x4787c62a, 12);
- MD5STEP(F1, c, d, a, b, in[ 6] + 0xa8304613, 17);
- MD5STEP(F1, b, c, d, a, in[ 7] + 0xfd469501, 22);
- MD5STEP(F1, a, b, c, d, in[ 8] + 0x698098d8, 7);
- MD5STEP(F1, d, a, b, c, in[ 9] + 0x8b44f7af, 12);
- MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
- MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
- MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
- MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
- MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
- MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
-
- MD5STEP(F2, a, b, c, d, in[ 1] + 0xf61e2562, 5);
- MD5STEP(F2, d, a, b, c, in[ 6] + 0xc040b340, 9);
- MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
- MD5STEP(F2, b, c, d, a, in[ 0] + 0xe9b6c7aa, 20);
- MD5STEP(F2, a, b, c, d, in[ 5] + 0xd62f105d, 5);
- MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
- MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
- MD5STEP(F2, b, c, d, a, in[ 4] + 0xe7d3fbc8, 20);
- MD5STEP(F2, a, b, c, d, in[ 9] + 0x21e1cde6, 5);
- MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
- MD5STEP(F2, c, d, a, b, in[ 3] + 0xf4d50d87, 14);
- MD5STEP(F2, b, c, d, a, in[ 8] + 0x455a14ed, 20);
- MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
- MD5STEP(F2, d, a, b, c, in[ 2] + 0xfcefa3f8, 9);
- MD5STEP(F2, c, d, a, b, in[ 7] + 0x676f02d9, 14);
- MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
-
- MD5STEP(F3, a, b, c, d, in[ 5] + 0xfffa3942, 4);
- MD5STEP(F3, d, a, b, c, in[ 8] + 0x8771f681, 11);
- MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
- MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
- MD5STEP(F3, a, b, c, d, in[ 1] + 0xa4beea44, 4);
- MD5STEP(F3, d, a, b, c, in[ 4] + 0x4bdecfa9, 11);
- MD5STEP(F3, c, d, a, b, in[ 7] + 0xf6bb4b60, 16);
- MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
- MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
- MD5STEP(F3, d, a, b, c, in[ 0] + 0xeaa127fa, 11);
- MD5STEP(F3, c, d, a, b, in[ 3] + 0xd4ef3085, 16);
- MD5STEP(F3, b, c, d, a, in[ 6] + 0x04881d05, 23);
- MD5STEP(F3, a, b, c, d, in[ 9] + 0xd9d4d039, 4);
- MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
- MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
- MD5STEP(F3, b, c, d, a, in[ 2] + 0xc4ac5665, 23);
-
- MD5STEP(F4, a, b, c, d, in[ 0] + 0xf4292244, 6);
- MD5STEP(F4, d, a, b, c, in[ 7] + 0x432aff97, 10);
- MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
- MD5STEP(F4, b, c, d, a, in[ 5] + 0xfc93a039, 21);
- MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
- MD5STEP(F4, d, a, b, c, in[ 3] + 0x8f0ccc92, 10);
- MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
- MD5STEP(F4, b, c, d, a, in[ 1] + 0x85845dd1, 21);
- MD5STEP(F4, a, b, c, d, in[ 8] + 0x6fa87e4f, 6);
- MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
- MD5STEP(F4, c, d, a, b, in[ 6] + 0xa3014314, 15);
- MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
- MD5STEP(F4, a, b, c, d, in[ 4] + 0xf7537e82, 6);
- MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
- MD5STEP(F4, c, d, a, b, in[ 2] + 0x2ad7d2bb, 15);
- MD5STEP(F4, b, c, d, a, in[ 9] + 0xeb86d391, 21);
-
- buf[0] += a;
- buf[1] += b;
- buf[2] += c;
- buf[3] += d;
-}
-
-
-
-
-
-
-
-
-
-
-//########################################################################
-//########################################################################
-//### T H R E A D
-//########################################################################
-//########################################################################
-
-
-
-/**
- * This is the interface for a delegate class which can
- * be run by a Thread.
- * Thread thread(runnable);
- * thread.start();
- */
-class Runnable
-{
-public:
-
- Runnable()
- {}
- virtual ~Runnable()
- {}
-
- /**
- * The method of a delegate class which can
- * be run by a Thread. Thread is completed when this
- * method is done.
- */
- virtual void run() = 0;
-
-};
-
-
-
-/**
- * A simple wrapper of native threads in a portable class.
- * It can be used either to execute its own run() method, or
- * delegate to a Runnable class's run() method.
- */
-class Thread
-{
-public:
-
- /**
- * Create a thread which will execute its own run() method.
- */
- Thread()
- { runnable = NULL ; started = false; }
-
- /**
- * Create a thread which will run a Runnable class's run() method.
- */
- Thread(const Runnable &runner)
- { runnable = (Runnable *)&runner; started = false; }
-
- /**
- * This does not kill a spawned thread.
- */
- virtual ~Thread()
- {}
-
- /**
- * Static method to pause the current thread for a given
- * number of milliseconds.
- */
- static void sleep(unsigned long millis);
-
- /**
- * This method will be executed if the Thread was created with
- * no delegated Runnable class. The thread is completed when
- * the method is done.
- */
- virtual void run()
- {}
-
- /**
- * Starts the thread.
- */
- virtual void start();
-
- /**
- * Calls either this class's run() method, or that of a Runnable.
- * A user would normally not call this directly.
- */
- virtual void execute()
- {
- started = true;
- if (runnable)
- runnable->run();
- else
- run();
- }
-
-private:
-
- Runnable *runnable;
-
- bool started;
-
-};
-
-
-
-
-
-#ifdef __WIN32__
-
-
-static DWORD WINAPI WinThreadFunction(LPVOID context)
-{
- Thread *thread = (Thread *)context;
- thread->execute();
- return 0;
-}
-
-
-void Thread::start()
-{
- DWORD dwThreadId;
- HANDLE hThread = CreateThread(NULL, 0, WinThreadFunction,
- (LPVOID)this, 0, &dwThreadId);
- //Make sure the thread is started before 'this' is deallocated
- while (!started)
- sleep(10);
- CloseHandle(hThread);
-}
-
-void Thread::sleep(unsigned long millis)
-{
- Sleep(millis);
-}
-
-#else /* UNIX */
-
-
-void *PthreadThreadFunction(void *context)
-{
- Thread *thread = (Thread *)context;
- thread->execute();
- return NULL;
-}
-
-
-void Thread::start()
-{
- pthread_t thread;
-
- int ret = pthread_create(&thread, NULL,
- PthreadThreadFunction, (void *)this);
- if (ret != 0)
- printf("Thread::start: thread creation failed: %s\n", strerror(ret));
-
- //Make sure the thread is started before 'this' is deallocated
- while (!started)
- sleep(10);
-
-}
-
-void Thread::sleep(unsigned long millis)
-{
- timespec requested;
- requested.tv_sec = millis / 1000;
- requested.tv_nsec = (millis % 1000 ) * 1000000L;
- nanosleep(&requested, NULL);
-}
-
-#endif
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-//########################################################################
-//########################################################################
-//### S O C K E T
-//########################################################################
-//########################################################################
-
-
-
-/**
- * A socket wrapper that provides cross-platform capability, plus SSL
- */
-class TcpSocket
-{
-public:
-
- TcpSocket();
-
- TcpSocket(const std::string &hostname, int port);
-
- TcpSocket(const char *hostname, int port);
-
- TcpSocket(const TcpSocket &other);
-
- virtual ~TcpSocket();
-
- bool isConnected();
-
- void enableSSL(bool val);
-
- bool getEnableSSL();
-
- bool connect(const std::string &hostname, int portno);
-
- bool connect(const char *hostname, int portno);
-
- bool startTls();
-
- bool connect();
-
- bool disconnect();
-
- bool setReceiveTimeout(unsigned long millis);
-
- long available();
-
- bool write(int ch);
-
- bool write(char *str);
-
- bool write(const std::string &str);
-
- int read();
-
- std::string readLine();
-
-private:
- void init();
-
- std::string hostname;
- int portno;
- int sock;
- bool connected;
-
- bool sslEnabled;
-
- unsigned long receiveTimeout;
-
-#ifdef HAVE_SSL
- SSL_CTX *sslContext;
- SSL *sslStream;
-#endif
-
-};
-
-
-
-//#########################################################################
-//# U T I L I T Y
-//#########################################################################
-
-static void mybzero(void *s, size_t n)
-{
- unsigned char *p = (unsigned char *)s;
- while (n > 0)
- {
- *p++ = (unsigned char)0;
- n--;
- }
-}
-
-static void mybcopy(void *src, void *dest, size_t 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
-//#########################################################################
-
-TcpSocket::TcpSocket()
-{
- init();
-}
-
-
-TcpSocket::TcpSocket(const char *hostnameArg, int port)
-{
- init();
- hostname = hostnameArg;
- portno = port;
-}
-
-TcpSocket::TcpSocket(const std::string &hostnameArg, int port)
-{
- init();
- hostname = hostnameArg;
- portno = port;
-}
-
-
-#ifdef HAVE_SSL
-
-static void cryptoLockCallback(int mode, int type, const char *file, int line)
-{
- //printf("########### LOCK\n");
- static int modes[CRYPTO_NUM_LOCKS]; /* = {0, 0, ... } */
- const char *errstr = NULL;
-
- int rw = mode & (CRYPTO_READ|CRYPTO_WRITE);
- if (!((rw == CRYPTO_READ) || (rw == CRYPTO_WRITE)))
- {
- errstr = "invalid mode";
- goto err;
- }
-
- if (type < 0 || type >= CRYPTO_NUM_LOCKS)
- {
- errstr = "type out of bounds";
- goto err;
- }
-
- if (mode & CRYPTO_LOCK)
- {
- if (modes[type])
- {
- errstr = "already locked";
- /* must not happen in a single-threaded program
- * (would deadlock)
- */
- goto err;
- }
-
- modes[type] = rw;
- }
- else if (mode & CRYPTO_UNLOCK)
- {
- if (!modes[type])
- {
- errstr = "not locked";
- goto err;
- }
-
- if (modes[type] != rw)
- {
- errstr = (rw == CRYPTO_READ) ?
- "CRYPTO_r_unlock on write lock" :
- "CRYPTO_w_unlock on read lock";
- }
-
- modes[type] = 0;
- }
- else
- {
- errstr = "invalid mode";
- goto err;
- }
-
- err:
- if (errstr)
- {
- /* we cannot use bio_err here */
- fprintf(stderr, "openssl (lock_dbg_cb): %s (mode=%d, type=%d) at %s:%d\n",
- errstr, mode, type, file, line);
- }
-}
-
-static unsigned long cryptoIdCallback()
-{
-#ifdef __WIN32__
- unsigned long ret = (unsigned long) GetCurrentThreadId();
-#else
- unsigned long ret = (unsigned long) pthread_self();
-#endif
- return ret;
-}
-
-#endif
-
-
-TcpSocket::TcpSocket(const TcpSocket &other)
-{
- init();
- sock = other.sock;
- hostname = other.hostname;
- portno = other.portno;
-}
-
-static bool tcp_socket_inited = false;
-
-void TcpSocket::init()
-{
- if (!tcp_socket_inited)
- {
-#ifdef __WIN32__
- WORD wVersionRequested = MAKEWORD( 2, 2 );
- WSADATA wsaData;
- WSAStartup( wVersionRequested, &wsaData );
-#endif
-#ifdef HAVE_SSL
- sslStream = NULL;
- sslContext = NULL;
- CRYPTO_set_locking_callback(cryptoLockCallback);
- CRYPTO_set_id_callback(cryptoIdCallback);
- SSL_library_init();
- SSL_load_error_strings();
-#endif
- tcp_socket_inited = true;
- }
- sock = -1;
- connected = false;
- hostname = "";
- portno = -1;
- sslEnabled = false;
- receiveTimeout = 0;
-}
-
-TcpSocket::~TcpSocket()
-{
- disconnect();
-}
-
-bool TcpSocket::isConnected()
-{
- if (!connected || sock < 0)
- return false;
- return true;
-}
-
-void TcpSocket::enableSSL(bool val)
-{
- sslEnabled = val;
-}
-
-bool TcpSocket::getEnableSSL()
-{
- return sslEnabled;
-}
-
-
-bool TcpSocket::connect(const char *hostnameArg, int portnoArg)
-{
- hostname = hostnameArg;
- portno = portnoArg;
- return connect();
-}
-
-bool TcpSocket::connect(const std::string &hostnameArg, int portnoArg)
-{
- hostname = hostnameArg;
- portno = portnoArg;
- 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
-
-
-bool TcpSocket::startTls()
-{
-#ifdef HAVE_SSL
- sslStream = NULL;
- sslContext = NULL;
-
- //SSL_METHOD *meth = SSLv23_method();
- //SSL_METHOD *meth = SSLv3_client_method();
- SSL_METHOD *meth = TLSv1_client_method();
- sslContext = SSL_CTX_new(meth);
- //SSL_CTX_set_info_callback(sslContext, infoCallback);
-
-#if 0
- 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;
- }
-#endif
-
- /* Connect the SSL socket */
- sslStream = SSL_new(sslContext);
- SSL_set_fd(sslStream, sock);
-
- int ret = SSL_connect(sslStream);
- if (ret == 0)
- {
- fprintf(stderr, "SSL connection not successful\n");
- disconnect();
- return false;
- }
- else if (ret < 0)
- {
- int err = SSL_get_error(sslStream, ret);
- fprintf(stderr, "SSL connect error %d\n", err);
- disconnect();
- return false;
- }
-
- sslEnabled = true;
-#endif /*HAVE_SSL*/
- return true;
-}
-
-
-bool TcpSocket::connect()
-{
- if (hostname.size()<1)
- {
- fprintf(stderr, "open: null hostname\n");
- return false;
- }
-
- if (portno<1)
- {
- fprintf(stderr, "open: bad port number\n");
- return false;
- }
-
- sock = socket(PF_INET, SOCK_STREAM, 0);
- if (sock < 0)
- {
- fprintf(stderr, "open: error creating socket\n");
- return false;
- }
-
- char *c_hostname = (char *)hostname.c_str();
- struct hostent *server = gethostbyname(c_hostname);
- if (!server)
- {
- fprintf(stderr, "open: could not locate host '%s'\n", c_hostname);
- return false;
- }
-
- struct sockaddr_in serv_addr;
- mybzero((char *) &serv_addr, sizeof(serv_addr));
- serv_addr.sin_family = AF_INET;
- mybcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr,
- server->h_length);
- serv_addr.sin_port = htons(portno);
-
- int ret = ::connect(sock, (const sockaddr *)&serv_addr, sizeof(serv_addr));
- if (ret < 0)
- {
- fprintf(stderr, "open: could not connect to host '%s'\n", c_hostname);
- return false;
- }
-
- if (sslEnabled)
- {
- if (!startTls())
- return false;
- }
- connected = true;
- return true;
-}
-
-bool TcpSocket::disconnect()
-{
- bool ret = true;
- connected = false;
-#ifdef HAVE_SSL
- 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;
- }
- SSL_free(sslStream);
- }
- if (sslContext)
- SSL_CTX_free(sslContext);
- }
- sslStream = NULL;
- sslContext = NULL;
-#endif /*HAVE_SSL*/
-
-#ifdef __WIN32__
- closesocket(sock);
-#else
- ::close(sock);
-#endif
- sock = -1;
- sslEnabled = false;
-
- return ret;
-}
-
-
-
-bool TcpSocket::setReceiveTimeout(unsigned long millis)
-{
- receiveTimeout = millis;
- 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.
- */
-long TcpSocket::available()
-{
- if (!isConnected())
- return -1;
-
- long count = 0;
-#ifdef __WIN32__
- if (ioctlsocket(sock, FIONREAD, (unsigned long *)&count) != 0)
- return -1;
-#else
- if (ioctl(sock, FIONREAD, &count) != 0)
- return -1;
-#endif
- if (count<=0 && sslEnabled)
- {
-#ifdef HAVE_SSL
- return SSL_pending(sslStream);
-#endif
- }
- return count;
-}
-
-
-
-bool TcpSocket::write(int ch)
-{
- if (!isConnected())
- {
- fprintf(stderr, "write: socket closed\n");
- return false;
- }
- unsigned char c = (unsigned char)ch;
-
- if (sslEnabled)
- {
-#ifdef HAVE_SSL
- int r = SSL_write(sslStream, &c, 1);
- if (r<=0)
- {
- switch(SSL_get_error(sslStream, r))
- {
- default:
- fprintf(stderr, "SSL write problem");
- return -1;
- }
- }
-#endif
- }
- else
- {
- if (send(sock, (const char *)&c, 1, 0) < 0)
- //if (send(sock, &c, 1, 0) < 0)
- {
- fprintf(stderr, "write: could not send data\n");
- return false;
- }
- }
- return true;
-}
-
-bool TcpSocket::write(char *str)
-{
- if (!isConnected())
- {
- fprintf(stderr, "write(str): socket closed\n");
- return false;
- }
- int len = strlen(str);
-
- if (sslEnabled)
- {
-#ifdef HAVE_SSL
- int r = SSL_write(sslStream, (unsigned char *)str, len);
- if (r<=0)
- {
- switch(SSL_get_error(sslStream, r))
- {
- default:
- fprintf(stderr, "SSL write problem");
- return -1;
- }
- }
-#endif
- }
- else
- {
- if (send(sock, str, len, 0) < 0)
- //if (send(sock, &c, 1, 0) < 0)
- {
- fprintf(stderr, "write: could not send data\n");
- return false;
- }
- }
- return true;
-}
-
-bool TcpSocket::write(const std::string &str)
-{
- return write((char *)str.c_str());
-}
-
-int TcpSocket::read()
-{
- 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)
- {
- int avail = available();
- if (avail > 0)
- break;
- if (tim >= receiveTimeout)
- return -2;
- Thread::sleep(20);
- tim += 20;
- }
- }
-
- //check again
- if (!isConnected())
- return -1;
-
- unsigned char ch;
- if (sslEnabled)
- {
-#ifdef HAVE_SSL
- if (!sslStream)
- return -1;
- int r = SSL_read(sslStream, &ch, 1);
- unsigned long err = SSL_get_error(sslStream, r);
- switch (err)
- {
- case SSL_ERROR_NONE:
- break;
- case SSL_ERROR_ZERO_RETURN:
- return -1;
- case SSL_ERROR_SYSCALL:
- fprintf(stderr, "SSL read problem(syscall) %s\n",
- ERR_error_string(ERR_get_error(), NULL));
- return -1;
- default:
- fprintf(stderr, "SSL read problem %s\n",
- ERR_error_string(ERR_get_error(), NULL));
- return -1;
- }
-#endif
- }
- else
- {
- if (recv(sock, (char *)&ch, 1, 0) <= 0)
- {
- fprintf(stderr, "read: could not receive data\n");
- disconnect();
- return -1;
- }
- }
- return (int)ch;
-}
-
-std::string TcpSocket::readLine()
-{
- std::string ret;
-
- while (isConnected())
- {
- int ch = read();
- if (ch<0)
- return ret;
- if (ch=='\r' || ch=='\n')
- return ret;
- ret.push_back((char)ch);
- }
-
- return ret;
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
//########################################################################
//########################################################################
//# X M P P E V E N T