Android Open Source - steamchat Steam Connection






From Project

Back to project page steamchat.

License

The source code is released under:

Apache License

If you think the Android project steamchat listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package com.kevelbreh.steamchat.steam2;
/* ww  w .java2 s .  co  m*/
import com.kevelbreh.steamchat.SteamChat;
import com.kevelbreh.steamchat.steam.language.Language;
import com.kevelbreh.steamchat.steam.language.Message;
import com.kevelbreh.steamchat.steam.network.packet.HeartBeat;
import com.kevelbreh.steamchat.steam.proto.SteamMessagesClientServerProto.CMsgClientHeartBeat;
import com.kevelbreh.steamchat.steam.security.Cryptography;
import com.kevelbreh.steamchat.steam.util.BinaryReader;
import com.kevelbreh.steamchat.steam.util.BinaryWriter;
import com.kevelbreh.steamchat.steam2.packet.Packet;
import com.kevelbreh.steamchat.steam2.packet.ProtoPacket;

import java.io.IOException;
import java.net.Socket;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.util.Timer;
import java.util.TimerTask;

public class SteamConnection extends Thread {

    /**
     * This {@link java.net.Socket} is a connection to the Steam server.
     */
    private Socket socket;

    /**
     * The host of the Steam server.
     */
    private String host;

    /**
     * The port of the Steam server.
     */
    private int port;

    /**
     * The {@link com.kevelbreh.steamchat.steam.util.BinaryReader} reads the data from the
     * {@link java.net.Socket#getInputStream()}.
     */
    private BinaryReader in;

    /**
     * The {@link com.kevelbreh.steamchat.steam.util.BinaryWriter} writes the data to the
     * {@link java.net.Socket#getOutputStream()}.
     */
    private BinaryWriter out;

    /**
     * This is the {@link com.kevelbreh.steamchat.steam2.SteamConnection#socket} timeout in milliseconds.
     * The default timeout is set to 5 minutes.
     */
    private int timeout = 1000 * 60 * 5;

    /**
     * Session key is used to encrypt and decrypt steam data after {@link com.kevelbreh.steamchat.steam.language.Message#CHANNEL_ENCRYPT_RESPONSE}
     * has been received with an OK result.
     */
    private byte[] sessionKey;

    /**
     * The session id received once the user has logged in. This needs to be put in the header of each
     * packet being sent to steam after logging in.
     */
    private int sessionId;

    /**
     * The steam id received once the user has logged in. This needs to be put in the header of each
     * packet being sent to steam after logging in.
     */
    private long steamId;

    /**
     * This is used to dispatch data events to a listener bound to this connection.
     */
    private OnDataReceivedListener listener;

  /**
   * Heartbeat packet that needs to be sent to steam every few seconds.  This time is returned from steam during
   * the login procedure.  Once the user successfully logs in, a value is returned for the "out of game heartbeat"
   * time interval.
   */
  private ProtoPacket<CMsgClientHeartBeat.Builder> heartbeat;

  /**
   * Heartbeat timer that will send the a {@link #heartbeat} packet every few seconds defined by steam after
   * logging in.  Without the timer steam will reject the connection and treat it as if the user has timed out.
   */
  private Timer heartbeatTimer;

    /**
     *
     * @param host
     * @param port
     */
    public SteamConnection(String host, int port) {
        super("SteamConnection-Thread");
        this.host = host;
        this.port = port;
    }

    /**
     * Establish a connection to the steam server.
     *
     * @throws IOException
     */
    private void connect() throws IOException {
        Socket socket = null;
        try {
            socket = new Socket(this.host, this.port);
        }
        catch(final IOException e) {
            SteamChat.debug(this, e.getMessage(), e);
            if (socket != null) {
                socket.close();
            }
            throw e;
        }
        this.prepare(socket);
    }

    /**
     * Invoked by the {@link #connect()} method, this prepares the connection. It initializes the
     * input and output streams and then starts the thread for receiving messages from the Steam Network.
     *
     * @param socket which is used for the connection.
     * @throws IOException if errors occur.
     */
    private void prepare(Socket socket) throws IOException {
        if (socket == null) {
            throw new SocketException("Socket can not be null.");
        }
        this.socket = socket;
        this.socket.setSoTimeout(this.timeout);
        this.in = new BinaryReader(this.socket.getInputStream());
        this.out = new BinaryWriter(this.socket.getOutputStream());
    }

