prevent continuing attempts to send messages from client after it's

deleted the game those messages are part of.  I'm keeping a list of
dead games and checking against that, and currently that list will
grow for as long as the sender thread lives.  Shouldn't be a problem
but needs fixing.  Better would be to remove all messages from queues,
but that has synchronization issues.
This commit is contained in:
Eric House 2012-02-27 07:57:54 -08:00
parent 456dcca7b8
commit f1956ddcb4
2 changed files with 89 additions and 40 deletions

View file

@ -35,6 +35,7 @@ import java.io.DataOutputStream;
import java.io.OutputStream;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.ListIterator;
@ -62,6 +63,7 @@ public class BTService extends Service {
, MESSAGE_NOGAME
, MESSAGE_RESEND
, MESSAGE_FAILOUT
, MESSAGE_DROPPED
};
public interface BTEventListener {
@ -79,6 +81,7 @@ public class BTService extends Service {
private static final int SEND = 3;
private static final int RADIO = 4;
private static final int CLEAR = 5;
private static final int REMOVE = 6;
private static final String CMD_STR = "CMD";
private static final String MSG_STR = "MSG";
@ -110,6 +113,7 @@ public class BTService extends Service {
MESG_ACCPT,
MESG_DECL,
MESG_GAMEGONE,
REMOVE_FOR,
};
private class BTQueueElem {
@ -224,6 +228,13 @@ public class BTService extends Service {
targetName, targetAddr, gameID );
return buf.length;
}
public static void gameDied( Context context, int gameID )
{
Intent intent = getIntentTo( context, REMOVE );
intent.putExtra( GAMEID_STR, gameID );
context.startService( intent );
}
private static Intent getIntentTo( Context context, int cmd )
{
@ -307,6 +318,12 @@ public class BTService extends Service {
stopSelf();
}
break;
case REMOVE:
gameID = intent.getIntExtra( GAMEID_STR, -1 );
if ( -1 != gameID ) {
m_sender.removeFor( gameID );
}
break;
default:
Assert.fail();
}
@ -578,11 +595,13 @@ public class BTService extends Service {
private class BTSenderThread extends Thread {
private LinkedBlockingQueue<BTQueueElem> m_queue;
private HashMap<String,LinkedList<BTQueueElem> > m_resends;
private HashSet<Integer> m_deadGames;
public BTSenderThread()
{
m_queue = new LinkedBlockingQueue<BTQueueElem>();
m_resends = new HashMap<String,LinkedList<BTQueueElem> >();
m_deadGames = new HashSet<Integer>();
}
public void add( BTQueueElem elem )
@ -590,6 +609,13 @@ public class BTService extends Service {
m_queue.add( elem );
}
public void removeFor( int gameID )
{
synchronized( m_deadGames ) {
m_deadGames.add( gameID );
}
}
@Override
public void run()
{
@ -713,44 +739,58 @@ public class BTService extends Service {
private boolean sendMsg( BTQueueElem elem )
{
boolean success = false;
BTEvent evt = BTEvent.MESSAGE_REFUSED;
try {
BluetoothDevice dev = m_adapter.getRemoteDevice( elem.m_addr );
BluetoothSocket socket =
dev.createRfcommSocketToServiceRecord( XWApp.getAppUUID() );
if ( null != socket ) {
DataOutputStream outStream = connect( socket, BTCmd.MESG_SEND );
if ( null != outStream ) {
outStream.writeInt( elem.m_gameID );
boolean success;
synchronized( m_deadGames ) {
success = m_deadGames.contains( elem.m_gameID );
}
BTEvent evt;
if ( success ) {
evt = BTEvent.MESSAGE_DROPPED;
DbgUtils.logf( "dropping message because game %X dead",
elem.m_gameID );
} else {
evt = BTEvent.MESSAGE_REFUSED;
}
if ( !success ) {
try {
BluetoothDevice dev =
m_adapter.getRemoteDevice( elem.m_addr );
BluetoothSocket socket = dev.
createRfcommSocketToServiceRecord( XWApp.getAppUUID() );
if ( null != socket ) {
DataOutputStream outStream =
connect( socket, BTCmd.MESG_SEND );
if ( null != outStream ) {
outStream.writeInt( elem.m_gameID );
short len = (short)elem.m_msg.length;
outStream.writeShort( len );
outStream.write( elem.m_msg, 0, elem.m_msg.length );
short len = (short)elem.m_msg.length;
outStream.writeShort( len );
outStream.write( elem.m_msg, 0, elem.m_msg.length );
outStream.flush();
Thread killer = killSocketIn( socket );
outStream.flush();
Thread killer = killSocketIn( socket );
DataInputStream inStream =
new DataInputStream( socket.getInputStream() );
BTCmd reply = BTCmd.values()[inStream.readByte()];
killer.interrupt();
success = true;
DataInputStream inStream =
new DataInputStream( socket.getInputStream() );
BTCmd reply = BTCmd.values()[inStream.readByte()];
killer.interrupt();
success = true;
switch ( reply ) {
case MESG_ACCPT:
evt = BTEvent.MESSAGE_ACCEPTED;
break;
case MESG_GAMEGONE:
evt = BTEvent.MESSAGE_NOGAME;
break;
switch ( reply ) {
case MESG_ACCPT:
evt = BTEvent.MESSAGE_ACCEPTED;
break;
case MESG_GAMEGONE:
evt = BTEvent.MESSAGE_NOGAME;
break;
}
}
socket.close();
}
socket.close();
} catch ( java.io.IOException ioe ) {
DbgUtils.logf( "sendMsg: ioe: %s", ioe.toString() );
success = false;
}
} catch ( java.io.IOException ioe ) {
DbgUtils.logf( "sendMsg: ioe: %s", ioe.toString() );
success = false;
}
sendResult( evt, elem.m_gameID, 0, elem.m_recipient );

View file

@ -223,7 +223,7 @@ public class GameUtils {
public static void resetGame( Context context, long rowidIn )
{
GameLock lock = new GameLock( rowidIn, true ).lock();
tellRelayDied( context, lock, true );
tellDied( context, lock, true );
resetGame( context, lock, lock, false );
lock.unlock();
}
@ -286,7 +286,7 @@ public class GameUtils {
// does this need to be synchronized?
GameLock lock = new GameLock( rowid, true );
if ( lock.tryLock() ) {
tellRelayDied( context, lock, informNow );
tellDied( context, lock, informNow );
DBUtils.deleteGame( context, lock );
lock.unlock();
}
@ -757,7 +757,7 @@ public class GameUtils {
CommonPrefs cp = CommonPrefs.get( context );
if ( forceNew ) {
tellRelayDied( context, lock, true );
tellDied( context, lock, true );
} else {
byte[] stream = savedGame( context, lock );
// Will fail if there's nothing in the stream but a gi.
@ -814,15 +814,24 @@ public class GameUtils {
return rint;
}
private static void tellRelayDied( Context context, GameLock lock,
boolean informNow )
private static void tellDied( Context context, GameLock lock,
boolean informNow )
{
GameSummary summary = DBUtils.getSummary( context, lock );
if ( null != summary.relayID ) {
DBUtils.addDeceased( context, summary.relayID, summary.seed );
if ( informNow ) {
NetUtils.informOfDeaths( context );
}
tellRelayDied( context, summary, informNow );
}
if ( 0 != summary.gameID ) {
BTService.gameDied( context, summary.gameID );
}
}
private static void tellRelayDied( Context context, GameSummary summary,
boolean informNow )
{
DBUtils.addDeceased( context, summary.relayID, summary.seed );
if ( informNow ) {
NetUtils.informOfDeaths( context );
}
}