diff --git a/source/glest_game/main/main.cpp b/source/glest_game/main/main.cpp index 46f526250..4610b5cb2 100644 --- a/source/glest_game/main/main.cpp +++ b/source/glest_game/main/main.cpp @@ -225,6 +225,10 @@ void MainWindow::eventClose(){ program= NULL; } +void MainWindow::setProgram(Program *program) { + this->program= program; +} + // ===================================================== // Main // ===================================================== @@ -252,7 +256,7 @@ int glestMain(int argc, char** argv){ SystemFlags::debugLogFile = debugLogFile.c_str(); NetworkInterface::setDisplayMessageFunction(ExceptionHandler::DisplayMessage); - + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); //showCursor(config.getBool("Windowed")); diff --git a/source/glest_game/main/main.h b/source/glest_game/main/main.h index 7ea4b7eab..d132865c5 100644 --- a/source/glest_game/main/main.h +++ b/source/glest_game/main/main.h @@ -36,7 +36,7 @@ public: MainWindow(Program *program); ~MainWindow(); - void setProgram(Program *program) {this->program= program;} + void setProgram(Program *program); virtual void eventMouseDown(int x, int y, MouseButton mouseButton); virtual void eventMouseUp(int x, int y, MouseButton mouseButton); diff --git a/source/glest_game/main/program.cpp b/source/glest_game/main/program.cpp index e2342813f..1a68d62e7 100644 --- a/source/glest_game/main/program.cpp +++ b/source/glest_game/main/program.cpp @@ -223,12 +223,14 @@ void Program::resize(SizeState sizeState){ // ==================== misc ==================== -void Program::setState(ProgramState *programState) +void Program::setState(ProgramState *programState, bool cleanupOldState) { //SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s] START\n",__FILE__,__FUNCTION__); - delete this->programState; + if(cleanupOldState == true) { + delete this->programState; + } //SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s] %d\n",__FILE__,__FUNCTION__,__LINE__); @@ -259,7 +261,7 @@ void Program::exit() { // ==================== PRIVATE ==================== -void Program::init(WindowGl *window, bool initSound){ +void Program::init(WindowGl *window, bool initSound, bool toggleFullScreen){ SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); @@ -269,7 +271,9 @@ void Program::init(WindowGl *window, bool initSound){ SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); //set video mode - setDisplaySettings(); + if(toggleFullScreen == false) { + setDisplaySettings(); + } SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); @@ -331,7 +335,7 @@ void Program::init(WindowGl *window, bool initSound){ SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); //sound - if(initSound == true) { + if(initSound == true && toggleFullScreen == false) { SoundRenderer &soundRenderer= SoundRenderer::getInstance(); soundRenderer.init(window); } diff --git a/source/glest_game/main/program.h b/source/glest_game/main/program.h index 5b1e370fd..adebee7dd 100644 --- a/source/glest_game/main/program.h +++ b/source/glest_game/main/program.h @@ -128,12 +128,14 @@ public: void showMessage(const char *msg); //misc - void setState(ProgramState *programState); + void setState(ProgramState *programState,bool cleanupOldState=true); ProgramState * getState() { return programState;} + WindowGl * getWindow() { return window; } + void init(WindowGl *window, bool initSound=true, bool toggleFullScreen=false); void exit(); private: - void init(WindowGl *window, bool initSound=true); + void setDisplaySettings(); void restoreDisplaySettings(); }; diff --git a/source/glest_game/menu/menu_state_join_game.cpp b/source/glest_game/menu/menu_state_join_game.cpp index 1dc310ad9..f0f32ebce 100644 --- a/source/glest_game/menu/menu_state_join_game.cpp +++ b/source/glest_game/menu/menu_state_join_game.cpp @@ -356,11 +356,19 @@ void MenuStateJoinGame::keyDown(char key){ else if(key== 'A') { SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + string bestIPMatch = ""; std::vector serverList = clientInterface->discoverServers(); if(serverList.size() > 0) { - SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] serverList[0] = [%s]\n",__FILE__,__FUNCTION__,__LINE__,serverList[0].c_str()); + std::vector localIPList = Socket::getLocalIPAddressList(); + for(int idx = 0; idx < serverList.size(); idx++) { + bestIPMatch = serverList[idx]; + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] bestIPMatch = [%s] localIPList[0] = [%s]\n",__FILE__,__FUNCTION__,__LINE__,bestIPMatch.c_str(),localIPList[0].c_str()); + if(strncmp(localIPList[0].c_str(),serverList[idx].c_str(),4) == 0) { + break; + } + } - labelServerIp.setText(serverList[0]); + labelServerIp.setText(bestIPMatch); connectToServer(); } } diff --git a/source/shared_lib/include/platform/sdl/window.h b/source/shared_lib/include/platform/sdl/window.h index dc084ec6b..c762f1a44 100644 --- a/source/shared_lib/include/platform/sdl/window.h +++ b/source/shared_lib/include/platform/sdl/window.h @@ -112,7 +112,8 @@ private: static MouseState mouseState; static Vec2i mousePos; static bool isKeyPressedDown; - + static bool isFullScreen; + static void setLastMouseEvent(unsigned int lastMouseEvent) {Window::lastMouseEvent = lastMouseEvent;} static unsigned int getLastMouseEvent() {return Window::lastMouseEvent;} @@ -129,8 +130,10 @@ public: static bool handleEvent(); static void revertMousePos(); static bool isKeyDown() { return isKeyPressedDown; } + static void setupGraphicsScreen(int depthBits=-1, int stencilBits=-1); + static const bool getIsFullScreen() { return isFullScreen; } + static void setIsFullScreen(bool value) { isFullScreen = value; } - Window(); virtual ~Window(); diff --git a/source/shared_lib/include/platform/win32/platform_util.h b/source/shared_lib/include/platform/win32/platform_util.h index fd7557256..d9338f461 100755 --- a/source/shared_lib/include/platform/win32/platform_util.h +++ b/source/shared_lib/include/platform/win32/platform_util.h @@ -17,6 +17,7 @@ #include #include #include +#include #include "types.h" #include "checksum.h" @@ -25,6 +26,7 @@ using std::string; using std::vector; using std::exception; +using std::list; using Shared::Platform::int64; using Shared::Util::Checksum; @@ -78,6 +80,20 @@ private: int64 queryCounter(int multiplier) const; }; +// ===================================================== +// class ModeInfo +// ===================================================== +class ModeInfo { +public: + int width; + int height; + int depth; + + ModeInfo(int width, int height, int depth); + + string getString() const; +}; + // ===================================================== // class PlatformExceptionHandler // ===================================================== @@ -113,6 +129,7 @@ string extractDirectoryPathFromFile(string filename); string extractExtension(const string& filename); void getFullscreenVideoInfo(int &colorBits,int &screenWidth,int &screenHeight); +void getFullscreenVideoModes(list *modeinfos); bool changeVideoMode(int resH, int resW, int colorBits, int refreshFrequency); void restoreVideoMode(bool exitingApp=false); diff --git a/source/shared_lib/include/platform/win32/socket.h b/source/shared_lib/include/platform/win32/socket.h index 5a8fb67bb..40514a9ec 100644 --- a/source/shared_lib/include/platform/win32/socket.h +++ b/source/shared_lib/include/platform/win32/socket.h @@ -15,6 +15,8 @@ #include #include #include +#include +#include "thread.h" using std::string; @@ -54,14 +56,16 @@ private: protected: static SocketManager socketManager; SOCKET sock; + static int broadcast_portno; public: Socket(SOCKET sock); Socket(); - ~Socket(); + virtual ~Socket(); - static bool enableDebugText; - static bool enableNetworkDebugInfo; + static int getBroadCastPort() { return broadcast_portno; } + static void setBroadCastPort(int value) { broadcast_portno = value; } + static std::vector getLocalIPAddressList(); // Int lookup is socket fd while bool result is whether or not that socket was signalled for reading static bool hasDataToRead(std::map &socketTriggeredList); @@ -96,6 +100,27 @@ protected: class ClientSocket: public Socket{ public: void connect(const Ip &ip, int port); + static std::vector discoverServers(); +}; + +class BroadCastSocketThread : public Thread +{ +private: + Mutex mutexRunning; + Mutex mutexQuit; + + bool quit; + bool running; + + void setRunningStatus(bool value); + void setQuitStatus(bool value); + +public: + BroadCastSocketThread(); + virtual void execute(); + void signalQuit(); + bool getQuitStatus(); + bool getRunningStatus(); }; // ===================================================== @@ -105,13 +130,19 @@ public: class ServerSocket: public Socket{ public: + ServerSocket(); + virtual ~ServerSocket(); + void bind(int port); void listen(int connectionQueueSize= SOMAXCONN); Socket *accept(); + void stopBroadCastThread(); protected: - void broadcast_thread(); + BroadCastSocketThread *broadCastThread; + void startBroadCastThread(); + }; }}//end namespace diff --git a/source/shared_lib/sources/platform/posix/socket.cpp b/source/shared_lib/sources/platform/posix/socket.cpp index 227f8a732..aa818ebba 100644 --- a/source/shared_lib/sources/platform/posix/socket.cpp +++ b/source/shared_lib/sources/platform/posix/socket.cpp @@ -87,7 +87,8 @@ std::vector Socket::getLocalIPAddressList() { int ipIdx = 0; while (myhostent->h_addr_list[ipIdx] != 0) { sprintf(myhostaddr, "%s",inet_ntoa(*(struct in_addr *)myhostent->h_addr_list[ipIdx])); - printf("%s\n",myhostaddr); + //printf("%s\n",myhostaddr); + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] myhostaddr = [%s]\n",__FILE__,__FUNCTION__,__LINE__,myhostaddr); if(strlen(myhostaddr) > 0 && strncmp(myhostaddr,"127.",4) != 0) { ipList.push_back(myhostaddr); @@ -1035,7 +1036,10 @@ void BroadCastSocketThread::execute() { try { // Send this machine's host name and address in hostname:n.n.n.n format - sprintf(buff,"%s:%s",myhostname,ipList[0].c_str()); + strcat(buff,myhostname); + for(int idx = 0; idx < ipList.size() ++idx) { + sprintf(buff,"%s:%s",buf,ipList[idx].c_str()); + } time_t elapsed = 0; for( pn = 1; ; pn++ ) diff --git a/source/shared_lib/sources/platform/sdl/gl_wrap.cpp b/source/shared_lib/sources/platform/sdl/gl_wrap.cpp index ca6a1cc8d..c06d23b07 100644 --- a/source/shared_lib/sources/platform/sdl/gl_wrap.cpp +++ b/source/shared_lib/sources/platform/sdl/gl_wrap.cpp @@ -21,6 +21,7 @@ #include "sdl_private.h" #include "noimpl.h" #include "util.h" +#include "window.h" #include "leak_dumper.h" @@ -37,18 +38,18 @@ void PlatformContextGl::init(int colorBits, int depthBits, int stencilBits) { SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); - SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); - SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 1); - SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 1); - SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 1); - SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, stencilBits); - SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, depthBits); + Window::setupGraphicsScreen(depthBits, stencilBits); SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); int flags = SDL_OPENGL; - if(Private::shouldBeFullscreen) + if(Private::shouldBeFullscreen) { flags |= SDL_FULLSCREEN; + Window::setIsFullScreen(true); + } + else { + Window::setIsFullScreen(false); + } int resW = Private::ScreenWidth; int resH = Private::ScreenHeight; diff --git a/source/shared_lib/sources/platform/sdl/window.cpp b/source/shared_lib/sources/platform/sdl/window.cpp index e29293ddb..247044ce6 100644 --- a/source/shared_lib/sources/platform/sdl/window.cpp +++ b/source/shared_lib/sources/platform/sdl/window.cpp @@ -15,9 +15,11 @@ #include "conversion.h" #include "platform_util.h" -#include "leak_dumper.h" #include "sdl_private.h" #include "noimpl.h" +#include "util.h" +#include "SDL_syswm.h" +#include "leak_dumper.h" using namespace Shared::Util; using namespace std; @@ -37,6 +39,7 @@ unsigned int Window::lastMouseEvent = 0; /** for use in mouse hover calculations Vec2i Window::mousePos; MouseState Window::mouseState; bool Window::isKeyPressedDown = false; +bool Window::isFullScreen = false; // ========== PUBLIC ========== @@ -118,6 +121,7 @@ bool Window::handleEvent() { /* handle ALT+Return */ if(event.key.keysym.sym == SDLK_RETURN && (event.key.keysym.mod & (KMOD_LALT | KMOD_RALT))) { + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s %d] SDLK_RETURN pressed.\n",__FILE__,__FUNCTION__,__LINE__); toggleFullscreen(); } if(global_window) { @@ -206,8 +210,124 @@ void Window::destroy() { SDL_PushEvent(&event); } +void Window::setupGraphicsScreen(int depthBits, int stencilBits) { + static int newDepthBits = depthBits; + static int newStencilBits = stencilBits; + if(depthBits >= 0) + newDepthBits = depthBits; + if(stencilBits >= 0) + newStencilBits = stencilBits; + + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 1); + SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 1); + SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 1); + SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, newStencilBits); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, newDepthBits); +} + +static HWND GetSDLWindow() +{ + SDL_SysWMinfo info; + + SDL_VERSION(&info.version); + if (SDL_GetWMInfo(&info) == -1) + return NULL; + return info.window; +} + void Window::toggleFullscreen() { + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__); + + Window::isFullScreen = !Window::isFullScreen; +#ifdef WIN32 + /* -- Portable Fullscreen Toggling -- + As of SDL 1.2.10, if width and height are both 0, SDL_SetVideoMode will use the + width and height of the current video mode (or the desktop mode, if no mode has been set). + Use 0 for Height, Width, and Color Depth to keep the current values. */ + + /* + + //setupGraphicsScreen(); + //SDL_Surface *surface = SDL_GetVideoSurface(); + //int flags = surface->flags ^ SDL_FULLSCREEN; + //int flags = SDL_OPENGL; + //if(Window::isFullScreen) { + // flags |= SDL_FULLSCREEN; + //} + + //SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__); + + //SDL_SetVideoMode(0, 0, 0, flags); + + //SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__); + + SDL_Surface *sf = SDL_GetVideoSurface(); + SDL_Surface **surface = &sf; + uint32 *flags = NULL; + void *pixels = NULL; + SDL_Color *palette = NULL; + SDL_Rect clip; + int ncolors = 0; + Uint32 tmpflags = 0; + int w = 0; + int h = 0; + int bpp = 0; + + if ( (!surface) || (!(*surface)) ) // don't bother if there's no surface. + return; + + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__); + + tmpflags = (*surface)->flags; + w = (*surface)->w; + h = (*surface)->h; + bpp = (*surface)->format->BitsPerPixel; + + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s %d]\n w = %d, h = %d, bpp = %d",__FILE__,__FUNCTION__,__LINE__,w,h,bpp); + + if (flags == NULL) // use the surface's flags. + flags = &tmpflags; + + // + if ( *flags & SDL_FULLSCREEN ) + *flags &= ~SDL_FULLSCREEN; + // + else + *flags |= SDL_FULLSCREEN; + + SDL_GetClipRect(*surface, &clip); + + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__); + + *surface = SDL_SetVideoMode(w, h, bpp, (*flags)); + + if (*surface == NULL) { + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__); + *surface = SDL_SetVideoMode(w, h, bpp, tmpflags); + } // if + + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__); + + SDL_SetClipRect(*surface, &clip); + */ + + HWND handle = GetSDLWindow(); + + if(Window::isFullScreen == true) { + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s %d] Window::isFullScreen == true [%d]\n",__FILE__,__FUNCTION__,__LINE__,handle); + ShowWindow(handle, SW_MAXIMIZE); + } + else { + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s %d] Window::isFullScreen == false [%d]\n",__FILE__,__FUNCTION__,__LINE__,handle); + ShowWindow(handle, SW_RESTORE); + } + +#else SDL_WM_ToggleFullScreen(SDL_GetVideoSurface()); +#endif + + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__); } void Window::handleMouseDown(SDL_Event event) { diff --git a/source/shared_lib/sources/platform/win32/platform_util.cpp b/source/shared_lib/sources/platform/win32/platform_util.cpp index 9ca49c6a9..d90e9ce4d 100644 --- a/source/shared_lib/sources/platform/win32/platform_util.cpp +++ b/source/shared_lib/sources/platform/win32/platform_util.cpp @@ -650,6 +650,48 @@ void getFullscreenVideoInfo(int &colorBits,int &screenWidth,int &screenHeight) { } } +void getFullscreenVideoModes(list *modeinfos) { + // Get the current video hardware information + //const SDL_VideoInfo* vidInfo = SDL_GetVideoInfo(); + //colorBits = vidInfo->vfmt->BitsPerPixel; + //screenWidth = vidInfo->current_w; + //screenHeight = vidInfo->current_h; + + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + + /* Get available fullscreen/hardware modes */ + SDL_Rect**modes = SDL_ListModes(NULL, SDL_FULLSCREEN|SDL_HWSURFACE); + + /* Check if there are any modes available */ + if (modes == (SDL_Rect**)0) { + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] no hardware modes available.\n",__FILE__,__FUNCTION__,__LINE__); + + const SDL_VideoInfo* vidInfo = SDL_GetVideoInfo(); + modeinfos->push_back(ModeInfo(vidInfo->current_w,vidInfo->current_h,vidInfo->vfmt->BitsPerPixel)); + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] adding only current resolution: %d x %d.\n",__FILE__,__FUNCTION__,__LINE__,vidInfo->current_w,vidInfo->current_h); + } + /* Check if our resolution is restricted */ + else if (modes == (SDL_Rect**)-1) { + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] all resolutions available.\n",__FILE__,__FUNCTION__,__LINE__); + + const SDL_VideoInfo* vidInfo = SDL_GetVideoInfo(); + modeinfos->push_back(ModeInfo(vidInfo->current_w,vidInfo->current_h,vidInfo->vfmt->BitsPerPixel)); + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] adding only current resolution: %d x %d.\n",__FILE__,__FUNCTION__,__LINE__,vidInfo->current_w,vidInfo->current_h); + } + else{ + /* Print valid modes */ + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] available Modes are:\n",__FILE__,__FUNCTION__,__LINE__); + + int bestW = -1; + int bestH = -1; + for(int i=0; modes[i]; ++i) { + SystemFlags::OutputDebug(SystemFlags::debugSystem,"%d x %d\n",modes[i]->w, modes[i]->h,modes[i]->x); + modeinfos->push_back(ModeInfo(modes[i]->w,modes[i]->h,modes[i]->x)); + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] adding resolution: %d x %d.\n",__FILE__,__FUNCTION__,__LINE__,modes[i]->w,modes[i]->h); + } + } +} + bool changeVideoMode(int resW, int resH, int colorBits, int ) { Private::shouldBeFullscreen = true; return true; @@ -710,4 +752,18 @@ bool isKeyDown(int virtualKey){ return (GetKeyState(virtualKey) & 0x8000) != 0; } +// ===================================== +// ModeInfo +// ===================================== + +ModeInfo::ModeInfo(int w, int h, int d) { + width=w; + height=h; + depth=d; +} + +string ModeInfo::getString() const{ + return intToStr(width)+"x"+intToStr(height); +} + }}//end namespace diff --git a/source/shared_lib/sources/platform/win32/socket.cpp b/source/shared_lib/sources/platform/win32/socket.cpp index 06c5cccff..d718bad52 100644 --- a/source/shared_lib/sources/platform/win32/socket.cpp +++ b/source/shared_lib/sources/platform/win32/socket.cpp @@ -18,7 +18,7 @@ #include #include #include "util.h" - +#include "platform_util.h" #include "leak_dumper.h" #define socklen_t int @@ -155,6 +155,8 @@ const char* WSAGetLastErrorMessage(const char* pcMessagePrefix, namespace Shared{ namespace Platform{ +int Socket::broadcast_portno = 61357; + // ===================================================== // class Ip // ===================================================== @@ -208,6 +210,32 @@ Socket::SocketManager::~SocketManager(){ SystemFlags::OutputDebug(SystemFlags::debugNetwork,"Winsock cleanup complete.\n"); } +std::vector Socket::getLocalIPAddressList() { + std::vector ipList; + + /* get my host name */ + char myhostname[101]=""; + gethostname(myhostname,100); + + struct hostent* myhostent = gethostbyname(myhostname); + + // get all host IP addresses (Except for loopback) + char myhostaddr[101] = ""; + int ipIdx = 0; + while (myhostent->h_addr_list[ipIdx] != 0) { + sprintf(myhostaddr, "%s",inet_ntoa(*(struct in_addr *)myhostent->h_addr_list[ipIdx])); + //printf("%s\n",myhostaddr); + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] myhostaddr = [%s]\n",__FILE__,__FUNCTION__,__LINE__,myhostaddr); + + if(strlen(myhostaddr) > 0 && strncmp(myhostaddr,"127.",4) != 0) { + ipList.push_back(myhostaddr); + } + ipIdx++; + } + + return ipList; +} + Socket::Socket(SOCKET sock){ this->sock= sock; } @@ -757,9 +785,132 @@ void ClientSocket::connect(const Ip &ip, int port) } } +//======================================================================= +// Function : discovery_response_thread +// in : none +// return : none +// Description: To be forked in its own thread to listen and respond to broadcasts from +// other servers +// +std::vector ClientSocket::discoverServers() { + + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + + std::vector foundServers; + + short port; // The port for the broadcast. + struct sockaddr_in bcSender; // local socket address for the broadcast. + struct sockaddr_in bcaddr; // The broadcast address for the receiver. + int bcfd; // The file descriptor used for the broadcast. + bool one = true; // Parameter for "setscokopt". + char buff[10024]; // Buffers the data to be broadcasted. + socklen_t alen; + int nb; // The number of bytes read. + + port = htons( Socket::getBroadCastPort() ); + + // Prepare to receive the broadcast. + bcfd = socket(AF_INET, SOCK_DGRAM, 0); + if( bcfd <= 0 ) { + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"socket failed: %d\n", WSAGetLastError()); + //exit(-1); + } + else { + // Create the address we are receiving on. + memset( (char*)&bcaddr, 0, sizeof(bcaddr)); + bcaddr.sin_family = AF_INET; + bcaddr.sin_addr.s_addr = htonl(INADDR_ANY); + bcaddr.sin_port = port; + + int val = 1; + setsockopt(bcfd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val)); + + if(bind( bcfd, (struct sockaddr *)&bcaddr, sizeof(bcaddr) ) < 0 ) { + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"bind failed: %d\n", WSAGetLastError()); + } + else { + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + // Keep getting packets forever. + for( time_t elapsed = time(NULL); difftime(time(NULL),elapsed) <= 3; ) + { + alen = sizeof(struct sockaddr); + if( (nb = recvfrom(bcfd, buff, 10024, 0, (struct sockaddr *) &bcSender, &alen)) <= 0 ) + { + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"recvfrom failed: %d\n", WSAGetLastError()); + //exit(-1); + } + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"broadcast message received: [%s] from: [%s]\n", buff,inet_ntoa(bcSender.sin_addr) ); + + vector tokens; + Tokenize(buff,tokens,":"); + for(int idx = 1; idx < tokens.size(); idx++) { + foundServers.push_back(tokens[idx]); + } + break; + } + } + } + + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + + return foundServers; +} + // ===================================================== // class ServerSocket // ===================================================== +ServerSocket::ServerSocket() : Socket() { + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + + broadCastThread = NULL; + + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); +} + +ServerSocket::~ServerSocket() { + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + + stopBroadCastThread(); + + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); +} + +void ServerSocket::stopBroadCastThread() { + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + + if(broadCastThread != NULL) { + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + + broadCastThread->signalQuit(); + + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + + for( time_t elapsed = time(NULL); difftime(time(NULL),elapsed) <= 5; ) { + if(broadCastThread->getRunningStatus() == false) { + break; + } + sleep(100); + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + } + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + + delete broadCastThread; + broadCastThread = NULL; + } + + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); +} + +void ServerSocket::startBroadCastThread() { + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + + stopBroadCastThread(); + + broadCastThread = new BroadCastSocketThread(); + broadCastThread->start(); + + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); +} void ServerSocket::bind(int port){ //sockaddr structure @@ -779,6 +930,8 @@ void ServerSocket::listen(int connectionQueueSize){ if(err==SOCKET_ERROR){ throwException("Error listening socket"); } + broadCastThread = new BroadCastSocketThread(); + broadCastThread->start(); } Socket *ServerSocket::accept(){ @@ -792,4 +945,215 @@ Socket *ServerSocket::accept(){ return new Socket(newSock); } +BroadCastSocketThread::BroadCastSocketThread() { + + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + + setQuitStatus(false); + setRunningStatus(false); + + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); +} + +void BroadCastSocketThread::signalQuit() { + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + + setQuitStatus(true); + + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); +} + +void BroadCastSocketThread::setQuitStatus(bool value) { + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + + mutexQuit.p(); + quit = value; + mutexQuit.v(); + + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); +} + +bool BroadCastSocketThread::getQuitStatus() { + //SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + + bool retval = false; + mutexQuit.p(); + retval = quit; + mutexQuit.v(); + + //SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + + return retval; +} + +bool BroadCastSocketThread::getRunningStatus() { + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + + bool retval = false; + mutexRunning.p(); + retval = running; + mutexRunning.v(); + + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] running = %d\n",__FILE__,__FUNCTION__,__LINE__,retval); + + return retval; +} + +void BroadCastSocketThread::setRunningStatus(bool value) { + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] value = %d\n",__FILE__,__FUNCTION__,__LINE__,value); + + mutexRunning.p(); + running = value; + mutexRunning.v(); + + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] running = %d\n",__FILE__,__FUNCTION__,__LINE__,value); +} + +//======================================================================= +// Function : broadcast_thread +// in : none +// return : none +// Description: To be forked in its own thread to send out a broadcast to the local subnet +// the current broadcast message is +// +void BroadCastSocketThread::execute() { + + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + + unsigned int tbcaddr; // The broadcast address. + short port; // The port for the broadcast. + struct sockaddr_in bcLocal; // local socket address for the broadcast. + struct sockaddr_in bcaddr; // The broadcast address for the receiver. + int bcfd; // The socket used for the broadcast. + bool one = true; // Parameter for "setscokopt". + int pn; // The number of the packet broadcasted. + char buff[1024]; // Buffers the data to be broadcasted. + char myhostname[100]; // hostname of local machine + //char subnetmask[100]; // Subnet mask to broadcast to + struct in_addr myaddr; // My host address in net format + struct hostent* myhostent; + char * ptr; // some transient vars + int len,i; + + /* get my host name */ + gethostname(myhostname,100); + myhostent = gethostbyname(myhostname); + + // get only the first host IP address + std::vector ipList = Socket::getLocalIPAddressList(); + + /* + strcpy(subnetmask, ipList[0].c_str()); + ptr = &subnetmask[0]; + len = strlen(ptr); + + // substitute the address with class C subnet mask x.x.x.255 + for(i=len;i>0;i--) { + if(ptr[i] == '.') { + strcpy(&ptr[i+1],"255"); + break; + } + } + */ + + // Convert the broadcast address from dot notation to a broadcast address. + //if( (tbcaddr = inet_addr( subnetmask )) == INADDR_NONE ) + //{ + // SystemFlags::OutputDebug(SystemFlags::debugNetwork,"Badly formatted BC address: %d\n", WSAGetLastError()); + //exit(-1); + //} + //else + { + port = htons( Socket::getBroadCastPort() ); + + // Create the broadcast socket + memset( &bcLocal, 0, sizeof( struct sockaddr_in)); + bcLocal.sin_family = AF_INET; + bcLocal.sin_addr.s_addr = htonl( INADDR_BROADCAST ); + bcLocal.sin_port = port; // We are letting the OS fill in the port number for the local machine. + bcfd = socket( AF_INET, SOCK_DGRAM, 0 ); + + // If there is an error, report it and terminate. + if( bcfd <= 0 ) { + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"Unable to allocate broadcast socket.: %d\n", WSAGetLastError()); + //exit(-1); + } + // Mark the socket for broadcast. + else if( setsockopt( bcfd, SOL_SOCKET, SO_BROADCAST, (const char *) &one, sizeof( int ) ) < 0 ) { + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"Could not set socket to broadcast.: %d\n", WSAGetLastError()); + //exit(-1); + } + // Bind the address to the broadcast socket. + else { + + //int val = 1; + //setsockopt(bcfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); + + //if(::bind(bcfd, (struct sockaddr *) &bcLocal, sizeof(struct sockaddr_in)) < 0) { + // SystemFlags::OutputDebug(SystemFlags::debugNetwork,"Could not bind address to BC socket.: %d\n", WSAGetLastError()); + //exit(-1); + //} + //else + { + // Record the broadcast address of the receiver. + bcaddr.sin_family = AF_INET; + bcaddr.sin_addr.s_addr = htonl(INADDR_BROADCAST);//tbcaddr; + bcaddr.sin_port = port; + + setRunningStatus(true); + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"Broadcast thread is running\n"); + + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + + try { + // Send this machine's host name and address in hostname:n.n.n.n format + sprintf(buff,"%s",myhostname); + for(int idx = 0; idx < ipList.size(); idx++) { + sprintf(buff,"%s:%s",buff,ipList[idx].c_str()); + } + + time_t elapsed = 0; + for( pn = 1; ; pn++ ) + { + if(difftime(time(NULL),elapsed) >= 1) { + time_t elapsed = time(NULL); + // Broadcast the packet to the subnet + if( sendto( bcfd, buff, sizeof(buff) + 1, 0 , (struct sockaddr *)&bcaddr, sizeof(struct sockaddr_in) ) != sizeof(buff) + 1 ) + { + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"Sendto error: %d\n", WSAGetLastError()); + //exit(-1); + } + else { + //SystemFlags::OutputDebug(SystemFlags::debugNetwork,"Broadcasting to [%s] the message: [%s]\n",subnetmask,buff); + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"Broadcasting on port [%d] the message: [%s]\n",Socket::getBroadCastPort(),buff); + } + + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + } + if(getQuitStatus() == true) { + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + break; + } + sleep( 100 ); // send out broadcast every 1 seconds + } + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + } + catch(const exception &ex) { + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] error [%s]\n",__FILE__,__FUNCTION__,__LINE__,ex.what()); + setRunningStatus(false); + } + catch(...) { + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] unknown error\n",__FILE__,__FUNCTION__,__LINE__); + setRunningStatus(false); + } + + setRunningStatus(false); + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"Broadcast thread is exiting\n"); + } + } + } + + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); +} + }}//end namespace