mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-04-30 07:49:31 -05:00
added lua scripting functionality and fixed authentication to server
This commit is contained in:
@@ -63,7 +63,7 @@ namespace openspace{
|
||||
|
||||
~OSParallelConnection();
|
||||
|
||||
void connect();
|
||||
void clientConnect();
|
||||
|
||||
void setPort(const std::string &port);
|
||||
|
||||
@@ -79,7 +79,7 @@ namespace openspace{
|
||||
|
||||
void setSocket(_SOCKET socket);
|
||||
|
||||
_SOCKET socket();
|
||||
_SOCKET clientSocket();
|
||||
|
||||
void setHost(bool host);
|
||||
|
||||
@@ -88,6 +88,8 @@ namespace openspace{
|
||||
bool isRunning();
|
||||
|
||||
void requestHostship();
|
||||
|
||||
void setPassword(const std::string &password);
|
||||
|
||||
enum MessageTypes{
|
||||
Authentication=0,
|
||||
@@ -109,8 +111,39 @@ namespace openspace{
|
||||
protected:
|
||||
|
||||
private:
|
||||
uint32_t _passCode;
|
||||
std::string _password;
|
||||
//@TODO change this into the ghoul hasher for client AND server
|
||||
uint32_t hash(const std::string &val){
|
||||
uint32_t hashVal = 0, i;
|
||||
size_t len = val.length();
|
||||
|
||||
for (hashVal = i = 0; i < len; ++i){
|
||||
hashVal += val.c_str()[i];
|
||||
hashVal += (hashVal << 10);
|
||||
hashVal ^= (hashVal >> 6);
|
||||
}
|
||||
|
||||
hashVal += (hashVal << 3);
|
||||
hashVal ^= (hashVal >> 11);
|
||||
hashVal += (hashVal << 15);
|
||||
|
||||
return hashVal;
|
||||
};
|
||||
|
||||
void disconnect();
|
||||
|
||||
void closeSocket();
|
||||
|
||||
bool initNetworkAPI();
|
||||
|
||||
void connection(addrinfo *info);
|
||||
|
||||
void authenticate();
|
||||
|
||||
void communicate();
|
||||
|
||||
int receiveData(_SOCKET & socket, std::vector<char> &buffer, int length, int flags);
|
||||
|
||||
uint32_t _passCode;
|
||||
std::string _port;
|
||||
std::string _address;
|
||||
std::string _name;
|
||||
|
||||
@@ -22,21 +22,59 @@
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
//@TODO CHANGE THIS!
|
||||
const int headerSize = 8;
|
||||
|
||||
#ifdef __WIN32__
|
||||
#ifndef _ERRNO
|
||||
#define _ERRNO WSAGetLastError()
|
||||
#endif
|
||||
#else //Use BSD sockets
|
||||
#ifdef _XCODE
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <errno.h>
|
||||
#ifndef SOCKET_ERROR
|
||||
#define SOCKET_ERROR (-1)
|
||||
#endif
|
||||
|
||||
#ifndef INVALID_SOCKET
|
||||
#define INVALID_SOCKET (_SOCKET)(~0)
|
||||
#endif
|
||||
|
||||
#ifndef NO_ERROR
|
||||
#define NO_ERROR 0L
|
||||
#endif
|
||||
|
||||
#ifndef _ERRNO
|
||||
#define _ERRNO errno
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <openspace/network/osparallelconnection.h>
|
||||
#include <openspace/engine/openspaceengine.h>
|
||||
|
||||
#include "osparallelconnection_lua.inl"
|
||||
|
||||
namespace{
|
||||
const std::string _loggerCat = "Parallel";
|
||||
}
|
||||
|
||||
namespace openspace {
|
||||
namespace network{
|
||||
|
||||
OSParallelConnection::OSParallelConnection():
|
||||
_passCode(0),
|
||||
_port(""),
|
||||
_address(""),
|
||||
_port("20501"),
|
||||
_address("127.0.0.1"),
|
||||
_name("No name"),
|
||||
_password(""),
|
||||
_clientSocket(0),
|
||||
_clientSocket(INVALID_SOCKET),
|
||||
_thread(nullptr),
|
||||
_isRunning(false),
|
||||
_isHost(false)
|
||||
@@ -45,12 +83,195 @@ namespace openspace {
|
||||
}
|
||||
|
||||
OSParallelConnection::~OSParallelConnection(){
|
||||
|
||||
_isRunning.store(false);
|
||||
|
||||
disconnect();
|
||||
|
||||
#if defined(__WIN32__)
|
||||
WSACleanup();
|
||||
#endif
|
||||
}
|
||||
|
||||
void OSParallelConnection::connect(){
|
||||
|
||||
void OSParallelConnection::clientConnect(){
|
||||
if (!initNetworkAPI()){
|
||||
//error, handle this
|
||||
}
|
||||
|
||||
struct addrinfo *addresult = NULL, *ptr = NULL, hints;
|
||||
#ifdef __WIN32__ //WinSock
|
||||
ZeroMemory(&hints, sizeof(hints));
|
||||
#else
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
#endif
|
||||
hints.ai_family = AF_INET;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_protocol = IPPROTO_TCP;
|
||||
hints.ai_flags = AI_PASSIVE;
|
||||
|
||||
int result;
|
||||
|
||||
// Resolve the local address and port to be used by the server
|
||||
result = getaddrinfo(_address.c_str(), _port.c_str(), &hints, &addresult);
|
||||
if (result != 0)
|
||||
{
|
||||
#if defined(__WIN32__)
|
||||
WSACleanup();
|
||||
#endif
|
||||
std::cerr << "Failed to parse hints for connection!" << std::endl;
|
||||
}
|
||||
|
||||
// Attempt to connect to the first address returned by
|
||||
// the call to getaddrinfo
|
||||
ptr = addresult;
|
||||
|
||||
std::cout << "Client started on port " << _port << std::endl;
|
||||
|
||||
//start accept connections thread
|
||||
_isRunning.store(true);
|
||||
_thread = new (std::nothrow) std::thread(&OSParallelConnection::connection, this, addresult);
|
||||
|
||||
}
|
||||
|
||||
void OSParallelConnection::connection(addrinfo *info){
|
||||
int result;
|
||||
|
||||
while (_isRunning.load()){
|
||||
_clientSocket = socket(info->ai_family, info->ai_socktype, info->ai_protocol);
|
||||
|
||||
if (_clientSocket == INVALID_SOCKET){
|
||||
freeaddrinfo(info);
|
||||
#if defined(__WIN32__)
|
||||
WSACleanup();
|
||||
#endif
|
||||
std::cerr << "Failed to init client socket!" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
int flag = 1;
|
||||
int result;
|
||||
|
||||
//set send timeout
|
||||
int timeout = 0; //infinite
|
||||
result = setsockopt(
|
||||
_clientSocket,
|
||||
SOL_SOCKET,
|
||||
SO_SNDTIMEO,
|
||||
(char *)&timeout,
|
||||
sizeof(timeout));
|
||||
|
||||
//set receive timeout
|
||||
result = setsockopt(
|
||||
_clientSocket,
|
||||
SOL_SOCKET,
|
||||
SO_RCVTIMEO,
|
||||
(char *)&timeout,
|
||||
sizeof(timeout));
|
||||
|
||||
result = setsockopt(_clientSocket, SOL_SOCKET, SO_REUSEADDR, (char*)&flag, sizeof(int));
|
||||
if (result == SOCKET_ERROR)
|
||||
std::cout << "Failed to set reuse address with error:" << _ERRNO << std::endl;
|
||||
|
||||
result = setsockopt(_clientSocket, SOL_SOCKET, SO_KEEPALIVE, (char*)&flag, sizeof(int));
|
||||
if (result == SOCKET_ERROR)
|
||||
std::cout << "Failed to set keep alive with error: " << _ERRNO << std::endl;
|
||||
|
||||
result = connect(_clientSocket, info->ai_addr, (int)info->ai_addrlen);
|
||||
if (result != SOCKET_ERROR)
|
||||
{
|
||||
//send authentication
|
||||
authenticate();
|
||||
|
||||
//start listening for communication
|
||||
communicate();
|
||||
}
|
||||
|
||||
//one sec sleep
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
}
|
||||
|
||||
//cleanup
|
||||
freeaddrinfo(info);
|
||||
}
|
||||
|
||||
void OSParallelConnection::authenticate(){
|
||||
int pos = 4;
|
||||
uint16_t namelen = static_cast<uint16_t>(_name.length());
|
||||
int size = headerSize + sizeof(uint32_t) + sizeof(uint16_t) + static_cast<int>(namelen);
|
||||
std::vector<char> buffer;
|
||||
buffer.reserve(size);
|
||||
|
||||
//version
|
||||
buffer.insert(buffer.end(), 'O');
|
||||
buffer.insert(buffer.end(), 'S');
|
||||
buffer.insert(buffer.end(), 0);
|
||||
buffer.insert(buffer.end(), 0);
|
||||
|
||||
//msg type, 0 = auth
|
||||
int type = 0;
|
||||
buffer.insert(buffer.end(), reinterpret_cast<char*>(&type), reinterpret_cast<char*>(&type) + sizeof(int));
|
||||
|
||||
//passcode
|
||||
buffer.insert(buffer.end(), reinterpret_cast<char*>(&_passCode), reinterpret_cast<char*>(&_passCode) + sizeof(uint32_t));
|
||||
|
||||
//name length
|
||||
buffer.insert(buffer.end(), reinterpret_cast<char*>(&namelen), reinterpret_cast<char*>(&namelen) + sizeof(uint16_t));
|
||||
|
||||
//name
|
||||
buffer.insert(buffer.end(), _name.begin(), _name.end());
|
||||
|
||||
int result = send(_clientSocket, buffer.data(), size, 0);
|
||||
|
||||
if (result == SOCKET_ERROR){
|
||||
//failed to send auth msg.
|
||||
std::cerr << "Failed to send authentication message!" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void OSParallelConnection::communicate(){
|
||||
|
||||
std::vector<char> buffer;
|
||||
buffer.resize(8);
|
||||
int result;
|
||||
|
||||
while (_isRunning.load()){
|
||||
result = receiveData(_clientSocket, buffer, headerSize, 0);
|
||||
|
||||
if (result > 0){
|
||||
int i = 0;
|
||||
}
|
||||
else{
|
||||
if (result == 0){
|
||||
//connection rejected
|
||||
_isRunning.store(false);
|
||||
}
|
||||
else{
|
||||
std::cerr << "Error " << _ERRNO << " detected in connection!" << std::endl;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int OSParallelConnection::receiveData(_SOCKET & socket, std::vector<char> &buffer, int length, int flags){
|
||||
int result = 0;
|
||||
int received = 0;
|
||||
while (result < length){
|
||||
received = recv(socket, buffer.data() + result, length - result, flags);
|
||||
|
||||
if (received > 0){
|
||||
result += received;
|
||||
received = 0;
|
||||
}
|
||||
else{
|
||||
//error receiving
|
||||
result = received;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void OSParallelConnection::setPort(const std::string &port){
|
||||
_port = port;
|
||||
@@ -80,7 +301,7 @@ namespace openspace {
|
||||
_clientSocket = socket;
|
||||
}
|
||||
|
||||
_SOCKET OSParallelConnection::socket(){
|
||||
_SOCKET OSParallelConnection::clientSocket(){
|
||||
return _clientSocket;
|
||||
}
|
||||
|
||||
@@ -99,78 +320,107 @@ namespace openspace {
|
||||
void OSParallelConnection::requestHostship(){
|
||||
|
||||
}
|
||||
|
||||
|
||||
void OSParallelConnection::setPassword(const std::string& pwd){
|
||||
_passCode = hash(pwd);
|
||||
}
|
||||
|
||||
void OSParallelConnection::disconnect(){
|
||||
closeSocket();
|
||||
|
||||
if (_thread != nullptr){
|
||||
_thread->join();
|
||||
delete _thread;
|
||||
_thread = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void OSParallelConnection::closeSocket(){
|
||||
if (_clientSocket != INVALID_SOCKET)
|
||||
{
|
||||
/*
|
||||
Windows shutdown options
|
||||
* SD_RECIEVE
|
||||
* SD_SEND
|
||||
* SD_BOTH
|
||||
|
||||
Linux & Mac shutdown options
|
||||
* SHUT_RD (Disables further receive operations)
|
||||
* SHUT_WR (Disables further send operations)
|
||||
* SHUT_RDWR (Disables further send and receive operations)
|
||||
*/
|
||||
|
||||
#ifdef __WIN32__
|
||||
shutdown(_clientSocket, SD_BOTH);
|
||||
closesocket(_clientSocket);
|
||||
#else
|
||||
shutdown(_clientSocket, SHUT_RDWR);
|
||||
#endif
|
||||
|
||||
_clientSocket = INVALID_SOCKET;
|
||||
}
|
||||
}
|
||||
|
||||
bool OSParallelConnection::initNetworkAPI(){
|
||||
#if defined(__WIN32__)
|
||||
WSADATA wsaData;
|
||||
WORD version;
|
||||
int error;
|
||||
|
||||
version = MAKEWORD(2, 2);
|
||||
|
||||
error = WSAStartup(version, &wsaData);
|
||||
|
||||
if (error != 0 ||
|
||||
LOBYTE(wsaData.wVersion) != 2 ||
|
||||
HIBYTE(wsaData.wVersion) != 2)
|
||||
{
|
||||
/* incorrect WinSock version */
|
||||
std::cerr << "Failed to init winsock API!" << std::endl;
|
||||
WSACleanup();
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
//No init needed on unix
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
scripting::ScriptEngine::LuaLibrary OSParallelConnection::luaLibrary() {
|
||||
return {
|
||||
"",
|
||||
"parallel",
|
||||
{
|
||||
{
|
||||
"setPort",
|
||||
&luascriptfunctions::setPort,
|
||||
"string",
|
||||
"number",
|
||||
"Set the port for the parallel connection"
|
||||
},
|
||||
// {
|
||||
// "clearKeys",
|
||||
// &luascriptfunctions::clearKeys,
|
||||
// "",
|
||||
// "Clear all key bindings"
|
||||
// },
|
||||
// {
|
||||
// "bindKey",
|
||||
// &luascriptfunctions::bindKey,
|
||||
// "string, string",
|
||||
// "Binds a key by name to a lua string command"
|
||||
// },
|
||||
// {
|
||||
// "dt",
|
||||
// &luascriptfunctions::dt,
|
||||
// "",
|
||||
// "Get current frame time"
|
||||
// },
|
||||
// {
|
||||
// "distance",
|
||||
// &luascriptfunctions::distance,
|
||||
// "number",
|
||||
// "Change distance to origin"
|
||||
// },
|
||||
// {
|
||||
// "setInteractionSensitivity",
|
||||
// &luascriptfunctions::setInteractionSensitivity,
|
||||
// "number",
|
||||
// "Sets the global interaction sensitivity"
|
||||
// },
|
||||
// {
|
||||
// "interactionSensitivity",
|
||||
// &luascriptfunctions::interactionSensitivity,
|
||||
// "",
|
||||
// "Gets the current global interaction sensitivity"
|
||||
// },
|
||||
// {
|
||||
// "setInvertRoll",
|
||||
// &luascriptfunctions::setInvertRoll,
|
||||
// "bool",
|
||||
// "Sets the setting if roll movements are inverted"
|
||||
// },
|
||||
// {
|
||||
// "invertRoll",
|
||||
// &luascriptfunctions::invertRoll,
|
||||
// "",
|
||||
// "Returns the status of roll movement inversion"
|
||||
// },
|
||||
// {
|
||||
// "setInvertRotation",
|
||||
// &luascriptfunctions::setInvertRotation,
|
||||
// "bool",
|
||||
// "Sets the setting if rotation movements are inverted"
|
||||
// },
|
||||
// {
|
||||
// "invertRotation",
|
||||
// &luascriptfunctions::invertRotation,
|
||||
// "",
|
||||
// "Returns the status of rotation movement inversion"
|
||||
// }
|
||||
|
||||
{
|
||||
"setAddress",
|
||||
&luascriptfunctions::setAddress,
|
||||
"string",
|
||||
"Set the address for the parallel connection"
|
||||
},
|
||||
{
|
||||
"setPassword",
|
||||
&luascriptfunctions::setPassword,
|
||||
"string",
|
||||
"Set the password for the parallel connection"
|
||||
},
|
||||
{
|
||||
"setDisplayName",
|
||||
&luascriptfunctions::setDisplayName,
|
||||
"string",
|
||||
"Set your display name for the parallel connection"
|
||||
},
|
||||
{
|
||||
"connect",
|
||||
&luascriptfunctions::connect,
|
||||
"",
|
||||
"Connect to parallel"
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -32,24 +32,107 @@ namespace luascriptfunctions {
|
||||
* Set the port for parallel connection
|
||||
*/
|
||||
int setPort(lua_State* L) {
|
||||
using ghoul::lua::luaTypeToString;
|
||||
const std::string _loggerCat = "lua.setPort";
|
||||
const bool isFunction = (lua_isfunction(L, -1) != 0);
|
||||
if (isFunction) {
|
||||
// If the top of the stack is a function, it is ourself
|
||||
const char* msg = lua_pushfstring(L, "method called without argument");
|
||||
return luaL_error(L, "bad argument (%s)", msg);
|
||||
}
|
||||
|
||||
int nArguments = lua_gettop(L);
|
||||
if (nArguments != 1)
|
||||
return luaL_error(L, "Expected %i arguments, got %i", 1, nArguments);
|
||||
|
||||
const int type = lua_type(L, -1);
|
||||
if (type != LUA_TSTRING)
|
||||
return luaL_error(L, "Expected string, got %i", type);
|
||||
|
||||
std::string s = luaL_checkstring(L, -1);
|
||||
|
||||
OsEng.parallelConnection()->setPort(s);
|
||||
const bool isNumber = (lua_isnumber(L, -1) != 0);
|
||||
if (isNumber) {
|
||||
int value = lua_tonumber(L, -1);
|
||||
std::string port = std::to_string(value);
|
||||
OsEng.parallelConnection()->setPort(port);
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
const char* msg = lua_pushfstring(L, "%s expected, got %s",
|
||||
lua_typename(L, LUA_TNUMBER), luaL_typename(L, -1));
|
||||
return luaL_error(L, "bad argument #%d (%s)", 1, msg);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int setAddress(lua_State* L) {
|
||||
const bool isFunction = (lua_isfunction(L, -1) != 0);
|
||||
if (isFunction) {
|
||||
// If the top of the stack is a function, it is ourself
|
||||
const char* msg = lua_pushfstring(L, "method called without argument");
|
||||
return luaL_error(L, "bad argument (%s)", msg);
|
||||
}
|
||||
|
||||
const int type = lua_type(L, -1);
|
||||
if (type == LUA_TSTRING) {
|
||||
std::string address = luaL_checkstring(L, -1);
|
||||
OsEng.parallelConnection()->setAddress(address);
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
const char* msg = lua_pushfstring(L, "%s expected, got %s",
|
||||
lua_typename(L, LUA_TSTRING), luaL_typename(L, -1));
|
||||
return luaL_error(L, "bad argument #%d (%s)", 1, msg);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int setPassword(lua_State* L) {
|
||||
const bool isFunction = (lua_isfunction(L, -1) != 0);
|
||||
if (isFunction) {
|
||||
// If the top of the stack is a function, it is ourself
|
||||
const char* msg = lua_pushfstring(L, "method called without argument");
|
||||
return luaL_error(L, "bad argument (%s)", msg);
|
||||
}
|
||||
|
||||
const int type = lua_type(L, -1);
|
||||
if (type == LUA_TSTRING) {
|
||||
std::string pwd = luaL_checkstring(L, -1);
|
||||
OsEng.parallelConnection()->setPassword(pwd);
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
const char* msg = lua_pushfstring(L, "%s expected, got %s",
|
||||
lua_typename(L, LUA_TSTRING), luaL_typename(L, -1));
|
||||
return luaL_error(L, "bad argument #%d (%s)", 1, msg);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int setDisplayName(lua_State* L) {
|
||||
const bool isFunction = (lua_isfunction(L, -1) != 0);
|
||||
if (isFunction) {
|
||||
// If the top of the stack is a function, it is ourself
|
||||
const char* msg = lua_pushfstring(L, "method called without argument");
|
||||
return luaL_error(L, "bad argument (%s)", msg);
|
||||
}
|
||||
|
||||
const int type = lua_type(L, -1);
|
||||
if (type == LUA_TSTRING) {
|
||||
std::string name = luaL_checkstring(L, -1);
|
||||
OsEng.parallelConnection()->setName(name);
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
const char* msg = lua_pushfstring(L, "%s expected, got %s",
|
||||
lua_typename(L, LUA_TSTRING), luaL_typename(L, -1));
|
||||
return luaL_error(L, "bad argument #%d (%s)", 1, msg);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int connect(lua_State* L) {
|
||||
int nArguments = lua_gettop(L);
|
||||
if (nArguments != 0)
|
||||
return luaL_error(L, "Expected %i arguments, got %i", 0, nArguments);
|
||||
OsEng.parallelConnection()->clientConnect();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
} // namespace luascriptfunctions
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
Reference in New Issue
Block a user