View previous topic :: View next topic |
Author |
Message |
Mithreas
Joined: 09 May 2008 Posts: 24
|
Posted: Fri May 09, 2008 19:43 Post subject: Vaultster fix |
|
|
Hi folks,
I've just made the following fix to lines 182+ of Client.cpp in Vaultster to solve a bug we've encountered on Arelith. Posting it here in case anyone else wants it.
Now I just have to figure out how to build it
-Mith
Code: | void CClient::createPattern (char* pattern)
{
// make sure there is no dot in the filename
char* dot = strchr (character, '.');
if (dot != NULL)
dot[0] = 0;
// determine the length of the current pattern
// Edit by Mithreas - cap the pattern length to 12 (not 14). This is because
// if a player makes several chars with the same name, and their name is 14
// chars long, their filenames are (e.g.)
// daedinangthalion.bic
// daedinangthalio1.bic
// i.e. the last character(s) may be replaced by numbers.
int characterLen = strlen (character);
int patternLen = (characterLen >= 12) ? 12 : characterLen;
// create the pattern string
strncpy (pattern, character, characterLen);
strcat (pattern, "*.bic");
}
|
(I've also made an equivalent fix to CServerClient::createPattern, and merged across the no-dot-in-filenames fix to that method). |
|
Back to top |
|
|
Mithreas
Joined: 09 May 2008 Posts: 24
|
Posted: Fri May 09, 2008 20:29 Post subject: |
|
|
OK, as a Java type working in C for the first time, I'm finding this a bit challenging
I've downloaded MS Visual Studio 2008 Express, created a project, downloaded the NWNX base code to ensure that all the references I need are in place, and fixed up the errors so far by changing my project configuration (character sets, and a compiler option).
Now I'm left with this error:
1>.\Vaultster.cpp(12) : error C2491: 'GetClassObject' : definition of dllimport function not allowed
Problem is that in Vaultster.h we say... Code: | #ifdef VAULTSTER_EXPORTS
#define VAULTSTER_API extern "C" __declspec(dllexport)
#else
#define VAULTSTER_API extern "C" __declspec(dllimport)
#endif
VAULTSTER_API CNWNXBase* GetClassObject (); | We don't seem to have VAULTSTER_EXPORTS defined, so we're treating this as a dllimport function. But we then define the function in Vaultster.cpp:
Code: | VAULTSTER_API CNWNXBase* GetClassObject ()
{
return &vaultster;
} |
Google tells me that Visual Studio 6 probably allowed this but 2008 doesn't. Any ideas on what I should do to work around it (short of finding another version of VS)? Bear in mind this is my first time ever working with C++ code...
Cheers,
-Mith |
|
Back to top |
|
|
Skywing
Joined: 03 Jan 2008 Posts: 321
|
Posted: Fri May 09, 2008 21:44 Post subject: |
|
|
If that code is being compiled into the Vaultster dll, then you want to be getting the __declspec(dllexport) tag and not the __declspec(dllimport) tag. Perhaps you need to define the VAULTSTER_EXPORTS preprocessor symbol in the preprocessor properties node for the project.
- S |
|
Back to top |
|
|
Mithreas
Joined: 09 May 2008 Posts: 24
|
Posted: Fri May 09, 2008 21:52 Post subject: |
|
|
OK, I've added the #define VAULTSTER_EXPORTS line above the test to get myself moving fowards - I'll keep that there for now and look at putting into preprocessor properties later
Hitting further issues now which look like I'm unable to reference methods in Winsock.h. If I build the project as a debug project, I get output like this:
Code: | 1> Creating library C:\Documents and Settings\James\My Documents\Visual Studio 2008\Projects\Vaultster\Debug\Vaultster.lib and object C:\Documents and Settings\James\My Documents\Visual Studio 2008\Projects\Vaultster\Debug\Vaultster.exp
1>Server.obj : error LNK2028: unresolved token (0A0002F6) "extern "C" char * __stdcall inet_ntoa(struct in_addr)" (?inet_ntoa@@$$J14YGPADUin_addr@@@Z) referenced in function "protected: bool __thiscall CServer::isValidClient(struct sockaddr_in &)" (?isValidClient@CServer@@$$FIAE_NAAUsockaddr_in@@@Z)
1>Sock.obj : error LNK2028: unresolved token (0A0002A5) "extern "C" int __stdcall WSAGetLastError(void)" (?WSAGetLastError@@$$J10YGHXZ) referenced in function "public: bool __thiscall CSock::Create(int)" (?Create@CSock@@$$FQAE_NH@Z)
...(lots more)
|
Google tells me that inet_ntoa is defined in Winsock.h but simply including that leaves me with a whole raft of other errors (in code that isn't part of the project). After some googling I tried doing a release build instead of a debug build. I then get similar errors but referencing methods like gethostbyname which is part of Winsock2.h (the inet_ntoa errors go, though).
Any more tips for a novice?
Thanks,
-Mith |
|
Back to top |
|
|
Mithreas
Joined: 09 May 2008 Posts: 24
|
Posted: Fri May 09, 2008 22:46 Post subject: |
|
|
Nearly there...
I needed to link the following libraries in Properties > Configuration Properties > Linker > Input
wsock32.lib
ws2_32.lib
user32.lib
zlib.lib
Now I just have to figure out where the compress2 and uncompress methods come from since linking zlib hasn't found them... |
|
Back to top |
|
|
Mithreas
Joined: 09 May 2008 Posts: 24
|
Posted: Sat May 10, 2008 0:24 Post subject: |
|
|
Hrm, well, I don't seem to be making any further progress. The linker is definitely seeing my zlib.lib (I've now upgraded to the latest version of zlib and the file is now called zdll.lib, but exhibits the same symptoms). And the methods that aren't showing up are definitely part of zlib. I'd really appreciate it if anyone can give me a hint here - has anyone had similar issues in trying to link to a library?
Generated commands: Code: | Creating temporary file "c:\Documents and Settings\James\My Documents\Visual Studio 2008\Projects\Vaultster\Release\RSP00006528122532.rsp" with contents
[
/GL /I "C:\Documents and Settings\James\My Documents\Visual Studio 2008\Projects\Vaultster\lib" /D "WIN32" /D "NDEBUG" /D "_CRT_SECURE_NO_WARNINGS" /D "VAULTSTER_EXPORTS" /D "_WINDLL" /D "_MBCS" /FD /EHsc /MD /Fo"Release\\" /Fd"Release\vc90.pdb" /W3 /c /Zi /Gr /TP ".\Stdafx.cpp"
".\Vaultster.cpp"
".\Sock.cpp"
".\Server.cpp"
".\NWNXVaultster.cpp"
".\NWNXBase.cpp"
".\Client.cpp"
".\blowfish.cpp"
]
Creating command line "cl.exe @"c:\Documents and Settings\James\My Documents\Visual Studio 2008\Projects\Vaultster\Release\RSP00006528122532.rsp" /nologo /errorReport:prompt"
Creating temporary file "c:\Documents and Settings\James\My Documents\Visual Studio 2008\Projects\Vaultster\Release\RSP00006628122532.rsp" with contents
[
/OUT:"C:\Documents and Settings\James\My Documents\Visual Studio 2008\Projects\Vaultster\Release\Vaultster.dll" /INCREMENTAL:NO /DLL /MANIFEST /MANIFESTFILE:"Release\Vaultster.dll.intermediate.manifest" /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /DEBUG /PDB:"C:\Documents and Settings\James\My Documents\Visual Studio 2008\Projects\Vaultster\Release\Vaultster.pdb" /LTCG /DYNAMICBASE /NXCOMPAT /MACHINE:X86 wsock32.lib ws2_32.lib user32.lib zdll.lib
".\Release\blowfish.obj"
".\Release\Client.obj"
".\Release\NWNXBase.obj"
".\Release\NWNXVaultster.obj"
".\Release\Server.obj"
".\Release\Sock.obj"
".\Release\Vaultster.obj"
".\zdll.lib"
".\Release\Stdafx.obj"
]
Creating command line "link.exe @"c:\Documents and Settings\James\My Documents\Visual Studio 2008\Projects\Vaultster\Release\RSP00006628122532.rsp" /NOLOGO /ERRORREPORT:PROMPT" |
Output: Code: | Compiling...
Stdafx.cpp
Vaultster.cpp
Sock.cpp
Server.cpp
NWNXVaultster.cpp
.\NWNXVaultster.cpp(68) : warning C4800: 'int' : forcing value to bool 'true' or 'false' (performance warning)
.\NWNXVaultster.cpp(69) : warning C4800: 'int' : forcing value to bool 'true' or 'false' (performance warning)
NWNXBase.cpp
Client.cpp
.\Client.cpp(290) : warning C4800: 'BOOL' : forcing value to bool 'true' or 'false' (performance warning)
.\Client.cpp(293) : warning C4800: 'BOOL' : forcing value to bool 'true' or 'false' (performance warning)
blowfish.cpp
Linking...
Creating library C:\Documents and Settings\James\My Documents\Visual Studio 2008\Projects\Vaultster\Release\Vaultster.lib and object C:\Documents and Settings\James\My Documents\Visual Studio 2008\Projects\Vaultster\Release\Vaultster.exp
Sock.obj : error LNK2001: unresolved external symbol @uncompress@16
Sock.obj : error LNK2001: unresolved external symbol @compress2@20
C:\Documents and Settings\James\My Documents\Visual Studio 2008\Projects\Vaultster\Release\Vaultster.dll : fatal error LNK1120: 2 unresolved externals |
|
|
Back to top |
|
|
Mithreas
Joined: 09 May 2008 Posts: 24
|
Posted: Sat May 10, 2008 16:07 Post subject: |
|
|
Aha! I needed to use the _cdecl calling convention. I now, finally, have a DLL... woohoo. |
|
Back to top |
|
|
Zebranky
Joined: 04 Jun 2006 Posts: 415
|
Posted: Wed May 14, 2008 6:21 Post subject: |
|
|
You may find this works better for you:
Change
Code: | strncpy (pattern, character, characterLen); |
to
Code: | strncpy (pattern, character, patternLen); |
And make CClient::findLatestFile look like this:
Code: | bool CClient::findLatestFile (char* pattern, char* filename)
{
WIN32_FIND_DATA Search;
WIN32_FILE_ATTRIBUTE_DATA fad;
char path[MAX_PATH];
bool found = false;
// try to find the first file in the dir
sprintf (path, "%s\\%s\\%s", serverVault, gamespy, pattern);
vaultster.Log ("o Searching for %s\n", path);
HANDLE hSearch = FindFirstFile (path, &Search);
if (hSearch != INVALID_HANDLE_VALUE) {
FILETIME latestFT;
char buffer[256];
// get date from this first file
sprintf (buffer, "%s\\%s\\%s", serverVault, gamespy, Search.cFileName);
GetFileAttributesEx (buffer, GetFileExInfoStandard, &fad);
latestFT = fad.ftLastAccessTime;
strcpy (filename, buffer);
if(strlen(Search.cFileName) < 32)
{
memset (character, 0, 32);
strncpy(character, Search.cFileName, strcspn(Search.cFileName, "."));
}
else
{
vaultster.Log("o Name of found file too long: %s\n", Search.cFileName);
return false;
}
vaultster.Log ("o Found at least one file.\n");
// check the rest of the files (if any)
while (FindNextFile (hSearch, &Search)) {
sprintf (buffer, "%s%s\\%s", serverVault, gamespy, Search.cFileName);
GetFileAttributesEx (buffer, GetFileExInfoStandard, &fad);
if (CompareFileTime (&fad.ftLastAccessTime, &latestFT) > 0) {
latestFT = fad.ftLastAccessTime;
strcpy (filename, buffer);
if(strlen(Search.cFileName) < 32)
{
memset (character, 0, 32);
strncpy(character, Search.cFileName, strcspn(Search.cFileName, "."));
}
else
{
vaultster.Log("o Name of found file too long: %s\n", Search.cFileName);
return false;
}
}
}
// we at least found one, otherwise we wouldn't be here
found = true;
}
// finalize
FindClose (hSearch);
return found;
} |
This makes createPattern() actually behave usefully, and adds, uh... some kind of error-checking to findLatestFile(), I think. I made these changes in a psycho-coding spree over a year ago, along with a number of other bugfixes I should publish. We're still encountering a few bugs I'd like to squash before I do that, though. _________________ Win32 SVN builds: http://www.mercuric.net/nwn/nwnx/
<Fluffy-Kooshy> NWNx plugin is to this as nuclear warheads are to getting rid of fire ants.
<ThriWork> whenever I hear nwn extender, I think what does NWN need a penis extender for? |
|
Back to top |
|
|
Mithreas
Joined: 09 May 2008 Posts: 24
|
Posted: Mon Mar 01, 2010 4:38 Post subject: |
|
|
OK, there are three problems with your latest code.
Characters who have remade with the same name will have 13 characters + a number. By substringing to 14, you pick up the original copy and not the remade version. [This is the same bug I fixed above].
Characters who have changed their name no longer have a name that resembles their filename. The only way to work around this is to pass a pattern of *.bic and just pick up the latest file.
Which would be fine, but for a bug in the following code:
Code: | while (FindNextFile (hSearch, &Search)) {
sprintf (buffer, "%s%s\\%s", serverVault, gamespy, Search.cFileName); |
You're missing a \\ between the servervault and gamespy ID in the second line there. Which means that when I passed *.bic to the function, I ended up portalling the first alphabetically ordered char from everyone's vaults... painful! That'll teach me to test better
See also unrelated bug fix in http://www.nwnx.org/phpBB2/viewtopic.php?t=1521&highlight=.
-Mith _________________ Admin team, Arelith PW
Hakless world that relies heavily on the great work done by the NWNX team. |
|
Back to top |
|
|
Mithreas
Joined: 09 May 2008 Posts: 24
|
Posted: Mon Mar 01, 2010 21:39 Post subject: |
|
|
Fixed and fully working version of Client.cpp as follows. Note I also changed from using last access time to last modified time, since character files in use in game were not registering as having been accessed. This library is now live on Arelith (regularly hitting >100 concurrent players across 3 servers), which should be enough testing to declare it 'good'
Code: |
/***************************************************************************
Client.cpp - Implementation of the client class for Windows.
Copyright (C) 2004 Jeroen Broekhuizen (jeroen@nwnx.org)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************
Updates:
04-07-2005:
- Added extra logging information
05-07-2005:
- Fixed return value of transmitFile function. Now realy returns
value of the socket transmision functions.
- Added extra check for dots in the character name in the
createPattern function.
- Added extra logging.
***************************************************************************/
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memory.h>
#include <time.h>
#include <fstream>
using namespace std;
#include "nwnxvaultster.h"
#include "client.h"
typedef unsigned char uchar;
typedef unsigned long ulong;
// use this variable for logging purposes
extern CNWNXVaultster vaultster;
CClient::CClient(void)
{
status = STATUS_OK;
}
CClient::~CClient(void)
{
}
char CClient::serverVault[] = "";
char CClient::cryptoKey[] = "";
char CClient::password[] = "";
int CClient::port = 5100;
void CClient::setCommand (Functions cmd)
{
switch (cmd) {
case Get:
command = CMD_GET;
break;
case Put:
command = CMD_SEND;
break;
}
}
void CClient::setStatus (int stat)
{
status = stat;
}
int CClient::getStatus ()
{
return status;
}
void CClient::setPort (int p)
{
// save the port number, which is used to connect
port = p;
}
void CClient::setServervault (char* vault)
{
// save a static string with the servervault directory
strcpy (serverVault, vault);
}
void CClient::setCryptoKey (char* key)
{
// save a copy of the blowfish key
strcpy (cryptoKey, key);
}
void CClient::setPassword (char* pwd)
{
// save the password for identification
strcpy (password, pwd);
}
DWORD CClient::thread (LPVOID param)
{
CClient* client = (CClient*)param;
if (!client->run ()) {
client->setStatus (STATUS_ERROR);
vaultster.Log ("o There was an error during the transmission.\n");
}
else {
client->setStatus (STATUS_OK);
vaultster.Log ("o Portal successfully finished.\n");
}
int stat = client->getStatus ();
return stat;
}
bool CClient::run ()
{
char filename[256], pattern[32];
fish.Initialize ((unsigned char*)cryptoKey, strlen (cryptoKey));
memset (filename, 0, 256);
memset (pattern, 0, 32);
// make it linux compatible:
strlwr (character);
// try to find the latest file
createPattern (pattern);
vaultster.Log ("o Start searching for %s\n", pattern);
if (!findLatestFile (pattern, filename)) {
vaultster.Log ("o Could not find latest file for %s\\%s!\n", gamespy, character);
return false;
}
// make it linux compatible again:
strlwr (character);
vaultster.Log ("o Trying to connect to server %s...\n", server);
// try to connect to the server
socket.Create ();
if (!socket.Connect (server, port)) {
vaultster.Log ("o Could not connect to %s on port %d.\n", server, port);
return false;
}
if (!handShake ()) {
// wrong password, bail out!
vaultster.Log ("o Wrong password, can not finish job.\n");
socket.Close ();
return false;
}
vaultster.Log ("o Ready for file transmission.\n");
if (!transmitFile (filename)) {
// to bad! it failed
vaultster.Log ("o Failed to send over file '%s'.\n", filename);
socket.Close ();
return false;
}
vaultster.Log ("o Job ready\n");
socket.Close ();
return true;
}
void CClient::createPattern (char* pattern)
{
// make sure there is no dot in the filename
char* dot = strchr (character, '.');
if (dot != NULL)
dot[0] = 0;
// determine the length of the current pattern
int characterLen = strlen (character);
int patternLen = (characterLen >= 14) ? 14 : characterLen;
// create the pattern string
//strncpy (pattern, character, patternLen);
strcat (pattern, "*.bic");
}
bool CClient::findLatestFile (char* pattern, char* filename)
{
WIN32_FIND_DATA Search;
WIN32_FILE_ATTRIBUTE_DATA fad;
char path[MAX_PATH];
bool found = false;
// try to find the first file in the dir
sprintf (path, "%s\\%s\\%s", serverVault, gamespy, pattern);
vaultster.Log ("o Searching for %s\n", path);
HANDLE hSearch = FindFirstFile (path, &Search);
if (hSearch != INVALID_HANDLE_VALUE) {
FILETIME latestFT;
char buffer[256];
// get date from this first file
sprintf (buffer, "%s\\%s\\%s", serverVault, gamespy, Search.cFileName);
GetFileAttributesEx (buffer, GetFileExInfoStandard, &fad);
latestFT = fad.ftLastWriteTime;
strcpy (filename, buffer);
if(strlen(Search.cFileName) < 32)
{
memset (character, 0, 32);
strncpy(character, Search.cFileName, strcspn(Search.cFileName, "."));
}
else
{
vaultster.Log("o Name of found file too long: %s\n", Search.cFileName);
return false;
}
vaultster.Log ("o Found file: %s\n", Search.cFileName);
// check the rest of the files (if any)
while (FindNextFile (hSearch, &Search)) {
sprintf (buffer, "%s\\%s\\%s", serverVault, gamespy, Search.cFileName);
GetFileAttributesEx (buffer, GetFileExInfoStandard, &fad);
vaultster.Log ("o Found file: %s\n", Search.cFileName);
if (CompareFileTime (&fad.ftLastWriteTime, &latestFT) > 0) {
vaultster.Log ("o File has a later modified time.\n", Search.cFileName);
latestFT = fad.ftLastWriteTime;
strcpy (filename, buffer);
if(strlen(Search.cFileName) < 32)
{
memset (character, 0, 32);
strncpy(character, Search.cFileName, strcspn(Search.cFileName, "."));
}
else
{
vaultster.Log("o Name of found file too long: %s\n", Search.cFileName);
return false;
}
}
}
// we at least found one, otherwise we wouldn't be here
found = true;
}
// finalize
FindClose (hSearch);
return found;
}
void CClient::generatePassword (char pwd[128])
{
memset (pwd, 0, 128);
strcpy (pwd, password);
// build the dummy part of the password
srand ((unsigned)time(NULL));
for (int i = strlen(password); i < 128; i++)
pwd[i] = 33 + (rand() % 90);
}
bool CClient::handShake ()
{
int ret = 0;
char pwd[128];
uchar encrypted[128];
// send the command to the server
socket.Send (command);
socket.Receive (ret);
if (ret == INFO_NACK)
return false;
// now encrypt the password and send it over
generatePassword (pwd);
fish.Encode ((uchar*)pwd, encrypted, 128);
socket.Send (encrypted, 128);
// hopefully the password is accepted
socket.Receive (ret);
if (ret == INFO_NACK)
return false;
return true;
}
bool CClient::transmitFile (char* localFile)
{
int ret = 0;
sendEncrypted (gamespy);
sendEncrypted (character);
socket.Receive (ret);
if (ret == INFO_NACK)
return false;
// now perform the requested job
switch (command) {
case CMD_SEND:
vaultster.Log ("o Sending file\n");
return socket.SendFile (localFile);
case CMD_GET:
vaultster.Log ("o Receiving file\n");
return socket.ReceiveFile (localFile);
}
// invalid command (should not be able to get here).
return false;
}
void CClient::sendEncrypted (char* str)
{
uchar encrypted[256];
// encode the string
ulong patternLen = strlen (str);
ulong len = fish.GetOutputLength (patternLen);
fish.Encode ((uchar*)str, encrypted, patternLen);
// send the data to the server
socket.Send (len);
socket.Send (encrypted, len);
}
|
_________________ Admin team, Arelith PW
Hakless world that relies heavily on the great work done by the NWNX team. |
|
Back to top |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|