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:
parent
a1c041a116
commit
e0ece3f35b
|
@ -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);
|
||||||
|
|
|
@ -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; }
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue