'=========================================================================================================
'This service sends out a UDP broadcast "I'm a server" message while simultaneously looking for another
'device broadcasting the same message via UDP & keeping a TCP server socket open waiting for a connection.
'
'The first device to receive a broadcast message sends an "I'm a client" message to the server IP address,
'then stops the UDP broadcast & opens a TCP client socket connected to the other device's TCP server socket.
'
'When the other device receives the "I'm a client" message, it closes it's UDP socket & accepts the client
'connection on the TCP socket.
'
'Both devices then open an asynchronous stream to use for sending messages to each other.
Sub Process_Globals
'These global variables will be declared once when the application starts.
'These variables can be accessed from all modules.
Public sMyIP As String
Public aStream() As AsyncStreams
Public sClientIP() As String
Public iClientsConnected As Int = 0
Public sServerIP As String
Private UDPSocket1 As UDPSocket
Private Tablet As Reflector
Private UDPPort As Int = 13130
Private TCPPort As Int = 13131
Private sBroadCastIP As String
Private tmr As Timer
Private tcpClient() As Socket
Private tcpServer As ServerSocket
Private bFoundServer As Boolean = False
Private iTryCount As Int = 0
End Sub
Sub Service_Create
Tablet.Target = Tablet.GetContext
Tablet.Target = Tablet.RunMethod2("getSystemService", "wifi", "java.lang.String")
Tablet.Target = Tablet.RunMethod2("createMulticastLock", "mylock", "java.lang.String")
Tablet.RunMethod2("setReferenceCounted", False, "java.lang.boolean") 'not really necessary but safer
Tablet.RunMethod("acquire") 'acquire the lock
End Sub
Sub Service_Start (StartingIntent As Intent)
Private ws As PhoneWakeState
Private tcpClient(Starter.iNumPlayers) As Socket
Private aStream(Starter.iNumPlayers) As AsyncStreams
Private sClientIP(Starter.iNumPlayers) As String
ws.KeepAlive(True)
CallSub3(Main, "Update_btnRoll", "Connecting...", False)
GetNetIP
bFoundServer = False
iClientsConnected = 0
If Not(Starter.cOpts.ManualNet) Then
If sBroadCastIP = "" Then
CallSub3(Main, "Update_btnRoll", "Connection Failed", False)
CallSub(Main, "noUDPBroadcast")
Return
End If
UDPSocket1.Initialize("UDP", UDPPort, 256)
sServerIP = ""
CheckForServer
Else
If Starter.cOpts.PlayerOne Then
tcpServer.Initialize(TCPPort, "Server")
tcpServer.Listen
Else
tcpClient(0).Initialize("Client")
tcpClient(0).Connect(sServerIP, TCPPort, 10000)
End If
End If
End Sub
'Send "I'm a server" message
Sub SendMYID
Log("Sending my ID")
UDPSendMsg("Five Dice Server", sBroadCastIP)
End Sub
Sub UDPSendMsg(msg As String, IPAddr As String)
Private Packet As UDPPacket
Private data() As Byte
data = msg.GetBytes("UTF8")
Packet.Initialize(data, IPAddr, UDPPort)
'Log("Sending UDP message")
UDPSocket1.Send(Packet)
'Log("UDP message sent")
End Sub
'Receive UDP broadcast messages
Sub UDP_PacketArrived (Packet As UDPPacket)
Private msg As String
msg = BytesToString(Packet.Data, Packet.Offset, Packet.Length, "UTF8")
Private IP As String = Packet.HostAddress
Private parts() As String = Regex.Split("~", msg)
If IP <> sMyIP Then
Log(msg)
Select Case parts(0)
'If the other device is a server
Case "Five Dice Server"
tmr.Enabled = False
Log("Server IP: " & IP)
ToastMessageShow("Player found at " & IP, True)
UDPSendMsg("Five Dice Client", IP)
bFoundServer = True
sServerIP = IP
Log("Closing Socket")
UDPSocket1.Close
Log("Socket Closed")
tmr.Interval = 2000
tmr.Enabled = True
'If the other device is a client
Case "Five Dice Client"
Log("Found a client")
ToastMessageShow("Player found at " & IP, True)
Case Else
End Select
End If
End Sub
Sub Service_Destroy
Kill_Connections
End Sub
Sub Kill_Connections
Private ws As PhoneWakeState
Private iCnt As Int
UDPSocket1.Close
Tablet.RunMethod("release")
For iCnt = 0 To tcpClient.Length - 1
tcpClient(iCnt).Close
Next
tcpServer.Close
tmr.Enabled = False
ws.ReleaseKeepAlive
End Sub
'Get the network address & create a UDP broadcast address
Sub GetNetIP
Private netS As ServerSocket
netS.Initialize(0, "")
sMyIP = netS.GetMyIP
netS.Close
If Not(Starter.cOpts.ManualNet) Then
sBroadCastIP = GetBroadcastAddress
Log("Broadcast Address: " & sBroadCastIP)
Else
'sBroadCastIP = Starter.cOpts.OtherIP
sServerIP = Starter.cOpts.OtherIP
End If
End Sub
'Returns the UDP broadcast address.
'Returns an empty string if not available.
Sub GetBroadcastAddress As String
Dim niIterator As JavaObject
niIterator = niIterator.InitializeStatic("java.net.NetworkInterface").RunMethod("getNetworkInterfaces", Null)
Do While niIterator.RunMethod("hasMoreElements", Null)
Dim ni As JavaObject = niIterator.RunMethod("nextElement", Null)
If ni.RunMethod("isLoopback", Null) = False Then
Dim addresses As List = ni.RunMethod("getInterfaceAddresses", Null)
For Each ia As JavaObject In addresses
Dim broadcast As Object = ia.RunMethod("getBroadcast", Null)
If broadcast <> Null Then
Dim b As String = broadcast
Return b.SubString(1)
End If
Next
End If
Loop
Return ""
End Sub
Sub CheckForServer
tmr.Initialize("tmr", 5000)
tmr.Enabled = True
End Sub
Sub tmr_Tick
'Haven't found the server yet
If bFoundServer = False Then
iTryCount = iTryCount + 1
If tcpServer.IsInitialized = False Then
tcpServer.Initialize(TCPPort, "Server")
tcpServer.Listen
End If
tmr.Enabled = False
tmr.Interval = 1000
tmr.Enabled = True
SendMYID
Else
'Found the server so will TCP connect as a client
'Log("Connecting to Server")
tmr.Enabled = False
tcpClient(0).Initialize("Client")
tcpClient(0).Connect(sServerIP, TCPPort, 10000)
End If
End Sub
Sub Client_Connected(Successful As Boolean)
Try
tmr.Enabled = False
If Successful Then
'Connected as a client, so open a stream
ToastMessageShow("Connected", False)
Starter.NetGame.Initialize
aStream(0).InitializePrefix(tcpClient(0).InputStream, False, tcpClient(0).OutputStream, "AStream")
Starter.NetGame.SendConnectedMsg(1)
Else
'Connection failed
tcpClient(0).Close
ToastMessageShow("Connection Failed", False)
Starter.iNumPlayers = 1
Main.bNetGame = False
StopService("")
End If
Catch
Log(LastException.Message)
CallSub(Main, "showNetError")
End Try
End Sub
Sub Server_NewConnection(Successful As Boolean, NewSocket As Socket)
If Successful Then
'Connected to a client
iClientsConnected = iClientsConnected + 1
ToastMessageShow("Connected Player " & (iClientsConnected + 1) & " of " & Starter.iNumPlayers, False)
If iClientsConnected = 1 Then
Starter.NetGame.Initialize
Starter.NetGame.PlayerMe = 0'Starter.NetGame.PLAYER_FIRST
End If
tcpClient(iClientsConnected - 1) = NewSocket
aStream(iClientsConnected - 1).InitializePrefix(tcpClient(iClientsConnected - 1).InputStream, False, tcpClient(iClientsConnected - 1).OutputStream, "AStream")
sClientIP(iClientsConnected - 1) = Get_Client_IP(NewSocket)
Starter.NetGame.SendConnectedMsg(iClientsConnected)
If iClientsConnected < Starter.iNumPlayers - 1 Then tcpServer.Listen
Else
'Connection to client failed
tcpServer.Close
ToastMessageShow("Connection Failed", False)
Starter.iNumPlayers = 1
Main.bNetGame = False
StopService("")
End If
If iClientsConnected >= Starter.iNumPlayers - 1 Then
tmr.Enabled = False
UDPSocket1.Close
End If
End Sub
'Get the client IP address from the socket
Sub Get_Client_IP(ClientSock As Socket) As String
Private r As Reflector
r.Target = ClientSock
r.Target = r.GetField("socket")
r.Target = r.RunMethod("getInetAddress") 'InetAddress
Return r.RunMethod("getHostAddress")
End Sub
'Received a message on the stream
Sub AStream_NewData (Buffer() As Byte)
Private msg As String
msg = BytesToString(Buffer, 0, Buffer.Length, "UTF8")
Starter.NetGame.ReceiveMsg(msg)
End Sub