Move transision of cmd and gameid and port (pending) into smsproto

common code, simplifying and unifying what the platform-specific code
has to do. Seems to work.
This commit is contained in:
Eric House 2018-07-20 07:55:07 -07:00
parent a65498c132
commit 9ddc6e4b89
13 changed files with 475 additions and 416 deletions

View file

@ -41,6 +41,8 @@ import org.eehouse.android.xw4.MultiService.MultiEvent;
import org.eehouse.android.xw4.jni.CommsAddrRec;
import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnType;
import org.eehouse.android.xw4.jni.XwJNI;
import org.eehouse.android.xw4.jni.XwJNI.SMSProtoMsg;
import org.eehouse.android.xw4.jni.XwJNI.SMS_CMD;
import org.eehouse.android.xw4.loc.LocUtils;
import java.io.ByteArrayInputStream;
@ -82,10 +84,6 @@ public class SMSService extends XWService {
private static Boolean s_showToasts = null;
// All messages are base64-encoded byte arrays. The first byte is
// always one of these. What follows depends.
private enum SMS_CMD { NONE, INVITE, DATA, DEATH, ACK, };
private BroadcastReceiver m_sentReceiver;
private BroadcastReceiver m_receiveReceiver;
private OnSharedPreferenceChangeListener m_prefsListener;
@ -360,7 +358,7 @@ public class SMSService extends XWService {
break;
case RESEND:
phone = intent.getStringExtra( PHONE );
resendFor( phone, null, false );
resendFor( phone );
}
}
@ -377,98 +375,62 @@ public class SMSService extends XWService {
private void inviteRemote( String phone, String nliData )
{
Log.i( TAG, "inviteRemote()" );
ByteArrayOutputStream bas = new ByteArrayOutputStream( 128 );
DataOutputStream dos = new DataOutputStream( bas );
try {
dos.writeUTF( nliData );
dos.flush();
send( SMS_CMD.INVITE, bas.toByteArray(), phone );
} catch ( java.io.IOException ioe ) {
Log.ex( TAG, ioe );
byte[] asBytes = nliData.getBytes( "UTF-8" );
resendFor( phone, SMS_CMD.INVITE, 0, asBytes, true );
} catch ( java.io.UnsupportedEncodingException uee ) {
Log.ex( TAG, uee );
}
}
private void ackInvite( String phone, int gameID )
{
ByteArrayOutputStream bas = new ByteArrayOutputStream( 128 );
DataOutputStream dos = new DataOutputStream( bas );
try {
dos.writeInt( gameID );
dos.flush();
send( SMS_CMD.ACK, bas.toByteArray(), phone );
} catch ( java.io.IOException ioe ) {
Log.ex( TAG, ioe );
}
resendFor( phone, SMS_CMD.ACK_INVITE, gameID, null );
}
private void sendDiedPacket( String phone, int gameID )
{
if ( !s_sentDied.contains(gameID) ) {
ByteArrayOutputStream bas = new ByteArrayOutputStream( 32 );
DataOutputStream dos = new DataOutputStream( bas );
try {
dos.writeInt( gameID );
dos.flush();
send( SMS_CMD.DEATH, bas.toByteArray(), phone );
s_sentDied.add( gameID );
} catch ( java.io.IOException ioe ) {
Log.ex( TAG, ioe );
}
resendFor( phone, SMS_CMD.DEATH, gameID, null );
}
}
public int sendPacket( String phone, int gameID, byte[] bytes )
{
int nSent = -1;
ByteArrayOutputStream bas = new ByteArrayOutputStream( 128 );
DataOutputStream dos = new DataOutputStream( bas );
try {
dos.writeInt( gameID );
dos.write( bytes, 0, bytes.length );
dos.flush();
send( SMS_CMD.DATA, bas.toByteArray(), phone );
nSent = bytes.length;
} catch ( java.io.IOException ioe ) {
Log.ex( TAG, ioe );
}
return nSent;
resendFor( phone, SMS_CMD.DATA, gameID, bytes );
return bytes.length;
}
private void send( SMS_CMD cmd, byte[] bytes, String phone )
throws java.io.IOException
private void sendOrRetry( byte[][] msgs, String toPhone, int waitSecs )
{
Log.d( TAG, "send(%s, len=%d)", cmd, bytes.length );
ByteArrayOutputStream bas = new ByteArrayOutputStream( 128 );
DataOutputStream dos = new DataOutputStream( bas );
dos.writeByte( SMS_PROTO_VERSION );
if ( SMS_PROTO_VERSION_WITHPORT <= SMS_PROTO_VERSION ) {
dos.writeShort( getNBSPort() );
if ( null != msgs ) {
sendBuffers( msgs, toPhone );
}
dos.writeByte( cmd.ordinal() );
dos.write( bytes, 0, bytes.length );
dos.flush();
byte[] data = bas.toByteArray();
if ( waitSecs > 0 ) {
postResend( toPhone, waitSecs );
}
}
private void resendFor( String toPhone, SMS_CMD cmd, int gameID, byte[] data )
{
boolean newSMSEnabled = XWPrefs.getSMSProtoEnabled( this );
boolean forceNow = !newSMSEnabled; // || cmd == SMS_CMD.INVITE;
resendFor( phone, data, forceNow );
resendFor( toPhone, cmd, gameID, data, forceNow );
}
private void resendFor( String phone, byte[] data, boolean forceNow )
private void resendFor( String toPhone )
{
resendFor( toPhone, SMS_CMD.NONE, 0, null, false );
}
private void resendFor( String toPhone, SMS_CMD cmd, int gameID, byte[] data,
boolean forceNow )
{
int[] waitSecs = { 0 };
byte[][] msgs = XwJNI.smsproto_prepOutbound( data, phone, forceNow, waitSecs );
if ( null != msgs ) {
sendBuffers( msgs, phone );
}
if ( waitSecs[0] > 0 ) {
Assert.assertFalse( forceNow );
postResend( phone, waitSecs[0] );
}
byte[][] msgs = XwJNI.smsproto_prepOutbound( cmd, gameID, data, toPhone,
getNBSPort(), forceNow,
waitSecs );
sendOrRetry( msgs, toPhone, waitSecs[0] );
}
private void postResend( final String phone, final int waitSecs )
@ -492,51 +454,38 @@ public class SMSService extends XWService {
} ).start();
}
private void receive( SMS_CMD cmd, byte[] data, String phone )
private void receive( SMSProtoMsg msg, String phone )
{
Log.i( TAG, "receive(cmd=%s)", cmd.toString() );
DataInputStream dis =
new DataInputStream( new ByteArrayInputStream(data) );
try {
switch( cmd ) {
case INVITE:
String nliData = dis.readUTF();
makeForInvite( phone, new NetLaunchInfo( this, nliData ) );
break;
case DATA:
int gameID = dis.readInt();
byte[] rest = new byte[dis.available()];
dis.readFully( rest );
if ( feedMessage( gameID, rest, new CommsAddrRec( phone ) ) ) {
SMSResendReceiver.resetTimer( this );
}
break;
case DEATH:
gameID = dis.readInt();
postEvent( MultiEvent.MESSAGE_NOGAME, gameID );
break;
case ACK:
gameID = dis.readInt();
postEvent( MultiEvent.NEWGAME_SUCCESS,
gameID );
break;
default:
Log.w( TAG, "unexpected cmd %s", cmd.toString() );
break;
Log.i( TAG, "receive(cmd=%s)", msg.cmd );
switch( msg.cmd ) {
case INVITE:
NetLaunchInfo nli = new NetLaunchInfo( this, new String(msg.data) );
makeForInvite( phone, nli );
break;
case DATA:
if ( feedMessage( msg.gameID, msg.data, new CommsAddrRec( phone ) ) ) {
SMSResendReceiver.resetTimer( this );
}
} catch ( java.io.IOException ioe ) {
Log.ex( TAG, ioe );
break;
case DEATH:
postEvent( MultiEvent.MESSAGE_NOGAME, msg.gameID );
break;
case ACK_INVITE:
postEvent( MultiEvent.NEWGAME_SUCCESS, msg.gameID );
break;
default:
Log.w( TAG, "unexpected cmd %s", msg.cmd );
Assert.assertFalse( BuildConfig.DEBUG );
break;
}
}
private void receiveBuffer( byte[] buffer, String senderPhone )
{
byte[][] msgs = XwJNI.smsproto_prepInbound( buffer, senderPhone );
SMSProtoMsg[] msgs = XwJNI.smsproto_prepInbound( buffer, senderPhone );
if ( null != msgs ) {
for ( byte[] msg : msgs ) {
if ( !disAssemble( senderPhone, msg ) ) {
Log.e( TAG, "failed on message from %s", senderPhone );
}
for ( SMSProtoMsg msg : msgs ) {
receive( msg, senderPhone );
}
postEvent( MultiEvent.SMS_RECEIVE_OK );
} else {
@ -545,44 +494,6 @@ public class SMSService extends XWService {
}
}
private boolean disAssemble( String senderPhone, byte[] fullMsg )
{
boolean success = false;
DataInputStream dis =
new DataInputStream( new ByteArrayInputStream(fullMsg) );
try {
byte proto = dis.readByte();
short myPort = getNBSPort();
short gotPort;
if ( SMS_PROTO_VERSION_WITHPORT > proto ) {
gotPort = myPort;
} else {
gotPort = dis.readShort();
}
if ( SMS_PROTO_VERSION < proto ) {
Log.w( TAG, "SMSService.disAssemble: bad proto %d from %s;"
+ " dropping", proto, senderPhone );
postEvent( MultiEvent.BAD_PROTO_SMS, senderPhone );
} else if ( gotPort != myPort ) {
Log.d( TAG, "disAssemble(): received on port %d"
+ " but expected %d", gotPort, myPort );
} else {
SMS_CMD cmd = SMS_CMD.values()[dis.readByte()];
byte[] rest = new byte[dis.available()];
dis.readFully( rest );
receive( cmd, rest, senderPhone );
success = true;
}
} catch ( java.io.IOException ioe ) {
Log.ex( TAG, ioe );
} catch ( ArrayIndexOutOfBoundsException oob ) {
// enum this older code doesn't know about, or just another app's
// message; drop it
Log.w( TAG, "disAssemble: dropping message with too-new enum" );
}
return success;
}
@Override
protected void postNotification( String phone, int gameID, long rowid )
{

View file

@ -403,15 +403,22 @@ public class XwJNI {
public static native boolean comms_getAddrDisabled( GamePtr gamePtr, CommsConnType typ,
boolean send );
public static byte[][] smsproto_prepOutbound( byte[] buf, String phone, boolean forceNow,
/*out*/ int[] waitSecs )
{
int nowSeconds = (int)(System.currentTimeMillis() / 1000);
return smsproto_prepOutbound( getJNI().m_ptr, buf, phone, nowSeconds,
forceNow, waitSecs );
public enum SMS_CMD { NONE, INVITE, DATA, DEATH, ACK_INVITE, };
public static class SMSProtoMsg {
public SMS_CMD cmd;
public int gameID;
public byte[] data; // other cases
}
public static byte[][] smsproto_prepInbound( byte[] data, String fromPhone )
public static byte[][]
smsproto_prepOutbound( SMS_CMD cmd, int gameID, byte[] buf, String phone,
int port, boolean forceNow, /*out*/ int[] waitSecs )
{
return smsproto_prepOutbound( getJNI().m_ptr, cmd, gameID, buf, phone,
port, forceNow, waitSecs );
}
public static SMSProtoMsg[] smsproto_prepInbound( byte[] data, String fromPhone )
{
return smsproto_prepInbound( getJNI().m_ptr, data, fromPhone );
}
@ -502,13 +509,14 @@ public class XwJNI {
private static native int dict_iter_init( int jniState, byte[] dict,
String name, String path );
private static native byte[][] smsproto_prepOutbound( int jniState, byte[] buf,
String phone, int nowSeconds,
boolean forceNow,
/*out*/int[] waitSecs );
private static native byte[][]
smsproto_prepOutbound( int jniState, SMS_CMD cmd, int gameID, byte[] buf,
String phone, int port, boolean forceNow,
/*out*/int[] waitSecs );
private static native byte[][] smsproto_prepInbound( int jniState, byte[] data,
String fromPhone );
private static native SMSProtoMsg[] smsproto_prepInbound( int jniState,
byte[] data,
String fromPhone );
private static native boolean haveEnv( int jniState );
}

View file

@ -772,10 +772,11 @@ Java_org_eehouse_android_xw4_jni_XwJNI_dict_1getTileValue
static jobjectArray
msgArrayToByteArrays( JNIEnv* env, const SMSMsgArray* arr )
{
XP_ASSERT( arr->format == FORMAT_NET );
jclass clas = (*env)->FindClass( env, "[B" );
jobjectArray result = (*env)->NewObjectArray( env, arr->nMsgs, clas, NULL );
for ( int ii = 0; ii < arr->nMsgs; ++ii ) {
SMSMsg* msg = &arr->msgs[ii];
SMSMsgNet* msg = &arr->u.msgsNet[ii];
jbyteArray arr = makeByteArray( env, msg->len, (const jbyte*)msg->data );
(*env)->SetObjectArrayElement( env, result, ii, arr );
deleteLocalRef( env, arr );
@ -783,15 +784,43 @@ msgArrayToByteArrays( JNIEnv* env, const SMSMsgArray* arr )
return result;
}
static jobjectArray
msgArrayToJMsgArray( JNIEnv* env, const SMSMsgArray* arr )
{
XP_ASSERT( arr->format == FORMAT_LOC );
jclass clas = (*env)->FindClass( env, PKG_PATH("jni/XwJNI$SMSProtoMsg") );
jobjectArray result = (*env)->NewObjectArray( env, arr->nMsgs, clas, NULL );
jmethodID initId = (*env)->GetMethodID( env, clas, "<init>", "()V" );
for ( int ii = 0; ii < arr->nMsgs; ++ii ) {
jobject jmsg = (*env)->NewObject( env, clas, initId );
const SMSMsgLoc* msgsLoc = &arr->u.msgsLoc[ii];
intToJenumField( env, jmsg, msgsLoc->cmd, "cmd", PKG_PATH("jni/XwJNI$SMS_CMD") );
setInt( env, jmsg, "gameID", msgsLoc->gameID );
jbyteArray arr = makeByteArray( env, msgsLoc->len,
(const jbyte*)msgsLoc->data );
setObject( env, jmsg, "data", "[B", arr );
deleteLocalRef( env, arr );
(*env)->SetObjectArrayElement( env, result, ii, jmsg );
deleteLocalRef( env, jmsg );
}
return result;
}
JNIEXPORT jobjectArray JNICALL
Java_org_eehouse_android_xw4_jni_XwJNI_smsproto_1prepOutbound
( JNIEnv* env, jclass C, jint jniGlobalPtr, jbyteArray jData,
jstring jToPhone, jint jNow, jboolean jForce, jintArray jWaitSecsArr )
( JNIEnv* env, jclass C, jint jniGlobalPtr, jobject jCmd, jint jGameID,
jbyteArray jData, jstring jToPhone, jint jPort, jboolean jForce,
jintArray jWaitSecsArr )
{
jobjectArray result = NULL;
JNIGlobalState* globalState = (JNIGlobalState*)jniGlobalPtr;
map_thread( &globalState->ti, env );
SMS_CMD cmd = jEnumToInt( env, jCmd );
jbyte* data = NULL;
int len = 0;
if ( NULL != jData ) {
@ -801,8 +830,9 @@ Java_org_eehouse_android_xw4_jni_XwJNI_smsproto_1prepOutbound
const char* toPhone = (*env)->GetStringUTFChars( env, jToPhone, NULL );
XP_U16 waitSecs;
SMSMsgArray* arr = smsproto_prepOutbound( globalState->smsProto, (const XP_U8*)data,
len, toPhone, jForce, &waitSecs );
SMSMsgArray* arr = smsproto_prepOutbound( globalState->smsProto, cmd, jGameID,
(const XP_U8*)data, len,
toPhone, jPort, jForce, &waitSecs );
if ( !!arr ) {
result = msgArrayToByteArrays( env, arr );
smsproto_freeMsgArray( globalState->smsProto, arr );
@ -820,14 +850,14 @@ Java_org_eehouse_android_xw4_jni_XwJNI_smsproto_1prepOutbound
JNIEXPORT jobjectArray JNICALL
Java_org_eehouse_android_xw4_jni_XwJNI_smsproto_1prepInbound
( JNIEnv* env, jclass C, jint jniGlobalPtr, jbyteArray jData,
jstring jFromPhone )
( JNIEnv* env, jclass C, jint jniGlobalPtr, jbyteArray jData, jstring jFromPhone )
{
jobjectArray result = NULL;
JNIGlobalState* globalState = (JNIGlobalState*)jniGlobalPtr;
map_thread( &globalState->ti, env );
if ( !!jData ) {
JNIGlobalState* globalState = (JNIGlobalState*)jniGlobalPtr;
map_thread( &globalState->ti, env );
int len = (*env)->GetArrayLength( env, jData );
jbyte* data = (*env)->GetByteArrayElements( env, jData, NULL );
const char* fromPhone = (*env)->GetStringUTFChars( env, jFromPhone, NULL );
@ -835,7 +865,7 @@ Java_org_eehouse_android_xw4_jni_XwJNI_smsproto_1prepInbound
SMSMsgArray* arr = smsproto_prepInbound( globalState->smsProto, fromPhone,
(XP_U8*)data, len );
if ( !!arr ) {
result = msgArrayToByteArrays( env, arr );
result = msgArrayToJMsgArray( env, arr );
smsproto_freeMsgArray( globalState->smsProto, arr );
}

View file

@ -3,24 +3,31 @@
set -e -u
NODE=xw4
VARIANT=xw4
CLASSPATH=${CLASSPATH:-""}
usage() {
[ $# -gt 0 ] && echo "Error: $1"
echo "usage: $0 "
echo "usage: $0 [--variant xw4|xw4d]"
exit 1
}
while [ $# -gt 0 ]; do
case $1 in
--help) usage
;;
*) usage "unexpected flag $1"
;;
--help)
usage
;;
--variant)
VARIANT=$2
shift
;;
*)
usage "unexpected flag $1"
;;
esac
shift
done
cd $(dirname $0)/../app/build/intermediates/classes/${NODE}/debug
cd $(dirname $0)/../app/build/intermediates/classes/${VARIANT}/debug
javah -o /tmp/javah$$.txt org.eehouse.android.${NODE}.jni.XwJNI
javap -s org.eehouse.android.${NODE}.jni.XwJNI

View file

@ -77,6 +77,7 @@ void nli_makeAddrRec( const NetLaunchInfo* invit, CommsAddrRec* addr );
void nli_setDevID( NetLaunchInfo* invit, XP_U32 devID );
void nli_setInviteID( NetLaunchInfo* invit, const XP_UCHAR* inviteID );
void nli_setGameName( NetLaunchInfo* invit, const XP_UCHAR* gameName );
#endif

View file

@ -38,7 +38,7 @@
typedef struct _MsgRec {
XP_U32 createSeconds;
SMSMsg msg;
SMSMsgNet msgNet;
} MsgRec;
typedef struct _ToPhoneRec {
@ -82,11 +82,13 @@ struct SMSProto {
#define KEY_NEXTID PERSIST_KEY("nextID")
static int nextMsgID( SMSProto* state );
static SMSMsgArray* toMsgs( SMSProto* state, ToPhoneRec* rec, XP_Bool forceOld );
static XWStreamCtxt* mkStream( SMSProto* state );
static SMSMsgArray* toNetMsgs( SMSProto* state, ToPhoneRec* rec, XP_Bool forceOld );
static ToPhoneRec* getForPhone( SMSProto* state, const XP_UCHAR* phone,
XP_Bool create );
static void addToRec( SMSProto* state, ToPhoneRec* rec, const XP_U8* buf,
XP_U16 buflen, XP_U32 nowSeconds );
static void addToOutRec( SMSProto* state, ToPhoneRec* rec, SMS_CMD cmd,
XP_U32 gameID, const XP_U8* buf, XP_U16 buflen,
XP_U32 nowSeconds );
static void addMessage( SMSProto* state, const XP_UCHAR* fromPhone, int msgID,
int indx, int count, const XP_U8* data, XP_U16 len );
static SMSMsgArray* completeMsgs( SMSProto* state, SMSMsgArray* arr,
@ -149,6 +151,43 @@ smsproto_free( SMSProto* state )
}
}
static void
headerToStream( XWStreamCtxt* stream, SMS_CMD cmd, XP_U32 gameID )
{
// XP_LOGF( "%s(cmd: %d; gameID: %d)", __func__, cmd, gameID );
stream_putU8( stream, cmd );
switch ( cmd ) {
case NONE:
XP_ASSERT(0);
break;
case INVITE:
break;
default:
stream_putU32( stream, gameID );
}
}
static XP_Bool
headerFromStream( XWStreamCtxt* stream, SMS_CMD* cmd, XP_U32* gameID )
{
XP_Bool success = XP_FALSE;
XP_U8 tmp;
if ( stream_gotU8( stream, &tmp ) ) {
*cmd = tmp;
switch( *cmd ) {
case INVITE:
success = XP_TRUE;
break;
default:
success = stream_gotU32( stream, gameID );
break;
}
}
// XP_LOGF( "%s() => cmd: %d; gameID: %d", __func__, *cmd, *gameID );
return success;
}
/* Maintain a list of pending messages per phone number. When called and it's
* been at least some amount of time since we last added something, or at
* least some longer time since the oldest message was added, return an array
@ -159,26 +198,27 @@ smsproto_free( SMSProto* state )
* UtilCtxt around.
*/
SMSMsgArray*
smsproto_prepOutbound( SMSProto* state, const XP_U8* buf,
XP_U16 buflen, const XP_UCHAR* toPhone,
XP_Bool forceOld, XP_U16* waitSecsP )
smsproto_prepOutbound( SMSProto* state, SMS_CMD cmd, XP_U32 gameID,
const void* buf, XP_U16 buflen, const XP_UCHAR* toPhone,
int toPort, XP_Bool forceOld, XP_U16* waitSecsP )
{
XP_USE( toPort );
SMSMsgArray* result = NULL;
#ifdef DEBUG
XP_UCHAR* checksum = dutil_md5sum( state->dutil, buf, buflen );
XP_LOGF( "%s(): len=%d, sum=%s, toPhone=%s", __func__, buflen,
checksum, toPhone );
XP_LOGF( "%s(cmd=%d, gameID=%d): len=%d, sum=%s, toPhone=%s", __func__, cmd,
gameID, buflen, checksum, toPhone );
XP_FREEP( state->mpool, &checksum );
#endif
checkThread( state );
ToPhoneRec* rec = getForPhone( state, toPhone, !!buf );
ToPhoneRec* rec = getForPhone( state, toPhone, cmd != NONE );
/* First, add the new message (if present) to the array */
XP_U32 nowSeconds = dutil_getCurSeconds( state->dutil );
if ( !!buf ) {
addToRec( state, rec, buf, buflen, nowSeconds );
if ( cmd != NONE ) {
addToOutRec( state, rec, cmd, gameID, buf, buflen, nowSeconds );
}
/* rec will be non-null if there's something in it */
@ -191,7 +231,7 @@ smsproto_prepOutbound( SMSProto* state, const XP_U8* buf,
}
if ( doSend ) {
result = toMsgs( state, rec, forceOld );
result = toNetMsgs( state, rec, forceOld );
freeForPhone( state, toPhone );
}
@ -207,15 +247,34 @@ smsproto_prepOutbound( SMSProto* state, const XP_U8* buf,
}
static SMSMsgArray*
appendMsg( SMSProto* state, SMSMsgArray* arr, SMSMsg* msg )
appendLocMsg( SMSProto* state, SMSMsgArray* arr, SMSMsgLoc* msg )
{
if ( NULL == arr ) {
arr = XP_CALLOC( state->mpool, sizeof(*arr) );
arr->format = FORMAT_LOC;
} else {
XP_ASSERT( arr->format == FORMAT_LOC );
}
arr->msgs = XP_REALLOC( state->mpool, arr->msgs,
(arr->nMsgs + 1) * sizeof(*arr->msgs) );
arr->msgs[arr->nMsgs++] = *msg;
arr->u.msgsLoc = XP_REALLOC( state->mpool, arr->u.msgsLoc,
(arr->nMsgs + 1) * sizeof(*arr->u.msgsLoc) );
arr->u.msgsLoc[arr->nMsgs++] = *msg;
return arr;
}
static SMSMsgArray*
appendNetMsg( SMSProto* state, SMSMsgArray* arr, SMSMsgNet* msg )
{
if ( NULL == arr ) {
arr = XP_CALLOC( state->mpool, sizeof(*arr) );
arr->format = FORMAT_NET;
} else {
XP_ASSERT( arr->format == FORMAT_NET );
}
arr->u.msgsNet = XP_REALLOC( state->mpool, arr->u.msgsNet,
(arr->nMsgs + 1) * sizeof(*arr->u.msgsNet) );
arr->u.msgsNet[arr->nMsgs++] = *msg;
return arr;
}
@ -226,8 +285,7 @@ smsproto_prepInbound( SMSProto* state, const XP_UCHAR* fromPhone,
XP_LOGF( "%s(): len=%d, fromPhone=%s", __func__, len, fromPhone );
checkThread( state );
XWStreamCtxt* stream = mem_stream_make_raw( MPPARM(state->mpool)
dutil_getVTManager(state->dutil) );
XWStreamCtxt* stream = mkStream( state );
stream_putBytes( stream, data, len );
SMSMsgArray* result = NULL;
@ -253,20 +311,34 @@ smsproto_prepInbound( SMSProto* state, const XP_UCHAR* fromPhone,
XP_U8 oneLen, msgID;
while ( stream_gotU8( stream, &oneLen )
&& stream_gotU8( stream, &msgID ) ) {
XP_U8 buf[oneLen];
if ( stream_gotBytes( stream, buf, oneLen ) ) {
SMSMsg msg = { .len = oneLen,
.msgID = msgID,
.data = XP_MALLOC( state->mpool, oneLen ),
};
XP_MEMCPY( msg.data, buf, oneLen );
result = appendMsg( state, result, &msg );
XP_U8 tmp[oneLen];
stream_getBytes( stream, tmp, oneLen );
XWStreamCtxt* msgStream = mkStream( state );
stream_putBytes( msgStream, tmp, oneLen );
XP_U32 gameID;
SMS_CMD cmd;
if ( headerFromStream( msgStream, &cmd, &gameID ) ) {
XP_U16 msgLen = stream_getSize( msgStream );
XP_U8 buf[msgLen];
if ( stream_gotBytes( msgStream, buf, msgLen ) ) {
SMSMsgLoc msg = { .len = msgLen,
.cmd = cmd,
.gameID = gameID,
.data = XP_MALLOC( state->mpool, msgLen ),
};
XP_MEMCPY( msg.data, buf, msgLen );
result = appendLocMsg( state, result, &msg );
}
}
stream_destroy( msgStream );
}
}
break;
default:
XP_LOGF( "%s(): unexpected proto %d", __func__, proto );
XP_ASSERT( 0 );
break;
}
}
@ -283,17 +355,31 @@ smsproto_freeMsgArray( SMSProto* state, SMSMsgArray* arr )
checkThread( state );
for ( int ii = 0; ii < arr->nMsgs; ++ii ) {
XP_FREEP( state->mpool, &arr->msgs[ii].data );
XP_U8** ptr = arr->format == FORMAT_LOC
? &arr->u.msgsLoc[ii].data : &arr->u.msgsNet[ii].data;
XP_FREEP( state->mpool, ptr );
}
XP_FREEP( state->mpool, &arr->msgs );
void** ptr;
switch( arr->format ) {
case FORMAT_LOC:
ptr = (void**)&arr->u.msgsLoc;
break;
case FORMAT_NET:
ptr = (void**)&arr->u.msgsNet;
break;
default:
XP_ASSERT(0);
ptr = NULL;
}
XP_FREEP( state->mpool, ptr );
XP_FREEP( state->mpool, &arr );
}
static void
freeMsg( SMSProto* state, MsgRec** msgp )
{
XP_FREEP( state->mpool, &(*msgp)->msg.data );
XP_FREEP( state->mpool, &(*msgp)->msgNet.data );
XP_FREEP( state->mpool, msgp );
}
@ -353,20 +439,28 @@ freeForPhone( SMSProto* state, const XP_UCHAR* phone )
}
static void
addToRec( SMSProto* state, ToPhoneRec* rec, const XP_U8* buf, XP_U16 buflen,
XP_U32 nowSeconds )
addToOutRec( SMSProto* state, ToPhoneRec* rec, SMS_CMD cmd,
XP_U32 gameID, const XP_U8* buf, XP_U16 buflen,
XP_U32 nowSeconds )
{
XWStreamCtxt* stream = mkStream( state );
headerToStream( stream, cmd, gameID );
stream_putBytes( stream, buf, buflen );
MsgRec* mRec = XP_CALLOC( state->mpool, sizeof(*rec) );
mRec->msg.len = buflen;
mRec->msg.data = XP_MALLOC( state->mpool, buflen );
XP_MEMCPY( mRec->msg.data, buf, buflen );
XP_U16 len = stream_getSize( stream );
mRec->msgNet.len = len;
mRec->msgNet.data = XP_MALLOC( state->mpool, len );
XP_MEMCPY( mRec->msgNet.data, stream_getPtr(stream), len );
stream_destroy( stream );
mRec->createSeconds = nowSeconds;
rec->msgs = XP_REALLOC( state->mpool, rec->msgs, (1 + rec->nMsgs) * sizeof(*rec->msgs) );
rec->msgs[rec->nMsgs++] = mRec;
rec->totalSize += buflen;
rec->totalSize += len;
XP_LOGF( "%s(): added msg to %s of len %d; total now %d", __func__, rec->phone,
buflen, rec->totalSize );
len, rec->totalSize );
if ( rec->nMsgs == 1 ) {
rec->createSeconds = nowSeconds;
@ -513,9 +607,7 @@ savePartials( SMSProto* state )
{
checkThread( state );
XWStreamCtxt* stream
= mem_stream_make_raw( MPPARM(state->mpool)
dutil_getVTManager(state->dutil) );
XWStreamCtxt* stream = mkStream( state );
stream_putU8( stream, PARTIALS_FORMAT );
stream_putU8( stream, state->nFromPhones );
@ -553,8 +645,8 @@ savePartials( SMSProto* state )
static void
restorePartials( SMSProto* state )
{
XWStreamCtxt* stream = mem_stream_make_raw( MPPARM(state->mpool)
dutil_getVTManager(state->dutil) );
XWStreamCtxt* stream = mkStream( state );
dutil_loadStream( state->dutil, KEY_PARTIALS, stream );
if ( stream_getSize( stream ) >= 1
&& PARTIALS_FORMAT == stream_getU8( stream ) ) {
@ -607,16 +699,24 @@ completeMsgs( SMSProto* state, SMSMsgArray* arr, const XP_UCHAR* fromPhone,
}
if ( haveAll ) {
SMSMsg msg = { .len = len,
.msgID = msgID,
.data = XP_MALLOC( state->mpool, len ),
};
XP_U8* ptr = msg.data;
XWStreamCtxt* stream = mkStream( state );
for ( int ii = 0; ii < rec->count; ++ii ) {
XP_MEMCPY( ptr, rec->parts[ii].data, rec->parts[ii].len );
ptr += rec->parts[ii].len;
stream_putBytes( stream, rec->parts[ii].data, rec->parts[ii].len );
}
arr = appendMsg( state, arr, &msg );
XP_U32 gameID;
SMS_CMD cmd;
if ( headerFromStream( stream, &cmd, &gameID ) ) {
XP_U16 len = stream_getSize( stream );
SMSMsgLoc msg = { .len = len,
.cmd = cmd,
.gameID = gameID,
.data = XP_MALLOC( state->mpool, len ),
};
stream_getBytes( stream, msg.data, len );
arr = appendLocMsg( state, arr, &msg );
}
stream_destroy( stream );
freeMsgIDRec( state, rec, fromPhoneIndex, msgIDIndex );
}
@ -625,13 +725,13 @@ completeMsgs( SMSProto* state, SMSMsgArray* arr, const XP_UCHAR* fromPhone,
}
static SMSMsgArray*
toMsgs( SMSProto* state, ToPhoneRec* rec, XP_Bool forceOld )
toNetMsgs( SMSProto* state, ToPhoneRec* rec, XP_Bool forceOld )
{
SMSMsgArray* result = NULL;
for ( XP_U16 ii = 0; ii < rec->nMsgs; ) {
// XP_LOGF( "%s(): looking at msg %d of %d", __func__, ii, rec->nMsgs );
XP_U16 count = (rec->msgs[ii]->msg.len + (MAX_LEN_BINARY-1)) / MAX_LEN_BINARY;
XP_U16 count = (rec->msgs[ii]->msgNet.len + (MAX_LEN_BINARY-1)) / MAX_LEN_BINARY;
/* First, see if this message and some number of its neighbors can be
combined */
@ -639,7 +739,7 @@ toMsgs( SMSProto* state, ToPhoneRec* rec, XP_Bool forceOld )
int sum = 0;
if ( count == 1 && !forceOld ) {
for ( ; last < rec->nMsgs; ++last ) {
int nextLen = rec->msgs[last]->msg.len;
int nextLen = rec->msgs[last]->msgNet.len;
if ( sum + nextLen > MAX_LEN_BINARY ) {
break;
}
@ -654,23 +754,23 @@ toMsgs( SMSProto* state, ToPhoneRec* rec, XP_Bool forceOld )
last - 1, nMsgs );
}
int len = 1 + sum + (nMsgs * 2); /* 1: len & msgID */
SMSMsg newMsg = { .len = len,
.data = XP_MALLOC( state->mpool, len )
SMSMsgNet newMsg = { .len = len,
.data = XP_MALLOC( state->mpool, len )
};
int indx = 0;
newMsg.data[indx++] = SMS_PROTO_VERSION_COMBO;
for ( int jj = ii; jj < last; ++jj ) {
const SMSMsg* msg = &rec->msgs[jj]->msg;
const SMSMsgNet* msg = &rec->msgs[jj]->msgNet;
newMsg.data[indx++] = msg->len;
newMsg.data[indx++] = nextMsgID( state );
XP_MEMCPY( &newMsg.data[indx], msg->data, msg->len ); /* bad! */
indx += msg->len;
}
result = appendMsg( state, result, &newMsg );
result = appendNetMsg( state, result, &newMsg );
ii = last;
} else {
int msgID = nextMsgID( state );
const SMSMsg* msg = &rec->msgs[ii]->msg;
const SMSMsgNet* msg = &rec->msgs[ii]->msgNet;
XP_U8* nextStart = msg->data;
XP_U16 lenLeft = msg->len;
for ( XP_U16 indx = 0; indx < count; ++indx ) {
@ -681,8 +781,8 @@ toMsgs( SMSProto* state, ToPhoneRec* rec, XP_Bool forceOld )
}
lenLeft -= useLen;
SMSMsg newMsg = { .len = useLen + 4,
.data = XP_MALLOC( state->mpool, useLen + 4 )
SMSMsgNet newMsg = { .len = useLen + 4,
.data = XP_MALLOC( state->mpool, useLen + 4 )
};
newMsg.data[0] = SMS_PROTO_VERSION;
newMsg.data[1] = msgID;
@ -691,7 +791,7 @@ toMsgs( SMSProto* state, ToPhoneRec* rec, XP_Bool forceOld )
XP_MEMCPY( newMsg.data + 4, nextStart, useLen );
nextStart += useLen;
result = appendMsg( state, result, &newMsg );
result = appendNetMsg( state, result, &newMsg );
}
++ii;
}
@ -710,6 +810,14 @@ nextMsgID( SMSProto* state )
return result;
}
static XWStreamCtxt*
mkStream( SMSProto* state )
{
XWStreamCtxt* stream = mem_stream_make_raw( MPPARM(state->mpool)
dutil_getVTManager(state->dutil) );
return stream;
}
#ifdef DEBUG
static void
checkThread( SMSProto* state )
@ -745,17 +853,19 @@ smsproto_runTests( MPFORMAL XW_DUtilCtxt* dutil )
}
/* Loop until all the messages are ready. */
const XP_U32 gameID = 12344321;
const int port = 1;
for ( XP_Bool firstTime = XP_TRUE; ; firstTime = XP_FALSE) {
XP_Bool allDone = XP_TRUE;
for ( int ii = 0; ii < VSIZE(arrs); ++ii ) {
XP_U16 waitSecs;
if ( firstTime ) {
XP_U16 len = (ii + 1) * 30;
arrs[ii] = smsproto_prepOutbound( state, (XP_U8*)buf, len, phones[ii],
forceOld, &waitSecs );
arrs[ii] = smsproto_prepOutbound( state, DATA, gameID, buf, len, phones[ii],
port, forceOld, &waitSecs );
} else if ( NULL == arrs[ii]) {
arrs[ii] = smsproto_prepOutbound( state, NULL, 0, phones[ii],
forceOld, &waitSecs );
arrs[ii] = smsproto_prepOutbound( state, DATA, gameID, NULL, 0, phones[ii],
port, forceOld, &waitSecs );
} else {
continue;
}
@ -772,13 +882,17 @@ smsproto_runTests( MPFORMAL XW_DUtilCtxt* dutil )
XP_Bool haveOne = XP_FALSE;
for ( int ii = 0; ii < VSIZE(arrs); ++ii ) {
if (!!arrs[ii] && indx < arrs[ii]->nMsgs) {
XP_ASSERT( arrs[ii]->format == FORMAT_NET );
haveOne = XP_TRUE;
SMSMsgArray* outArr = smsproto_prepInbound( state, phones[ii],
arrs[ii]->msgs[indx].data,
arrs[ii]->msgs[indx].len );
arrs[ii]->u.msgsNet[indx].data,
arrs[ii]->u.msgsNet[indx].len );
if ( !!outArr ) {
SMSMsg* msg = &outArr->msgs[0];
XP_LOGF( "%s(): got msgID %d", __func__, msg->msgID );
XP_ASSERT( outArr->format == FORMAT_LOC );
SMSMsgLoc* msg = &outArr->u.msgsLoc[0];
XP_ASSERT( msg->gameID == gameID );
XP_ASSERT( msg->cmd == DATA );
// XP_LOGF( "%s(): got msgID %d", __func__, msg->msgID );
XP_ASSERT( outArr->nMsgs == 1 );
XP_ASSERT( 0 == memcmp(buf, msg->data, (ii + 1) * 30) );
smsproto_freeMsgArray( state, outArr );
@ -796,8 +910,8 @@ smsproto_runTests( MPFORMAL XW_DUtilCtxt* dutil )
/* Now let's send a bunch of small messages that should get combined */
for ( int nUsed = 0; ; ++nUsed ) {
XP_U16 waitSecs;
SMSMsgArray* sendArr = smsproto_prepOutbound( state, (XP_U8*)&buf[nUsed],
smallSiz, phones[0],
SMSMsgArray* sendArr = smsproto_prepOutbound( state, DATA, gameID, &buf[nUsed],
smallSiz, phones[0], port,
XP_FALSE, &waitSecs );
if ( sendArr == NULL ) {
XP_LOGF( "%s(): msg[%d] of len %d sent; still not ready", __func__, nUsed, smallSiz );
@ -805,17 +919,21 @@ smsproto_runTests( MPFORMAL XW_DUtilCtxt* dutil )
}
XP_ASSERT( waitSecs == 0 );
XP_ASSERT( sendArr->format == FORMAT_NET );
int totalBack = 0;
for ( int jj = 0; jj < sendArr->nMsgs; ++jj ) {
SMSMsgArray* recvArr = smsproto_prepInbound( state, phones[0],
sendArr->msgs[jj].data,
sendArr->msgs[jj].len );
sendArr->u.msgsNet[jj].data,
sendArr->u.msgsNet[jj].len );
if ( !!recvArr ) {
XP_ASSERT( recvArr->format == FORMAT_LOC );
XP_LOGF( "%s(): got %d msgs (from %d)", __func__, recvArr->nMsgs, nUsed + 1 );
for ( int kk = 0; kk < recvArr->nMsgs; ++kk ) {
SMSMsg* msg = &recvArr->msgs[kk];
XP_LOGF( "%s(): got msgID %d", __func__, msg->msgID );
SMSMsgLoc* msg = &recvArr->u.msgsLoc[kk];
// XP_LOGF( "%s(): got msgID %d", __func__, msg->msgID );
XP_ASSERT( msg->gameID == gameID );
XP_ASSERT( msg->cmd == DATA );
XP_ASSERT( msg->len == smallSiz );
XP_ASSERT( 0 == memcmp( msg->data, &buf[totalBack], smallSiz ) );
++totalBack;
@ -833,25 +951,44 @@ smsproto_runTests( MPFORMAL XW_DUtilCtxt* dutil )
/* Now let's add a too-long message and unpack only the first part. Make
sure it's cleaned up correctly */
XP_U16 waitSecs;
SMSMsgArray* arr = smsproto_prepOutbound( state, (XP_U8*)buf, 200, "33333", XP_TRUE, &waitSecs );
SMSMsgArray* arr = smsproto_prepOutbound( state, DATA, gameID, buf, 200, "33333",
port, XP_TRUE, &waitSecs );
XP_ASSERT( !!arr && arr->nMsgs > 1 );
/* add only part 1 */
SMSMsgArray* out = smsproto_prepInbound( state, "33333", arr->msgs[0].data, arr->msgs[0].len );
SMSMsgArray* out = smsproto_prepInbound( state, "33333", arr->u.msgsNet[0].data,
arr->u.msgsNet[0].len );
XP_ASSERT( !out );
smsproto_freeMsgArray( state, arr );
/* Try the no-buffer messages */
XP_LOGF( "%s(): trying DEATH", __func__ );
arr = smsproto_prepOutbound( state, DEATH, gameID, NULL, 0, "33333",
port, XP_TRUE, &waitSecs );
XP_ASSERT( arr->format == FORMAT_NET );
out = smsproto_prepInbound( state, "33333",
arr->u.msgsNet[0].data,
arr->u.msgsNet[0].len );
XP_ASSERT( out->format == FORMAT_LOC );
XP_ASSERT( out->u.msgsLoc[0].cmd == DEATH );
XP_ASSERT( out->u.msgsLoc[0].gameID == gameID );
smsproto_freeMsgArray( state, arr );
smsproto_freeMsgArray( state, out );
XP_LOGF( "%s(): DEATH checked out", __func__ );
/* now a message that's unpacked across multiple sessions to test store/load */
XP_LOGF( "%s(): testing store/restore", __func__ );
arr = smsproto_prepOutbound( state, (XP_U8*)buf, 200, "33333", XP_TRUE, &waitSecs );
arr = smsproto_prepOutbound( state, DATA, gameID, (XP_U8*)buf, 200, "33333",
port, XP_TRUE, &waitSecs );
for ( int ii = 0; ii < arr->nMsgs; ++ii ) {
SMSMsgArray* out = smsproto_prepInbound( state, "33333", arr->msgs[ii].data,
arr->msgs[ii].len );
SMSMsgArray* out = smsproto_prepInbound( state, "33333",
arr->u.msgsNet[ii].data,
arr->u.msgsNet[ii].len );
if ( !!out ) {
XP_ASSERT( out->nMsgs == 1);
XP_ASSERT( out->format == FORMAT_LOC );
XP_LOGF( "%s(): got the message on the %dth loop", __func__, ii );
XP_ASSERT( out->msgs[0].len == 200 );
XP_ASSERT( 0 == memcmp( out->msgs[0].data, buf, 200 ) );
XP_ASSERT( out->u.msgsLoc[0].len == 200 );
XP_ASSERT( 0 == memcmp( out->u.msgsLoc[0].data, buf, 200 ) );
smsproto_freeMsgArray( state, out );
break;
}

View file

@ -44,23 +44,44 @@
#include "xptypes.h"
#include "mempool.h" /* debug only */
#include "nli.h"
typedef struct SMSProto SMSProto;
typedef struct _SMSMsg {
typedef enum { NONE, INVITE, DATA, DEATH, ACK_INVITE, } SMS_CMD;
/* Unpacked/local format with relevant fields exposed */
typedef struct _SMSMsgLoc {
// XP_U16 msgID;
SMS_CMD cmd;
XP_U32 gameID;
XP_U16 len;
XP_U8* data; // will be NetLaunchInfo* if cmd == INVITE
} SMSMsgLoc;
/* Flattened format suitable for transmission over wire. Encapsulates Loc
format data */
typedef struct _SMSMsgNet {
// XP_U16 msgID;
XP_U16 len;
XP_U16 msgID;
XP_U8* data;
} SMSMsg;
} SMSMsgNet;
typedef enum { FORMAT_NONE, FORMAT_LOC, FORMAT_NET } SMS_FORMAT;
typedef struct _SMSMsgArray {
XP_U16 nMsgs;
SMSMsg* msgs;
SMS_FORMAT format;
union {
SMSMsgNet* msgsNet;
SMSMsgLoc* msgsLoc;
} u;
} SMSMsgArray;
struct SMSProto* smsproto_init( MPFORMAL XW_DUtilCtxt* dutil );
void smsproto_free( SMSProto* state );
/* Return ptr to structure if one's ready to be sent, otherwise null. Caller *
* should interpret null as meaning it's meant to call again. To support that,
* null buf is legit.
@ -68,8 +89,10 @@ void smsproto_free( SMSProto* state );
* When send() returns a non-null value, that value must be passed to
* freeMsgArray() or there will be leakage.
*/
SMSMsgArray* smsproto_prepOutbound( SMSProto* state, const XP_U8* buf,
XP_U16 buflen, const XP_UCHAR* toPhone,
SMSMsgArray* smsproto_prepOutbound( SMSProto* state, SMS_CMD cmd,
XP_U32 gameID, const void* buf, XP_U16 buflen,
const XP_UCHAR* toPhone, int port,
XP_Bool forceOld, XP_U16* waitSecs );
/* When a message is received, pass it in for reassambly. Non-null return

View file

@ -189,6 +189,26 @@ stream_gotU8( XWStreamCtxt* stream, XP_U8* ptr )
return success;
}
XP_Bool
stream_gotU16( XWStreamCtxt* stream, XP_U16* ptr )
{
XP_Bool success = sizeof(*ptr) <= stream_getSize( stream );
if ( success ) {
*ptr = stream_getU16( stream );
}
return success;
}
XP_Bool
stream_gotU32( XWStreamCtxt* stream, XP_U32* ptr )
{
XP_Bool success = sizeof(*ptr) <= stream_getSize( stream );
if ( success ) {
*ptr = stream_getU32( stream );
}
return success;
}
XP_Bool
stream_gotBytes( XWStreamCtxt* stream, void* ptr, XP_U16 len )
{

View file

@ -57,6 +57,8 @@ XP_U16 stringFromStreamHere( XWStreamCtxt* stream, XP_UCHAR* buf, XP_U16 len );
void stringToStream( XWStreamCtxt* stream, const XP_UCHAR* str );
XP_Bool stream_gotU8( XWStreamCtxt* stream, XP_U8* ptr );
XP_Bool stream_gotU32( XWStreamCtxt* stream, XP_U32* ptr );
XP_Bool stream_gotU16( XWStreamCtxt* stream, XP_U16* ptr );
XP_Bool stream_gotBytes( XWStreamCtxt* stream, void* ptr, XP_U16 len );
XP_UCHAR* p_copyString( MPFORMAL const XP_UCHAR* instr

View file

@ -1659,8 +1659,7 @@ send_invites( CommonGlobals* cGlobals, XP_U16 nPlayers,
gchar gameName[64];
snprintf( gameName, VSIZE(gameName), "Game %d", cGlobals->gi->gameID );
linux_sms_invite( cGlobals->params, cGlobals->gi, &addr, gameName,
nPlayers, forceChannel,
linux_sms_invite( cGlobals->params, &nli,
addrs->u.sms.phone, addrs->u.sms.port );
}
if ( 0 != devID || !!relayID ) {

View file

@ -746,26 +746,29 @@ gtkNoticeRcvd( void* closure )
}
static void
smsInviteReceived( void* closure, const XP_UCHAR* XP_UNUSED_DBG(gameName),
XP_U32 gameID, XP_U16 dictLang, const XP_UCHAR* dictName,
XP_U16 nPlayers, XP_U16 nHere, XP_U16 forceChannel,
/* smsInviteReceived( void* closure, const XP_UCHAR* XP_UNUSED_DBG(gameName), */
/* XP_U32 gameID, XP_U16 dictLang, const XP_UCHAR* dictName, */
/* XP_U16 nPlayers, XP_U16 nHere, XP_U16 forceChannel, */
/* const CommsAddrRec* returnAddr ) */
smsInviteReceived( void* closure, const NetLaunchInfo* nli,
const CommsAddrRec* returnAddr )
{
GtkAppGlobals* apg = (GtkAppGlobals*)closure;
LaunchParams* params = apg->params;
XP_LOGF( "%s(gameName=%s, gameID=%d, dictName=%s, nPlayers=%d, "
"nHere=%d, forceChannel=%d)", __func__, gameName, gameID, dictName,
nPlayers, nHere, forceChannel );
"nHere=%d, forceChannel=%d)", __func__, nli->gameName,
nli->gameID, nli->dict, nli->nPlayersT,
nli->nPlayersH, nli->forceChannel );
CurGameInfo gi = {0};
gi_copy( MPPARM(params->mpool) &gi, &params->pgi );
gi_setNPlayers( &gi, nPlayers, nHere );
gi.gameID = gameID;
gi.dictLang = dictLang;
gi.forceChannel = forceChannel;
gi_setNPlayers( &gi, nli->nPlayersT, nli->nPlayersH );
gi.gameID = nli->gameID;
gi.dictLang = nli->lang;
gi.forceChannel = nli->forceChannel;
gi.serverRole = SERVER_ISCLIENT; /* recipient of invitation is client */
replaceStringIfDifferent( params->mpool, &gi.dictName, dictName );
replaceStringIfDifferent( params->mpool, &gi.dictName, nli->dict );
GtkGameGlobals* globals = malloc( sizeof(*globals) );
params->needsNewGame = XP_FALSE;

View file

@ -68,12 +68,10 @@ typedef struct _LinSMSData {
SMSProto* protoState;
} LinSMSData;
static void doSend( LaunchParams* params, const XP_U8* buf,
XP_U16 buflen, const XP_UCHAR* phone, XP_U16 port,
XP_U32 gameID );
static gboolean retrySend( gpointer data );
static void sendOrRetry( LaunchParams* params, SMSMsgArray* arr, XP_U16 waitSecs,
const XP_UCHAR* phone, XP_U16 port, XP_U32 gameID );
static void sendOrRetry( LaunchParams* params, SMSMsgArray* arr, SMS_CMD cmd,
XP_U16 waitSecs, const XP_UCHAR* phone, XP_U16 port,
XP_U32 gameID );
static gint check_for_files( gpointer data );
static gint check_for_files_once( gpointer data );
@ -85,13 +83,7 @@ formatQueuePath( const XP_UCHAR* phone, XP_U16 port, XP_UCHAR* path,
snprintf( path, pathlen, "%s/%s_%d", SMS_DIR, phone, port );
}
typedef enum { NONE, INVITE, DATA, DEATH, ACK, } SMS_CMD;
#define SMS_PROTO_VERSION 0
static LinSMSData* getStorage( LaunchParams* params );
static void writeHeader( XWStreamCtxt* stream, SMS_CMD cmd );
static void
lock_queue( LinSMSData* storage )
@ -114,7 +106,7 @@ unlock_queue( LinSMSData* storage )
}
static XP_S16
write_fake_sms( LaunchParams* params, XWStreamCtxt* stream,
write_fake_sms( LaunchParams* params, const void* buf, XP_U16 buflen,
const XP_UCHAR* phone, XP_U16 port )
{
XP_S16 nSent;
@ -122,13 +114,11 @@ write_fake_sms( LaunchParams* params, XWStreamCtxt* stream,
XP_Bool skipWrite = pct < params->smsSendFailPct;
if ( skipWrite ) {
nSent = stream_getSize( stream );
nSent = buflen;
XP_LOGF( "%s(): dropping sms msg of len %d to phone %s", __func__,
nSent, phone );
} else {
LinSMSData* storage = getStorage( params );
const XP_U8* buf = stream_getPtr( stream );
XP_U16 buflen = stream_getSize( stream );
XP_LOGF( "%s(phone=%s, port=%d, len=%d)", __func__, phone,
port, buflen );
@ -236,81 +226,38 @@ decodeAndDelete( LinSMSData* storage, const gchar* name,
return nRead;
} /* decodeAndDelete */
static void
dispatch_invite( LinSMSData* storage, XP_U16 XP_UNUSED(proto),
XWStreamCtxt* stream, CommsAddrRec* addr )
{
XP_UCHAR gameName[256];
XP_UCHAR dictName[256];
XP_U32 gameID = stream_getU32( stream );
XP_LOGF( "%s: got gameID %d", __func__, gameID );
stringFromStreamHere( stream, gameName, VSIZE(gameName) );
XP_U32 dictLang = stream_getU32( stream );
stringFromStreamHere( stream, dictName, VSIZE(dictName) );
XP_U8 nMissing = stream_getU8( stream );
XP_U8 nPlayers = stream_getU8( stream );
XP_U16 forceChannel = stream_getU8( stream );
addrFromStream( addr, stream );
(*storage->procs->inviteReceived)( storage->procClosure, gameName,
gameID, dictLang, dictName, nPlayers,
nMissing, forceChannel, addr );
}
static void
dispatch_data( LinSMSData* storage, XP_U16 XP_UNUSED(proto),
XWStreamCtxt* stream, const CommsAddrRec* addr )
{
LOG_FUNC();
XP_U32 gameID = stream_getU32( stream );
XP_U16 len = stream_getSize( stream );
XP_U8 data[len];
stream_getBytes( stream, data, len );
const XP_UCHAR* fromPhone = addr->u.sms.phone;
SMSMsgArray* arr = smsproto_prepInbound( storage->protoState, fromPhone,
data, len );
if ( NULL != arr ) {
for ( XP_U16 ii = 0; ii < arr->nMsgs; ++ii ) {
SMSMsg* msg = &arr->msgs[ii];
(*storage->procs->msgReceived)( storage->procClosure, addr, gameID,
msg->data, msg->len );
}
smsproto_freeMsgArray( storage->protoState, arr );
}
}
static void
parseAndDispatch( LaunchParams* params, uint8_t* buf, int len,
CommsAddrRec* addr )
{
LinSMSData* storage = getStorage( params );
XWStreamCtxt* stream = mem_stream_make_raw( MPPARM(params->mpool)
params->vtMgr );
stream_setVersion( stream, CUR_STREAM_VERS );
stream_putBytes( stream, buf, len );
XP_U8 proto = stream_getU8( stream );
XP_ASSERT( SMS_PROTO_VERSION == proto );
XP_U8 cmd = stream_getU8( stream );
switch( cmd ) {
case INVITE:
dispatch_invite( storage, proto, stream, addr );
break;
case DATA:
dispatch_data( storage, proto, stream, addr );
break;
case DEATH:
case ACK:
break;
default:
XP_ASSERT( 0 );
const XP_UCHAR* fromPhone = addr->u.sms.phone;
SMSMsgArray* arr = smsproto_prepInbound( storage->protoState, fromPhone,
buf, len );
if ( NULL != arr ) {
XP_ASSERT( arr->format == FORMAT_LOC );
for ( XP_U16 ii = 0; ii < arr->nMsgs; ++ii ) {
SMSMsgLoc* msg = &arr->u.msgsLoc[ii];
switch ( msg->cmd ) {
case DATA:
(*storage->procs->msgReceived)( storage->procClosure, addr,
msg->gameID,
msg->data, msg->len );
break;
case INVITE:
(*storage->procs->inviteReceived)( storage->procClosure,
(NetLaunchInfo*)msg->data, addr );
/* gameName, */
/* gameID, dictLang, dictName, nPlayers, */
/* nMissing, forceChannel, addr ); */
break;
default:
XP_ASSERT(0); /* implement me!! */
break;
}
}
smsproto_freeMsgArray( storage->protoState, arr );
}
stream_destroy( stream );
}
void
@ -341,28 +288,18 @@ linux_sms_init( LaunchParams* params, const gchar* myPhone, XP_U16 myPort,
} /* linux_sms_init */
void
linux_sms_invite( LaunchParams* params, const CurGameInfo* gi,
const CommsAddrRec* addr, const gchar* gameName,
XP_U16 nMissing, int forceChannel,
linux_sms_invite( LaunchParams* params, const NetLaunchInfo* nli,
const gchar* toPhone, int toPort )
{
LOG_FUNC();
XWStreamCtxt* stream;
stream = mem_stream_make_raw( MPPARM(params->mpool) params->vtMgr );
writeHeader( stream, INVITE );
stream_putU32( stream, gi->gameID );
stringToStream( stream, gameName );
stream_putU32( stream, gi->dictLang );
stringToStream( stream, gi->dictName );
stream_putU8( stream, nMissing );
stream_putU8( stream, gi->nPlayers );
stream_putU8( stream, forceChannel );
LinSMSData* storage = getStorage( params );
addrToStream( stream, addr );
write_fake_sms( params, stream, toPhone, toPort );
stream_destroy( stream );
XP_U16 waitSecs;
SMSMsgArray* arr
= smsproto_prepOutbound( storage->protoState, INVITE, nli->gameID, nli,
sizeof(*nli), toPhone, toPort, XP_FALSE,
&waitSecs );
sendOrRetry( params, arr, INVITE, waitSecs, toPhone, toPort, nli->gameID );
}
XP_S16
@ -372,43 +309,32 @@ linux_sms_send( LaunchParams* params, const XP_U8* buf,
{
LinSMSData* storage = getStorage( params );
XP_U16 waitSecs;
SMSMsgArray* arr = smsproto_prepOutbound( storage->protoState, buf, buflen,
phone, XP_TRUE, &waitSecs );
sendOrRetry( params, arr, waitSecs, phone, port, gameID );
SMSMsgArray* arr = smsproto_prepOutbound( storage->protoState, DATA, gameID,
buf, buflen, phone, port,
XP_TRUE, &waitSecs );
sendOrRetry( params, arr, DATA, waitSecs, phone, port, gameID );
return buflen;
}
static void
doSend( LaunchParams* params, const XP_U8* buf,
XP_U16 buflen, const XP_UCHAR* phone, XP_U16 port,
XP_U32 gameID )
{
XP_LOGF( "%s(len=%d)", __func__, buflen );
XWStreamCtxt* stream = mem_stream_make_raw( MPPARM(params->mpool)
params->vtMgr );
writeHeader( stream, DATA );
stream_putU32( stream, gameID );
stream_putBytes( stream, buf, buflen );
(void)write_fake_sms( params, stream, phone, port );
stream_destroy( stream );
}
typedef struct _RetryClosure {
LaunchParams* params;
SMS_CMD cmd;
XP_U16 port;
XP_U32 gameID;
XP_UCHAR phone[32];
} RetryClosure;
static void
sendOrRetry( LaunchParams* params, SMSMsgArray* arr, XP_U16 waitSecs,
const XP_UCHAR* phone, XP_U16 port, XP_U32 gameID )
sendOrRetry( LaunchParams* params, SMSMsgArray* arr, SMS_CMD cmd,
XP_U16 waitSecs, const XP_UCHAR* phone, XP_U16 port,
XP_U32 gameID )
{
if ( !!arr ) {
for ( XP_U16 ii = 0; ii < arr->nMsgs; ++ii ) {
SMSMsg* msg = &arr->msgs[ii];
doSend( params, msg->data, msg->len, phone, port, gameID );
const SMSMsgNet* msg = &arr->u.msgsNet[ii];
// doSend( params, msg->data, msg->len, phone, port, gameID );
(void)write_fake_sms( params, msg->data, msg->len,
phone, port );
}
LinSMSData* storage = getStorage( params );
@ -420,6 +346,7 @@ sendOrRetry( LaunchParams* params, SMSMsgArray* arr, XP_U16 waitSecs,
XP_STRCAT( closure->phone, phone );
closure->port = port;
closure->gameID = gameID;
closure->cmd = cmd;
g_timeout_add_seconds( 5, retrySend, closure );
}
}
@ -430,9 +357,11 @@ retrySend( gpointer data )
RetryClosure* closure = (RetryClosure*)data;
LinSMSData* storage = getStorage( closure->params );
XP_U16 waitSecs;
SMSMsgArray* arr = smsproto_prepOutbound( storage->protoState, NULL, 0,
closure->phone, XP_TRUE, &waitSecs );
sendOrRetry( closure->params, arr, waitSecs, closure->phone,
SMSMsgArray* arr = smsproto_prepOutbound( storage->protoState, closure->cmd,
closure->gameID, NULL, 0,
closure->phone, closure->port,
XP_TRUE, &waitSecs );
sendOrRetry( closure->params, arr, closure->cmd, waitSecs, closure->phone,
closure->port, closure->gameID );
XP_FREEP( closure->params->mpool, &closure );
return FALSE;
@ -538,11 +467,4 @@ getStorage( LaunchParams* params )
return storage;
}
static void
writeHeader( XWStreamCtxt* stream, SMS_CMD cmd )
{
stream_putU8( stream, SMS_PROTO_VERSION );
stream_putU8( stream, cmd );
}
#endif /* XWFEATURE_SMS */

View file

@ -23,12 +23,10 @@
#ifdef XWFEATURE_SMS
#include "main.h"
#include "nli.h"
typedef struct _SMSProcs {
void (*inviteReceived)( void* closure, const XP_UCHAR* gameName,
XP_U32 gameID, XP_U16 dictLang,
const XP_UCHAR* dictName, XP_U16 nPlayers,
XP_U16 nHere, XP_U16 forceChannel,
void (*inviteReceived)( void* closure, const NetLaunchInfo* nli,
const CommsAddrRec* returnAddr );
void (*msgReceived)( void* closure, const CommsAddrRec* from, XP_U32 gameID,
const XP_U8* buf, XP_U16 len );
@ -45,9 +43,7 @@ void linux_sms_init( LaunchParams* params, const gchar* phone,
XP_S16 linux_sms_send( LaunchParams* params, const XP_U8* buf,
XP_U16 buflen, const XP_UCHAR* phone, XP_U16 port,
XP_U32 gameID );
void linux_sms_invite( LaunchParams* params, const CurGameInfo* info,
const CommsAddrRec* addr, const gchar* gameName,
XP_U16 nMissing, int forceChannel,
void linux_sms_invite( LaunchParams* params, const NetLaunchInfo* nli,
const gchar* phone, int port );
void linux_sms_cleanup( LaunchParams* params );