ovcc-network-message.vala 4.03 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/* 
 * 
 * Copyright (C) 2011 Colomban Wendling <ban@herbesfolles.org>
 *                    Jonathan Michalon <studios.chalmion@no-log.org>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
 */

21
/*
22
 * How to add a new message:
23 24
 * 1) Subclass OVCC.Network.Message (or one of its subclass);
 *    don't forget to append your filename to Makefile.am's libovcc_la_SOURCES
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
 * 2) Implement the abstract methods and properties
 * 3) Append the message type in OVCC.Network.MessageType
 * 4) Append the type of your class in OVCC.Network.Message.message_types
 * 
 */

namespace OVCC.Network
{
  public errordomain MessageError
  {
    MALFORMED_MESSAGE,
    INVALID_TYPE,
    FAILED
  }

  public enum MessageType
  {
    ERROR,
    WELCOME,
44
    LOGIN,
45 46
    JOIN,
    GAMEDATA,
47
    SIGNAL,
48
    DISCONNECT,
49
    LIST_GAMES,
50 51 52 53 54 55 56 57 58
    INVALID
  }


  public abstract class Message : Object
  {
    private static Type[] message_types = {
      typeof (ErrorMessage),
      typeof (WelcomeMessage),
59
      typeof (LoginMessage),
60 61
      typeof (JoinMessage),
      typeof (GamedataMessage),
62
      typeof (SignalMessage),
63
      typeof (DisconnectMessage),
64
      typeof (ListGamesMessage)
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
    };
    
    public abstract MessageType message_type { get; }
    public abstract bool        serialize (DataOutputStream stream,
                                           Cancellable?     cancel = null)
      throws Error;
    public abstract bool        deserialize (DataInputStream  stream,
                                             Cancellable?     cancel = null)
      throws Error;
    
    
    public static Message receive (DataInputStream stream,
                                   Cancellable?    cancel = null)
      throws Error
    {
80 81
      /* hack to call the class_init before using length and content of message_types */
      TypeClass   klass = typeof (Message).class_ref ();
82
      (void) klass;
83

84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
      Message     message = null;
      MessageType type;
      
      type = (MessageType)stream.read_uint16 (cancel);
      if (type >= message_types.length) {
        throw new MessageError.INVALID_TYPE ("Invalid message type %u", type);
      }
      message = Object.new (message_types[type]) as Message;
      assert (message.message_type == type);
      message.deserialize (stream, cancel);
      
      return message;
    }
    
    public bool send (DataOutputStream  stream,
                      Cancellable?      cancel = null)
      throws Error
    {
      stream.put_uint16 ((uint16)this.message_type, cancel);
      this.serialize (stream, cancel);
      return true;
    }
106

107 108
    protected uint8[] read_buffer (DataInputStream  stream,
                                   Cancellable?     cancel = null)
109 110 111
      throws Error
    {
      var len = stream.read_uint16 (cancel);
112
      if (len < 0 || len > 0x4000 /* arbitrary limit not to fulfill memory */) {
113 114 115 116
        throw new MessageError.MALFORMED_MESSAGE ("Invalid message length %u",
                                                  len);
      }

117
      var buf = new uint8[len];
118 119 120
      if (len > 0) {
        stream.read (buf, cancel);
      }
121
      return buf;
122 123
    }

124 125 126
    protected bool write_buffer (DataOutputStream  stream,
                                 uint8[]           buf,
                                 Cancellable?      cancel = null)
127 128 129
      throws Error
    {
      stream.put_uint16 ((uint16)buf.length, cancel);
130 131 132 133 134
      if (buf.length > 0) {
        return stream.write (buf, cancel) == buf.length;
      } else {
        return true;
      }
135
    }
136 137
  }
}