    /**
     * The {@link java.lang.Thread} is started by the {@link #connect()} method. It's task is to
     * receive data from the Steam network and hand them over to the {@link #process(byte[])} method.
     */
    @Override
    public void run() {
        try {
            connect();

            while(!in.isAtEnd()) {
                final int length = in.readInt();
                final int magic = in.readInt();

                if (magic != 0x31305456) {
                    throw new IOException("Invalid magic");
                }

                byte[] data = in.readBytes(length);
                if (data.length != length) {
                    throw new IOException("Connection lost while reading packet");
                }

                if (sessionKey != null) {
                    data = Cryptography.SymmetricDecrypt(data, sessionKey);
                }

                process(data);
                sleep(500);
            }
        }
        catch(SocketException e) {
      /*
      09-23 15:05:49.157  22263-22881/com.kevelbreh.steamchat:SteamService D/SteamConnection? recvfrom failed: ETIMEDOUT (Connection timed out)
        java.net.SocketException: recvfrom failed: ETIMEDOUT (Connection timed out)
            at libcore.io.IoBridge.maybeThrowAfterRecvfrom(IoBridge.java:552)

            On ETIMEDOUT we should set a timeout thing to auto-reconnect after x amount of seconds.
       */
            SteamChat.debug(this, e.getMessage(), e);
            close();
        }
        catch(IOException e) {
            SteamChat.debug(this, e.getMessage(), e);
            close();
        }
        catch(InterruptedException e) {
            SteamChat.debug(this, e.getMessage(), e);
            close();
        }
        finally {
            close();
        }
    }

    /**
     * Serialize the packet data and then write it to the {@link #out} stream.
     * @param packet that will be sent to Steam.
     */
    public synchronized void send(Packet packet) {
        try {
            if (steamId != 0) {
                packet.setSteamId(steamId);
            }

            if (sessionId != 0) {
                packet.setSessionId(sessionId);
            }

            byte[] data = packet.serialize();
            if (sessionKey != null) {
                data = Cryptography.SymmetricEncrypt(data, sessionKey);
            }

            out.write(data.length);
            out.write(0x31305456);
            out.write(data);
            out.flush();
        }
        catch(final IOException e) {
            SteamChat.debug(this, e.getMessage(), e);
        }
    }

    /**
     * Process an incoming packet.  Retrieve the message message type from the data, then fire an
     * {@link com.kevelbreh.steamchat.steam2.SteamConnection.OnDataReceivedListener#onDataReceived(int, boolean, byte[])}
     * event to whichever handler is attached.
     *
     * @param data that needs to be processed.
     */
    private void process(final byte[] data) throws IOException {
        final byte[] type = new byte[4];
        for (int i = 0; i < 4; i++) {
            type[3 - i] = data[i];
        }

        final ByteBuffer buffer = ByteBuffer.wrap(type);
        final int rawType = buffer.getInt();

        // Set a default listener that does nothing.
        if (listener == null) {
            listener = new OnDataReceivedListener() {
                @Override
                public synchronized void onDataReceived(final int event, final boolean isProto, final byte[] data) {
                    SteamChat.debug(this, "Received some data from Steam...");
                }
            };
        }

        listener.onDataReceived(Message.forType(rawType), Message.isProtoBuffed(rawType), data);
    }

    /**
     * Close down the connection.
     */
    public synchronized void close() {
    stopHeartbeat();

        try {
            if (!isInterrupted()) {
                interrupt();
            }
        } catch(Exception e) {
            SteamChat.debug(this, e.getMessage(), e);
        }

        try {
            if (this.socket != null) {
                //this.socket.shutdownOutput();
                //this.socket.shutdownInput();
                this.socket.close();
            }
        } catch(Exception e) {
            SteamChat.debug(this, e.getMessage(), e);
        }

        this.socket = null;
        this.in = null;
        this.out = null;
    }

