diff --git a/rosapps/games/ArchBlackmann/.cvsignore b/rosapps/games/ArchBlackmann/.cvsignore new file mode 100644 index 00000000000..c6f3c2ca7df --- /dev/null +++ b/rosapps/games/ArchBlackmann/.cvsignore @@ -0,0 +1,5 @@ +*.ncb +*.opt +*.plg +Debug +Release \ No newline at end of file diff --git a/rosapps/games/ArchBlackmann/ArchBlackmann.cpp b/rosapps/games/ArchBlackmann/ArchBlackmann.cpp new file mode 100644 index 00000000000..905af5ebbd8 --- /dev/null +++ b/rosapps/games/ArchBlackmann/ArchBlackmann.cpp @@ -0,0 +1,123 @@ +// irc_test.cpp + +#ifdef _MSC_VER +#pragma warning ( disable : 4786 ) +#endif//_MSC_VER + +#include +#include + +#include "IRCClient.h" + +using std::string; +using std::vector; + +// do custom stuff with the IRCClient from your subclass via the provided callbacks... +class MyIRCClient : public IRCClient +{ +public: + // see IRCClient.h for documentation on these callbacks... + bool OnConnected() + { + return true; + } + bool OnJoin ( const string& user, const string& channel ) + { + return true; + } + bool OnEndChannelUsers ( const string& channel ) + { + return true; + } + bool OnPrivMsg ( const string& from, const string& text ) + { + printf ( "<%s> %s\n", from.c_str(), text.c_str() ); + return true; + } + bool OnChannelMsg ( const string& channel, const string& from, const string& text ) + { + printf ( "%s <%s> %s\n", channel.c_str(), from.c_str(), text.c_str() ); + if ( !stricmp ( from.c_str(), "royce3" ) ) + PrivMsg ( channel, text ); + return true; + } + bool OnChannelMode ( const string& channel, const string& mode ) + { + //printf ( "OnChannelMode(%s,%s)\n", channel.c_str(), mode.c_str() ); + return true; + } + bool OnUserModeInChannel ( const string& src, const string& channel, const string& user, const string& mode ) + { + //printf ( "OnUserModeInChannel(%s,%s%s,%s)\n", src.c_str(), channel.c_str(), user.c_str(), mode.c_str() ); + return true; + } + bool OnMode ( const string& user, const string& mode ) + { + //printf ( "OnMode(%s,%s)\n", user.c_str(), mode.c_str() ); + return true; + } + bool OnChannelUsers ( const string& channel, const vector& users ) + { + printf ( "[%s has %i users]: ", channel.c_str(), users.size() ); + for ( int i = 0; i < users.size(); i++ ) + { + if ( i ) + printf ( ", " ); + printf ( "%s", users[i].c_str() ); + } + printf ( "\n" ); + return true; + } +}; + +int main ( int argc, char** argv ) +{ + printf ( "initializing IRCClient debugging\n" ); + IRCClient::SetDebug ( true ); + printf ( "calling suStartup()\n" ); + suStartup(); + printf ( "creating IRCClient object\n" ); + MyIRCClient irc; + printf ( "connecting to freenode\n" ); + if ( !irc.Connect ( "140.211.166.3" ) ) // irc.freenode.net + { + printf ( "couldn't connect to server\n" ); + return -1; + } + printf ( "sending user command\n" ); + if ( !irc.User ( "Royce3", "", "irc.freenode.net", "Royce Mitchell III" ) ) + { + printf ( "USER command failed\n" ); + return -1; + } + printf ( "sending nick\n" ); + if ( !irc.Nick ( "Royce3" ) ) + { + printf ( "NICK command failed\n" ); + return -1; + } + printf ( "setting mode\n" ); + if ( !irc.Mode ( "+i" ) ) + { + printf ( "MODE command failed\n" ); + return -1; + } + printf ( "joining #ReactOS\n" ); + if ( !irc.Join ( "#ReactOS" ) ) + { + printf ( "JOIN command failed\n" ); + return -1; + } + printf ( "entering irc client processor\n" ); + irc.Run ( true ); // do the processing in this thread... + string cmd; + for ( ;; ) + { + char c = getch(); + if ( c == '\n' || c == '\r' ) + { + + } + } + return 0; +} diff --git a/rosapps/games/ArchBlackmann/ArchBlackmann.dsp b/rosapps/games/ArchBlackmann/ArchBlackmann.dsp new file mode 100644 index 00000000000..9b959184d44 --- /dev/null +++ b/rosapps/games/ArchBlackmann/ArchBlackmann.dsp @@ -0,0 +1,196 @@ +# Microsoft Developer Studio Project File - Name="ArchBlackmann" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=ArchBlackmann - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "ArchBlackmann.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "ArchBlackmann.mak" CFG="ArchBlackmann - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "ArchBlackmann - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "ArchBlackmann - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "ArchBlackmann - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "ArchBlackmann - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "ArchBlackmann - Win32 Release" +# Name "ArchBlackmann - Win32 Debug" +# Begin Source File + +SOURCE=.\ArchBlackmann.cpp +# End Source File +# Begin Source File + +SOURCE=.\auto_ptr.h +# End Source File +# Begin Source File + +SOURCE=.\auto_vector.h +# End Source File +# Begin Source File + +SOURCE=.\base64.cpp +# End Source File +# Begin Source File + +SOURCE=.\base64.h +# End Source File +# Begin Source File + +SOURCE=.\chomp.cpp +# End Source File +# Begin Source File + +SOURCE=.\chomp.h +# End Source File +# Begin Source File + +SOURCE=.\cram_md5.cpp +# End Source File +# Begin Source File + +SOURCE=.\cram_md5.h +# End Source File +# Begin Source File + +SOURCE=.\IRCClient.cpp +# End Source File +# Begin Source File + +SOURCE=.\IRCClient.h +# End Source File +# Begin Source File + +SOURCE=.\MD5.cpp +# End Source File +# Begin Source File + +SOURCE=.\MD5.h +# End Source File +# Begin Source File + +SOURCE=.\panic.cpp +# End Source File +# Begin Source File + +SOURCE=.\panic.h +# End Source File +# Begin Source File + +SOURCE=.\QueueT.h +# End Source File +# Begin Source File + +SOURCE=.\Reli.h +# End Source File +# Begin Source File + +SOURCE=.\ReliMT.cpp +# End Source File +# Begin Source File + +SOURCE=.\ReliMT.h +# End Source File +# Begin Source File + +SOURCE=.\SockUtils.cpp +# End Source File +# Begin Source File + +SOURCE=.\SockUtils.h +# End Source File +# Begin Source File + +SOURCE=.\SplitJoin.cpp +# End Source File +# Begin Source File + +SOURCE=.\SplitJoin.h +# End Source File +# Begin Source File + +SOURCE=.\ThreadPool.cpp +# End Source File +# Begin Source File + +SOURCE=.\ThreadPool.h +# End Source File +# Begin Source File + +SOURCE=.\trim.cpp +# End Source File +# Begin Source File + +SOURCE=.\trim.h +# End Source File +# Begin Source File + +SOURCE=.\verify.h +# End Source File +# End Target +# End Project diff --git a/rosapps/games/ArchBlackmann/ArchBlackmann.dsw b/rosapps/games/ArchBlackmann/ArchBlackmann.dsw new file mode 100644 index 00000000000..d8c4784be0e --- /dev/null +++ b/rosapps/games/ArchBlackmann/ArchBlackmann.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "ArchBlackmann"=.\ArchBlackmann.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/rosapps/games/ArchBlackmann/IRCClient.cpp b/rosapps/games/ArchBlackmann/IRCClient.cpp new file mode 100644 index 00000000000..7ad97871580 --- /dev/null +++ b/rosapps/games/ArchBlackmann/IRCClient.cpp @@ -0,0 +1,322 @@ +// IRCClient.cpp +// This file is (C) 2004 Royce Mitchell III +// and released under the BSD & LGPL licenses + +#ifdef _MSC_VER +#pragma warning ( disable : 4786 ) +#endif//_MSC_VER + +#include +#include + +#include "IRCClient.h" +#include "md5.h" +#include "cram_md5.h" +#include "trim.h" +#include "chomp.h" +#include "SplitJoin.h" +#include "base64.h" + +using std::string; +using std::stringstream; +using std::vector; + +bool IRCClient::_debug = true; + +IRCClient::IRCClient() + : _timeout(10*60*1000), _inRun(false) +{ +} + +bool IRCClient::Connect ( const string& server, short port ) +{ + string buf; + Close(); + Attach ( suTcpSocket() ); + if ( !suConnect ( *this, server.c_str(), port ) ) + return false; + return true; +} + +bool +IRCClient::User ( const string& user, const string& mode, + const string& network, const string& realname ) +{ + string buf; + buf = "USER " + user + " \"" + mode + "\" \"" + network + "\" :" + realname + "\n"; + return Send ( buf ); +} + +bool +IRCClient::Nick ( const string& nick ) +{ + _nick = nick; + return Send ( "NICK " + _nick + "\n" ); +} + +bool +IRCClient::Mode ( const string& mode ) +{ + return Send ( "MODE " + _nick + " " + mode + "\n" ); +} + +bool +IRCClient::Names ( const string& channel ) +{ + return Send ( "NAMES " + channel + "\n" ); +} + +bool +IRCClient::Mode ( const string& channel, const string& mode, const string& target ) +{ + return Send ( "MODE " + channel + " " + mode + " " + target + "\n" ); +} + +bool +IRCClient::Join ( const string& channel ) +{ + return Send ( "JOIN " + channel + "\n" ); +} + +bool +IRCClient::PrivMsg ( const string& to, const string& text ) +{ + return Send ( "PRIVMSG " + to + " :" + text + "\n" ); +} + +bool +IRCClient::Part ( const string& channel, const string& text ) +{ + return Send ( "PART " + channel + " :" + text + "\n" ); +} + +bool +IRCClient::Quit ( const string& text ) +{ + return Send( "QUIT :" + text + "\n"); +} + +bool IRCClient::_Recv ( string& buf ) +{ + bool b = (recvUntil ( buf, '\n', _timeout ) > 0); + if ( b && _debug ) + { + printf ( ">> %s", buf.c_str() ); + if ( buf[buf.length()-1] != '\n' ) + printf ( "\n" ); + } + return b; +} + +bool IRCClient::Send ( const string& buf ) +{ + if ( _debug ) + { + printf ( "<< %s", buf.c_str() ); + if ( buf[buf.length()-1] != '\n' ) + printf ( "\n" ); + } + return ( buf.length() == (size_t)send ( *this, buf.c_str(), buf.length(), 0 ) ); +} + +bool IRCClient::OnPing( const string& text ) +{ + return Send( "PONG " + text + "\n" ); +} + + +int THREADAPI IRCClient::Callback ( IRCClient* irc ) +{ + return irc->Run ( false ); +} + +int IRCClient::Run ( bool launch_thread ) +{ + if ( (SOCKET)*this == INVALID_SOCKET ) + return 0; + if ( _inRun ) return 1; + if ( launch_thread ) + { + ThreadPool::Instance().Launch ( (ThreadPoolFunc*)IRCClient::Callback, this ); + return 1; + } + _inRun = true; + if ( _debug ) printf ( "IRCClient::Run() - waiting for responses\n" ); + string buf; + while ( _Recv(buf) ) + { + if ( !strnicmp ( buf.c_str(), "NOTICE ", 7 ) ) + { + //printf ( "recv'd NOTICE msg...\n" ); + // TODO... + //OnAuth ( + } + else if ( !strnicmp ( buf.c_str(), "PING ", 5 ) ) + { + const char* p = &buf[5]; // point to first char after "PING " + while ( *p == ':' ) // then read past the colons + p++; + const char* p2 = strpbrk ( p, "\r\n" ); // find the end of line + string text ( p, p2-p ); // and set the text + OnPing( text ); + } + else if ( buf[0] == ':' ) + { + const char* p = &buf[1]; // skip first colon... + const char* p2 = strpbrk ( p, " !" ); + if ( !p2 ) + { + printf ( "!!!:OnRecv failure 0: ", buf.c_str() ); + continue; + } + string src ( p, p2-p ); + if ( !src.length() ) + { + printf ( "!!!:OnRecv failure 0.5: %s", buf.c_str() ); + continue; + } + p = p2 + 1; + if ( *p2 == '!' ) + { + p2 = strchr ( p, ' ' ); + if ( !p2 ) + { + printf ( "!!!:OnRecv failure 1: %s", buf.c_str() ); + continue; + } + //string srchost ( p, p2-p ); + p = p2 + 1; + } + p2 = strchr ( p, ' ' ); + if ( !p2 ) + { + printf ( "!!!:OnRecv failure 2: %s", buf.c_str() ); + continue; + } + string cmd ( p, p2-p ); + p = p2 + 1; + p2 = strpbrk ( p, " :" ); + if ( !p2 ) + { + printf ( "!!!:OnRecv failure 3: %s", buf.c_str() ); + continue; + } + string tgt ( p, p2-p ); + p = p2 + 1; + p += strspn ( p, " " ); + if ( *p == '=' ) + { + p++; + p += strspn ( p, " " ); + } + if ( *p == ':' ) + p++; + p2 = strpbrk ( p, "\r\n" ); + if ( !p2 ) + { + printf ( "!!!:OnRecv failure 4: %s", buf.c_str() ); + continue; + } + string text ( p, p2-p ); + strlwr ( &cmd[0] ); + if ( cmd == "privmsg" ) + { + if ( !tgt.length() ) + { + printf ( "!!!:OnRecv failure 5 (PRIVMSG w/o target): %s", buf.c_str() ); + continue; + } + if ( tgt[0] == '#' ) + OnChannelMsg ( tgt, src, text ); + else + OnPrivMsg ( src, text ); + } + else if ( cmd == "mode" ) + { + // two diff. kinds of mode notifications... + //printf ( "[MODE] src='%s' cmd='%s' tgt='%s' text='%s'", src.c_str(), cmd.c_str(), tgt.c_str(), text.c_str() ); + //OnMode ( + // self mode change: + // [MODE] src=Relic3_14 cmd=mode tgt=Relic3_14 text=+i + // channel mode change: + // [MODE] src=Royce3 cmd=mode tgt=#Royce3 text=+o Relic3_14 + if ( tgt[0] == '#' ) + { + p = text.c_str(); + p2 = strchr ( p, ' ' ); + if ( !p2 ) + OnChannelMode ( tgt, text ); + else + { + string user ( p, p2-p ); + p = p2 + 1; + p += strspn ( p, " " ); + OnUserModeInChannel ( src, tgt, user, p ); + } + } + else + OnMode ( tgt, text ); + } + else if ( cmd == "join" ) + { + OnJoin ( src, text ); + } + else if ( isdigit(cmd[0]) ) + { + int i = atoi(cmd.c_str()); + switch ( i ) + { + case 1: // "Welcome!" - i.e. it's okay to issue commands now... + OnConnected(); + break; + case 353: // user list for channel.... + { + p = text.c_str(); + p2 = strpbrk ( p, " :" ); + if ( !p2 ) continue; + string channel ( p, p2-p ); + p = strchr ( p2, ':' ); + if ( !p ) continue; + p++; + vector users; + while ( *p ) + { + p2 = strchr ( p, ' ' ); + if ( !p2 ) + p2 = p + strlen(p); + users.push_back ( string ( p, p2-p ) ); + p = p2+1; + p += strspn ( p, " " ); + } + OnChannelUsers ( channel, users ); + } + break; + case 366: // END of user list for channel + { + p = text.c_str(); + p2 = strpbrk ( p, " :" ); + if ( !p2 ) continue; + string channel ( p, p2-p ); + OnEndChannelUsers ( channel ); + } + break; + default: + if ( _debug ) printf ( "unknown command %i: %s", i, buf.c_str() ); + break; + } + } + else + { + if ( _debug ) printf ( "unrecognized ':' response: %s", buf.c_str() ); + } + } + else + { + if ( _debug ) printf ( "unrecognized irc msg: %s", buf.c_str() ); + } + //OnRecv ( buf ); + } + if ( _debug ) printf ( "IRCClient::Run() - exiting\n" ); + _inRun = false; + return 0; +} diff --git a/rosapps/games/ArchBlackmann/IRCClient.h b/rosapps/games/ArchBlackmann/IRCClient.h new file mode 100644 index 00000000000..6f8f36061de --- /dev/null +++ b/rosapps/games/ArchBlackmann/IRCClient.h @@ -0,0 +1,124 @@ +// IRCClient.h +// This file is (C) 2004 Royce Mitchell III +// and released under the BSD & LGPL licenses + +#ifndef IRCCLIENT_H +#define IRCCLIENT_H + +#include +#include +#include "SockUtils.h" +#include "ThreadPool.h" + +class IRCClient : public suBufferedRecvSocket +{ +public: + IRCClient(); + + static bool GetDebug() { return _debug; } + static bool SetDebug ( bool debug ) { bool old = _debug; _debug = debug; return old; } + + // connect to server ( record greeting for apop if it exists ) + bool Connect ( const std::string& server, short port = 6667 ); + + bool Running() { return _inRun; } + + ////////////////////////// IRC Client Protocol commands /////////////////////// + + // first thing you must call... mode can be "" + // network can be same as name of server used in Connect() above + bool User ( const std::string& user, const std::string& mode, + const std::string& network, const std::string& realname ); + + // change nick... + bool Nick ( const std::string& nick ); + + // change mode for self... + bool Mode ( const std::string& mode ); + + // set someone's mode in channel ( like oping someone ) + bool Mode ( const std::string& channel, const std::string& mode, const std::string& target ); + + // request a list of names of clients in a channel + bool Names ( const std::string& channel ); + + // join a channel... + bool Join ( const std::string& channel ); + + // send message to someone or some channel + bool PrivMsg ( const std::string& to, const std::string& text ); + + // leave a channel + bool Part ( const std::string& channel, const std::string& text ); + + // log off + bool Quit ( const std::string& text ); + + ////////////////////// callback functions //////////////////////////// + + // OnConnected: you just successfully logged into irc server + virtual bool OnConnected() = 0; + + // OnJoin: you just successfully joined this channel + virtual bool OnJoin ( const std::string& user, const std::string& channel ) = 0; + + // OnPrivMsg: you just received a private message from a user + virtual bool OnPrivMsg ( const std::string& from, const std::string& text ) = 0; + + // OnChannelMsg: you just received a chat line in a channel + virtual bool OnChannelMsg ( const std::string& channel, const std::string& from, + const std::string& text ) = 0; + + // OnChannelMode: notification of a change of a channel's mode + virtual bool OnChannelMode ( const std::string& channel, const std::string& mode ) = 0; + + // OnUserModeInChannel: notification of a mode change of a user with respect to a channel. + // f.ex.: this will be called when someone is oped in a channel. + virtual bool OnUserModeInChannel ( const std::string& src, const std::string& channel, + const std::string& user, const std::string& mode ) = 0; + + // OnMode: you will receive this when you change your own mode, at least... + virtual bool OnMode ( const std::string& user, const std::string& mode ) = 0; + + // notification of what users are in a channel ( you may get multiple of these... ) + virtual bool OnChannelUsers ( const std::string& channel, const std::vector& users ) = 0; + + // notification that you have received the entire list of users for a channel + virtual bool OnEndChannelUsers ( const std::string& channel ) = 0; + + // OnPing - default implementation replies to PING with a valid PONG. required on some systems to + // log in. Most systems require a response in order to stay connected, used to verify a client hasn't + // dropped. + virtual bool OnPing ( const std::string& text ); + + ////////////////////// other functions //////////////////////////// + + // this is for sending data to irc server. it's public in case you need to send some + // command not supported by this base class... + bool Send ( const std::string& buf ); + + // if launch_thread is true, this function will spawn a thread that will process + // incoming packets until the socket dies. + // otherwise ( launch_thread is false ) this function will do that processing + // in *this* thread, and not return until the socket dies. + int Run ( bool launch_thread ); + + ////////////////////// private stuff //////////////////////////// +private: + bool _Recv ( std::string& buf ); + + static int THREADAPI Callback ( IRCClient* irc ); + + static bool _debug; + std::string _nick; + int _timeout; + std::string _apop_challenge; + + volatile bool _inRun; + + // disable copy semantics + IRCClient ( const IRCClient& ); + IRCClient& operator = ( const IRCClient& ); +}; + +#endif//IRCCLIENT_H diff --git a/rosapps/games/ArchBlackmann/MD5.cpp b/rosapps/games/ArchBlackmann/MD5.cpp new file mode 100644 index 00000000000..43200cfa1a1 --- /dev/null +++ b/rosapps/games/ArchBlackmann/MD5.cpp @@ -0,0 +1,418 @@ +// MD5.CPP - RSA Data Security, Inc., MD5 message-digest algorithm + +/* +Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All +rights reserved. + +License to copy and use this software is granted provided that it +is identified as the "RSA Data Security, Inc. MD5 Message-Digest +Algorithm" in all material mentioning or referencing this software +or this function. + +License is also granted to make and use derivative works provided +that such works are identified as "derived from the RSA Data +Security, Inc. MD5 Message-Digest Algorithm" in all material +mentioning or referencing the derived work. + +RSA Data Security, Inc. makes no representations concerning either +the merchantability of this software or the suitability of this +software for any particular purpose. It is provided "as is" +without express or implied warranty of any kind. + +These notices must be retained in any copies of any part of this +documentation and/or software. +*/ + +//#include +#include +#include +#include +#include "MD5.h" + +using std::string; +using std::vector; + +// Constants for MD5Transform routine. +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + +static void MD5Transform ( UINT4 [4], const uchar [64] ); +static void Encode ( unsigned char *, UINT4 *, unsigned int ); +static void Decode ( UINT4 *, const uchar *, unsigned int ); + +static unsigned char PADDING[64] = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +// F, G, H and I are basic MD5 functions. +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | (~z))) + +// ROTATE_LEFT rotates x left n bits. +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +// FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. +// Rotation is separate from addition to prevent recomputation. +#define FF(a, b, c, d, x, s, ac) { \ + (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define GG(a, b, c, d, x, s, ac) { \ + (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define HH(a, b, c, d, x, s, ac) { \ + (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define II(a, b, c, d, x, s, ac) { \ + (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + +// MD5 initialization. Begins an MD5 operation, writing a new context. +void MD5Init ( + MD5_CTX *context ) // context +{ + context->count[0] = context->count[1] = 0; + // Load magic initialization constants. + context->state[0] = 0x67452301; + context->state[1] = 0xefcdab89; + context->state[2] = 0x98badcfe; + context->state[3] = 0x10325476; +} + +// MD5 block update operation. Continues an MD5 message-digest +// operation, processing another message block, and updating the +// context. +void MD5Update ( + MD5_CTX *context, // context + const char *input_, // input block + unsigned int inputLen ) // length of input block +{ + unsigned int i, index, partLen; + const uchar* input = (const uchar*)input_; + + // Compute number of bytes mod 64 + index = (unsigned int)((context->count[0] >> 3) & 0x3F); + + // Update number of bits + if ((context->count[0] += ((UINT4)inputLen << 3)) + < ((UINT4)inputLen << 3)) + context->count[1]++; + context->count[1] += ((UINT4)inputLen >> 29); + + partLen = 64 - index; + + // Transform as many times as possible. + if (inputLen >= partLen) + { + memcpy + ((POINTER)&context->buffer[index], (POINTER)input, partLen); + MD5Transform (context->state, context->buffer); + + for (i = partLen; i + 63 < inputLen; i += 64) + MD5Transform (context->state, &input[i]); + + index = 0; + } + else + i = 0; + + // Buffer remaining input + memcpy + ((POINTER)&context->buffer[index], (POINTER)&input[i], + inputLen-i); +} + +// MD5 finalization. Ends an MD5 message-digest operation, writing the +// the message digest and zeroizing the context. +void MD5Final ( + unsigned char digest[16], // message digest + MD5_CTX *context ) // context +{ + uchar bits[8]; + unsigned int index, padLen; + + // Save number of bits + Encode (bits, context->count, 8); + + // Pad out to 56 mod 64. + index = (unsigned int)((context->count[0] >> 3) & 0x3f); + padLen = (index < 56) ? (56 - index) : (120 - index); + MD5Update (context, (const char*)PADDING, padLen); + + // Append length (before padding) + MD5Update (context, (const char*)bits, 8); + + // Store state in digest + Encode (digest, context->state, 16); + + // Zeroize sensitive information. + memset ((POINTER)context, 0, sizeof (*context)); +} + +// MD5 basic transformation. Transforms state based on block. +static void MD5Transform ( + UINT4 state[4], + const uchar block[64] ) +{ + UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; + + Decode (x, block, 64); + + // Round 1 + FF (a, b, c, d, x[ 0], S11, 0xd76aa478); // 1 + FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); // 2 + FF (c, d, a, b, x[ 2], S13, 0x242070db); // 3 + FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); // 4 + FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); // 5 + FF (d, a, b, c, x[ 5], S12, 0x4787c62a); // 6 + FF (c, d, a, b, x[ 6], S13, 0xa8304613); // 7 + FF (b, c, d, a, x[ 7], S14, 0xfd469501); // 8 + FF (a, b, c, d, x[ 8], S11, 0x698098d8); // 9 + FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); // 10 + FF (c, d, a, b, x[10], S13, 0xffff5bb1); // 11 + FF (b, c, d, a, x[11], S14, 0x895cd7be); // 12 + FF (a, b, c, d, x[12], S11, 0x6b901122); // 13 + FF (d, a, b, c, x[13], S12, 0xfd987193); // 14 + FF (c, d, a, b, x[14], S13, 0xa679438e); // 15 + FF (b, c, d, a, x[15], S14, 0x49b40821); // 16 + + // Round 2 + GG (a, b, c, d, x[ 1], S21, 0xf61e2562); // 17 + GG (d, a, b, c, x[ 6], S22, 0xc040b340); // 18 + GG (c, d, a, b, x[11], S23, 0x265e5a51); // 19 + GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); // 20 + GG (a, b, c, d, x[ 5], S21, 0xd62f105d); // 21 + GG (d, a, b, c, x[10], S22, 0x2441453); // 22 + GG (c, d, a, b, x[15], S23, 0xd8a1e681); // 23 + GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); // 24 + GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); // 25 + GG (d, a, b, c, x[14], S22, 0xc33707d6); // 26 + GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); // 27 + GG (b, c, d, a, x[ 8], S24, 0x455a14ed); // 28 + GG (a, b, c, d, x[13], S21, 0xa9e3e905); // 29 + GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); // 30 + GG (c, d, a, b, x[ 7], S23, 0x676f02d9); // 31 + GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); // 32 + + // Round 3 + HH (a, b, c, d, x[ 5], S31, 0xfffa3942); // 33 + HH (d, a, b, c, x[ 8], S32, 0x8771f681); // 34 + HH (c, d, a, b, x[11], S33, 0x6d9d6122); // 35 + HH (b, c, d, a, x[14], S34, 0xfde5380c); // 36 + HH (a, b, c, d, x[ 1], S31, 0xa4beea44); // 37 + HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); // 38 + HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); // 39 + HH (b, c, d, a, x[10], S34, 0xbebfbc70); // 40 + HH (a, b, c, d, x[13], S31, 0x289b7ec6); // 41 + HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); // 42 + HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); // 43 + HH (b, c, d, a, x[ 6], S34, 0x4881d05); // 44 + HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); // 45 + HH (d, a, b, c, x[12], S32, 0xe6db99e5); // 46 + HH (c, d, a, b, x[15], S33, 0x1fa27cf8); // 47 + HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); // 48 + + // Round 4 + II (a, b, c, d, x[ 0], S41, 0xf4292244); // 49 + II (d, a, b, c, x[ 7], S42, 0x432aff97); // 50 + II (c, d, a, b, x[14], S43, 0xab9423a7); // 51 + II (b, c, d, a, x[ 5], S44, 0xfc93a039); // 52 + II (a, b, c, d, x[12], S41, 0x655b59c3); // 53 + II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); // 54 + II (c, d, a, b, x[10], S43, 0xffeff47d); // 55 + II (b, c, d, a, x[ 1], S44, 0x85845dd1); // 56 + II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); // 57 + II (d, a, b, c, x[15], S42, 0xfe2ce6e0); // 58 + II (c, d, a, b, x[ 6], S43, 0xa3014314); // 59 + II (b, c, d, a, x[13], S44, 0x4e0811a1); // 60 + II (a, b, c, d, x[ 4], S41, 0xf7537e82); // 61 + II (d, a, b, c, x[11], S42, 0xbd3af235); // 62 + II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); // 63 + II (b, c, d, a, x[ 9], S44, 0xeb86d391); // 64 + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + + // Zeroize sensitive information. + memset ((POINTER)x, 0, sizeof (x)); +} + +// Encodes input (UINT4) into output (unsigned char). Assumes len is +// a multiple of 4. +static void Encode ( + unsigned char *output, + UINT4 *input, + unsigned int len ) +{ + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) { + output[j] = (unsigned char)(input[i] & 0xff); + output[j+1] = (unsigned char)((input[i] >> 8) & 0xff); + output[j+2] = (unsigned char)((input[i] >> 16) & 0xff); + output[j+3] = (unsigned char)((input[i] >> 24) & 0xff); + } +} + +// Decodes input (unsigned char) into output (UINT4). Assumes len is +// a multiple of 4. +static void Decode ( + UINT4 *output, + const uchar *input, + unsigned int len ) +{ + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) + output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | + (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24); +} + +void digest2ascii ( char *ascii, const unsigned char *digest ) +{ + int i; + static char* table = "0123456789abcdef"; + for ( i = 0; i < 16; i++ ) + { + *ascii++ = table[(*digest)>>4]; + *ascii++ = table[(*digest++)%16]; + } + *ascii++ = 0; +} + +void ascii2digest ( unsigned char *digest, const char *ascii ) +{ + int i; +#define CONV(c) (unsigned char)( (toupper(c)>='A') ? (toupper(c)+10-'A') : ((c)-'0') ) +#define MAKECHAR(a,b) ((CONV(a)%16)<<4)|(CONV(b)%16) + for ( i = 0; i < 16; i++ ) + { + *digest++ = MAKECHAR(ascii[0],ascii[1]); + ascii += 2; + } +} + +#ifdef __cplusplus +MD5::MD5() +{ + Init(); +} + +void MD5::Init() +{ + MD5Init(&_ctx); +} + +void MD5::Update ( const string& s ) +{ + MD5Update ( &_ctx, s.c_str(), s.size() ); +} + +string MD5::Final ( char* digest ) +{ + vector v; + v.resize(16); + MD5Final ( &v[0], &_ctx ); + if ( digest ) + memmove ( digest, &v[0], 16 ); + string s; + static char* tohex = "0123456789abcdef"; + for ( int i = 0; i < 16; i++ ) + { + uchar c = v[i]; + s += tohex[ (c>>4) & 0xF ]; + s += tohex[ c & 0xF ]; + } + return s; +} + +string MD5Hex ( const string& s ) +{ + MD5 md5; + md5.Update ( s ); + return md5.Final(); +} + +string MD5Bin ( const string& s ) +{ + MD5 md5; + md5.Update ( s ); + char digest[16]; + md5.Final ( digest ); + return string ( digest, 16 ); +} + +string HMAC_MD5 ( const string& key, const string& text, char* out_bin ) +{ + MD5 md5; + char k_ipad[65]; // inner padding - key XORd with ipad + char k_opad[65]; // outer padding - key XORd with opad + string tmp; + char digest[16]; + int i; + // if key is longer than 64 bytes reset it to key=MD5(key) + if ( key.length() > 64 ) + { + md5.Init(); + md5.Update ( key ); + md5.Final ( digest ); + tmp = string ( digest, 16 ); + } + else + tmp = key; + + // start out by storing key in pads + memset ( k_ipad, 0, sizeof(k_ipad) ); + memset ( k_opad, 0, sizeof(k_opad) ); + memcpy ( k_ipad, tmp.c_str(), tmp.length() ); + memcpy ( k_opad, tmp.c_str(), tmp.length() ); + + // XOR key with ipad and opad values + for ( i=0; i<64; i++ ) + { + k_ipad[i] ^= 0x36; + k_opad[i] ^= 0x5c; + } + + // "inner" MD5 + md5.Init(); + md5.Update(k_ipad); + md5.Update(text); + md5.Final ( digest ); + + // "outer" MD5 + md5.Init(); + md5.Update(k_opad); + md5.Update(string(digest,16)); + return md5.Final(out_bin); +} +#endif//__cplusplus diff --git a/rosapps/games/ArchBlackmann/MD5.h b/rosapps/games/ArchBlackmann/MD5.h new file mode 100644 index 00000000000..f4bd3c19d9a --- /dev/null +++ b/rosapps/games/ArchBlackmann/MD5.h @@ -0,0 +1,95 @@ +// MD5.H - header file for MD5.CPP + +/* +Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All +rights reserved. + +License to copy and use this software is granted provided that it +is identified as the "RSA Data Security, Inc. MD5 Message-Digest +Algorithm" in all material mentioning or referencing this software +or this function. + +License is also granted to make and use derivative works provided +that such works are identified as "derived from the RSA Data +Security, Inc. MD5 Message-Digest Algorithm" in all material +mentioning or referencing the derived work. + +RSA Data Security, Inc. makes no representations concerning either +the merchantability of this software or the suitability of this +software for any particular purpose. It is provided "as is" +without express or implied warranty of any kind. + +These notices must be retained in any copies of any part of this +documentation and/or software. +*/ + +#ifndef __MD5_H +#define __MD5_H + +#ifdef __cplusplus +#include +#endif//__cplusplus + +#ifndef uchar +#define uchar unsigned char +#endif//uchar + +#ifndef ushort +#define ushort unsigned short +#endif//ushort + +#ifndef ulong +#define ulong unsigned long +#endif//ulong + +#ifdef __cplusplus +extern "C" { +#endif//__cplusplus + +typedef uchar *POINTER; // POINTER defines a generic pointer type +typedef ushort UINT2; // UINT2 defines a two byte word +typedef ulong UINT4; // UINT4 defines a four byte word + +// MD5 context. +typedef struct +{ + UINT4 state[4]; // state (ABCD) + UINT4 count[2]; // number of bits, modulo 2^64 (lsb first) + unsigned char buffer[64]; // input buffer +} MD5_CTX; + +void MD5Init ( MD5_CTX * ); +void MD5Update ( MD5_CTX *, const char *, unsigned int ); +void MD5Final ( uchar [16], MD5_CTX * ); + +void digest2ascii ( char *ascii, const uchar *digest ); +void ascii2digest ( uchar *digest, const char *ascii ); + +#ifdef __cplusplus + +} // extern "C" + +class MD5 +{ +public: + MD5(); + void Init(); + void Update ( const std::string& s ); + std::string Final ( char* digest = 0 ); + +private: + MD5_CTX _ctx; +}; + +std::string MD5Hex ( const std::string& s ); + +std::string MD5Bin ( const std::string& s ); + +std::string HMAC_MD5 ( + const std::string& key, + const std::string& text, + char* out_bin = NULL ); + +#endif//__cplusplus + +#endif//__MD5_H diff --git a/rosapps/games/ArchBlackmann/QueueT.h b/rosapps/games/ArchBlackmann/QueueT.h new file mode 100644 index 00000000000..3d15bcbf741 --- /dev/null +++ b/rosapps/games/ArchBlackmann/QueueT.h @@ -0,0 +1,315 @@ +/* +** Author: Samuel R. Blackburn +** Internet: wfc@pobox.com +** +** You can use it any way you like as long as you don't try to sell it. +** +** Any attempt to sell WFC in source code form must have the permission +** of the original author. You can produce commercial executables with +** WFC but you can't sell WFC. +** +** Copyright, 2000, Samuel R. Blackburn +** +** NOTE: I modified the info block below so it hopefully wouldn't conflict +** with the original file. Royce Mitchell III +*/ + +#ifndef QUEUET_CLASS_HEADER +#define QUEUET_CLASS_HEADER + +#include "ReliMT.h" + +#ifdef WIN32 +#include // off_t +#define HEAPCREATE(size) m_Heap = ::HeapCreate ( HEAP_NO_SERIALIZE, size, 0 ) +#define HEAPALLOC(size) ::HeapAlloc ( m_Heap, HEAP_NO_SERIALIZE, size ) +#define HEAPREALLOC(p,size) ::HeapReAlloc( m_Heap, HEAP_NO_SERIALIZE, p, size ) +#define HEAPFREE(p) ::HeapFree ( m_Heap, HEAP_NO_SERIALIZE, p ) +#define HEAPDESTROY() ::HeapDestroy ( m_Heap ); m_Heap = 0; +#else +#define HEAPCREATE(size) +#define HEAPALLOC(size) malloc(size) +#define HEAPREALLOC(p,size) realloc(p,size); +#define HEAPFREE(p) free(p) +#define HEAPDESTROY() +#endif + +template +class CQueueT : public Uncopyable +{ +protected: + + // What we want to protect + + Mutex m_AddMutex; + Mutex m_GetMutex; + + T* m_Items; + + off_t m_AddIndex; + off_t m_GetIndex; + size_t m_Size; + +#ifdef WIN32 + HANDLE m_Heap; +#endif//WIN32 + inline void m_GrowBy ( size_t number_of_new_items ); + +public: + + inline CQueueT ( size_t initial_size = 1024 ); + inline ~CQueueT(); + + inline bool Add( const T& new_item ); + inline void Empty() { m_AddIndex = 0; m_GetIndex = 0; }; + inline bool Get( T& item ); + inline size_t GetLength() const; + inline size_t GetMaximumLength() const { return( m_Size ); }; + inline bool AddArray ( const T* new_items, int item_count ); + inline int GetArray ( T* items, const int maxget, const T& tEnd ); + inline bool Contains ( const T& t ); +}; + +template +inline CQueueT::CQueueT ( size_t initial_size ) +{ + m_AddIndex = 0; + m_GetIndex = 0; + m_Items = NULL; + + if ( initial_size == 0 ) + initial_size = 1; + + /* + ** 1999-11-05 + ** We create our own heap because all of the pointers used are allocated + ** and freed be us. We don't have to worry about a non-serialized thread + ** accessing something we allocated. Because of this, we can perform our + ** memory allocations in a heap dedicated to queueing. This means when we + ** have to allocate more memory, we don't have to wait for all other threads + ** to pause while we allocate from the shared heap (like the C Runtime heap) + */ + + HEAPCREATE( ( ( ( 2 * initial_size * sizeof(T) ) < 65536 ) ? 65536 : (2 * initial_size * sizeof(T) ) ) ); + + m_Items = (T*)HEAPALLOC ( initial_size * sizeof(T) ); + + m_Size = ( m_Items == NULL ) ? 0 : initial_size; +} + +template +inline CQueueT::~CQueueT() +{ + m_AddIndex = 0; + m_GetIndex = 0; + m_Size = 0; + + if ( m_Items != NULL ) + { + HEAPFREE(m_Items); + m_Items = NULL; + } + + HEAPDESTROY(); +} + +template +inline bool CQueueT::Add ( const T& item ) +{ + // Block other threads from entering Add(); + Mutex::Lock addlock ( m_AddMutex ); + + // Add the item + + m_Items[ m_AddIndex ] = item; + + // 1999-12-08 + // Many many thanks go to Lou Franco (lfranco@spheresoft.com) + // for finding an bug here. It rare but recreatable situations, + // m_AddIndex could be in an invalid state. + + // Make sure m_AddIndex is never invalid + + off_t new_add_index = ( ( m_AddIndex + 1 ) >= (off_t)m_Size ) ? 0 : m_AddIndex + 1; + + if ( new_add_index == m_GetIndex ) + { + // The queue is full. We need to grow. + // Stop anyone from getting from the queue + Mutex::Lock getlock ( m_GetMutex ); + + m_AddIndex = new_add_index; + + // One last double-check. + + if ( m_AddIndex == m_GetIndex ) + { + m_GrowBy ( m_Size ); + } + + } + else + { + m_AddIndex = new_add_index; + } + + return true; +} + +template +inline bool CQueueT::Get( T& item ) +{ + // Prevent other threads from entering Get() + Mutex::Lock getlock ( m_GetMutex ); + + if ( m_GetIndex == m_AddIndex ) + { + // Let's check to see if our queue has grown too big + // If it has, then shrink it + + if ( m_Size > 1024 ) + { + // Yup, we're too big for our britches + Mutex::TryLock addlock ( m_AddMutex ); + if ( addlock ) + { + // Now, no one can add to the queue + + if ( m_GetIndex == m_AddIndex ) // is queue empty? + { + // See if we can just shrink it... + T* return_value = (T*)HEAPREALLOC(m_Items,1024 * sizeof(T)); + + if ( return_value != NULL ) + { + m_Items = (T*) return_value; + } + else + { + // Looks like we'll have to do it the hard way + HEAPFREE ( m_Items ); + m_Items = (T*) HEAPALLOC ( 1024 * sizeof(T) ); + } + + m_Size = ( m_Items == NULL ) ? 0 : 1024; + m_AddIndex = 0; + m_GetIndex = 0; + } + else + { + // m_GetIndex != m_AddIndex, this means that someone added + // to the queue between the time we checked m_Size for being + // too big and the time we entered the add critical section. + // If this happened then we are too busy to shrink + } + } + } + return false; + } + + item = m_Items[ m_GetIndex ]; + + // Make sure m_GetIndex is never invalid + + m_GetIndex = ( ( m_GetIndex + 1 ) >= (off_t)m_Size ) ? 0 : m_GetIndex + 1; + + return true; +} + +template +inline int CQueueT::GetArray ( T* items, const int maxget, const T& tEnd ) +{ + // TODO - oooh baby does this need to be optimized + // Prevent other threads from entering Get() + Mutex::Lock getlock ( m_GetMutex ); //::EnterCriticalSection( &m_GetCriticalSection ); + + int iResult = 0; + for ( int i = 0; i < maxget; i++ ) + { + if ( !Get(items[i]) ) + break; + iResult++; + if ( items[i] == tEnd ) + break; + } + // Let other threads call Get() now + //::LeaveCriticalSection( &m_GetCriticalSection ); + return iResult; +} + +template +inline size_t CQueueT::GetLength() const +{ + // This is a very expensive process! + // No one can call Add() or Get() while we're computing this + + size_t number_of_items_in_the_queue = 0; + + Mutex::Lock addlock ( m_AddMutex ); + Mutex::Lock getlock ( m_GetMutex ); + + number_of_items_in_the_queue = ( m_AddIndex >= m_GetIndex ) ? + ( m_AddIndex - m_GetIndex ) : + ( ( m_AddIndex + m_Size ) - m_GetIndex ); + + return number_of_items_in_the_queue; +} + +template +inline void CQueueT::m_GrowBy ( size_t number_of_new_items ) +{ + // Prevent other threads from calling Get(). + // We don't need to enter the AddCriticalSection because + // m_GrowBy() is only called from Add(); + + T* new_array = NULL; + T* pointer_to_free = NULL; + + size_t new_size = m_Size + number_of_new_items; + + { // Prevent other threads from getting + Mutex::Lock getlock ( m_GetMutex ); + + // 2000-05-16 + // Thanks go to Royce Mitchell III (royce3@aim-controls.com) for finding + // a HUGE bug here. I was using HeapReAlloc as a short cut but my logic + // was flawed. In certain circumstances, queue items were being dropped. + + new_array = (T*)HEAPALLOC ( new_size * sizeof(T) ); + + // Now copy all of the old items from the old queue to the new one. + + // Get the entries from the get-index to the end of the array + memcpy ( new_array, &m_Items[m_GetIndex], ( m_Size - m_GetIndex ) * sizeof(T) ); + + // Get the entries from the beginning of the array to the add-index + memcpy ( &new_array[m_Size-m_GetIndex], m_Items, m_AddIndex * sizeof(T) ); + + m_AddIndex = (off_t)m_Size; + m_GetIndex = 0; + m_Size = new_size; + pointer_to_free = m_Items; + m_Items = new_array; + } // Mutex::Lock + HEAPFREE ( pointer_to_free ); +} + +template +inline bool CQueueT::Contains ( const T& t ) +{ + Mutex::Lock addlock ( m_AddMutex ); + Mutex::Lock getlock ( m_GetMutex ); + + for ( int i = m_GetIndex; i != m_AddIndex; i++ ) + { + if ( i == m_Size ) + i = 0; + if ( m_Items[i] == t ) + return true; + } + return m_Items[m_AddIndex] == t; +} + +typedef CQueueT CCharQueue; + +#endif // QUEUE_CLASS_HEADER diff --git a/rosapps/games/ArchBlackmann/Reli.h b/rosapps/games/ArchBlackmann/Reli.h new file mode 100644 index 00000000000..ebc35d3a4a8 --- /dev/null +++ b/rosapps/games/ArchBlackmann/Reli.h @@ -0,0 +1,143 @@ +// Reli.h +// lots of code here is (c) Bartosz Milewski, 1996, www.relisoft.com +// The rest is (C) 2002-2004 Royce Mitchell III +// and released under the LGPL & BSD licenses + +#ifndef __RELI_H +#define __RELI_H + +//////////////////////////////////////////////////////////////////////////////// +// Assert + +#undef Assert +#ifdef NDEBUG + #define Assert(exp) ((void)0) +#else + void _wassert (char* szExpr, char* szFile, int line); + #define Assert(exp) (void)( (exp) || (_wassert(#exp, __FILE__, __LINE__), 0) ) +#endif /* NDEBUG */ + +//////////////////////////////////////////////////////////////////////////////// +// Swap + +template +void Swap(T a,T b) +{ + T t = a; + a = b; + b = t; +} + +//////////////////////////////////////////////////////////////////////////////// +// Uncopyable - base class disabling copy ctors +class Uncopyable +{ +public: + Uncopyable(){} // need a default ctor +private: + Uncopyable ( const Uncopyable& ); + const Uncopyable& operator = ( const Uncopyable& ); +}; + +//////////////////////////////////////////////////////////////////////////////// +// SPtr - Smart Pointer's must be passed by reference or const reference + +template +class SPtr : public Uncopyable +{ +public: + virtual ~SPtr () { Destroy(); } + T * operator->() { return _p; } + T const * operator->() const { return _p; } + operator T&() { Assert(_p); return *_p; } + operator const T&() const { Assert(_p); return *_p; } + void Acquire ( SPtr& t ) { Destroy(); Swap(_p,t._p); } + void Destroy() { if ( _p ) { delete _p; _p = 0; } } +protected: + SPtr (): _p (0) {} + explicit SPtr (T* p): _p (p) {} + T * _p; +private: + operator T* () { return _p; } +}; + +#define DECLARE_SPTR(cls,init,init2) \ +class S##cls : public SPtr \ +{ \ +public: \ + S##cls ( cls* p ) : SPtr(p) {} \ + explicit S##cls init : SPtr (new cls init2) {} \ +}; +/* Example Usage of DECLARE_SPTR: +class MyClass +{ +public: // can be protected + MyClass ( int i ) + { + ... + } + ... +}; DECLARE_SPTR(MyClass,(int i),(i)) +SMyClass ptr(i); +*/ +#define DECLARE_SPTRV(cls) typedef SPtr S##cls; +/* Example Usage of DECLARE_SPTRV: +class MyAbstractClass +{ +public: // can be protected + MyAbstractClass ( int i ) + { + ... + } + void MyPureVirtFunc() = 0; + ... +}; DECLARE_SPTRV(MyAbstractClass) +SMyAbstractClass ptr ( new MySubClass(i) ); +*/ + +#define DECLARE_PTR(cls,init,init2) \ + class Ptr : public SPtr \ + { \ + Ptr(cls* p) : SPtr ( p ) \ + { \ + } \ + Ptr init : SPtr ( new cls init2 ) {} \ + }; +/* Example Usage of DECLARE_PTR: +class MyClass +{ + DECLARE_PTR(MyClass,(int i),(i)) +public: // can be protected + MyClass ( int i ) + { + ... + } + void MyPureVirtFunc() = 0; + ... +}; +MyClass::Ptr ptr ( i ); +*/ + +#define DECLARE_PTRV(cls) \ + class Ptr : public SPtr \ + { \ + Ptr(cls* p) : SPtr ( p ) \ + { \ + } \ + }; +/* Example Usage of DECLARE_PTRV: +class MyAbstractClass +{ + DECLARE_PTRV(MyAbstractClass) +public: // can be protected + MyAbstractClass ( int i ) + { + ... + } + void MyPureVirtFunc() = 0; + ... +}; +MyAbstractClass::Ptr ptr ( new MySubClass(i) ); +*/ + +#endif//__RELI_H diff --git a/rosapps/games/ArchBlackmann/ReliMT.cpp b/rosapps/games/ArchBlackmann/ReliMT.cpp new file mode 100644 index 00000000000..2c50dc40f1c --- /dev/null +++ b/rosapps/games/ArchBlackmann/ReliMT.cpp @@ -0,0 +1,331 @@ +// ReliMT.cpp +// lots of code here is (c) Bartosz Milewski, 1996, www.relisoft.com +// The rest is (C) 2002-2004 Royce Mitchell III +// and released under the LGPL & BSD licenses + +#include +#include +#ifdef WIN32 +# define WIN32_LEAN_AND_MEAN +# include +# define snprintf _snprintf +#elif defined(UNIX) +# include +# include +#else +# error unrecognized target +#endif//WIN32|UNIX +#include "verify.h" +#include "ReliMT.h" + +//////////////////////////////////////////////////////////////////////////////// +// Assert + +void _wassert ( char* szExpr, char* szFile, int line ) +{ + fprintf ( stderr, "Assertion Failure: \"%s\" in file %s, line %d", szExpr, szFile, line ); + exit (-1); +} + + +//////////////////////////////////////////////////////////////////////////////// +// Thread + +Thread::Thread ( long (THREADAPI * pFun) (void* arg), void* pArg ) +{ +#ifdef WIN32 + verify ( _handle = CreateThread ( + 0, // Security attributes + 0, // Stack size + (DWORD (WINAPI*)(void*))pFun, + pArg, + 0, // don't create suspended. + &_tid )); +#elif defined(UNIX) + // set up the thread attribute: right now, we do nothing with it. + pthread_attr_t attr; + pthread_attr_init(&attr); + + // this will make the threads created by this process really concurrent + verify ( !pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM) ); + + // create the new OS thread object + verify ( !pthread_create ( &_threadId, &attr, (void* (*) (void*))pFun, pArg ) ); + + verify ( !pthread_attr_destroy(&attr) ); +#else +# error unrecognized target +#endif//WIN32|UNIX +} + +Thread::~Thread() +{ +#ifdef WIN32 + verify ( CloseHandle ( _handle ) ); +#elif defined(UNIX) + verify ( !pthread_cancel ( _threadId ) ); +#else +# error unrecognized target +#endif//WIN32|UNIX +} + +/*void Thread::Resume() +{ +#ifdef WIN32 + ResumeThread (_handle); +#elif defined(UNIX) +# error how to resume thread in unix? +#else +# error unrecognized target +#endif//WIN32|UNIX +}*/ + +void Thread::WaitForDeath() +{ +#ifdef WIN32 + DWORD dw = WaitForSingleObject ( _handle, 2000 ); + ASSERT ( dw != WAIT_FAILED ); +#elif defined(UNIX) + verify ( !pthread_join ( _threadId, (void**)NULL ) ); +#else +# error unrecognized target +#endif//WIN32|UNIX +} + + +//////////////////////////////////////////////////////////////////////////////// +// ActiveObject + +// The constructor of the derived class +// should call +// _thread.Resume(); +// at the end of construction + +ActiveObject::ActiveObject() : _isDying (0), _thread (0) +{ +} + +ActiveObject::~ActiveObject() +{ + ASSERT ( !_thread ); // call Kill() from subclass's dtor + // Kill() - // You can't call a virtual function from a dtor, EVEN INDIRECTLY + // so, you must call Kill() in the subclass's dtor +} + +// FlushThread must reset all the events on which the thread might be waiting. +void ActiveObject::Kill() +{ + if ( _thread ) + { + _isDying++; + FlushThread(); + // Let's make sure it's gone + _thread->WaitForDeath(); + delete _thread; + _thread = 0; + } +} + +void ActiveObject::Start() +{ + ASSERT ( !_thread ); + _thread = new Thread ( ThreadEntry, this ); +} + +long THREADAPI ActiveObject::ThreadEntry ( void* pArg ) +{ + ActiveObject * pActive = (ActiveObject*)pArg; + pActive->InitThread(); + pActive->Run(); + pActive->Kill(); + return 0; +} + + +/////////////////////////////////////////////////////////////////////////////// +// Mutex + +Mutex::Mutex() +{ +#ifdef WIN32 + verify ( _h = CreateMutex ( NULL, FALSE, NULL ) ); +#elif defined(UNIX) + pthread_mutexattr_t attrib; + verify ( !pthread_mutexattr_init( &attrib ) ); + // allow recursive locks + verify ( !pthread_mutexattr_settype( &attrib, PTHREAD_MUTEX_RECURSIVE ) ); + verify ( !pthread_mutex_init ( &_mutex, &attrib ) ); +#else +# error unrecognized target +#endif +} + +Mutex::~Mutex() +{ +#ifdef WIN32 + verify ( CloseHandle ( _h ) ); +#elif defined(UNIX) + verify ( !pthread_mutex_destroy(&_mutex) ); +#else +# error unrecognized target +#endif +} + +void Mutex::Acquire() +{ +#ifdef WIN32 + DWORD dw = WaitForSingleObject ( _h, INFINITE ); + ASSERT ( dw == WAIT_OBJECT_0 || dw == WAIT_ABANDONED ); +#elif defined(UNIX) + verify ( !pthread_mutex_lock(&_mutex) ); +#else +# error unrecognized target +#endif +} + +bool Mutex::TryAcquire() +{ +#ifdef WIN32 + DWORD dw = WaitForSingleObject ( _h, 1 ); + ASSERT ( dw == WAIT_OBJECT_0 || dw == WAIT_TIMEOUT || dw == WAIT_ABANDONED ); + return (dw != WAIT_TIMEOUT); +#elif defined(UNIX) + int err = pthread_mutex_trylock(&_mutex); + ASSERT ( err == EBUSY || err == 0 ); + return (err == 0); +#else +# error unrecognized target +#endif +} + +void Mutex::Release() +{ +#ifdef WIN32 + verify ( ReleaseMutex ( _h ) ); +#elif defined(UNIX) + verify ( !pthread_mutex_unlock(&_mutex) ); + // we could allow EPERM return value too, but we are forcing user into RIIA +#else +# error unrecognized target +#endif +} + +Mutex::Lock::Lock ( Mutex& m ) : _m(m) +{ + _m.Acquire(); +} + +Mutex::Lock::~Lock() +{ + _m.Release(); +} + +Mutex::TryLock::TryLock ( Mutex& m ) : _m(m) +{ + _bLocked = _m.TryAcquire(); +} + +Mutex::TryLock::~TryLock() +{ + if ( _bLocked ) + _m.Release(); +} + +/////////////////////////////////////////////////////////////////////////////// +// Event + +Event::Event() +{ +#ifdef WIN32 + // start in non-signaled state (red light) + // auto reset after every Wait + verify ( _handle = CreateEvent ( 0, FALSE, FALSE, 0 ) ); +#elif defined(UNIX) + //verify ( !pthread_cond_init ( &_cond, NULL /* default attributes */) ); + sem_init(); + //verify(sem_init()); +#else +# error unrecognized target +#endif +} + +Event::~Event() +{ +#ifdef WIN32 + verify ( CloseHandle ( _handle ) ); +#elif defined(UNIX) + //verify ( !pthread_cond_destroy ( &_cond ) ); + sem_destroy(); +#else +# error unrecognized target +#endif +} + +void Event::Release() // put into signaled state +{ +#ifdef WIN32 + verify ( SetEvent ( _handle ) ); +#elif defined(UNIX) + //verify ( !pthread_cond_signal ( &_cond ) ); + verify(!sem_V()); +#else +# error unrecognized target +#endif +} + +void Event::Wait() +{ +#ifdef WIN32 + // Wait until event is in signaled (green) state + DWORD dw = WaitForSingleObject ( _handle, INFINITE ); + ASSERT ( dw == WAIT_OBJECT_0 || dw == WAIT_ABANDONED ); +#elif defined(UNIX) + // According to docs: The pthread_cond_wait() and pthread_cond_timedwait() + // functions are used to block on a condition variable. They are called + // with mutex locked by the calling thread or undefined behaviour will + // result. + //Mutex::Lock lock ( _mutex ); + //verify ( !pthread_cond_wait ( &_cond, _mutex ) ); + verify(!sem_P()); +#else +# error unrecognized target +#endif +} + +#ifdef UNIX +void Event::sem_init() +{ + sem_id = semget(IPC_PRIVATE, 1, 0666 | IPC_CREAT); + ASSERT(sem_id != -1); +} + +int Event::sem_P() +{ + struct sembuf sb; + sb.sem_num = 0; + sb.sem_op = -1; + sb.sem_flg = 0; + return semop(sem_id, &sb, 1); +} + +int Event::sem_V() +{ + struct sembuf sb; + sb.sem_num = 0; + sb.sem_op = 1; + sb.sem_flg = 0; + return semop(sem_id, &sb, 1); +} + +void Event::sem_destroy() +{ +#ifdef MACOSX + semun mactmp; + mactmp.val = 0; + semctl(sem_id, 0, IPC_RMID, mactmp); +#else + semctl(sem_id, 0, IPC_RMID, 0); +#endif +} +#endif + diff --git a/rosapps/games/ArchBlackmann/ReliMT.h b/rosapps/games/ArchBlackmann/ReliMT.h new file mode 100644 index 00000000000..17fb12169a6 --- /dev/null +++ b/rosapps/games/ArchBlackmann/ReliMT.h @@ -0,0 +1,229 @@ +// ReliMT.h +// lots of code here is (c) Bartosz Milewski, 1996, www.relisoft.com +// The rest is (C) 2003-2004 Royce Mitchell III +// and released under the LGPL & BSD licenses + + +#ifndef __RELIMT_H +#define __RELIMT_H + +#include "Reli.h" + +#ifdef WIN32 +# ifndef _WINDOWS_ +# define WIN32_LEAN_AND_MEAN +# include +# endif +# define THREADAPI WINAPI +#elif defined(UNIX) +# include +# include +# include "string.h" +# include //Semaphore +# include //Semaphore +# include //Semaphore +# define THREADAPI +#else +# error unrecognized target +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// Thread + +class Thread : public Uncopyable +{ +public: + Thread ( long (THREADAPI * pFun) (void* arg), void* pArg ); + ~Thread(); + //void Resume(); + void WaitForDeath(); + + // platform-specific stuff: +private: +#ifdef WIN32 + HANDLE _handle; + DWORD _tid; // thread id +#elif defined(UNIX) + pthread_t _threadId; // id of the thread +#else +# error unrecognized target +#endif + //DECLARE_PTR(Thread,(long (THREADAPI * pFun) (void* arg), void* pArg),(pFun,pArg)); +}; //DECLARE_SPTR(Thread,(long (THREADAPI * pFun) (void* arg), void* pArg),(pFun,pArg)); + +//////////////////////////////////////////////////////////////////////////////// +// ActiveObject + +class ActiveObject : public Uncopyable +{ +public: + ActiveObject(); + virtual ~ActiveObject(); + void Kill(); + void Start(); + +protected: + virtual void InitThread() = 0; + virtual void Run() = 0; + virtual void FlushThread() = 0; + + int _isDying; + + static long THREADAPI ThreadEntry ( void *pArg ); + Thread *_thread; + + //DECLARE_PTRV(ActiveObject); +}; //DECLARE_SPTRV(ActiveObject); + +// Last thing in the constructor of a class derived from +// ActiveObject you must call +// Start(); +// Inside the loop the Run method you must keep checking _isDying +// if (_isDying) +// return; +// FlushThread must reset all the events on which the thread might be waiting. +// Example: +#if 0 +// MyAsyncOutputter - class that outputs strings to a file asynchronously +class MyAsyncOutputter : public ActiveObject +{ +public: + MyAsyncOutputter ( const string& filename ) : _filename(filename), _currentBuf(0) + { + Start(); // start thread + } + void InitThread() + { + _f.open ( _filename, "wb" ); + } + void Output ( const string& s ) + { + { + // acquire lock long enough to add the string to the active buffer + Mutex::Lock lock ( _mutex ); + _buf[_currentBuf].push_back ( s ); + } + _event.Release(); // don't need the lock fire the event + } + void Run() + { + while ( !_isDying ) + { + // wait for signal from Output() or FlushThread() + _event.Wait(); + { + // acquire lock long enough to switch active buffers + Mutex::Lock lock ( _mutex ); + _currentBuf = 1-_currentBuf; + ASSERT ( !_buf[_currentBuf].size() ); + } + // get a reference to the old buffer + vector& buf = _buf[1-_currentBuf]; + // write each string out to file and then empty the buffer + for ( int i = 0; i < buf.size(); i++ ) + _f.write ( buf[i].c_str(), buf[i].size() ); + buf.resize(0); + } + } + void FlushThread() + { + // _isDying is already set: signal thread so it can see that too + _event.Release(); + } +private: + string _filename; + File _f; + int _currentBuf; + vector _buf[2]; + Event _event; + Mutex _mutex; +}; +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Mutex + +class Mutex : public Uncopyable +{ +public: + Mutex(); + ~Mutex(); +private: + void Acquire(); + bool TryAcquire(); + void Release(); +public: + // sub-class used to lock the Mutex + class Lock : public Uncopyable + { + public: + Lock ( Mutex& m ); + ~Lock(); + + private: + // private data + Mutex& _m; + }; + friend class Mutex::Lock; + + + // sub-class used to attempt to lock the mutex. Use operator bool() + // to test if the lock was successful + class TryLock : public Uncopyable + { + public: + TryLock ( Mutex& m ); + ~TryLock(); + operator bool () { return _bLocked; } + + private: + // private data + bool _bLocked; + Mutex& _m; + }; + friend class Mutex::TryLock; + +private: + // platform-specific stuff: +#ifdef WIN32 + HANDLE _h; +#elif defined(UNIX) + pthread_mutex_t _mutex; +public: operator pthread_mutex_t* () { return &_mutex; } +#else +# error unrecognized target +#endif +}; + +//////////////////////////////////////////////////////////////////////////////// +// Event + +class Event : public Uncopyable +{ +public: + Event(); + ~Event(); + void Release(); // put into signaled state + void Wait(); + +private: +#ifdef WIN32 + HANDLE _handle; +#elif defined(UNIX) + //Sem util functions + void sem_init(); + int sem_P(); + int sem_V(); + void sem_destroy(); + + int sem_id; + //pthread_cond_t _cond; + //Mutex _mutex; +#else +# error unrecognized target +#endif + //DECLARE_PTR(Event,(),()); +}; //DECLARE_SPTR(Event,(),()); + +#endif//__RELIWIN32_H diff --git a/rosapps/games/ArchBlackmann/SockUtils.cpp b/rosapps/games/ArchBlackmann/SockUtils.cpp new file mode 100644 index 00000000000..3398b8d88c1 --- /dev/null +++ b/rosapps/games/ArchBlackmann/SockUtils.cpp @@ -0,0 +1,504 @@ +// SockUtils.cpp - Some basic socket utility functions. +// (C) 2002-2004 Royce Mitchell III +// This file is under the BSD & LGPL licenses + +#include +#include "SockUtils.h" +#ifdef WIN32 +# ifndef SD_SEND // defined in winsock2.h, but not winsock.h +# define SD_SEND 1 +# endif +# define snprintf _snprintf +# ifdef _MSC_VER +# pragma comment ( lib, "ws2_32.lib" ) +# endif//_MSC_VER +#elif defined(UNIX) +# include +# include "string.h" // memset +# include // hostent +# include //inet_addr +# include +# define SD_SEND SHUT_WR //bah thou shalt name thy defines the same +#else +# error unrecognized target +#endif +//// Constants ///////////////////////////////////////////////////////// +const int kBufferSize = 1024; +// creates broadcast address +SockAddrIn::SockAddrIn() +{ + memset ( this, 0, sizeof(sockaddr_in) ); + sin_family = AF_INET; +} +SockAddrIn::SockAddrIn ( const char* szAddr, u_short iPort ) +{ + memset ( this, 0, sizeof(sockaddr_in) ); + sin_family = AF_INET; + sin_addr.s_addr = suLookupAddress(szAddr); + sin_port = htons(iPort); +} +SockAddrIn::SockAddrIn ( in_addr_t iAddr, u_short iPort ) +{ + memset ( this, 0, sizeof(sockaddr_in) ); + sin_family = AF_INET; + sin_addr.s_addr = iAddr; + sin_port = htons(iPort); +} +bool suStartup() +{ +#ifdef WIN32 + WSADATA wsaData; + if ( WSAStartup ( MAKEWORD(2,0), &wsaData ) ) + return false; + if ( wsaData.wVersion != MAKEWORD(2,0) ) + { + WSACleanup(); + return false; + } + return true; +#elif defined(UNIX) + // nothing special required here + return true; +#else +# error unrecognized target +#endif +} +//// suTcpSocket //////////////////////////////////////////////// +// Creates a TCP socket. +SOCKET suTcpSocket() +{ + SOCKET so = socket ( AF_INET, SOCK_STREAM, 0 ); +#if defined(_DEBUG) && defined(WIN32) + if ( so == INVALID_SOCKET && WSANOTINITIALISED == WSAGetLastError() ) + MessageBox ( NULL, "You forgot to call suStartup()!", "SockUtils", MB_OK|MB_ICONEXCLAMATION ); +#endif + return so; +} +//// suUdpSocket //////////////////////////////////////////////// +// Creates a UDP socket. Compensates for new "functionality" introduced +// in Win2K with regards to select() calls +// MS Transport Provider IOCTL to control +// reporting PORT_UNREACHABLE messages +// on UDP sockets via recv/WSARecv/etc. +// Path TRUE in input buffer to enable (default if supported), +// FALSE to disable. +#ifndef SIO_UDP_CONNRESET +#define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR,12) +#endif//SIO_UDP_CONNRESET +SOCKET suUdpSocket() +{ + SOCKET so = socket ( AF_INET, SOCK_DGRAM, 0 ); +#if defined(_DEBUG) && defined(WIN32) + if ( so == INVALID_SOCKET && WSANOTINITIALISED == WSAGetLastError() ) + MessageBox ( NULL, "You forgot to call suStartup()!", "SockUtils", MB_OK|MB_ICONEXCLAMATION ); +#endif +#ifdef WIN32 + // for Windows 2000, disable new behavior... + // see: http://www-pc.uni-regensburg.de/systemsw/W2KPRO/UPDATE/POSTSP1/Q263823.htm + // this code is innocuous on other win32 platforms + DWORD dwBytesReturned = 0; + BOOL bNewBehavior = FALSE; + // disable new Win2K behavior using + // IOCTL: SIO_UDP_CONNRESET + // we don't care about return value :) + WSAIoctl(so, SIO_UDP_CONNRESET, + &bNewBehavior, sizeof(bNewBehavior), + NULL, 0, &dwBytesReturned, + NULL, NULL); +#endif + return so; +} +//// suShutdownConnection //////////////////////////////////////////////// +// Gracefully shuts the connection sd down. Returns true if it was able +// to shut it down nicely, false if we had to "slam" it shut. +// (either way, the socket does get closed) +bool suShutdownConnection(SOCKET sd) +{ + if ( sd == INVALID_SOCKET ) + return true; + // Disallow any further data sends. This will tell the other side + // that we want to go away now. If we skip this step, we don't + // shut the connection down nicely. + if (shutdown(sd, SD_SEND) == SOCKET_ERROR) + { + closesocket(sd); + return false; + } + // Receive any extra data still sitting on the socket. After all + // data is received, this call will block until the remote host + // acknowledges the TCP control packet sent by the shutdown above. + // Then we'll get a 0 back from recv, signalling that the remote + // host has closed its side of the connection. + char acReadBuffer[kBufferSize]; + for ( ;; ) + { + int nNewBytes = recv(sd, acReadBuffer, kBufferSize, 0); + if (nNewBytes == SOCKET_ERROR) + { + closesocket(sd); + return false; + } + else if (nNewBytes != 0) + { + // FYI, received (nNewBytes) unexpected bytes during shutdown. + } + else + { + // Okay, we're done! + break; + } + } + // Close the socket. + if (closesocket(sd) == SOCKET_ERROR) + { + return false; + } + return true; +} +//// suLookupAddress //////////////////////////////////////////////// +// Basically converts a name address to an ip address +in_addr_t suLookupAddress ( const char* pcHost ) +{ + in_addr_t nRemoteAddr = inet_addr(pcHost); + if ( nRemoteAddr == INADDR_NONE ) + { + // pcHost isn't a dotted IP, so resolve it through DNS + hostent* pHE = gethostbyname(pcHost); + if ( pHE == 0 ) + { +#if defined(_DEBUG) && defined(WIN32) + if ( WSANOTINITIALISED == WSAGetLastError() ) + MessageBox ( NULL, "You forgot to call suStartup()!", "SockUtils", MB_OK|MB_ICONEXCLAMATION ); +#endif + return INADDR_NONE; + } + nRemoteAddr = *((in_addr_t*)pHE->h_addr_list[0]); + } + return nRemoteAddr; +} +bool suConnect ( SOCKET so, in_addr_t iAddress, u_short iPort ) +{ + SockAddrIn sinRemote ( iAddress, iPort ); + if ( SOCKET_ERROR == connect(so,sinRemote,sizeof(sinRemote)) ) + { +#if defined(_DEBUG) && defined(WIN32) + if ( WSANOTINITIALISED == WSAGetLastError() ) + MessageBox ( NULL, "You forgot to call suStartup()!", "SockUtils", MB_OK|MB_ICONEXCLAMATION ); +#endif + return false; + } + return true; +} +bool suConnect ( SOCKET so, const char* szAddress, u_short iPort ) +{ + return suConnect ( so, suLookupAddress(szAddress), iPort ); +} +//// suEstablishConnection //////////////////////////////////////////////// +// creates a socket of the specified type, connects to the ip address/port +// requested, and returns the SOCKET created +SOCKET suEstablishConnection ( in_addr_t iAddress, u_short iPort, int type ) +{ + // Create a socket + if ( type != SOCK_STREAM && type != SOCK_DGRAM ) + return INVALID_SOCKET; + SOCKET so = socket(AF_INET, type, 0); + if ( so == INVALID_SOCKET ) + return so; + if ( !suConnect(so, iAddress, iPort) ) + { + closesocket(so); + return INVALID_SOCKET; + } + return so; +} +//// suEstablishConnection //////////////////////////////////////////////// +// creates a socket of the specified type, connects to the address/port +// requested, and returns the SOCKET created +SOCKET suEstablishConnection ( const char* szAddress, u_short iPort, int type ) +{ + return suEstablishConnection ( suLookupAddress ( szAddress ), iPort, type ); +} +//// suBroadcast //////////////////////////////////////////////// +// takes a previously created broadcast-enabled UDP socket, and broadcasts +// a message on the local network +bool suBroadcast ( SOCKET so, u_short port, const char* buf, int len /* = -1 */ ) +{ + if ( len == -1 ) + len = (int)strlen(buf); +#if 1 + SockAddrIn to ( INADDR_BROADCAST, port ); +#else // some strange MS OS's don't broadcast to localhost... + SockAddrIn to ( "127.0.0.1", port ); + if ( SOCKET_ERROR == sendto ( so, buf, len, 0, to, sizeof(to) ) ) + return false; + to.sin_addr.s_addr = INADDR_BROADCAST; +#endif + if ( SOCKET_ERROR == sendto ( so, buf, len, 0, to, sizeof(to) ) ) + return false; + return true; +} +//// suRecv //////////////////////////////////////////////// +// retrieves data sent to our TCP socket. If no data, waits for +// a period of timeout ms. +// returns bytes received +// -1 == SOCKET_ERROR +// -2 == timed out waiting for data +int suRecv ( SOCKET so, char* buf, int buflen, int timeout ) +{ + struct timeval to; + fd_set rread; + int res; + FD_ZERO(&rread); // clear the fd_set + FD_SET(so,&rread); // indicate which socket(s) we want to check + memset((char *)&to,0,sizeof(to)); // clear the timeval struct + to.tv_sec = timeout; // timeout select after (timeout) seconds + // select returns > 0 if there is an event on the socket + res = select((int)so+1, &rread, (fd_set *)0, (fd_set *)0, &to ); + if (res < 0) + return -1; // socket error + // there was an event on the socket + if ( (res>0) && (FD_ISSET(so,&rread)) ) + return recv ( so, buf, buflen, 0 ); + return -2; +} +//// suRecvFrom //////////////////////////////////////////////// +// retrieves data sent to our UDP socket. If no data, waits for +// a period of timeout ms. +// returns bytes received +// returns bytes received +// -1 == SOCKET_ERROR +// -2 == timed out waiting for data +int suRecvFrom ( SOCKET so, char* buf, int buflen, int timeout, sockaddr_in* from, socklen_t* fromlen ) +{ + struct timeval to; + fd_set rread; + int res; + FD_ZERO(&rread); // clear the fd_set + FD_SET(so,&rread); // indicate which socket(s) we want to check + memset((char *)&to,0,sizeof(to)); // clear the timeval struct + to.tv_sec = timeout; // timeout select after (timeout) seconds + // select returns > 0 if there is an event on the socket + res = select((int)so+1, &rread, (fd_set *)0, (fd_set *)0, &to ); + if (res < 0) + return -1; // socket error + // there was an event on the socket + if ( (res>0) && (FD_ISSET(so,&rread)) ) + return recvfrom ( so, buf, buflen, 0, (sockaddr*)from, fromlen ); + return -2; // timeout +} +//// suBind //////////////////////////////////////////////// +// binds a UDP socket to an interface & port to receive +// data on that port +bool suBind ( SOCKET so, in_addr_t iInterfaceAddress, u_short iListenPort, bool bReuseAddr /* = false */ ) +{ + SockAddrIn sinInterface ( iInterfaceAddress, iListenPort ); + if ( bReuseAddr ) + { + int optval = -1; // true + if ( SOCKET_ERROR == setsockopt ( so, SOL_SOCKET, SO_REUSEADDR, (const char*)&optval, sizeof(optval) ) ) + { +#if defined(_DEBUG) && defined(WIN32) + if ( WSANOTINITIALISED == WSAGetLastError() ) + MessageBox ( NULL, "You forgot to call suStartup()!", "SockUtils", MB_OK|MB_ICONEXCLAMATION ); +#endif + return false; + } + } + if ( SOCKET_ERROR == bind(so, sinInterface, sizeof(sinInterface)) ) + { + int err = SUERRNO; + if ( err != EADDRINUSE ) + return false; +#if defined(_DEBUG) && defined(WIN32) + if ( WSANOTINITIALISED == WSAGetLastError() ) + MessageBox ( NULL, "You forgot to call suStartup()!", "SockUtils", MB_OK|MB_ICONEXCLAMATION ); +#endif + } + return true; +} +//// suBind //////////////////////////////////////////////// +// binds a UDP socket to an interface & port to receive +// data on that port +bool suBind ( SOCKET so, const char* szInterfaceAddress, u_short iListenPort, bool bReuseAddr /* = false */ ) +{ + in_addr_t iInterfaceAddr = inet_addr(szInterfaceAddress); + if ( iInterfaceAddr == INADDR_NONE ) + return false; + return suBind ( so, iInterfaceAddr, iListenPort, bReuseAddr ); +} +//// suEnableBroadcast //////////////////////////////////////////////// +// in order to send broadcast messages on a UDP socket, this function +// must be called first +bool suEnableBroadcast ( SOCKET so, bool bEnable /* = true */ ) +{ + int optval = bEnable ? -1 : 0; + if ( SOCKET_ERROR == setsockopt ( so, SOL_SOCKET, SO_BROADCAST, (const char*)&optval, sizeof(optval) ) ) + return false; + return true; +} +//// suErrDesc //////////////////////////////////////////////// +// returns text description of error code +const char* suErrDesc ( int err ) +{ + static char errbuf[256]; +#ifdef WIN32 + switch ( err ) + { +#define X(E) case E: return #E; + X(WSAEINTR) X(WSAEBADF) + X(WSAEACCES) X(WSAEFAULT) + X(WSAEINVAL) X(WSAEMFILE) + X(WSAEWOULDBLOCK) X(WSAEINPROGRESS) + X(WSAEALREADY) X(WSAENOTSOCK) + X(WSAEDESTADDRREQ) X(WSAEMSGSIZE) + X(WSAEPROTOTYPE) X(WSAENOPROTOOPT) + X(WSAEPROTONOSUPPORT) X(WSAESOCKTNOSUPPORT) + X(WSAEOPNOTSUPP) X(WSAEPFNOSUPPORT) + X(WSAEAFNOSUPPORT) X(WSAEADDRINUSE) + X(WSAEADDRNOTAVAIL) X(WSAENETDOWN) + X(WSAENETUNREACH) X(WSAENETRESET) + X(WSAECONNABORTED) X(WSAECONNRESET) + X(WSAENOBUFS) X(WSAEISCONN) + X(WSAENOTCONN) X(WSAESHUTDOWN) + X(WSAETOOMANYREFS) X(WSAETIMEDOUT) + X(WSAECONNREFUSED) X(WSAELOOP) + X(WSAENAMETOOLONG) X(WSAEHOSTDOWN) + X(WSAEHOSTUNREACH) X(WSAENOTEMPTY) + X(WSAEPROCLIM) X(WSAEUSERS) + X(WSAEDQUOT) X(WSAESTALE) + X(WSAEREMOTE) X(WSASYSNOTREADY) + X(WSAVERNOTSUPPORTED) X(WSANOTINITIALISED) + X(WSAEDISCON) X(WSAENOMORE) + X(WSAECANCELLED) X(WSAEINVALIDPROCTABLE) + X(WSAEINVALIDPROVIDER) X(WSAEPROVIDERFAILEDINIT) + X(WSASYSCALLFAILURE) X(WSASERVICE_NOT_FOUND) + X(WSATYPE_NOT_FOUND) X(WSA_E_NO_MORE) + X(WSA_E_CANCELLED) X(WSAEREFUSED) +#undef X + } + snprintf ( errbuf, sizeof(errbuf), "Unknown socket error (%lu)", err ); + errbuf[sizeof(errbuf)-1] = '\0'; + return errbuf; +#elif defined(UNIX) + perror(errbuf); + return errbuf; +#else +# error unrecognized target +#endif +} +#if defined(UNICODE) || defined(_UNICODE) +in_addr_t suLookupAddress ( const wchar_t* pcHost ) +{ + int len = wcslen(pcHost); + char* p = new char[len+1]; + wcstombs ( p, pcHost, len ); + p[len] = 0; + in_addr_t rc = suLookupAddress ( p ); + delete[] p; + return rc; +} +bool suBroadcast ( SOCKET so, u_short port, const wchar_t* buf, int len /* = -1 */ ) +{ + char* p = new char[len+1]; + wcstombs ( p, buf, len ); + p[len] = 0; + bool rc = suBroadcast ( so, port, p, len ); + delete[] p; + return rc; +} +int suRecv ( SOCKET so, wchar_t* buf, int buflen, int timeout ) +{ + char* p = new char[buflen+1]; + int rc = suRecv ( so, p, buflen, timeout ); + p[buflen] = 0; + mbstowcs ( buf, p, buflen ); + delete[] p; + return rc; +} +int suRecvFrom ( SOCKET so, wchar_t* buf, int buflen, int timeout, sockaddr_in* from, int* fromlen ) +{ + char* p = new char[buflen+1]; + int rc = suRecvFrom ( so, p, buflen, timeout, from, fromlen ); + p[buflen] = 0; + mbs2wcs ( buf, p, buflen ); + delete[] p; + return rc; +} +bool suBind ( SOCKET so, const wchar_t* szInterfaceAddress, u_short iListenPort, bool bReuseAddr /* = false */ ) +{ + int len = wcslen(szInterfaceAddress); + char* p = new char[len+1]; + wcstombs ( p, szInterfaceAddress, len ); + p[len] = 0; + bool rc = suBind ( so, p, iListenPort, bReuseAddr ); + delete[] p; + return rc; +} +#endif//UNICODE + +suBufferedRecvSocket::suBufferedRecvSocket ( SOCKET so ) + : suSocket ( so ), _off(0), _len(0) +{ +} + +int suBufferedRecvSocket::recvUntil ( std::string& buf, char until, int timeout ) +{ + if ( !_len ) + _off = 0; + else if ( _off > (sizeof(_buf)>>1) ) + { + memmove ( _buf, &_buf[_off], _len ); + _off = 0; + } + char* poff = &_buf[_off]; + for ( ;; ) + { + char* p = (char*)memchr ( poff, until, _len ); + if ( p /*&& p < &poff[_len]*/ ) + { + int ret_len = p-poff+1; + buf.resize ( ret_len ); + memmove ( &buf[0], poff, ret_len ); + _off += ret_len; + _len -= ret_len; + return ret_len; + } + int rc = suRecv ( *this, &poff[_len], sizeof(_buf)-_len-_off, timeout ); + if ( rc < 0 ) + { + if ( _len ) + { + rc = _len; + buf.resize ( rc ); + memmove ( &buf[0], &_buf[_off], rc ); + _len = 0; + } + return rc; + } + _len += rc; + } +} + +void suBufferedRecvSocket::recvPending() +{ + if ( !_len ) + _off = 0; + else if ( _off > (sizeof(_buf)>>1) ) + { + memmove ( _buf, &_buf[_off], _len ); + _off = 0; + } + char* poff = &_buf[_off]; + while ( sizeof(_buf)-_len-_off ) + { + int rc = suRecv ( *this, &poff[_len], sizeof(_buf)-_len-_off, 1 ); + if ( rc <= 0 ) + break; + _len += rc; + } +} + +bool suBufferedRecvSocket::recvInStr ( char c ) +{ + return NULL != memchr ( &_buf[_off], c, _len ); +} diff --git a/rosapps/games/ArchBlackmann/SockUtils.h b/rosapps/games/ArchBlackmann/SockUtils.h new file mode 100644 index 00000000000..60853f05964 --- /dev/null +++ b/rosapps/games/ArchBlackmann/SockUtils.h @@ -0,0 +1,132 @@ +// SockUtils.h - Declarations for the Winsock utility functions module. +// (C) 2002-2004 Royce Mitchell III +// This file is under the BSD & LGPL licenses + +#ifndef __SOCKUTILS_H +#define __SOCKUTILS_H + +#include +#ifdef WIN32 +# include +# define in_addr_t u_long +# define SUERRNO WSAGetLastError() +# define EADDRINUSE WSAEADDRINUSE +# define ENOTSOCK WSAENOTSOCK +# define socklen_t int +#elif defined(UNIX) +# include +# include +# include +# include +# include +# define closesocket(so) close(so) +# define SOCKET int +# define INVALID_SOCKET -1 +# define SOCKET_ERROR -1 +# define SUERRNO errno +# ifdef MACOSX +# define socklen_t int //Stupid mac +# endif +#else +# error unrecognized target +#endif + +#include + +extern bool suStartup(); +extern SOCKET suTcpSocket(); +extern SOCKET suUdpSocket(); +extern bool suShutdownConnection(SOCKET sd); +extern in_addr_t suLookupAddress ( const char* pcHost ); +extern bool suConnect ( SOCKET so, in_addr_t iAddress, u_short iPort ); +extern bool suConnect ( SOCKET so, const char* szAddress, u_short iPort ); +extern SOCKET suEstablishConnection ( in_addr_t iAddress, u_short iPort, int type ); +extern SOCKET suEstablishConnection ( const char* szAddress, u_short iPort, int type ); +extern bool suBroadcast ( SOCKET so, u_short port, const char* buf, int len = -1 ); +extern int suRecv ( SOCKET so, char* buf, int buflen, int timeout ); +extern int suRecvFrom ( SOCKET so, char* buf, int buflen, int timeout, sockaddr_in* from, socklen_t* fromlen ); +extern bool suBind ( SOCKET so, in_addr_t iInterfaceAddress, u_short iListenPort, bool bReuseAddr = false ); +extern bool suBind ( SOCKET so, const char* szInterfaceAddress, u_short iListenPort, bool bReuseAddr = false ); +extern bool suEnableBroadcast ( SOCKET so, bool bEnable = true ); +extern const char* suErrDesc ( int err ); + +#if defined(UNICODE) || defined(_UNICODE) +extern in_addr_t suLookupAddress ( const wchar_t* pcHost ); +extern bool suBroadcast ( SOCKET so, u_short port, const wchar_t* buf, int len = -1 ); +extern int suRecv ( SOCKET so, wchar_t* buf, int buflen, int timeout ); +extern int suRecvFrom ( SOCKET so, wchar_t* buf, int buflen, int timeout, sockaddr_in* from, int* fromlen ); +extern bool suBind ( SOCKET so, const wchar_t* szInterfaceAddress, u_short iListenPort, bool bReuseAddr = false ); +#endif//UNICODE + +class suSocket +{ + SOCKET _so; +public: + suSocket ( SOCKET so = INVALID_SOCKET ) : _so(so) + { + } + const suSocket& operator = ( SOCKET so ) + { + assert ( _so == INVALID_SOCKET ); // must Detach() or Close() existing socket first + _so = so; + return *this; + } + virtual ~suSocket() + { + Close(); + } + void Close() + { + if ( _so != INVALID_SOCKET ) + { + //suShutdownConnection ( _so ); // TODO - only valid on TCP sockets + closesocket ( _so ); + _so = INVALID_SOCKET; + } + } + operator SOCKET() const + { + return _so; + } + SOCKET Attach ( SOCKET so ) + { + SOCKET old = Detach(); + _so = so; + return old; + } + SOCKET Detach() + { + SOCKET so = _so; + _so = INVALID_SOCKET; + return so; + } + +private: + // disable copy semantics + suSocket ( const suSocket& ); + const suSocket& operator = ( const suSocket& ); +}; + +class suBufferedRecvSocket : public suSocket +{ + char _buf[2048]; + int _off; + int _len; +public: + suBufferedRecvSocket ( SOCKET so = INVALID_SOCKET ); + int recvUntil ( std::string& buf, char until, int timeout ); + void recvPending(); + bool recvInStr ( char c ); +}; + +class SockAddrIn : public sockaddr_in +{ +public: + SockAddrIn(); // creates broadcast address + SockAddrIn ( const char* szAddr, u_short iPort ); + SockAddrIn ( in_addr_t iAddr, u_short iPort ); + operator sockaddr* () { return (sockaddr*)this; } + operator sockaddr_in* () { return (sockaddr_in*)this; } +}; + +#endif//__SOCKUTILS_H diff --git a/rosapps/games/ArchBlackmann/SplitJoin.cpp b/rosapps/games/ArchBlackmann/SplitJoin.cpp new file mode 100644 index 00000000000..f7dd8a4c9d7 --- /dev/null +++ b/rosapps/games/ArchBlackmann/SplitJoin.cpp @@ -0,0 +1,96 @@ +// SplitJoin.cpp +// +// This code is copyright 2003-2004 Royce Mitchell III +// and released under the BSD & LGPL licenses + +#ifdef _MSC_VER +#pragma warning ( disable : 4786 ) // MSVC6 can't handle too-long template names +#endif//_MSC_VER + +//#include + +#include "SplitJoin.h" + +#include + +using std::string; +using std::vector; +//using std::stringstream; + +static const char* quotes = "\"\'"; + +bool Split ( vector& vec, const char* csv, char sep, bool merge ) +{ + string scsv ( csv ); + char* col = &scsv[0]; + vec.resize ( 0 ); + for ( ;; ) + { + char* p = col; + while ( isspace(*p) && *p != sep ) + p++; + char quote = 0; + if ( strchr ( quotes, *p ) ) + quote = *p++; + while ( *p && (*p != sep || quote) ) + { + if ( *p++ == quote ) + break; + } + + while ( isspace(*p) && *p != sep ) + p++; + + if ( *p && *p != sep ) + return false; + + string scol ( col, p-col ); + + //quote = scol[0]; + if ( quote ) + { + if ( scol[scol.size()-1] == quote ) + scol = string ( &scol[1], scol.size()-2 ); + } + + if ( scol.length() || !merge ) + vec.push_back ( scol ); + + if ( !*p ) + break; + + col = p + 1; + } + return true; +} + +bool Join ( string& csv, vector& vec, char sep ) +{ + csv.resize(0); + for ( int i = 0; i < vec.size(); i++ ) + { + if ( i ) + csv += sep; + string& s = vec[i]; + if ( strchr ( s.c_str(), sep ) ) + { + if ( strchr ( s.c_str(), '\"' ) ) + { + if ( strchr ( s.c_str(), '\'' ) ) + return false; // the sep, " and ' are all in the string, can't build valid output + csv += '\''; + csv += s; + csv += '\''; + } + else + { + csv += '\"'; + csv += s; + csv += '\"'; + } + } + else + csv += s; + } + return true; +} diff --git a/rosapps/games/ArchBlackmann/SplitJoin.h b/rosapps/games/ArchBlackmann/SplitJoin.h new file mode 100644 index 00000000000..8f1311457f7 --- /dev/null +++ b/rosapps/games/ArchBlackmann/SplitJoin.h @@ -0,0 +1,32 @@ +// SplitJoin.h +// +// This code is copyright 2003-2004 Royce Mitchell III +// and released under the BSD & LGPL licenses + +#ifndef SPLITJOIN_H +#define SPLITJOIN_H + +#include +#include + +bool Split ( + std::vector& vec, + const char* csv, + char sep=',', + bool merge=false ); + +bool Join ( + std::string& csv, + std::vector& vec, + char sep=',' ); + +inline bool Split ( + std::vector& vec, + const std::string& csv, + char sep=',', + bool merge=false ) +{ + return Split ( vec, csv.c_str(), sep, merge ); +} + +#endif//SPLIT_H diff --git a/rosapps/games/ArchBlackmann/ThreadPool.cpp b/rosapps/games/ArchBlackmann/ThreadPool.cpp new file mode 100644 index 00000000000..c545cd7b91b --- /dev/null +++ b/rosapps/games/ArchBlackmann/ThreadPool.cpp @@ -0,0 +1,240 @@ +// ThreadPool.cpp +// This file is (C) 2003-2004 Royce Mitchell III +// and released under the LGPL & BSD licenses + +#include +using std::vector; +#include "ThreadPool.h" +#include "QueueT.h" +#include "auto_vector.h" +#include "verify.h" +#include "ReliMT.h" + +class PoolableThread : public ActiveObject +{ +public: + PoolableThread ( ThreadPoolImpl& ); + ~PoolableThread() + { + Kill(); + } + void InitThread(); + void Run(); + void FlushThread(); + + ThreadPoolImpl& _pool; +}; + +class ThreadPoolLaunchData +{ +public: + ThreadPoolFunc* pFun; + void* pArg; +}; + +template +class AtomicCounter : public Uncopyable +{ + Mutex _m; + T _t; +public: + AtomicCounter ( T init = 0 ) : _t(init) + { + } + AtomicCounter ( const AtomicCounter& t ) + { + //Mutex::Lock l ( _m ); // don't need to lock since this is a ctor + Mutex::Lock l2 ( t._m ); + _t = t._t; + } + const AtomicCounter& operator = ( const AtomicCounter& t ) + { + Mutex::Lock l ( _m ); + Mutex::Lock l2 ( t._m ); + _t = t._t; + return *this; + } + T operator ++ () + { + Mutex::Lock l ( _m ); + T t = _t++; + return t; + } + const AtomicCounter& operator ++ ( int ) + { + Mutex::Lock l ( _m ); + ++_t; + return *this; + } + T operator -- () + { + Mutex::Lock l ( _m ); + T t = _t--; + return t; + } + const AtomicCounter& operator -- ( int ) + { + Mutex::Lock l ( _m ); + --_t; + return *this; + } + const AtomicCounter& operator += ( T t ) + { + Mutex::Lock l ( _m ); + return _t += t; + return *this; + } + const AtomicCounter& operator -= ( T t ) + { + Mutex::Lock l ( _m ); + return _t -= t; + return *this; + } + operator const T& () const + { + //Mutex::Lock l ( _m ); + return _t; + } + T operator !() const + { + //Mutex::Lock l ( _m ); + return !_t; + } +}; + +class ThreadPoolImpl : public Uncopyable +{ +public: + ThreadPoolImpl() : _isDying(false), _idleThreads(0) + { + } + + ~ThreadPoolImpl() + { + } + + void Shutdown() + { + _isDying = true; + while ( _idleThreads ) + { + _threadWaitEvent.Release(); + _threadStartEvent.Wait(); // let thread actually get a grip + } + } + + void Launch ( ThreadPoolFunc* pFun, void* pArg ) + { + // this mutex is necessary to make sure we never have a conflict + // between checking !_idleThreads and the call to _threadStartEvent.Wait() + // basically if 2 threads call Launch() simultaneously, and there is only + // 1 idle thread, it's possible that a new thread won't be created to + // satisfy the 2nd request until an existing thread finishes. + Mutex::Lock launchlock ( _launchMutex ); + + ASSERT ( pFun ); + ThreadPoolLaunchData* data; + { + Mutex::Lock lock ( _vectorMutex ); + if ( !_spareData.size() ) + _spareData.push_back ( new ThreadPoolLaunchData() ); + data = _spareData.pop_back().release(); + if ( !_idleThreads ) + _threads.push_back ( new PoolableThread(*this) ); + } + + data->pFun = pFun; + data->pArg = pArg; + verify ( _pendingData.Add ( data ) ); + _threadWaitEvent.Release(); // tell a thread to do it's thing... + _threadStartEvent.Wait(); // wait on a thread to pick up the request + } + + // functions for threads to call... + ThreadPoolLaunchData* GetPendingData() + { + ThreadPoolLaunchData* data = NULL; + ++_idleThreads; + _threadWaitEvent.Wait(); // waits until there's a request + --_idleThreads; + _threadStartEvent.Release(); // tell requester we got it + if ( _isDying ) + return NULL; + _pendingData.Get ( data ); + ASSERT ( data ); + return data; + } + + void RecycleData ( ThreadPoolLaunchData* data ) + { + Mutex::Lock lock ( _vectorMutex ); + _spareData.push_back ( data ); + } + + bool _isDying; + Mutex _vectorMutex, _launchMutex; + auto_vector _threads; + auto_vector _spareData; + CQueueT _pendingData; + Event _threadWaitEvent, _threadStartEvent; + AtomicCounter _idleThreads; +}; + +/////////////////////////////////////////////////////////////////////////////// +// ThreadPool + +/*static*/ ThreadPool& ThreadPool::Instance() +{ + static ThreadPool tp; + return tp; +} + +ThreadPool::ThreadPool() : _pimpl ( new ThreadPoolImpl ) +{ +}; + +ThreadPool::~ThreadPool() +{ + _pimpl->Shutdown(); + delete _pimpl; + _pimpl = 0; +} + +void ThreadPool::Launch ( ThreadPoolFunc* pFun, void* pArg ) +{ + _pimpl->Launch ( pFun, pArg ); +} + +int ThreadPool::IdleThreads() +{ + return _pimpl->_idleThreads; +} + +/////////////////////////////////////////////////////////////////////////////// +// PoolableThread + +PoolableThread::PoolableThread ( ThreadPoolImpl& pool ) : _pool(pool) +{ + Start(); +} + +void PoolableThread::InitThread() +{ +} + +void PoolableThread::Run() +{ + ThreadPoolLaunchData* data; + while ( !_isDying ) + { + data = _pool.GetPendingData(); // enter wait state if none... + if ( !data ) // NULL data means kill thread + break; + (*data->pFun) ( data->pArg ); // call the function + _pool.RecycleData ( data ); + } +} + +void PoolableThread::FlushThread() +{ +} diff --git a/rosapps/games/ArchBlackmann/ThreadPool.h b/rosapps/games/ArchBlackmann/ThreadPool.h new file mode 100644 index 00000000000..84e36f3993c --- /dev/null +++ b/rosapps/games/ArchBlackmann/ThreadPool.h @@ -0,0 +1,28 @@ +// ThreadPool.h +// This file is (C) 2003-2004 Royce Mitchell III +// and released under the LGPL & BSD licenses + +#ifndef THREADPOOL_H +#define THREADPOOL_H + +#include "ReliMT.h" + +typedef void THREADAPI ThreadPoolFunc ( void* ); + +class ThreadPoolImpl; + +class ThreadPool : public Uncopyable +{ +public: + static ThreadPool& Instance(); + ~ThreadPool(); + + void Launch ( ThreadPoolFunc* pFun, void* pArg ); + int IdleThreads(); + +private: + ThreadPool(); + ThreadPoolImpl *_pimpl; +}; + +#endif// THREADPOOL_H diff --git a/rosapps/games/ArchBlackmann/auto_ptr.h b/rosapps/games/ArchBlackmann/auto_ptr.h new file mode 100644 index 00000000000..861501eb8e7 --- /dev/null +++ b/rosapps/games/ArchBlackmann/auto_ptr.h @@ -0,0 +1,87 @@ +// auto_ptr.h +// This file is (C) 2002-2003 Royce Mitchell III +// and released under the LGPL & BSD licenses + +#ifndef AUTO_PTR_H +#define AUTO_PTR_H + +template +class auto_ptr +{ +public: + typedef T element_type; + + explicit auto_ptr(T *p = 0) : _p(p) + { + } + + auto_ptr(auto_ptr& rhs) : _p(rhs.release()) + { + } + + auto_ptr& operator=(auto_ptr& rhs) + { + if ( &rhs != this ) + { + dispose(); + _p = rhs.release(); + } + return *this; + } + + auto_ptr& set ( auto_ptr& rhs ) + { + if ( &rhs != this ) + { + dispose(); + _p = rhs.release(); + } + return *this; + } + + ~auto_ptr() + { + dispose(); + } + + void dispose() + { + if ( _p ) + { + delete _p; + _p = 0; + } + } + + T& operator[] ( int i ) + { + return _p[i]; + } + + T& operator*() const + { + return *_p; + } + + T* operator->() const + { + return _p; + } + + T* get() const + { + return _p; + } + + T* release() + { + T* p = _p; + _p = 0; + return p; + } + +private: + T* _p; +}; + +#endif//AUTO_PTR_H diff --git a/rosapps/games/ArchBlackmann/auto_vector.h b/rosapps/games/ArchBlackmann/auto_vector.h new file mode 100644 index 00000000000..cc07bb42472 --- /dev/null +++ b/rosapps/games/ArchBlackmann/auto_vector.h @@ -0,0 +1,141 @@ +// auto_vector.h +// This file is (C) 2002-2004 Royce Mitchell III +// and released under the LGPL & BSD licenses + +#ifndef AUTO_VECTOR_H +#define AUTO_VECTOR_H + +#include +#include "verify.h" +#include "auto_ptr.h" + +template +class auto_vector +{ +public: + explicit auto_vector ( size_t capacity = 0 ) + : _arr(0), _capacity(0), _end(0) + { + if ( capacity != 0 ) + _arr = new auto_ptr[capacity]; + _capacity = capacity; + } + + ~auto_vector() + { + delete []_arr; + } + + size_t size() const + { + return _end; + } + + const auto_ptr& operator [] ( size_t i ) const + { + ASSERT ( i < _end ); + return _arr[i]; + } + + auto_ptr& operator [] ( size_t i ) + { + ASSERT ( i < _end ); + return _arr[i]; + } + + void assign ( size_t i, auto_ptr& p ) + { + ASSERT ( i < _end ); + _arr[i] = p; + } + + void assign_direct ( size_t i, T * p ) + { + ASSERT ( i < _end ); + reserve ( i + 1 ); + _arr[i].reset ( ptr ); + } + + void push_back ( auto_ptr& p ) + { + reserve ( _end + 1 ); + _arr[_end++] = p; + } + + auto_ptr& back() + { + ASSERT ( _end != 0 ); + return _arr[_end-1]; + } + + void push_back ( T * p ) + { + reserve ( _end + 1 ); + auto_ptr tmp(p); + _arr[_end++] = tmp; + //GCC is pedantic, this is an error. + //_arr[_end++] = auto_ptr(p); + } + + auto_ptr pop_back() + { + ASSERT ( _end != 0 ); + if ( !_end ) + { + auto_ptr tmp((T*)0); + return tmp; + //GCC, this is an error. + //return auto_ptr(NULL); + } + return _arr[--_end]; + } + + void resize ( size_t newSize ) + { + ASSERT ( newSize >= 0 ); + reserve ( newSize ); // make sure we have at least this much room + _end = newSize; + } + + void reserve ( size_t reqCapacity ) + { + if ( reqCapacity <= _capacity ) + return; + size_t newCapacity = 2 * _capacity; + if ( reqCapacity > newCapacity ) + newCapacity = reqCapacity; + // allocate new array + auto_ptr * arrNew = new auto_ptr [newCapacity]; + // transfer all entries + for ( size_t i = 0; i < _capacity; ++i ) + arrNew[i] = _arr[i]; + _capacity = newCapacity; + // free old memory + delete[] _arr; + // substitute new array for old array + _arr = arrNew; + } + + void remove ( size_t off ) + { + size_t last = _end-1; + if ( off == last ) + resize ( last ); + else if ( off < last ) + { + auto_ptr tmp ( pop_back().release() ); + _arr[off] = tmp; + } + } + + //typedef const_auto_iterator const_iterator; + //const_iterator begin () const { return _arr; } + //const_iterator end () const { return _arr + _end; } + +private: + auto_ptr *_arr; + size_t _capacity; + size_t _end; +}; + +#endif//AUTO_VECTOR_H diff --git a/rosapps/games/ArchBlackmann/base64.cpp b/rosapps/games/ArchBlackmann/base64.cpp new file mode 100644 index 00000000000..6fdc8528698 --- /dev/null +++ b/rosapps/games/ArchBlackmann/base64.cpp @@ -0,0 +1,58 @@ +// base64.cpp + +#include "base64.h" + +using std::string; + +static const char* alfabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +string base64_encode ( const string& sInput ) +{ + unsigned char x=0, topbit=0; + int v=0; + string sOutput; + do + { + if ( topbit < 6 ) + { + x++; + v <<= 8; + if ( x <= sInput.length() ) v += sInput[x-1]; + topbit += 8; + } + topbit -= 6; + if ( x > sInput.length() && !v ) + break; + sOutput += alfabet[(v >> topbit) & 63]; + v &= (1 << topbit) - 1; + } while ( x < sInput.length() || v ); + int eq = (8 - (sOutput.length() % 4)) % 4; + while ( eq-- ) + sOutput += '='; + return sOutput; +} + +string base64_decode ( const string& sInput ) +{ + unsigned char x=0, topbit=0; + int v=0, inlen = sInput.length(); + string sOutput; + while ( inlen && sInput[inlen-1] == '=' ) + inlen--; + do + { + while ( topbit < 8 ) + { + x++; + v <<= 6; + if ( x <= inlen ) v += (strchr(alfabet, sInput[x-1]) - alfabet); + topbit += 6; + } + topbit -= 8; + if ( x > inlen && !v ) + break; + sOutput += (char)((v >> topbit) & 255); + v &= ((1 << topbit) - 1); + } while ( x <= inlen || v ); + return sOutput; +} diff --git a/rosapps/games/ArchBlackmann/base64.h b/rosapps/games/ArchBlackmann/base64.h new file mode 100644 index 00000000000..e307b7aeaca --- /dev/null +++ b/rosapps/games/ArchBlackmann/base64.h @@ -0,0 +1,12 @@ +// base64.h + +#ifndef BASE64_H +#define BASE64_H + +#include + +std::string base64_encode ( const std::string& s ); + +std::string base64_decode ( const std::string& s ); + +#endif//BASE64_H diff --git a/rosapps/games/ArchBlackmann/chomp.cpp b/rosapps/games/ArchBlackmann/chomp.cpp new file mode 100644 index 00000000000..5a3a2080018 --- /dev/null +++ b/rosapps/games/ArchBlackmann/chomp.cpp @@ -0,0 +1,15 @@ +// chomp.cpp +// This file is (C) 2004 Royce Mitchell III +// and released under the BSD & LGPL licenses + +#include "chomp.h" + +std::string chomp ( const std::string& s ) +{ + const char* p = &s[0]; + const char* p2 = &s[0] + s.size(); + while ( p2 > p && strchr("\r\n", p2[-1]) ) + p2--; + return std::string ( p, p2-p ); +} + diff --git a/rosapps/games/ArchBlackmann/chomp.h b/rosapps/games/ArchBlackmann/chomp.h new file mode 100644 index 00000000000..80bd8dce071 --- /dev/null +++ b/rosapps/games/ArchBlackmann/chomp.h @@ -0,0 +1,13 @@ +// chomp.h +// This file is (C) 2004 Royce Mitchell III +// and released under the BSD & LGPL licenses + +#ifndef CHOMP_H +#define CHOMP_H + +#include + +std::string chomp ( const std::string& s ); + +#endif//TRIM_H + diff --git a/rosapps/games/ArchBlackmann/cram_md5.cpp b/rosapps/games/ArchBlackmann/cram_md5.cpp new file mode 100644 index 00000000000..dfaf771f031 --- /dev/null +++ b/rosapps/games/ArchBlackmann/cram_md5.cpp @@ -0,0 +1,23 @@ +// cram_md5.cpp +// This file is (C) 2004 Royce Mitchell III +// and released under the BSD & LGPL licenses + +#include "md5.h" +#include "cram_md5.h" +#include "base64.h" + +using std::string; + +string cram_md5 ( const string& username, const string& password, const string& greeting ) +{ + string challenge = base64_decode ( greeting ); + + string hmac = HMAC_MD5 ( password, challenge ); + //printf ( "(cram_md5): hmac = %s\n", hmac.c_str() ); + string raw_response = username; + raw_response += " "; + raw_response += hmac; + //printf ( "(cram_md5): raw_response = %s\n", raw_response.c_str() ); + + return base64_encode ( raw_response ); +} diff --git a/rosapps/games/ArchBlackmann/cram_md5.h b/rosapps/games/ArchBlackmann/cram_md5.h new file mode 100644 index 00000000000..c0741b8efde --- /dev/null +++ b/rosapps/games/ArchBlackmann/cram_md5.h @@ -0,0 +1,15 @@ +// cram_md5.h +// This file is (C) 2004 Royce Mitchell III +// and released under the BSD & LGPL licenses + +#ifndef CRAM_MD5_H +#define CRAM_MD5_H + +#include + +std::string cram_md5 ( + const std::string& username, + const std::string& password, + const std::string& greeting ); + +#endif//CRAM_MD5_H diff --git a/rosapps/games/ArchBlackmann/panic.cpp b/rosapps/games/ArchBlackmann/panic.cpp new file mode 100644 index 00000000000..3ad0604b311 --- /dev/null +++ b/rosapps/games/ArchBlackmann/panic.cpp @@ -0,0 +1,34 @@ +// panic.cpp +// This file is (C) 2003-2004 Royce Mitchell III +// and released under the BSD & LGPL licenses + +#include +#include +#include +#ifdef WIN32 +#include +#include +#endif//WIN32 +#include "panic.h" + +void panic ( const char* format, ... ) +{ + va_list arg; + int done; + + va_start(arg, format); +#if defined(WIN32) && !defined(_CONSOLE) + char buf[4096]; + _vsnprintf ( buf, sizeof(buf)-1, format, arg ); + MessageBox ( NULL, buf, "Panic!", MB_OK|MB_ICONEXCLAMATION ); +#else + done = vprintf(format, arg); + printf ( "\n" ); +#endif + va_end(arg); +#if defined(WIN32) && defined(_CONSOLE) + printf ( "Press any key to exit\n" ); + (void)getch(); +#endif//WIN32 && _CONSOLE + exit ( -1 ); +} diff --git a/rosapps/games/ArchBlackmann/panic.h b/rosapps/games/ArchBlackmann/panic.h new file mode 100644 index 00000000000..e15cafab27f --- /dev/null +++ b/rosapps/games/ArchBlackmann/panic.h @@ -0,0 +1,18 @@ +// panic.h +// This file is (C) 2003-2004 Royce Mitchell III +// and released under the BSD & LGPL licenses + +#ifndef PANIC_H +#define PANIC_H + +void panic ( const char* format, ... ); + +#define suAssert(expr) if ( !(expr) ) panic ( "%s(%lu): SOCKET ERROR %s\nExpression: %s\n", __FILE__, __LINE__, suErrDesc(SUERRNO), #expr ) + +#if defined(DEBUG) || defined(_DEBUG) +# define suVerify(expr) suAssert(expr) +#else +# define suVerify(expr) expr +#endif + +#endif//PANIC_H diff --git a/rosapps/games/ArchBlackmann/trim.cpp b/rosapps/games/ArchBlackmann/trim.cpp new file mode 100644 index 00000000000..c721f25dded --- /dev/null +++ b/rosapps/games/ArchBlackmann/trim.cpp @@ -0,0 +1,17 @@ +// trim.cpp +// This file is (C) 2004 Royce Mitchell III +// and released under the BSD & LGPL licenses + +#include "trim.h" + +std::string trim ( const std::string& s ) +{ + const char* p = &s[0]; + const char* p2 = p + s.size(); + while ( *p == ' ' ) + p++; + while ( p2 > p && p2[-1] == ' ' ) + p2--; + return std::string ( p, p2-p ); +} + diff --git a/rosapps/games/ArchBlackmann/trim.h b/rosapps/games/ArchBlackmann/trim.h new file mode 100644 index 00000000000..4f2ba721f4b --- /dev/null +++ b/rosapps/games/ArchBlackmann/trim.h @@ -0,0 +1,13 @@ +// trim.h +// This file is (C) 2004 Royce Mitchell III +// and released under the BSD & LGPL licenses + +#ifndef TRIM_H +#define TRIM_H + +#include + +std::string trim ( const std::string& s ); + +#endif//TRIM_H + diff --git a/rosapps/games/ArchBlackmann/verify.h b/rosapps/games/ArchBlackmann/verify.h new file mode 100644 index 00000000000..5d491cfef41 --- /dev/null +++ b/rosapps/games/ArchBlackmann/verify.h @@ -0,0 +1,37 @@ +// verify.h +// This code is (C) 2003-2004 Royce Mitchell III +// and released under the LGPL & BSD licenses + +#ifndef VERIFY_H +#define VERIFY_H + +//#include + +#ifdef ASSERT +#undef ASSERT +#endif//ASSERT + +#include "panic.h" + +#if defined(DEBUG) || defined(_DEBUG) +inline void AssertHandler ( bool b, const char* str ) +{ + if ( !b ) + panic ( str ); +} +# define ASSERT(x) AssertHandler((x) ? true : false, #x ) +#else +# define ASSERT(x) +#endif + +#ifdef verify +#undef verify +#endif//verify + +#if defined(DEBUG) || defined(_DEBUG) +# define verify(x) ASSERT(x) +#else +# define verify(x) x +#endif + +#endif//VERIFY_H