Skip to content

A minimal library for building scalable TCP servers in Erlang

License

Notifications You must be signed in to change notification settings

sinasamavati/condor

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

21 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Condor

Condor is a minimal library for building scalable TCP servers in Erlang.

Quick Overview

-module(ping_server).
-behaviour(condor_listener).

%% condor_listener callbacks
-export([init/1]).
-export([handle_packet/2]).
-export([handle_info/2]).
-export([terminate/2]).

init([]) ->
    {ok, undefined}.

handle_packet(<<"stop">>, State) ->
    {send_and_stop, <<"ok">>, normal, State};
handle_packet(<<"ping">>, State) ->
    {send, <<"pong">>, State}.

handle_info(_Msg, State) ->
    {ok, State}.

terminate(_Reason, _State) ->
    ok.

Features

  • Reusable supervised connection acceptors
  • Neat packet frames and buffers

API

Start a Listener

 condor:start_listener(Name, Opts, Module, InitialState) ->
     {ok, Pid} | {error, Reason}

 Name = atom()
 Opts = #{
          ip => inet:ip_address(),
          port => inet:port_number(),
          max_acceptors => non_neg_integer(),
          len => 1 | 2,
          timeout => non_neg_integer()
        }
Module = atom()
InitialState = any()
Pid = pid()
Reason = any()

Opts:

  • ip: to what IP Condor should bind.
  • port: on what port Condor should listen.
  • max_acceptors: maximum number of socket acceptors, or in other words, maximum number of concurrent connections.
  • len: length of the indicator of a packet’s size.
  • timeout: the time limit, in milliseconds, for a packet to be buffered.

Default Opts:

#{
   ip => {127, 0, 0, 1},
   len => 2,
   timeout => 10000,
   max_acceptors => 100
 }

Stop a Listener

condor:stop_listener(Name) -> ok

Name = atom()

Condor Listener Callbacks

Behaviour: condor_listener

init(State) -> Result

handle_packet(Packet, State) -> Result

handle_info(Msg, State) -> Result

terminate(Reason, State) -> ok

Result = {ok, State}
       | {send, Packet, State}
       | {stop, Reason, State}
       | {send_and_stop, Packet, Reason, State}

Packet = binary()
State = any()
Reason = atom()

Events that invoke callbacks:

event                       callback module
-----                       ---------------
new connection         ---> Module:init/1
new packet             ---> Module:handle_packet/2
receiving a message    ---> Module:handle_info/2
packet timeout         ---> Module:handle_info/2
connection termination ---> Module:terminate/2

Condor takes care of framing packets. Each packet frame consists of two segments: Len | Packet.

Len indicates the length of Packet in big-endian order.

The length of Len is two bytes by default, though it can be modified with the len option.

Condor also takes care of buffering. So, Module:handle_packet/2 is called only when an entire packet is received. That is, when Packet is buffered according to the value of Len. Len will then be stripped off, and only Packet will be passed to Module:handle_packet/2. However, if Packet is not received completely in Timeout milliseconds (which would be specified in Opts), Module:handle_info/2 will be invoked with Msg being {timeout, Buffer :: binary()}.

A callback’s Result:

  • {send, Packet, State} sends Packet (in the frame: Len | Packet).
  • {stop, Reason, State} terminates the connection.
  • {send_and_stop, Packet, Reason, State} sends Packet (in the frame: Len | Packet), and then terminates the connection.

License

Apache License, Version 2.0

About

A minimal library for building scalable TCP servers in Erlang

Topics

Resources

License

Stars

Watchers

Forks