  /**
   * Create or return an already created heart beat packet which will be sent to steam to keep the connection alive
   * .  Without this steam will terminate the connection as if the client timed out.
   *
   * @return a {@link com.kevelbreh.steamchat.steam2.packet.ProtoPacket} for steam heart beating.
   */
  private ProtoPacket getHeartbeat() {
    if (heartbeat == null) {
      heartbeat = new ProtoPacket<CMsgClientHeartBeat.Builder>(CMsgClientHeartBeat.class,
          Language.Message.CLIENT_HEARTBEAT);
    }
    return heartbeat;
  }

  /**
   * Start a timer to send the {@link #getHeartbeat()} packet every few seconds defined by steam once the user has
   * successfully logged in.  Without heart beating, steam will terminate the connection.
   *
   * @param interval in which the heartbeat needs to be sent.
   */
  public synchronized void startHeartbeat(int interval) {
    heartbeatTimer = new Timer();
    heartbeatTimer.scheduleAtFixedRate(new TimerTask() {
      @Override
      public void run() {
        send(getHeartbeat());
        SteamChat.debug(this, "Client -> PING -> Server.");
      }
    }, 0, interval * 1000);
  }

  /**
   * Stop steam heart beating.  This could only possibly be called when the steam connection gets recycled and
   * broke down.
   */
  private void stopHeartbeat() {
    if (heartbeatTimer != null) {
      heartbeatTimer.cancel();
    }
  }

    /**
     * Set the {@link #listener} of this connection.  When a packet is received, the packet will
     * be dispatched to this listener.
     * @param listener to be attached.
     */
    public synchronized void setDataReceivedListener(OnDataReceivedListener listener) {
        this.listener = listener;
    }

    /**
     * Set the {@link #sessionKey} for this connection.  This is a requirement else any data received
     * will be mushed up and any data received will be exposed to anyone.
     * @param key to be used for cryptography.
     */
    public synchronized void setSessionKey(byte[] key) {
        this.sessionKey = key;
    }

    /**
     *
     * @param id of the currently logged in steam user.
     */
    public synchronized void setSteamId(long id) {
        this.steamId = id;
    }

    /**
     *
     * @param id of the currently logged in steam user's connection session.
     */
    public synchronized void setSessionId(int id) {
        this.sessionId = id;
    }

    /**
     * Interface for receiving data.
     */
    public interface OnDataReceivedListener {

        /**
         * Fired when a packet is received.
         *
         * @param event message type.
         * @param proto boolean whether the data is proto buffed or not.
         * @param data payload.
         */
        public void onDataReceived(final int event, final boolean proto, final byte[] data);
    }
}




Java Source Code List

