What is Megaphone?

What is Megaphone?
The Megaphone project is about enhancing open source chat software. Specifically, the goal is to allow ejabberd to support 1,000,000 simultaneous users. See The Plan page for more details on how I plan to solve this problem. See the About this Blog page for more details on why I created this blog.

Wednesday, January 18, 2012

receive_packet_headers

Previously...
  • I did an analysis of the event sequence that should take place in order to use a single process.
  • I made some plans about how to create megaphone_tcp.
    • Determine if segment contains a complete header
      • If not, then keep reading until you do have a complete header
    • Parse out the connection ID and packet length, 
      • If you have a complete header, then determine if you have a complete megaphone packet
        • If not, then keep reading until you have a complete megaphone packet
    • Send the megaphone process the completed packet.
    • Wait for another packet to arrive.
  • I created receive_loop, which takes care of controlling the process.
In today's report, I created receive_header


%
%% extract a complete megaphone header from the supplied data and from the 
%% supplied socket if the data is not enough.
%%
%% This function attempts to combine any leftover data with any newly received
%% data.  It then determines if it has enough data to form a complete megaphone
%% header.  If it does then it extracts out the fields from the data according
%% the standard locations and returns them.
%%
%% If the function does not have enough data to form a complete megaphone 
%% header, it will try to read more data from the supplied socket until it 
%% receives a complete packet.
%%
%% Socket --- The TCP socket that should be used to get more data.
%% LeftOvers --- Any data that should appear before the Data parameter.
%%     This value may be undefined if there was no left over data from the 
%%     previous packet.
%% Data --- Some newly received data from the socket.  This should appear after 
%%     the leftovers from the previous packet, if any exist.
%%
%% Returns { Length, CID, Content } where Length is an integer that is the 
%% number of bytes in the complete message, including the megaphone header.
%% CID is the connection ID of the connection, as a string (list).  Content
%% is the content, if any is left over from the header.  If there is no 
%% data left over from the header, then his value is returned as undefined.
%% 
receive_header(Socket, LeftOvers, Data) ->
    Data2 = case LeftOvers of
        undefined -> Data;
        true -> LeftOvers ++ Data
    end,
    case byte_size(Data2) of
        Length < ?PREFIX_LENGTH ->
            case gen_tcp:recv(Socket, 0) ->
                {ok, NewData},
                receive_header(Socket, Data2, NewData)
            end;

        true ->
            extract_CID_length_body(Data2)
    end.



This function takes create of detecting when the system has not received a complete packet and therefore needs to wait for more data from the client.  It uses the extract_CID_length_body function to extract out the data from the packet:

%%

%% extract out the packet length, the connection ID and the packet contents
%% from a binary block of data.
%%
%% Binary --- this should be the binary representation of a megaphone packet
%%    header.  The binary may also contain the partial or complete contents
%%    of a megaphone packet content.
%%
%% The function returns the tuple {Length, CID, Content} where Length is the 
%% length of the complete packet, include the megaphone header.  CID is the 
%% connection ID as an integer value.  Content is the megaphone packet contents.
%%
%% The input packet may contain no content or only part of the content of the 
%% packet and may therefore have a value of undefine or it may be a binary 
%% whose length is less than that of the complete content.
%%
extract_CID_length_body(Binary) ->
    BinaryPacketLength = binary_part(Binary, ?PACKET_LENGTH_START, ?PACKET_LENGTH_LENGTH),
    StringPacketLength = binary_to_list(BinaryPacketLength),
    { PacketLength, _ } = to_integer(StringPacketLength),

    BinaryConnectionID = binary_part(Binary, ?PACKET_CID_START, ?PACKET_CID_LENGTH),
    StringConnectionID = binary_to_list(BinaryConnectionID),

    BinaryContent = binary_part(Binary, ?PACKET_CONTENT_START, byte_size(Binary) - ?PACKET_HEADER_LENGTH),
    {PacketLength, StringConnectionID, BinaryContent}.

Next time, more functions that handle the extraction of packets.

No comments:

Post a Comment