Merge: New map directory structure and player passwords
commit
76e241392d
|
@ -95,6 +95,8 @@ set(minetest_SRCS
|
|||
tile.cpp
|
||||
game.cpp
|
||||
main.cpp
|
||||
sha1.cpp
|
||||
base64.cpp
|
||||
)
|
||||
|
||||
# Server sources
|
||||
|
|
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
base64.cpp and base64.h
|
||||
|
||||
Copyright (C) 2004-2008 René Nyffenegger
|
||||
|
||||
This source code is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the author be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this source code must not be misrepresented; you must not
|
||||
claim that you wrote the original source code. If you use this source code
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original source code.
|
||||
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
René Nyffenegger rene.nyffenegger@adp-gmbh.ch
|
||||
|
||||
*/
|
||||
|
||||
#include "base64.h"
|
||||
#include <iostream>
|
||||
|
||||
static const std::string base64_chars =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789+/";
|
||||
|
||||
|
||||
static inline bool is_base64(unsigned char c) {
|
||||
return (isalnum(c) || (c == '+') || (c == '/'));
|
||||
}
|
||||
|
||||
std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) {
|
||||
std::string ret;
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
unsigned char char_array_3[3];
|
||||
unsigned char char_array_4[4];
|
||||
|
||||
while (in_len--) {
|
||||
char_array_3[i++] = *(bytes_to_encode++);
|
||||
if (i == 3) {
|
||||
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
|
||||
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
|
||||
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
|
||||
char_array_4[3] = char_array_3[2] & 0x3f;
|
||||
|
||||
for(i = 0; (i <4) ; i++)
|
||||
ret += base64_chars[char_array_4[i]];
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (i)
|
||||
{
|
||||
for(j = i; j < 3; j++)
|
||||
char_array_3[j] = '\0';
|
||||
|
||||
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
|
||||
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
|
||||
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
|
||||
char_array_4[3] = char_array_3[2] & 0x3f;
|
||||
|
||||
for (j = 0; (j < i + 1); j++)
|
||||
ret += base64_chars[char_array_4[j]];
|
||||
|
||||
while((i++ < 3))
|
||||
ret += '=';
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
std::string base64_decode(std::string const& encoded_string) {
|
||||
int in_len = encoded_string.size();
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int in_ = 0;
|
||||
unsigned char char_array_4[4], char_array_3[3];
|
||||
std::string ret;
|
||||
|
||||
while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
|
||||
char_array_4[i++] = encoded_string[in_]; in_++;
|
||||
if (i ==4) {
|
||||
for (i = 0; i <4; i++)
|
||||
char_array_4[i] = base64_chars.find(char_array_4[i]);
|
||||
|
||||
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
|
||||
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
|
||||
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
|
||||
|
||||
for (i = 0; (i < 3); i++)
|
||||
ret += char_array_3[i];
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (i) {
|
||||
for (j = i; j <4; j++)
|
||||
char_array_4[j] = 0;
|
||||
|
||||
for (j = 0; j <4; j++)
|
||||
char_array_4[j] = base64_chars.find(char_array_4[j]);
|
||||
|
||||
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
|
||||
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
|
||||
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
|
||||
|
||||
for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
#include <string>
|
||||
|
||||
std::string base64_encode(unsigned char const* , unsigned int len);
|
||||
std::string base64_decode(std::string const& s);
|
|
@ -68,6 +68,7 @@ void * MeshUpdateThread::Thread()
|
|||
Client::Client(
|
||||
IrrlichtDevice *device,
|
||||
const char *playername,
|
||||
std::string password,
|
||||
MapDrawControl &control):
|
||||
m_mesh_update_thread(),
|
||||
m_env(
|
||||
|
@ -83,7 +84,9 @@ Client::Client(
|
|||
m_server_ser_ver(SER_FMT_VER_INVALID),
|
||||
m_inventory_updated(false),
|
||||
m_time_of_day(0),
|
||||
m_map_seed(0)
|
||||
m_map_seed(0),
|
||||
m_password(password),
|
||||
m_access_denied(false)
|
||||
{
|
||||
m_packetcounter_timer = 0.0;
|
||||
m_delete_unused_sectors_timer = 0.0;
|
||||
|
@ -299,11 +302,14 @@ void Client::step(float dtime)
|
|||
// [0] u16 TOSERVER_INIT
|
||||
// [2] u8 SER_FMT_VER_HIGHEST
|
||||
// [3] u8[20] player_name
|
||||
SharedBuffer<u8> data(2+1+PLAYERNAME_SIZE);
|
||||
// [23] u8[28] password
|
||||
SharedBuffer<u8> data(2+1+PLAYERNAME_SIZE+PASSWORD_SIZE);
|
||||
writeU16(&data[0], TOSERVER_INIT);
|
||||
writeU8(&data[2], SER_FMT_VER_HIGHEST);
|
||||
memset((char*)&data[3], 0, PLAYERNAME_SIZE);
|
||||
snprintf((char*)&data[3], PLAYERNAME_SIZE, "%s", myplayer->getName());
|
||||
snprintf((char*)&data[23], PASSWORD_SIZE, "%s", m_password.c_str());
|
||||
|
||||
// Send as unreliable
|
||||
Send(0, data, false);
|
||||
}
|
||||
|
@ -597,7 +603,16 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
|
|||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if(command == TOCLIENT_ACCESS_DENIED)
|
||||
{
|
||||
// The server didn't like our password. Note, this needs
|
||||
// to be processed even if the serialisation format has
|
||||
// not been agreed yet, the same as TOCLIENT_INIT.
|
||||
m_access_denied = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if(ser_version == SER_FMT_VER_INVALID)
|
||||
{
|
||||
dout_client<<DTIME<<"WARNING: Client: Server serialization"
|
||||
|
|
|
@ -207,6 +207,7 @@ public:
|
|||
Client(
|
||||
IrrlichtDevice *device,
|
||||
const char *playername,
|
||||
std::string password,
|
||||
MapDrawControl &control
|
||||
);
|
||||
|
||||
|
@ -377,6 +378,11 @@ public:
|
|||
// Get event from queue. CE_NONE is returned if queue is empty.
|
||||
ClientEvent getClientEvent();
|
||||
|
||||
inline bool accessDenied()
|
||||
{
|
||||
return m_access_denied;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
// Virtual methods from con::PeerHandler
|
||||
|
@ -430,6 +436,9 @@ private:
|
|||
// The seed returned by the server in TOCLIENT_INIT is stored here
|
||||
u64 m_map_seed;
|
||||
|
||||
std::string m_password;
|
||||
bool m_access_denied;
|
||||
|
||||
InventoryContext m_inventory_context;
|
||||
|
||||
Queue<ClientEvent> m_client_event_queue;
|
||||
|
|
|
@ -150,6 +150,11 @@ enum ToClientCommand
|
|||
f1000 player pitch
|
||||
f1000 player yaw
|
||||
*/
|
||||
|
||||
TOCLIENT_ACCESS_DENIED = 0x35,
|
||||
/*
|
||||
u16 command
|
||||
*/
|
||||
};
|
||||
|
||||
enum ToServerCommand
|
||||
|
@ -161,6 +166,7 @@ enum ToServerCommand
|
|||
[0] u16 TOSERVER_INIT
|
||||
[2] u8 SER_FMT_VER_HIGHEST
|
||||
[3] u8[20] player_name
|
||||
[23] u8[28] password
|
||||
*/
|
||||
|
||||
TOSERVER_INIT2 = 0x11,
|
||||
|
|
|
@ -290,5 +290,24 @@ bool RecursiveDeleteContent(std::string path)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool CreateAllDirs(std::string path)
|
||||
{
|
||||
|
||||
size_t pos;
|
||||
std::vector<std::string> tocreate;
|
||||
std::string basepath = path;
|
||||
while(!PathExists(basepath))
|
||||
{
|
||||
tocreate.push_back(basepath);
|
||||
pos = basepath.rfind('/');
|
||||
if(pos == std::string::npos)
|
||||
return false;
|
||||
basepath = basepath.substr(0,pos);
|
||||
}
|
||||
for(int i=tocreate.size()-1;i>=0;i--)
|
||||
CreateDir(tocreate[i]);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace fs
|
||||
|
||||
|
|
|
@ -38,6 +38,9 @@ std::vector<DirListNode> GetDirListing(std::string path);
|
|||
// Returns true if already exists
|
||||
bool CreateDir(std::string path);
|
||||
|
||||
// Create all directories on the given path that don't already exist.
|
||||
bool CreateAllDirs(std::string path);
|
||||
|
||||
bool PathExists(std::string path);
|
||||
|
||||
// Only pass full paths to this one. True on success.
|
||||
|
|
22
src/game.cpp
22
src/game.cpp
|
@ -634,6 +634,7 @@ void the_game(
|
|||
gui::IGUIFont* font,
|
||||
std::string map_dir,
|
||||
std::string playername,
|
||||
std::string password,
|
||||
std::string address,
|
||||
u16 port,
|
||||
std::wstring &error_message
|
||||
|
@ -672,7 +673,6 @@ void the_game(
|
|||
guienv->drawAll();
|
||||
driver->endScene();
|
||||
|
||||
std::cout<<DTIME<<"Creating server and client"<<std::endl;
|
||||
|
||||
/*
|
||||
Create server.
|
||||
|
@ -680,6 +680,7 @@ void the_game(
|
|||
*/
|
||||
SharedPtr<Server> server;
|
||||
if(address == ""){
|
||||
std::cout<<DTIME<<"Creating server"<<std::endl;
|
||||
server = new Server(map_dir);
|
||||
server->start(port);
|
||||
}
|
||||
|
@ -688,7 +689,8 @@ void the_game(
|
|||
Create client
|
||||
*/
|
||||
|
||||
Client client(device, playername.c_str(), draw_control);
|
||||
std::cout<<DTIME<<"Creating client"<<std::endl;
|
||||
Client client(device, playername.c_str(), password, draw_control);
|
||||
|
||||
Address connect_address(0,0,0,0, port);
|
||||
try{
|
||||
|
@ -727,6 +729,10 @@ void the_game(
|
|||
could_connect = true;
|
||||
break;
|
||||
}
|
||||
if(client.accessDenied())
|
||||
{
|
||||
break;
|
||||
}
|
||||
// Wait for 10 seconds
|
||||
if(time_counter >= 10.0)
|
||||
{
|
||||
|
@ -755,8 +761,16 @@ void the_game(
|
|||
|
||||
if(could_connect == false)
|
||||
{
|
||||
std::cout<<DTIME<<"Timed out."<<std::endl;
|
||||
error_message = L"Connection timed out.";
|
||||
if(client.accessDenied())
|
||||
{
|
||||
error_message = L"Access denied. Check your password and try again.";
|
||||
std::cout<<DTIME<<"Access denied."<<std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
error_message = L"Connection timed out.";
|
||||
std::cout<<DTIME<<"Timed out."<<std::endl;
|
||||
}
|
||||
gui_loadingtext->remove();
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -67,6 +67,7 @@ void the_game(
|
|||
gui::IGUIFont* font,
|
||||
std::string map_dir,
|
||||
std::string playername,
|
||||
std::string password,
|
||||
std::string address,
|
||||
u16 port,
|
||||
std::wstring &error_message
|
||||
|
|
|
@ -164,30 +164,38 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
|
|||
//t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
|
||||
}
|
||||
|
||||
// Nickname
|
||||
// Nickname + password
|
||||
{
|
||||
core::rect<s32> rect(0, 0, 100, 20);
|
||||
rect += topleft_client + v2s32(40, 50+6);
|
||||
const wchar_t *text = L"Nickname";
|
||||
core::rect<s32> rect(0, 0, 110, 20);
|
||||
rect += topleft_client + v2s32(35, 50+6);
|
||||
const wchar_t *text = L"Name/Password";
|
||||
Environment->addStaticText(text, rect, false, true, this, -1);
|
||||
}
|
||||
{
|
||||
core::rect<s32> rect(0, 0, 250, 30);
|
||||
core::rect<s32> rect(0, 0, 230, 30);
|
||||
rect += topleft_client + v2s32(160, 50);
|
||||
gui::IGUIElement *e =
|
||||
Environment->addEditBox(text_name.c_str(), rect, true, this, 258);
|
||||
if(text_name == L"")
|
||||
Environment->setFocus(e);
|
||||
}
|
||||
{
|
||||
core::rect<s32> rect(0, 0, 120, 30);
|
||||
rect += topleft_client + v2s32(size_client.X-60-100, 50);
|
||||
gui::IGUIEditBox *e =
|
||||
Environment->addEditBox(L"", rect, true, this, 264);
|
||||
e->setPasswordBox(true);
|
||||
|
||||
}
|
||||
// Address + port
|
||||
{
|
||||
core::rect<s32> rect(0, 0, 100, 20);
|
||||
rect += topleft_client + v2s32(40, 100+6);
|
||||
const wchar_t *text = L"Address + Port";
|
||||
core::rect<s32> rect(0, 0, 110, 20);
|
||||
rect += topleft_client + v2s32(35, 100+6);
|
||||
const wchar_t *text = L"Address/Port";
|
||||
Environment->addStaticText(text, rect, false, true, this, -1);
|
||||
}
|
||||
{
|
||||
core::rect<s32> rect(0, 0, 250, 30);
|
||||
core::rect<s32> rect(0, 0, 230, 30);
|
||||
rect += topleft_client + v2s32(160, 100);
|
||||
gui::IGUIElement *e =
|
||||
Environment->addEditBox(text_address.c_str(), rect, true, this, 256);
|
||||
|
@ -195,9 +203,9 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
|
|||
Environment->setFocus(e);
|
||||
}
|
||||
{
|
||||
core::rect<s32> rect(0, 0, 100, 30);
|
||||
core::rect<s32> rect(0, 0, 120, 30);
|
||||
//rect += topleft_client + v2s32(160+250+20, 125);
|
||||
rect += topleft_client + v2s32(size_client.X-40-100, 100);
|
||||
rect += topleft_client + v2s32(size_client.X-60-100, 100);
|
||||
Environment->addEditBox(text_port.c_str(), rect, true, this, 257);
|
||||
}
|
||||
{
|
||||
|
@ -208,13 +216,13 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
|
|||
}
|
||||
{
|
||||
core::rect<s32> rect(0, 0, 250, 30);
|
||||
rect += topleft_client + v2s32(40, 150);
|
||||
rect += topleft_client + v2s32(35, 150);
|
||||
Environment->addCheckBox(fancy_trees, rect, this, 263,
|
||||
L"Fancy trees");
|
||||
}
|
||||
{
|
||||
core::rect<s32> rect(0, 0, 250, 30);
|
||||
rect += topleft_client + v2s32(40, 150+30);
|
||||
rect += topleft_client + v2s32(35, 150+30);
|
||||
Environment->addCheckBox(smooth_lighting, rect, this, 262,
|
||||
L"Smooth Lighting");
|
||||
}
|
||||
|
@ -245,12 +253,12 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
|
|||
// Server parameters
|
||||
{
|
||||
core::rect<s32> rect(0, 0, 250, 30);
|
||||
rect += topleft_server + v2s32(40, 30);
|
||||
rect += topleft_server + v2s32(35, 30);
|
||||
Environment->addCheckBox(creative_mode, rect, this, 259, L"Creative Mode");
|
||||
}
|
||||
{
|
||||
core::rect<s32> rect(0, 0, 250, 30);
|
||||
rect += topleft_server + v2s32(40, 60);
|
||||
rect += topleft_server + v2s32(35, 60);
|
||||
Environment->addCheckBox(enable_damage, rect, this, 261, L"Enable Damage");
|
||||
}
|
||||
// Map delete button
|
||||
|
@ -296,6 +304,11 @@ void GUIMainMenu::acceptInput()
|
|||
if(e != NULL)
|
||||
m_data->name = e->getText();
|
||||
}
|
||||
{
|
||||
gui::IGUIElement *e = getElementFromId(264);
|
||||
if(e != NULL)
|
||||
m_data->password = e->getText();
|
||||
}
|
||||
{
|
||||
gui::IGUIElement *e = getElementFromId(256);
|
||||
if(e != NULL)
|
||||
|
@ -380,7 +393,7 @@ bool GUIMainMenu::OnEvent(const SEvent& event)
|
|||
{
|
||||
switch(event.GUIEvent.Caller->getID())
|
||||
{
|
||||
case 256: case 257: case 258:
|
||||
case 256: case 257: case 258: case 264:
|
||||
acceptInput();
|
||||
quitMenu();
|
||||
return true;
|
||||
|
|
|
@ -46,6 +46,7 @@ struct MainMenuData
|
|||
std::wstring address;
|
||||
std::wstring port;
|
||||
std::wstring name;
|
||||
std::wstring password;
|
||||
bool fancy_trees;
|
||||
bool smooth_lighting;
|
||||
// Server options
|
||||
|
|
28
src/main.cpp
28
src/main.cpp
|
@ -325,6 +325,8 @@ Making it more portable:
|
|||
#include "materials.h"
|
||||
#include "game.h"
|
||||
#include "keycode.h"
|
||||
#include "sha1.h"
|
||||
#include "base64.h"
|
||||
|
||||
// This makes textures
|
||||
ITextureSource *g_texturesource = NULL;
|
||||
|
@ -1170,6 +1172,7 @@ int main(int argc, char *argv[])
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
More parameters
|
||||
*/
|
||||
|
@ -1324,11 +1327,15 @@ int main(int argc, char *argv[])
|
|||
*/
|
||||
std::wstring error_message = L"";
|
||||
|
||||
// The password entered during the menu screen,
|
||||
std::string password;
|
||||
|
||||
/*
|
||||
Menu-game loop
|
||||
*/
|
||||
while(device->run() && kill == false)
|
||||
{
|
||||
|
||||
// This is used for catching disconnects
|
||||
try
|
||||
{
|
||||
|
@ -1428,6 +1435,26 @@ int main(int argc, char *argv[])
|
|||
}
|
||||
|
||||
playername = wide_to_narrow(menudata.name);
|
||||
|
||||
// Get an sha-1 hash of the player's name combined with
|
||||
// the password entered. That's what the server uses as
|
||||
// their password. (Exception : if the password field is
|
||||
// blank, we send a blank password - this is for backwards
|
||||
// compatibility with password-less players).
|
||||
if(menudata.password.length() > 0)
|
||||
{
|
||||
std::string slt=playername + wide_to_narrow(menudata.password);
|
||||
SHA1 *sha1 = new SHA1();
|
||||
sha1->addBytes(slt.c_str(), slt.length());
|
||||
unsigned char *digest = sha1->getDigest();
|
||||
password = base64_encode(digest, 20);
|
||||
free(digest);
|
||||
}
|
||||
else
|
||||
{
|
||||
password = "";
|
||||
}
|
||||
|
||||
address = wide_to_narrow(menudata.address);
|
||||
int newport = stoi(wide_to_narrow(menudata.port));
|
||||
if(newport != 0)
|
||||
|
@ -1474,6 +1501,7 @@ int main(int argc, char *argv[])
|
|||
font,
|
||||
map_dir,
|
||||
playername,
|
||||
password,
|
||||
address,
|
||||
port,
|
||||
error_message
|
||||
|
|
124
src/map.cpp
124
src/map.cpp
|
@ -4875,9 +4875,9 @@ plan_b:
|
|||
return (s16)level;
|
||||
}
|
||||
|
||||
void ServerMap::createDir(std::string path)
|
||||
void ServerMap::createDirs(std::string path)
|
||||
{
|
||||
if(fs::CreateDir(path) == false)
|
||||
if(fs::CreateAllDirs(path) == false)
|
||||
{
|
||||
m_dout<<DTIME<<"ServerMap: Failed to create directory "
|
||||
<<"\""<<path<<"\""<<std::endl;
|
||||
|
@ -4885,29 +4885,52 @@ void ServerMap::createDir(std::string path)
|
|||
}
|
||||
}
|
||||
|
||||
std::string ServerMap::getSectorSubDir(v2s16 pos)
|
||||
std::string ServerMap::getSectorDir(v2s16 pos, int layout)
|
||||
{
|
||||
char cc[9];
|
||||
snprintf(cc, 9, "%.4x%.4x",
|
||||
(unsigned int)pos.X&0xffff,
|
||||
(unsigned int)pos.Y&0xffff);
|
||||
switch(layout)
|
||||
{
|
||||
case 1:
|
||||
snprintf(cc, 9, "%.4x%.4x",
|
||||
(unsigned int)pos.X&0xffff,
|
||||
(unsigned int)pos.Y&0xffff);
|
||||
|
||||
return std::string(cc);
|
||||
}
|
||||
return m_savedir + "/sectors/" + cc;
|
||||
case 2:
|
||||
snprintf(cc, 9, "%.3x/%.3x",
|
||||
(unsigned int)pos.X&0xfff,
|
||||
(unsigned int)pos.Y&0xfff);
|
||||
|
||||
std::string ServerMap::getSectorDir(v2s16 pos)
|
||||
{
|
||||
return m_savedir + "/sectors/" + getSectorSubDir(pos);
|
||||
return m_savedir + "/sectors2/" + cc;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
v2s16 ServerMap::getSectorPos(std::string dirname)
|
||||
{
|
||||
if(dirname.size() != 8)
|
||||
throw InvalidFilenameException("Invalid sector directory name");
|
||||
unsigned int x, y;
|
||||
int r = sscanf(dirname.c_str(), "%4x%4x", &x, &y);
|
||||
if(r != 2)
|
||||
throw InvalidFilenameException("Invalid sector directory name");
|
||||
int r;
|
||||
size_t spos = dirname.rfind('/') + 1;
|
||||
assert(spos != std::string::npos);
|
||||
if(dirname.size() - spos == 8)
|
||||
{
|
||||
// Old layout
|
||||
r = sscanf(dirname.substr(spos).c_str(), "%4x%4x", &x, &y);
|
||||
}
|
||||
else if(dirname.size() - spos == 3)
|
||||
{
|
||||
// New layout
|
||||
r = sscanf(dirname.substr(spos-4).c_str(), "%3x/%3x", &x, &y);
|
||||
// Sign-extend the 12 bit values up to 16 bits...
|
||||
if(x&0x800) x|=0xF000;
|
||||
if(y&0x800) y|=0xF000;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false);
|
||||
}
|
||||
assert(r == 2);
|
||||
v2s16 pos((s16)x, (s16)y);
|
||||
return pos;
|
||||
}
|
||||
|
@ -5106,7 +5129,7 @@ void ServerMap::saveMapMeta()
|
|||
<<"seed="<<m_seed<<", chunksize="<<m_chunksize
|
||||
<<std::endl;
|
||||
|
||||
createDir(m_savedir);
|
||||
createDirs(m_savedir);
|
||||
|
||||
std::string fullpath = m_savedir + "/map_meta.txt";
|
||||
std::ofstream os(fullpath.c_str(), std::ios_base::binary);
|
||||
|
@ -5179,7 +5202,7 @@ void ServerMap::saveChunkMeta()
|
|||
dstream<<"INFO: ServerMap::saveChunkMeta(): Saving metadata of "
|
||||
<<count<<" chunks"<<std::endl;
|
||||
|
||||
createDir(m_savedir);
|
||||
createDirs(m_savedir);
|
||||
|
||||
std::string fullpath = m_savedir + "/chunk_meta";
|
||||
std::ofstream os(fullpath.c_str(), std::ios_base::binary);
|
||||
|
@ -5267,10 +5290,8 @@ void ServerMap::saveSectorMeta(ServerMapSector *sector)
|
|||
u8 version = SER_FMT_VER_HIGHEST;
|
||||
// Get destination
|
||||
v2s16 pos = sector->getPos();
|
||||
createDir(m_savedir);
|
||||
createDir(m_savedir+"/sectors");
|
||||
std::string dir = getSectorDir(pos);
|
||||
createDir(dir);
|
||||
createDirs(dir);
|
||||
|
||||
std::string fullpath = dir + "/meta";
|
||||
std::ofstream o(fullpath.c_str(), std::ios_base::binary);
|
||||
|
@ -5282,22 +5303,21 @@ void ServerMap::saveSectorMeta(ServerMapSector *sector)
|
|||
sector->differs_from_disk = false;
|
||||
}
|
||||
|
||||
MapSector* ServerMap::loadSectorMeta(std::string dirname)
|
||||
MapSector* ServerMap::loadSectorMeta(std::string sectordir, bool save_after_load)
|
||||
{
|
||||
DSTACK(__FUNCTION_NAME);
|
||||
// Get destination
|
||||
v2s16 p2d = getSectorPos(dirname);
|
||||
std::string dir = m_savedir + "/sectors/" + dirname;
|
||||
v2s16 p2d = getSectorPos(sectordir);
|
||||
|
||||
ServerMapSector *sector = NULL;
|
||||
|
||||
std::string fullpath = dir + "/meta";
|
||||
|
||||
std::string fullpath = sectordir + "/meta";
|
||||
std::ifstream is(fullpath.c_str(), std::ios_base::binary);
|
||||
if(is.good() == false)
|
||||
{
|
||||
// If the directory exists anyway, it probably is in some old
|
||||
// format. Just go ahead and create the sector.
|
||||
if(fs::PathExists(dir))
|
||||
if(fs::PathExists(sectordir))
|
||||
{
|
||||
dstream<<"ServerMap::loadSectorMeta(): Sector metafile "
|
||||
<<fullpath<<" doesn't exist but directory does."
|
||||
|
@ -5307,12 +5327,16 @@ MapSector* ServerMap::loadSectorMeta(std::string dirname)
|
|||
m_sectors.insert(p2d, sector);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw FileNotGoodException("Cannot open sector metafile");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sector = ServerMapSector::deSerialize
|
||||
(is, this, p2d, m_sectors);
|
||||
if(save_after_load)
|
||||
saveSectorMeta(sector);
|
||||
}
|
||||
|
||||
sector->differs_from_disk = false;
|
||||
|
@ -5323,14 +5347,31 @@ MapSector* ServerMap::loadSectorMeta(std::string dirname)
|
|||
bool ServerMap::loadSectorFull(v2s16 p2d)
|
||||
{
|
||||
DSTACK(__FUNCTION_NAME);
|
||||
std::string sectorsubdir = getSectorSubDir(p2d);
|
||||
|
||||
MapSector *sector = NULL;
|
||||
|
||||
// The directory layout we're going to load from.
|
||||
// 1 - original sectors/xxxxzzzz/
|
||||
// 2 - new sectors2/xxx/zzz/
|
||||
// If we load from anything but the latest structure, we will
|
||||
// immediately save to the new one, and remove the old.
|
||||
int loadlayout = 1;
|
||||
std::string sectordir1 = getSectorDir(p2d, 1);
|
||||
std::string sectordir;
|
||||
if(fs::PathExists(sectordir1))
|
||||
{
|
||||
sectordir = sectordir1;
|
||||
}
|
||||
else
|
||||
{
|
||||
loadlayout = 2;
|
||||
sectordir = getSectorDir(p2d, 2);
|
||||
}
|
||||
|
||||
//JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
|
||||
|
||||
try{
|
||||
sector = loadSectorMeta(sectorsubdir);
|
||||
sector = loadSectorMeta(sectordir, loadlayout != 2);
|
||||
}
|
||||
catch(InvalidFilenameException &e)
|
||||
{
|
||||
|
@ -5349,7 +5390,7 @@ bool ServerMap::loadSectorFull(v2s16 p2d)
|
|||
Load blocks
|
||||
*/
|
||||
std::vector<fs::DirListNode> list2 = fs::GetDirListing
|
||||
(m_savedir+"/sectors/"+sectorsubdir);
|
||||
(sectordir);
|
||||
std::vector<fs::DirListNode>::iterator i2;
|
||||
for(i2=list2.begin(); i2!=list2.end(); i2++)
|
||||
{
|
||||
|
@ -5357,16 +5398,25 @@ bool ServerMap::loadSectorFull(v2s16 p2d)
|
|||
if(i2->dir)
|
||||
continue;
|
||||
try{
|
||||
loadBlock(sectorsubdir, i2->name, sector);
|
||||
loadBlock(sectordir, i2->name, sector, loadlayout != 2);
|
||||
}
|
||||
catch(InvalidFilenameException &e)
|
||||
{
|
||||
// This catches unknown crap in directory
|
||||
}
|
||||
}
|
||||
|
||||
if(loadlayout != 2)
|
||||
{
|
||||
dstream<<"Sector converted to new layout - deleting "<<
|
||||
sectordir1<<std::endl;
|
||||
fs::RecursiveDelete(sectordir1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void ServerMap::saveBlock(MapBlock *block)
|
||||
{
|
||||
DSTACK(__FUNCTION_NAME);
|
||||
|
@ -5386,12 +5436,9 @@ void ServerMap::saveBlock(MapBlock *block)
|
|||
// Get destination
|
||||
v3s16 p3d = block->getPos();
|
||||
v2s16 p2d(p3d.X, p3d.Z);
|
||||
createDir(m_savedir);
|
||||
createDir(m_savedir+"/sectors");
|
||||
std::string dir = getSectorDir(p2d);
|
||||
createDir(dir);
|
||||
createDirs(dir);
|
||||
|
||||
// Block file is map/sectors/xxxxxxxx/xxxx
|
||||
char cc[5];
|
||||
snprintf(cc, 5, "%.4x", (unsigned int)p3d.Y&0xffff);
|
||||
std::string fullpath = dir + "/" + cc;
|
||||
|
@ -5427,12 +5474,11 @@ void ServerMap::saveBlock(MapBlock *block)
|
|||
block->resetChangedFlag();
|
||||
}
|
||||
|
||||
void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSector *sector)
|
||||
void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSector *sector, bool save_after_load)
|
||||
{
|
||||
DSTACK(__FUNCTION_NAME);
|
||||
|
||||
// Block file is map/sectors/xxxxxxxx/xxxx
|
||||
std::string fullpath = m_savedir+"/sectors/"+sectordir+"/"+blockfile;
|
||||
std::string fullpath = sectordir+"/"+blockfile;
|
||||
try{
|
||||
|
||||
std::ifstream is(fullpath.c_str(), std::ios_base::binary);
|
||||
|
@ -5496,7 +5542,7 @@ void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSecto
|
|||
*/
|
||||
|
||||
// Save old format blocks in new format
|
||||
if(version < SER_FMT_VER_HIGHEST)
|
||||
if(version < SER_FMT_VER_HIGHEST || save_after_load)
|
||||
{
|
||||
saveBlock(block);
|
||||
}
|
||||
|
|
12
src/map.h
12
src/map.h
|
@ -545,13 +545,9 @@ public:
|
|||
Misc. helper functions for fiddling with directory and file
|
||||
names when saving
|
||||
*/
|
||||
void createDir(std::string path);
|
||||
void createSaveDir();
|
||||
// returns something like "xxxxxxxx"
|
||||
std::string getSectorSubDir(v2s16 pos);
|
||||
void createDirs(std::string path);
|
||||
// returns something like "map/sectors/xxxxxxxx"
|
||||
std::string getSectorDir(v2s16 pos);
|
||||
std::string createSectorDir(v2s16 pos);
|
||||
std::string getSectorDir(v2s16 pos, int layout = 2);
|
||||
// dirname: final directory name
|
||||
v2s16 getSectorPos(std::string dirname);
|
||||
v3s16 getBlockPos(std::string sectordir, std::string blockfile);
|
||||
|
@ -572,7 +568,7 @@ public:
|
|||
// (no MapBlocks)
|
||||
// DEPRECATED? Sectors have no metadata anymore.
|
||||
void saveSectorMeta(ServerMapSector *sector);
|
||||
MapSector* loadSectorMeta(std::string dirname);
|
||||
MapSector* loadSectorMeta(std::string dirname, bool save_after_load);
|
||||
|
||||
// Full load of a sector including all blocks.
|
||||
// returns true on success, false on failure.
|
||||
|
@ -583,7 +579,7 @@ public:
|
|||
|
||||
void saveBlock(MapBlock *block);
|
||||
// This will generate a sector with getSector if not found.
|
||||
void loadBlock(std::string sectordir, std::string blockfile, MapSector *sector);
|
||||
void loadBlock(std::string sectordir, std::string blockfile, MapSector *sector, bool save_after_load=false);
|
||||
|
||||
// For debug printing
|
||||
virtual void PrintInfo(std::ostream &out);
|
||||
|
|
|
@ -87,6 +87,7 @@ Player::Player():
|
|||
m_position(0,0,0)
|
||||
{
|
||||
updateName("<not set>");
|
||||
updatePassword("");
|
||||
resetInventory();
|
||||
}
|
||||
|
||||
|
@ -145,6 +146,7 @@ void Player::serialize(std::ostream &os)
|
|||
Settings args;
|
||||
args.setS32("version", 1);
|
||||
args.set("name", m_name);
|
||||
args.set("password", m_password);
|
||||
args.setFloat("pitch", m_pitch);
|
||||
args.setFloat("yaw", m_yaw);
|
||||
args.setV3F("position", m_position);
|
||||
|
@ -179,6 +181,10 @@ void Player::deSerialize(std::istream &is)
|
|||
//args.getS32("version");
|
||||
std::string name = args.get("name");
|
||||
updateName(name.c_str());
|
||||
std::string password = "";
|
||||
if(args.exists("password"))
|
||||
password = args.get("password");
|
||||
updatePassword(password.c_str());
|
||||
m_pitch = args.getFloat("pitch");
|
||||
m_yaw = args.getFloat("yaw");
|
||||
m_position = args.getV3F("position");
|
||||
|
|
13
src/player.h
13
src/player.h
|
@ -25,6 +25,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
#include "collision.h"
|
||||
|
||||
#define PLAYERNAME_SIZE 20
|
||||
#define PASSWORD_SIZE 28 // Maximum password length. Allows for
|
||||
// base64-encoded SHA-1.
|
||||
|
||||
#define PLAYERNAME_ALLOWED_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.,"
|
||||
|
||||
|
@ -121,6 +123,16 @@ public:
|
|||
return m_name;
|
||||
}
|
||||
|
||||
virtual void updatePassword(const char *password)
|
||||
{
|
||||
snprintf(m_password, PASSWORD_SIZE, "%s", password);
|
||||
}
|
||||
|
||||
const char * getPassword()
|
||||
{
|
||||
return m_password;
|
||||
}
|
||||
|
||||
virtual bool isLocal() const = 0;
|
||||
|
||||
virtual void updateLight(u8 light_at_pos) {};
|
||||
|
@ -157,6 +169,7 @@ public:
|
|||
|
||||
protected:
|
||||
char m_name[PLAYERNAME_SIZE];
|
||||
char m_password[PASSWORD_SIZE];
|
||||
f32 m_pitch;
|
||||
f32 m_yaw;
|
||||
v3f m_speed;
|
||||
|
|
|
@ -1734,8 +1734,9 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
|||
// [0] u16 TOSERVER_INIT
|
||||
// [2] u8 SER_FMT_VER_HIGHEST
|
||||
// [3] u8[20] player_name
|
||||
// [23] u8[28] password <--- can be sent without this, from old versions
|
||||
|
||||
if(datasize < 3)
|
||||
if(datasize < 2+1+PLAYERNAME_SIZE)
|
||||
return;
|
||||
|
||||
derr_server<<DTIME<<"Server: Got TOSERVER_INIT from "
|
||||
|
@ -1767,17 +1768,41 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
|||
*/
|
||||
|
||||
// Get player name
|
||||
const u32 playername_size = 20;
|
||||
char playername[playername_size];
|
||||
for(u32 i=0; i<playername_size-1; i++)
|
||||
char playername[PLAYERNAME_SIZE];
|
||||
for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
|
||||
{
|
||||
playername[i] = data[3+i];
|
||||
}
|
||||
playername[playername_size-1] = 0;
|
||||
|
||||
playername[PLAYERNAME_SIZE-1] = 0;
|
||||
|
||||
// Get password
|
||||
char password[PASSWORD_SIZE];
|
||||
if(datasize == 2+1+PLAYERNAME_SIZE)
|
||||
{
|
||||
// old version - assume blank password
|
||||
password[0] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
for(u32 i=0; i<PASSWORD_SIZE-1; i++)
|
||||
{
|
||||
password[i] = data[23+i];
|
||||
}
|
||||
password[PASSWORD_SIZE-1] = 0;
|
||||
}
|
||||
Player *checkplayer = m_env.getPlayer(playername);
|
||||
if(checkplayer != NULL && strcmp(checkplayer->getPassword(),password))
|
||||
{
|
||||
derr_server<<DTIME<<"Server: peer_id="<<peer_id
|
||||
<<": supplied invalid password for "
|
||||
<<playername<<std::endl;
|
||||
SendAccessDenied(m_con, peer_id);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get player
|
||||
Player *player = emergePlayer(playername, "", peer_id);
|
||||
//Player *player = m_env.getPlayer(peer_id);
|
||||
Player *player = emergePlayer(playername, password, peer_id);
|
||||
|
||||
|
||||
/*{
|
||||
// DEBUG: Test serialization
|
||||
|
@ -3138,6 +3163,20 @@ void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
|
|||
con.Send(peer_id, 0, data, true);
|
||||
}
|
||||
|
||||
void Server::SendAccessDenied(con::Connection &con, u16 peer_id)
|
||||
{
|
||||
DSTACK(__FUNCTION_NAME);
|
||||
std::ostringstream os(std::ios_base::binary);
|
||||
|
||||
writeU16(os, TOCLIENT_ACCESS_DENIED);
|
||||
|
||||
// Make data buffer
|
||||
std::string s = os.str();
|
||||
SharedBuffer<u8> data((u8*)s.c_str(), s.size());
|
||||
// Send as reliable
|
||||
con.Send(peer_id, 0, data, true);
|
||||
}
|
||||
|
||||
/*
|
||||
Non-static send methods
|
||||
*/
|
||||
|
@ -4052,8 +4091,7 @@ v3f findSpawnPos(ServerMap &map)
|
|||
), BS);
|
||||
}
|
||||
|
||||
Player *Server::emergePlayer(const char *name, const char *password,
|
||||
u16 peer_id)
|
||||
Player *Server::emergePlayer(const char *name, const char *password, u16 peer_id)
|
||||
{
|
||||
/*
|
||||
Try to get an existing player
|
||||
|
@ -4099,6 +4137,7 @@ Player *Server::emergePlayer(const char *name, const char *password,
|
|||
//player->peer_id = PEER_ID_INEXISTENT;
|
||||
player->peer_id = peer_id;
|
||||
player->updateName(name);
|
||||
player->updatePassword(password);
|
||||
|
||||
/*
|
||||
Set player position
|
||||
|
|
|
@ -436,6 +436,7 @@ private:
|
|||
*/
|
||||
|
||||
static void SendHP(con::Connection &con, u16 peer_id, u8 hp);
|
||||
static void SendAccessDenied(con::Connection &con, u16 peer_id);
|
||||
|
||||
/*
|
||||
Non-static send methods
|
||||
|
@ -476,11 +477,12 @@ private:
|
|||
/*
|
||||
Get a player from memory or creates one.
|
||||
If player is already connected, return NULL
|
||||
The password is not checked here - it is only used to
|
||||
set the password if a new player is created.
|
||||
|
||||
Call with env and con locked.
|
||||
*/
|
||||
Player *emergePlayer(const char *name, const char *password,
|
||||
u16 peer_id);
|
||||
Player *emergePlayer(const char *name, const char *password, u16 peer_id);
|
||||
|
||||
/*
|
||||
Update water pressure.
|
||||
|
|
|
@ -0,0 +1,207 @@
|
|||
/* sha1.cpp
|
||||
|
||||
Copyright (c) 2005 Michael D. Leonhard
|
||||
|
||||
http://tamale.net/
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "sha1.h"
|
||||
|
||||
// print out memory in hexadecimal
|
||||
void SHA1::hexPrinter( unsigned char* c, int l )
|
||||
{
|
||||
assert( c );
|
||||
assert( l > 0 );
|
||||
while( l > 0 )
|
||||
{
|
||||
printf( " %02x", *c );
|
||||
l--;
|
||||
c++;
|
||||
}
|
||||
}
|
||||
|
||||
// circular left bit rotation. MSB wraps around to LSB
|
||||
Uint32 SHA1::lrot( Uint32 x, int bits )
|
||||
{
|
||||
return (x<<bits) | (x>>(32 - bits));
|
||||
};
|
||||
|
||||
// Save a 32-bit unsigned integer to memory, in big-endian order
|
||||
void SHA1::storeBigEndianUint32( unsigned char* byte, Uint32 num )
|
||||
{
|
||||
assert( byte );
|
||||
byte[0] = (unsigned char)(num>>24);
|
||||
byte[1] = (unsigned char)(num>>16);
|
||||
byte[2] = (unsigned char)(num>>8);
|
||||
byte[3] = (unsigned char)num;
|
||||
}
|
||||
|
||||
|
||||
// Constructor *******************************************************
|
||||
SHA1::SHA1()
|
||||
{
|
||||
// make sure that the data type is the right size
|
||||
assert( sizeof( Uint32 ) * 5 == 20 );
|
||||
|
||||
// initialize
|
||||
H0 = 0x67452301;
|
||||
H1 = 0xefcdab89;
|
||||
H2 = 0x98badcfe;
|
||||
H3 = 0x10325476;
|
||||
H4 = 0xc3d2e1f0;
|
||||
unprocessedBytes = 0;
|
||||
size = 0;
|
||||
}
|
||||
|
||||
// Destructor ********************************************************
|
||||
SHA1::~SHA1()
|
||||
{
|
||||
// erase data
|
||||
H0 = H1 = H2 = H3 = H4 = 0;
|
||||
for( int c = 0; c < 64; c++ ) bytes[c] = 0;
|
||||
unprocessedBytes = size = 0;
|
||||
}
|
||||
|
||||
// process ***********************************************************
|
||||
void SHA1::process()
|
||||
{
|
||||
assert( unprocessedBytes == 64 );
|
||||
//printf( "process: " ); hexPrinter( bytes, 64 ); printf( "\n" );
|
||||
int t;
|
||||
Uint32 a, b, c, d, e, K, f, W[80];
|
||||
// starting values
|
||||
a = H0;
|
||||
b = H1;
|
||||
c = H2;
|
||||
d = H3;
|
||||
e = H4;
|
||||
// copy and expand the message block
|
||||
for( t = 0; t < 16; t++ ) W[t] = (bytes[t*4] << 24)
|
||||
+(bytes[t*4 + 1] << 16)
|
||||
+(bytes[t*4 + 2] << 8)
|
||||
+ bytes[t*4 + 3];
|
||||
for(; t< 80; t++ ) W[t] = lrot( W[t-3]^W[t-8]^W[t-14]^W[t-16], 1 );
|
||||
|
||||
/* main loop */
|
||||
Uint32 temp;
|
||||
for( t = 0; t < 80; t++ )
|
||||
{
|
||||
if( t < 20 ) {
|
||||
K = 0x5a827999;
|
||||
f = (b & c) | ((b ^ 0xFFFFFFFF) & d);//TODO: try using ~
|
||||
} else if( t < 40 ) {
|
||||
K = 0x6ed9eba1;
|
||||
f = b ^ c ^ d;
|
||||
} else if( t < 60 ) {
|
||||
K = 0x8f1bbcdc;
|
||||
f = (b & c) | (b & d) | (c & d);
|
||||
} else {
|
||||
K = 0xca62c1d6;
|
||||
f = b ^ c ^ d;
|
||||
}
|
||||
temp = lrot(a,5) + f + e + W[t] + K;
|
||||
e = d;
|
||||
d = c;
|
||||
c = lrot(b,30);
|
||||
b = a;
|
||||
a = temp;
|
||||
//printf( "t=%d %08x %08x %08x %08x %08x\n",t,a,b,c,d,e );
|
||||
}
|
||||
/* add variables */
|
||||
H0 += a;
|
||||
H1 += b;
|
||||
H2 += c;
|
||||
H3 += d;
|
||||
H4 += e;
|
||||
//printf( "Current: %08x %08x %08x %08x %08x\n",H0,H1,H2,H3,H4 );
|
||||
/* all bytes have been processed */
|
||||
unprocessedBytes = 0;
|
||||
}
|
||||
|
||||
// addBytes **********************************************************
|
||||
void SHA1::addBytes( const char* data, int num )
|
||||
{
|
||||
assert( data );
|
||||
assert( num > 0 );
|
||||
// add these bytes to the running total
|
||||
size += num;
|
||||
// repeat until all data is processed
|
||||
while( num > 0 )
|
||||
{
|
||||
// number of bytes required to complete block
|
||||
int needed = 64 - unprocessedBytes;
|
||||
assert( needed > 0 );
|
||||
// number of bytes to copy (use smaller of two)
|
||||
int toCopy = (num < needed) ? num : needed;
|
||||
// Copy the bytes
|
||||
memcpy( bytes + unprocessedBytes, data, toCopy );
|
||||
// Bytes have been copied
|
||||
num -= toCopy;
|
||||
data += toCopy;
|
||||
unprocessedBytes += toCopy;
|
||||
|
||||
// there is a full block
|
||||
if( unprocessedBytes == 64 ) process();
|
||||
}
|
||||
}
|
||||
|
||||
// digest ************************************************************
|
||||
unsigned char* SHA1::getDigest()
|
||||
{
|
||||
// save the message size
|
||||
Uint32 totalBitsL = size << 3;
|
||||
Uint32 totalBitsH = size >> 29;
|
||||
// add 0x80 to the message
|
||||
addBytes( "\x80", 1 );
|
||||
|
||||
unsigned char footer[64] = {
|
||||
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, 0 };
|
||||
// block has no room for 8-byte filesize, so finish it
|
||||
if( unprocessedBytes > 56 )
|
||||
addBytes( (char*)footer, 64 - unprocessedBytes);
|
||||
assert( unprocessedBytes <= 56 );
|
||||
// how many zeros do we need
|
||||
int neededZeros = 56 - unprocessedBytes;
|
||||
// store file size (in bits) in big-endian format
|
||||
storeBigEndianUint32( footer + neededZeros , totalBitsH );
|
||||
storeBigEndianUint32( footer + neededZeros + 4, totalBitsL );
|
||||
// finish the final block
|
||||
addBytes( (char*)footer, neededZeros + 8 );
|
||||
// allocate memory for the digest bytes
|
||||
unsigned char* digest = (unsigned char*)malloc( 20 );
|
||||
// copy the digest bytes
|
||||
storeBigEndianUint32( digest, H0 );
|
||||
storeBigEndianUint32( digest + 4, H1 );
|
||||
storeBigEndianUint32( digest + 8, H2 );
|
||||
storeBigEndianUint32( digest + 12, H3 );
|
||||
storeBigEndianUint32( digest + 16, H4 );
|
||||
// return the digest
|
||||
return digest;
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/* sha1.h
|
||||
|
||||
Copyright (c) 2005 Michael D. Leonhard
|
||||
|
||||
http://tamale.net/
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef SHA1_HEADER
|
||||
typedef unsigned int Uint32;
|
||||
|
||||
class SHA1
|
||||
{
|
||||
private:
|
||||
// fields
|
||||
Uint32 H0, H1, H2, H3, H4;
|
||||
unsigned char bytes[64];
|
||||
int unprocessedBytes;
|
||||
Uint32 size;
|
||||
void process();
|
||||
public:
|
||||
SHA1();
|
||||
~SHA1();
|
||||
void addBytes( const char* data, int num );
|
||||
unsigned char* getDigest();
|
||||
// utility methods
|
||||
static Uint32 lrot( Uint32 x, int bits );
|
||||
static void storeBigEndianUint32( unsigned char* byte, Uint32 num );
|
||||
static void hexPrinter( unsigned char* c, int l );
|
||||
};
|
||||
|
||||
#define SHA1_HEADER
|
||||
#endif
|
Loading…
Reference in New Issue