LINK: Continue simplifying the link init oode

git-svn-id: https://svn.code.sf.net/p/vbam/code/branches/bgk-link@1127 a31d4220-a93d-0410-bf67-fe4944624d44
This commit is contained in:
bgk 2012-09-09 11:01:20 +00:00
parent a1c041a116
commit e0ece3f35b
4 changed files with 296 additions and 387 deletions

View File

@ -148,9 +148,13 @@ int WaitForSingleObject(sem_t *s, int t)
#define UPDATE_REG(address, value) WRITE16LE(((u16 *)&ioMem[address]),value) #define UPDATE_REG(address, value) WRITE16LE(((u16 *)&ioMem[address]),value)
static LinkMode gba_link_mode = LINK_DISCONNECTED; static LinkMode gba_link_mode = LINK_DISCONNECTED;
static ConnectionState gba_connection_state = LINK_OK;
LinkMode GetLinkMode() { LinkMode GetLinkMode() {
return gba_link_mode; if (gba_connection_state == LINK_OK)
return gba_link_mode;
else
return LINK_DISCONNECTED;
} }
int linktime = 0; int linktime = 0;
@ -224,11 +228,6 @@ int gbtime = 1024;
int GetSIOMode(u16, u16); int GetSIOMode(u16, u16);
void LinkClientThread(void *);
void LinkServerThread(void *);
int StartServer(void);
u16 StartRFU(u16); u16 StartRFU(u16);
void StartLink(u16 value) void StartLink(u16 value)
@ -244,7 +243,6 @@ void StartLink(u16 value)
switch (GetSIOMode(value, READ16LE(&ioMem[COMM_RCNT]))) { switch (GetSIOMode(value, READ16LE(&ioMem[COMM_RCNT]))) {
case MULTIPLAYER: { case MULTIPLAYER: {
bool start = (value & 0x80) && !linkid && !transfer && GetLinkMode() != LINK_DISCONNECTED; bool start = (value & 0x80) && !linkid && !transfer && GetLinkMode() != LINK_DISCONNECTED;
u16 si = value & 4;
// clear start, seqno, si (RO on slave, start = pulse on master) // clear start, seqno, si (RO on slave, start = pulse on master)
value &= 0xff4b; value &= 0xff4b;
// get current si. This way, on slaves, it is low during xfer // get current si. This way, on slaves, it is low during xfer
@ -956,13 +954,13 @@ u16 StartRFU(u16 value)
} }
} }
static bool InitIPC() { static ConnectionState InitIPC() {
linkid = 0; linkid = 0;
#if (defined __WIN32__ || defined _WIN32) #if (defined __WIN32__ || defined _WIN32)
if((mmf=CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(LINKDATA), LOCAL_LINK_NAME))==NULL){ if((mmf=CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(LINKDATA), LOCAL_LINK_NAME))==NULL){
systemMessage(0, N_("Error creating file mapping")); systemMessage(0, N_("Error creating file mapping"));
return false; return LINK_ERROR;
} }
if(GetLastError() == ERROR_ALREADY_EXISTS) if(GetLastError() == ERROR_ALREADY_EXISTS)
@ -974,7 +972,7 @@ static bool InitIPC() {
if((linkmem=(LINKDATA *)MapViewOfFile(mmf, FILE_MAP_WRITE, 0, 0, sizeof(LINKDATA)))==NULL){ if((linkmem=(LINKDATA *)MapViewOfFile(mmf, FILE_MAP_WRITE, 0, 0, sizeof(LINKDATA)))==NULL){
CloseHandle(mmf); CloseHandle(mmf);
systemMessage(0, N_("Error mapping file")); systemMessage(0, N_("Error mapping file"));
return false; return LINK_ERROR;
} }
#else #else
if((mmf = shm_open("/" LOCAL_LINK_NAME, O_RDWR|O_CREAT|O_EXCL, 0777)) < 0) { if((mmf = shm_open("/" LOCAL_LINK_NAME, O_RDWR|O_CREAT|O_EXCL, 0777)) < 0) {
@ -1024,7 +1022,7 @@ static bool InitIPC() {
close(mmf); close(mmf);
#endif #endif
systemMessage(0, N_("5 or more GBAs not supported.")); systemMessage(0, N_("5 or more GBAs not supported."));
return false; return LINK_ERROR;
} }
if(vbaid == n) if(vbaid == n)
linkmem->numgbas = n + 1; linkmem->numgbas = n + 1;
@ -1045,7 +1043,7 @@ static bool InitIPC() {
CloseHandle(linksync[j]); CloseHandle(linksync[j]);
} }
systemMessage(0, N_("Error opening event")); systemMessage(0, N_("Error opening event"));
return false; return LINK_ERROR;
} }
#else #else
if((linksync[i] = sem_open(linkevent, if((linksync[i] = sem_open(linkevent,
@ -1063,45 +1061,187 @@ static bool InitIPC() {
} }
} }
systemMessage(0, N_("Error opening event")); systemMessage(0, N_("Error opening event"));
return false; return LINK_ERROR;
} }
#endif #endif
} }
return true; return LINK_OK;
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// Probably from here down needs to be replaced with SFML goodness :) // Probably from here down needs to be replaced with SFML goodness :)
// tjm: what SFML goodness? SFML for network, yes, but not for IPC // tjm: what SFML goodness? SFML for network, yes, but not for IPC
bool InitLink(LinkMode mode) ConnectionState InitLink(LinkMode mode)
{ {
// Do nothing if we are already connected // Do nothing if we are already connected
if (GetLinkMode() != LINK_DISCONNECTED) { if (GetLinkMode() != LINK_DISCONNECTED) {
systemMessage(0, N_("Error, link already connected")); systemMessage(0, N_("Error, link already connected"));
return false; return LINK_ERROR;
} }
bool initOk = true; gba_connection_state = LINK_OK;
if (mode == LINK_GAMECUBE_DOLPHIN) { if (mode == LINK_GAMECUBE_DOLPHIN) {
JoyBusConnect(); JoyBusConnect();
} else if (mode == LINK_CABLE_IPC || mode == LINK_RFU_IPC) { } else if (mode == LINK_CABLE_IPC || mode == LINK_RFU_IPC) {
initOk = InitIPC(); gba_connection_state = InitIPC();
} else if (mode == LINK_CABLE_SOCKET) { } else if (mode == LINK_CABLE_SOCKET) {
for(i=0;i<4;i++) linkid = 0;
for(int i = 0; i < 4; i++)
linkdata[i] = 0xffff; linkdata[i] = 0xffff;
if (lanlink.server) {
lanlink.connectedSlaves = 0;
// should probably use GetPublicAddress()
//sid->ShowServerIP(sf::IPAddress::GetLocalAddress());
// too bad Listen() doesn't take an address as well
// then again, old code used INADDR_ANY anyway
if (!lanlink.tcpsocket.Listen(IP_LINK_PORT))
// Note: old code closed socket & retried once on bind failure
gba_connection_state = LINK_ERROR; // FIXME: error code?
else
gba_connection_state = LINK_NEEDS_UPDATE;
} else {
lc.serverport = IP_LINK_PORT;
if (!lc.serveraddr.IsValid()) {
gba_connection_state = LINK_ERROR;
} else {
lanlink.tcpsocket.SetBlocking(false);
sf::Socket::Status status = lanlink.tcpsocket.Connect(lc.serverport, lc.serveraddr);
if (status == sf::Socket::Error || status == sf::Socket::Disconnected)
gba_connection_state = LINK_ERROR;
else
gba_connection_state = LINK_NEEDS_UPDATE;
}
}
} }
// No errors, save the link mode // No errors, save the link mode
if (initOk) { if (gba_connection_state != LINK_ERROR) {
gba_link_mode = mode; gba_link_mode = mode;
} else { } else {
gba_link_mode = LINK_DISCONNECTED; gba_link_mode = LINK_DISCONNECTED;
} }
return initOk; return gba_connection_state;
}
ConnectionState ConnectLinkUpdate(char * const message, size_t size)
{
message[0] = '\0';
if (gba_connection_state != LINK_NEEDS_UPDATE) {
gba_connection_state = LINK_ERROR;
snprintf(message, size, N_("Link connection does not need updates."));
return LINK_ERROR;
}
if (gba_link_mode == LINK_CABLE_SOCKET && lanlink.server) {
sf::Selector<sf::SocketTCP> fdset;
fdset.Add(lanlink.tcpsocket);
if (fdset.Wait(0.1) == 1) {
int nextSlave = lanlink.connectedSlaves + 1;
sf::Socket::Status st = lanlink.tcpsocket.Accept(ls.tcpsocket[nextSlave]);
if (st == sf::Socket::Error) {
for (int j = 1; j < nextSlave; j++)
ls.tcpsocket[j].Close();
snprintf(message, size, N_("Network error."));
gba_connection_state = LINK_ERROR;
} else {
sf::Packet packet;
packet << static_cast<sf::Uint16>(nextSlave)
<< static_cast<sf::Uint16>(lanlink.numslaves);
ls.tcpsocket[nextSlave].Send(packet);
snprintf(message, size, N_("Player %d connected"), nextSlave);
lanlink.connectedSlaves++;
}
}
if (lanlink.numslaves == lanlink.connectedSlaves) {
lanlink.connected = true;
for (int i = 1; i <= lanlink.numslaves; i++) {
sf::Packet packet;
packet << true;
ls.tcpsocket[i].Send(packet);
}
snprintf(message, size, N_("All players connected"));
gba_connection_state = LINK_OK;
}
} else if (gba_link_mode == LINK_CABLE_SOCKET && !lanlink.server) {
sf::Packet packet;
sf::Socket::Status status = lanlink.tcpsocket.Receive(packet);
if (status == sf::Socket::Error || status == sf::Socket::Disconnected) {
snprintf(message, size, N_("Network error."));
gba_connection_state = LINK_ERROR;
} else if (status == sf::Socket::Done) {
if (linkid == 0) {
sf::Uint16 receivedId, receivedSlaves;
packet >> receivedId >> receivedSlaves;
if (packet) {
linkid = receivedId;
lanlink.numslaves = receivedSlaves;
snprintf(message, size, N_("Connected as #%d, Waiting for %d players to join"),
linkid + 1, lanlink.numslaves - linkid);
}
} else {
bool gameReady;
packet >> gameReady;
if (packet && gameReady) {
lanlink.connected = true;
gba_connection_state = LINK_OK;
snprintf(message, size, N_("All players joined."));
}
}
sf::Selector<sf::SocketTCP> fdset;
fdset.Add(lanlink.tcpsocket);
fdset.Wait(0.1);
}
}
return gba_connection_state;
}
void SetLinkServerHost(const char *host) {
lc.serveraddr = sf::IPAddress(host);
joybusHostAddr = sf::IPAddress(host);
}
void GetLinkServerHost(char * const host, size_t size) {
if (host == NULL || size == 0)
return;
host[0] = '\0';
if (gba_link_mode == LINK_GAMECUBE_DOLPHIN)
strncpy(host, joybusHostAddr.ToString().c_str(), size);
else if (lanlink.server)
strncpy(host, sf::IPAddress::GetLocalAddress().ToString().c_str(), size);
else
strncpy(host, lc.serveraddr.ToString().c_str(), size);
} }
static void ReInitLink() static void ReInitLink()
@ -1120,11 +1260,11 @@ static void ReInitLink()
} }
void CloseLink(void){ void CloseLink(void){
if (GetLinkMode() == LINK_DISCONNECTED) { if (gba_link_mode == LINK_DISCONNECTED) {
return; // Nothing to do return; // Nothing to do
} }
if (GetLinkMode() == LINK_GAMECUBE_DOLPHIN) { if (gba_link_mode == LINK_GAMECUBE_DOLPHIN) {
JoyBusShutdown(); JoyBusShutdown();
} }
@ -1147,45 +1287,48 @@ void CloseLink(void){
} }
} }
} }
int f = linkmem->linkflags;
f &= ~(1 << linkid);
if(f & 0xf) {
linkmem->linkflags = f;
int n = linkmem->numgbas;
for(int i = 0; i < n; i--)
if(f <= (1 << (i + 1)) - 1) {
linkmem->numgbas = i + 1;
break;
}
}
for(i=0;i<4;i++){ if (gba_link_mode == LINK_CABLE_IPC || gba_link_mode == LINK_RFU_IPC) {
if(linksync[i]!=NULL){ int f = linkmem->linkflags;
#if (defined __WIN32__ || defined _WIN32) f &= ~(1 << linkid);
ReleaseSemaphore(linksync[i], 1, NULL); if(f & 0xf) {
CloseHandle(linksync[i]); linkmem->linkflags = f;
#else int n = linkmem->numgbas;
sem_close(linksync[i]); for(int i = 0; i < n; i--)
if(!(f & 0xf)) { if(f <= (1 << (i + 1)) - 1) {
linkevent[sizeof(linkevent)-2]=(char)i+'1'; linkmem->numgbas = i + 1;
sem_unlink(linkevent); break;
} }
#endif
} }
}
#if (defined __WIN32__ || defined _WIN32)
CloseHandle(mmf);
UnmapViewOfFile(linkmem);
// FIXME: move to caller for(i=0;i<4;i++){
// (but there are no callers, so why bother?) if(linksync[i]!=NULL){
//regSetDwordValue("LAN", lanlink.active); #if (defined __WIN32__ || defined _WIN32)
ReleaseSemaphore(linksync[i], 1, NULL);
CloseHandle(linksync[i]);
#else #else
if(!(f & 0xf)) sem_close(linksync[i]);
shm_unlink("/" LOCAL_LINK_NAME); if(!(f & 0xf)) {
munmap(linkmem, sizeof(LINKDATA)); linkevent[sizeof(linkevent)-2]=(char)i+'1';
close(mmf); sem_unlink(linkevent);
}
#endif #endif
}
}
#if (defined __WIN32__ || defined _WIN32)
CloseHandle(mmf);
UnmapViewOfFile(linkmem);
// FIXME: move to caller
// (but there are no callers, so why bother?)
//regSetDwordValue("LAN", lanlink.active);
#else
if(!(f & 0xf))
shm_unlink("/" LOCAL_LINK_NAME);
munmap(linkmem, sizeof(LINKDATA));
close(mmf);
#endif
}
gba_link_mode = LINK_DISCONNECTED; gba_link_mode = LINK_DISCONNECTED;
@ -1215,81 +1358,6 @@ lserver::lserver(void){
oncewait = false; oncewait = false;
} }
bool lserver::Init(ServerInfoDisplay *sid){
// too bad Listen() doesn't take an address as well
// then again, old code used INADDR_ANY anyway
if(!lanlink.tcpsocket.Listen(IP_LINK_PORT))
// Note: old code closed socket & retried once on bind failure
return false; // FIXME: error code?
if(lanlink.thread!=NULL){
lanlink.terminate = true;
WaitForSingleObject(linksync[vbaid], 500);
lanlink.thread = NULL;
}
lanlink.terminate = false;
linkid = 0;
// should probably use GetPublicAddress()
sid->ShowServerIP(sf::IPAddress::GetLocalAddress());
lanlink.thread = new sf::Thread(LinkServerThread, sid);
lanlink.thread->Launch();
return true;
}
void LinkServerThread(void *_sid){
ServerInfoDisplay *sid = (ServerInfoDisplay *)_sid;
sf::Selector<sf::SocketTCP> fdset;
char inbuffer[256], outbuffer[256];
s32 *intinbuffer = (s32*)inbuffer;
u16 *u16inbuffer = (u16*)inbuffer;
s32 *intoutbuffer = (s32*)outbuffer;
u16 *u16outbuffer = (u16*)outbuffer;
i = 0;
while(i<lanlink.numslaves){
fdset.Clear();
fdset.Add(lanlink.tcpsocket);
if(lanlink.terminate){
ReleaseSemaphore(linksync[vbaid], 1, NULL);
goto CloseInfoDisplay;
}
if(fdset.Wait(0.1)==1){
sf::Socket::Status st =
lanlink.tcpsocket.Accept(ls.tcpsocket[i+1]);
if(st == sf::Socket::Error) {
for(int j=1;j<i;j++) ls.tcpsocket[j].Close();
systemMessage(0, N_("Network error."));
lanlink.terminate = true;
} else {
i++;
WRITE16LE(&u16outbuffer[0], i);
WRITE16LE(&u16outbuffer[1], lanlink.numslaves);
ls.tcpsocket[i].Send(outbuffer, 4);
sid->ShowConnect(i);
}
}
sid->Ping();
}
lanlink.connected = true;
sid->Connected();
for(i=1;i<=lanlink.numslaves;i++){
outbuffer[0] = 4;
ls.tcpsocket[i].Send(outbuffer, 4);
}
CloseInfoDisplay:
delete sid;
return;
}
void lserver::Send(void){ void lserver::Send(void){
if(lanlink.type==0){ // TCP if(lanlink.type==0){ // TCP
if(savedlinktime==-1){ if(savedlinktime==-1){
@ -1388,92 +1456,6 @@ lclient::lclient(void){
return; return;
} }
bool lclient::Init(sf::IPAddress addr, ClientInfoDisplay *cid){
serveraddr = addr;
serverport = IP_LINK_PORT;
lanlink.tcpsocket.SetBlocking(false);
if(lanlink.thread!=NULL){
lanlink.terminate = true;
WaitForSingleObject(linksync[vbaid], 500);
lanlink.thread = NULL;
}
cid->ConnectStart(addr);
lanlink.terminate = false;
lanlink.thread = new sf::Thread(LinkClientThread, cid);
lanlink.thread->Launch();
return true;
}
void LinkClientThread(void *_cid){
ClientInfoDisplay *cid = (ClientInfoDisplay *)_cid;
sf::Selector<sf::SocketTCP> fdset;
int numbytes;
char inbuffer[16];
u16 *u16inbuffer = (u16*)inbuffer;
unsigned long block = 0;
while(lanlink.tcpsocket.Connect(lc.serverport, lc.serveraddr) != sf::Socket::Done) {
// stupid SFML has no way of giving what sort of error occurred
// so we'll just have to do a retry loop, I guess.
cid->Ping();
if(lanlink.terminate)
goto CloseInfoDisplay;
// old code had broken sleep on socket, which isn't
// even connected yet
// corrected sleep on socket worked, but this is more sane
// and probably less portable... works with mingw32 at least
#if (defined __WIN32__ || defined _WIN32)
Sleep(100); // in milliseconds
#else
usleep(100000); // in microseconds
#endif
}
numbytes = 0;
size_t got;
while(numbytes<4) {
lanlink.tcpsocket.Receive(inbuffer+numbytes, 4 - numbytes, got);
numbytes += got;
fdset.Clear();
fdset.Add(lanlink.tcpsocket);
fdset.Wait(0.1);
cid->Ping();
if(lanlink.terminate) {
lanlink.tcpsocket.Close();
goto CloseInfoDisplay;
}
}
linkid = (int)READ16LE(&u16inbuffer[0]);
lanlink.numslaves = (int)READ16LE(&u16inbuffer[1]);
cid->ShowConnect(linkid + 1, lanlink.numslaves - linkid);
numbytes = 0;
inbuffer[0] = 1;
while(numbytes<inbuffer[0]) {
lanlink.tcpsocket.Receive(inbuffer+numbytes, inbuffer[0] - got, got);
numbytes += got;
fdset.Clear();
fdset.Add(lanlink.tcpsocket);
fdset.Wait(0.1);
cid->Ping();
if(lanlink.terminate) {
lanlink.tcpsocket.Close();
goto CloseInfoDisplay;
}
}
lanlink.connected = true;
cid->Connected();
CloseInfoDisplay:
delete cid;
return;
}
void lclient::CheckConn(void){ void lclient::CheckConn(void){
size_t nr; size_t nr;
lanlink.tcpsocket.Receive(inbuffer, 1, nr); lanlink.tcpsocket.Receive(inbuffer, 1, nr);

View File

@ -1,8 +1,6 @@
#ifndef GBA_GBALINK_H #ifndef GBA_GBALINK_H
#define GBA_GBALINK_H #define GBA_GBALINK_H
#pragma once
/** /**
* Link modes to be passed to InitLink * Link modes to be passed to InitLink
*/ */
@ -15,13 +13,32 @@ enum LinkMode
LINK_GAMECUBE_DOLPHIN LINK_GAMECUBE_DOLPHIN
}; };
/**
* State of the connection attempt
*/
enum ConnectionState
{
LINK_OK,
LINK_ERROR,
LINK_NEEDS_UPDATE,
LINK_ABORT
};
/** /**
* Initialize GBA linking * Initialize GBA linking
* *
* @param mode Device to emulate, plugged to the GBA link port. * @param mode Device to emulate, plugged to the GBA link port.
* @return success * @return success
*/ */
extern bool InitLink(LinkMode mode); extern ConnectionState InitLink(LinkMode mode);
/**
* Update a link connection request
*
* @param message Information message
* @param size Maximum message size
*/
extern ConnectionState ConnectLinkUpdate(char * const message, size_t size);
/** /**
* Get the currently enabled link mode * Get the currently enabled link mode
@ -30,6 +47,21 @@ extern bool InitLink(LinkMode mode);
*/ */
extern LinkMode GetLinkMode(); extern LinkMode GetLinkMode();
/**
* Set the host to connect to when in socket mode
*/
extern void SetLinkServerHost(const char *host);
/**
* Get the host relevant to context
*
* If in lan server mode, returns the external IP adress
* If in lan client mode, returns the IP adress of the host to connect to
* If in gamecube mode, returns the IP adress of the dolphin host
*
*/
extern void GetLinkServerHost(char * const host, size_t size);
/** /**
* Set the current link mode to LINK_DISCONNECTED * Set the current link mode to LINK_DISCONNECTED
*/ */
@ -87,18 +119,8 @@ extern const char *MakeInstanceFilename(const char *Input);
#ifndef NO_LINK #ifndef NO_LINK
// Link implementation // Link implementation
#include <SFML/System.hpp>
#include <SFML/Network.hpp> #include <SFML/Network.hpp>
class ServerInfoDisplay
{
public:
virtual void ShowServerIP(const sf::IPAddress& addr) = 0;
virtual void ShowConnect(const int player) = 0;
virtual void Ping() = 0;
virtual void Connected() = 0;
};
typedef struct { typedef struct {
u16 linkdata[5]; u16 linkdata[5];
u16 linkcmd; u16 linkcmd;
@ -130,19 +152,10 @@ public:
sf::SocketTCP tcpsocket[4]; sf::SocketTCP tcpsocket[4];
sf::IPAddress udpaddr[4]; sf::IPAddress udpaddr[4];
lserver(void); lserver(void);
bool Init(ServerInfoDisplay *);
void Send(void); void Send(void);
void Recv(void); void Recv(void);
}; };
class ClientInfoDisplay {
public:
virtual void ConnectStart(const sf::IPAddress& addr) = 0;
virtual void Ping() = 0;
virtual void ShowConnect(const int player, const int togo) = 0;
virtual void Connected() = 0;
};
class lclient{ class lclient{
sf::Selector<sf::SocketTCP> fdset; sf::Selector<sf::SocketTCP> fdset;
char inbuffer[256], outbuffer[256]; char inbuffer[256], outbuffer[256];
@ -157,7 +170,6 @@ public:
sf::SocketTCP noblock; sf::SocketTCP noblock;
int numtransfers; int numtransfers;
lclient(void); lclient(void);
bool Init(sf::IPAddress, ClientInfoDisplay *);
void Send(void); void Send(void);
void Recv(void); void Recv(void);
void CheckConn(void); void CheckConn(void);
@ -165,12 +177,10 @@ public:
typedef struct { typedef struct {
sf::SocketTCP tcpsocket; sf::SocketTCP tcpsocket;
//sf::SocketUDP udpsocket;
int numslaves; int numslaves;
sf::Thread *thread; int connectedSlaves;
int type; int type;
bool server; bool server;
bool terminate;
bool connected; bool connected;
bool speed; bool speed;
} LANLINKDATA; } LANLINKDATA;
@ -192,8 +202,6 @@ extern int linkid;
#else #else
// stubs to keep #ifdef's out of mainline // stubs to keep #ifdef's out of mainline
inline void JoyBusConnect() { }
inline void JoyBusShutdown() { }
inline void JoyBusUpdate(int) { } inline void JoyBusUpdate(int) { }
inline bool InitLink() { return true; } inline bool InitLink() { return true; }

View File

@ -689,7 +689,10 @@ void LinkOptions::GetAllData(LinkGeneral *src)
if (newMode != oldMode) { if (newMode != oldMode) {
CloseLink(); CloseLink();
InitLink(newMode); ConnectionState state = InitLink(newMode);
if (state != LINK_OK) {
CloseLink();
}
} }
return; return;

View File

@ -63,6 +63,7 @@ public:
// attached to OK, so skip when OK // attached to OK, so skip when OK
void NetConnect(wxCommandEvent &ev) void NetConnect(wxCommandEvent &ev)
{ {
static const int length = 256;
if(!dlg->Validate() || !dlg->TransferDataFromWindow()) if(!dlg->Validate() || !dlg->TransferDataFromWindow())
return; return;
update_opts(); // save fast flag and client host update_opts(); // save fast flag and client host
@ -70,150 +71,62 @@ public:
// Close any previous link // Close any previous link
CloseLink(); CloseLink();
wxString connmsg, pmsg; wxString connmsg;
wxString title;
wxMutex lock;
wxCondition sig(lock);
lock.Lock();
bool done = false;
if(lanlink.server) { if(lanlink.server) {
lanlink.numslaves = n_players - 1; char host[length];
class sid_t : public ServerInfoDisplay GetLinkServerHost(host, length);
{
wxMutex *lock; lanlink.numslaves = n_players - 1;
wxCondition *sig;
wxString *connmsg, *pmsg; title.Printf(_("Waiting for clients..."));
bool *done; connmsg.Printf(_("Server IP address is: %s\n"), wxString(host, wxConvLibc).c_str());
bool conn[3];
public:
sid_t(wxMutex *m, wxCondition *c, wxString *cm, wxString *pm,
bool *d) :
lock(m), sig(c), connmsg(cm), pmsg(pm), done(d) {}
void ShowServerIP(const sf::IPAddress &addr) {
wxString addr_s(addr.ToString().c_str(), wxConvLibc);
wxString msg;
msg.Printf(_("Server IP address is: %s\n"), addr_s.c_str());
connmsg->append(msg);
conn[0] = conn[1] = conn[2] = false;
}
void ShowConnect(int player) {
wxString msg;
conn[player - 1] = true;
lock->Lock();
pmsg->clear();
for(int i = 0; i < 3; i++)
if(conn[i]) {
msg.Printf(_("Player %d connected\n"), i + 2);
pmsg->append(msg);
}
sig->Signal();
lock->Unlock();
}
void Ping() {
lock->Lock();
sig->Signal();
if(*done)
lanlink.terminate = true;
lock->Unlock();
}
void Connected() {
lock->Lock();
*done = true;
sig->Signal();
lock->Unlock();
}
};
sid_t* sid = new sid_t(&lock, &sig, &connmsg, &pmsg, &done);
if (!ls.Init(sid)) {
wxLogError(_("Error occurred.\nPlease try again."));
lock.Unlock();
delete sid;
return;
}
wxProgressDialog
pdlg(_("Waiting for clients..."), connmsg,
100, dlg, wxPD_APP_MODAL|wxPD_CAN_ABORT|wxPD_ELAPSED_TIME);
while(!done) {
if(!pdlg.Pulse(connmsg + pmsg))
done = true;
sig.Wait();
}
} else { } else {
class cid_t : public ClientInfoDisplay SetLinkServerHost(gopts.link_host.mb_str());
{
wxMutex *lock; title.Printf(_("Waiting for connection..."));
wxCondition *sig; connmsg.Printf(_("Connecting to %s\n"), gopts.link_host.c_str());
wxString *connmsg, *pmsg;
bool *done;
public:
cid_t(wxMutex *m, wxCondition *c, wxString *cm, wxString *pm,
bool *d) :
lock(m), sig(c), connmsg(cm), pmsg(pm), done(d) {}
void ConnectStart(const sf::IPAddress &addr) {
wxString addr_s(addr.ToString().c_str(), wxConvLibc);
connmsg->Printf(_("Connecting to %s\n"), addr_s.c_str());
}
void ShowConnect(int player, int togo) {
wxString msg;
lock->Lock();
pmsg->Printf(_("Connected as #%d\n"), player);
if(togo)
msg.Printf(_("Waiting for %d players to join"), togo);
else
msg = _("All players joined.");
pmsg->append(msg);
sig->Signal();
lock->Unlock();
}
void Ping() {
lock->Lock();
sig->Signal();
if(*done)
lanlink.terminate = true;
lock->Unlock();
}
void Connected() {
lock->Lock();
*done = true;
sig->Signal();
lock->Unlock();
}
};
cid_t* cid = new cid_t(&lock, &sig, &connmsg, &pmsg, &done);
if (!lc.Init(sf::IPAddress(std::string(gopts.link_host.mb_str())), cid)) {
wxLogError(_("Error occurred.\nPlease try again."));
lock.Unlock();
delete cid;
return;
}
wxProgressDialog
pdlg(_("Waiting for connection..."), connmsg,
100, dlg, wxPD_APP_MODAL|wxPD_CAN_ABORT|wxPD_ELAPSED_TIME);
while(!done) {
if(!pdlg.Pulse(connmsg + pmsg))
done = true;
sig.Wait();
}
} }
lock.Unlock();
// Init link
ConnectionState state = InitLink(LINK_CABLE_SOCKET);
// Display a progress dialog while the connection is establishing
if (state == LINK_NEEDS_UPDATE) {
wxProgressDialog pdlg(title, connmsg,
100, dlg, wxPD_APP_MODAL | wxPD_CAN_ABORT | wxPD_ELAPSED_TIME);
while (state == LINK_NEEDS_UPDATE) {
// Ask the core for updates
char message[length];
state = ConnectLinkUpdate(message, length);
connmsg = wxString(message, wxConvLibc);
// Does the user want to abort?
if (!pdlg.Pulse(connmsg)) {
state = LINK_ABORT;
}
}
}
// The user canceled the connection attempt
if (state == LINK_ABORT) {
CloseLink();
}
// Something failed during init
if (state == LINK_ERROR) {
CloseLink();
wxLogError(_("Error occurred.\nPlease try again."));
}
if(lanlink.connected) { if(lanlink.connected) {
pmsg.Replace(wxT("\n"), wxT(" ")); connmsg.Replace(wxT("\n"), wxT(" "));
systemScreenMessage(pmsg); systemScreenMessage(connmsg);
// Init link ev.Skip(); // all OK
InitLink(LINK_CABLE_SOCKET);
ev.Skip(); // all OK
} }
} }
} net_link_handler; } net_link_handler;
@ -3228,7 +3141,10 @@ bool MainFrame::InitMore(void)
} }
} }
InitLink(linkMode); ConnectionState linkState = InitLink(linkMode);
if (linkState != LINK_OK) {
CloseLink();
}
if (GetLinkMode() != LINK_DISCONNECTED) if (GetLinkMode() != LINK_DISCONNECTED)
cmd_enable |= CMDEN_LINK_ANY; cmd_enable |= CMDEN_LINK_ANY;