com.kevelbreh.steamchat.SteamChat.java
com.kevelbreh.steamchat.account.AuthenticatorService.java
com.kevelbreh.steamchat.account.Authenticator.java
com.kevelbreh.steamchat.account.SteamAccount.java
com.kevelbreh.steamchat.activity.AuthenticationActivity.java
com.kevelbreh.steamchat.activity.ConversationActivity.java
com.kevelbreh.steamchat.activity.FriendsActivity.java
com.kevelbreh.steamchat.activity.InteractionsActivity.java
com.kevelbreh.steamchat.activity.LauncherActivity.java
com.kevelbreh.steamchat.activity.SettingsActivity.java
com.kevelbreh.steamchat.fragment.ConversationFragment.java
com.kevelbreh.steamchat.fragment.FriendsFragment.java
com.kevelbreh.steamchat.fragment.InteractionsFragment.java
com.kevelbreh.steamchat.fragment.SettingsFragment.java
com.kevelbreh.steamchat.provider.SteamProviderUtils.java
com.kevelbreh.steamchat.provider.SteamProvider.java
com.kevelbreh.steamchat.provider.content.InteractionContentItem.java
com.kevelbreh.steamchat.provider.content.PersonaContentItem.java
com.kevelbreh.steamchat.provider.content.UserContentItem.java
com.kevelbreh.steamchat.steam2.SteamConnection.java
com.kevelbreh.steamchat.steam2.SteamEventBus.java
com.kevelbreh.steamchat.steam2.SteamService.java
com.kevelbreh.steamchat.steam2.handler.ConnectionHandler.java
com.kevelbreh.steamchat.steam2.handler.FriendHandler.java
com.kevelbreh.steamchat.steam2.handler.MessageHandler.java
com.kevelbreh.steamchat.steam2.handler.UserHandler.java
com.kevelbreh.steamchat.steam2.packet.Packet.java
com.kevelbreh.steamchat.steam2.packet.ProtoPacket.java
com.kevelbreh.steamchat.steam.SteamClient.java
com.kevelbreh.steamchat.steam.SteamID.java
com.kevelbreh.steamchat.steam.SteamServiceHandler.java
com.kevelbreh.steamchat.steam.SteamService.java
com.kevelbreh.steamchat.steam.handler2.ConnectionHandler.java
com.kevelbreh.steamchat.steam.handler2.FriendHandler.java
com.kevelbreh.steamchat.steam.handler2.Handler.java
com.kevelbreh.steamchat.steam.handler2.UserHandler.java
com.kevelbreh.steamchat.steam.handler.AEventHandler.java
com.kevelbreh.steamchat.steam.handler.AuthenticationHandler.java
com.kevelbreh.steamchat.steam.handler.FriendsHandler.java
com.kevelbreh.steamchat.steam.handler.IEventHandler.java
com.kevelbreh.steamchat.steam.handler.IHandler.java
com.kevelbreh.steamchat.steam.handler.MessageDebugHandler.java
com.kevelbreh.steamchat.steam.language.Language.java
com.kevelbreh.steamchat.steam.language.Message.java
com.kevelbreh.steamchat.steam.network.TCPConnection.java
com.kevelbreh.steamchat.steam.network.packet.ChannelEncryptRequest.java
com.kevelbreh.steamchat.steam.network.packet.ChannelEncryptResponse.java
com.kevelbreh.steamchat.steam.network.packet.ChannelEncryptResult.java
com.kevelbreh.steamchat.steam.network.packet.ClientLogOnResponse.java
com.kevelbreh.steamchat.steam.network.packet.ClientLogOn.java
com.kevelbreh.steamchat.steam.network.packet.HeartBeat.java
com.kevelbreh.steamchat.steam.network.packet.MultiPacket.java
com.kevelbreh.steamchat.steam.network.packet.Packet.java
com.kevelbreh.steamchat.steam.network.packet.ProtoPacket.java
com.kevelbreh.steamchat.steam.proto.DescriptorsProto.java
com.kevelbreh.steamchat.steam.proto.EncryptedAppTicketProto.java
com.kevelbreh.steamchat.steam.proto.SteamMessagesBaseProto.java
com.kevelbreh.steamchat.steam.proto.SteamMessagesClientServerProto.java
com.kevelbreh.steamchat.steam.security.AsnKeyParser.java
com.kevelbreh.steamchat.steam.security.AsnParser.java
com.kevelbreh.steamchat.steam.security.BerDecodeException.java
com.kevelbreh.steamchat.steam.security.Cryptography.java
com.kevelbreh.steamchat.steam.security.NetEncryption.java
com.kevelbreh.steamchat.steam.security.PublicKey.java
com.kevelbreh.steamchat.steam.security.RSA.java
com.kevelbreh.steamchat.steam.util.BinaryReader.java
com.kevelbreh.steamchat.steam.util.BinaryWriter.java
com.kevelbreh.steamchat.steam.util.BitVector64.java
com.kevelbreh.steamchat.steam.util.JenkinsHash.java
com.kevelbreh.steamchat.util.AServiceActivity.java
com.kevelbreh.steamchat.util.Dump.java
com.kevelbreh.steamchat.util.MiscUtils.java
com.kevelbreh.steamchat.widget.adapter.ChatAdapter.java
com.kevelbreh.steamchat.widget.adapter.ConversationAdapter.java
com.kevelbreh.steamchat.widget.adapter.FriendAdapter.java
com.kevelbreh.steamchat.widget.view.AvatarView.java
com.kevelbreh.steamchat.widget.view.FriendInteractionsView.java