Skip to content

Commit

Permalink
rebar-ified build;Added optional callback listening/2 for notifying b…
Browse files Browse the repository at this point in the history
…ehavior impls when a dynamic port is chosen
  • Loading branch information
Kevin Smith committed Apr 15, 2010
1 parent 33f8d12 commit 2251bfb
Show file tree
Hide file tree
Showing 12 changed files with 177 additions and 33 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ebin/*.beam
32 changes: 7 additions & 25 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,34 +1,16 @@
LIBDIR=`erl -eval 'io:format("~s~n", [code:lib_dir()])' -s init stop -noshell`
PKGNAME=giza
VERSION=0.1.0

all: compile docs

ebin:
mkdir ebin

compile: ebin
cd src;erl -make
cp src/gen_nb_server.app ebin

package: clean
mkdir ebin
@mkdir $(PKGNAME)-$(VERSION)/ && cp -rf ebin Makefile README.markdown src t $(PKGNAME)-$(VERSION)
@COPYFILE_DISABLE=true tar zcf $(PKGNAME)-$(VERSION).tgz $(PKGNAME)-$(VERSION)
@rm -rf $(PKGNAME)-$(VERSION)/
compile:
@./rebar compile

doc:
mkdir -p doc
@mkdir -p doc

docs: doc doc/*.html

doc/*.html:
erl -eval 'edoc:files(["./src/gen_nb_server.erl"])' -noshell -s init stop
mv *.html erlang.png stylesheet.css edoc-info doc
@erl -eval 'edoc:files(["./src/gen_nb_server.erl"])' -noshell -s init stop
@mv *.html erlang.png stylesheet.css edoc-info doc
clean:
rm -f *.tgz *.tar.gz edoc-info *.html erlang.png erl_crash.dump
rm -rf $(PKGNAME)-$(VERSION)
rm -rf ebin
rm -rf doc
rm -f t/*.beam
rm -rf include
@rm -rf doc
@./rebar clean
7 changes: 7 additions & 0 deletions ebin/gen_nb_server.app
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
% -*- mode: erlang -*-
{application, gen_nb_server,
[{description, "Non-blocking TCP socket listener library"},
{vsn, "0.2"},
{modules, [gen_nb_server]},
{registered, []},
{applications, [kernel, stdlib, sasl]}]}.
Binary file added priv/example/ebin/example.beam
Binary file not shown.
Binary file added priv/example/ebin/http_server.beam
Binary file not shown.
Binary file added priv/example/ebin/http_worker.beam
Binary file not shown.
21 changes: 19 additions & 2 deletions priv/example/src/example.erl
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ handle_call(_Msg, _From, State) ->
handle_cast(_Msg, State) ->
{noreply, State}.

handle_info({tcp, Sock, Data}, State) ->
Me = self(),
P = spawn(fun() -> worker(Me, Sock, Data) end),
gen_tcp:controlling_process(Sock, P),
{noreply, State};

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

Expand All @@ -49,6 +55,17 @@ sock_opts() ->
[binary, {active, once}, {packet, 0}].

new_connection(Sock, State) ->
gen_tcp:send(Sock, list_to_binary(io_lib:format("No soup for you!~n", []))),
gen_tcp:close(Sock),
Me = self(),
P = spawn(fun() -> worker(Me, Sock) end),
gen_tcp:controlling_process(Sock, P),
{ok, State}.

worker(Owner, Sock) ->
gen_tcp:send(Sock, "Hello"),
inet:setopts(Sock, [{active, once}]),
gen_tcp:controlling_process(Sock, Owner).

worker(Owner, Sock, Data) ->
gen_tcp:send(Sock, Data),
inet:setopts(Sock, [{active, once}]),
gen_tcp:controlling_process(Sock, Owner).
56 changes: 56 additions & 0 deletions priv/example/src/http_server.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
%% Copyright (c) 2009 Hypothetical Labs, Inc.

%% Permission is hereby granted, free of charge, to any person obtaining a copy
%% of this software and associated documentation files (the "Software"), to deal
%% in the Software without restriction, including without limitation the rights
%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
%% copies of the Software, and to permit persons to whom the Software is
%% furnished to do so, subject to the following conditions:
%%
%% The above copyright notice and this permission notice shall be included in
%% all copies or substantial portions of the Software.
%%
%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
%% THE SOFTWARE.

-module(http_server).

-export([start/0, start_link/2]).

-export([init/1, handle_call/3, handle_cast/2, handle_info/2]).
-export([terminate/2, sock_opts/0, new_connection/2]).

-behavior(gen_nb_server).

start() ->
start_link("0.0.0.0", 9292).

start_link(IpAddr, Port) ->
gen_nb_server:start_link(?MODULE, IpAddr, Port, []).

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

handle_call(_Msg, _From, State) ->
{reply, ignored, State}.

handle_cast(_Msg, State) ->
{noreply, State}.

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

terminate(_Reason, _State) ->
ok.

sock_opts() ->
[binary, {active, once}, {packet, 0}].

new_connection(Sock, State) ->
http_worker:start(Sock),
{ok, State}.
70 changes: 70 additions & 0 deletions priv/example/src/http_worker.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
-module(http_worker).

-behaviour(gen_server).

-define(RESPONSE, "HTTP/1.0 200 OK\r\nConnection: close\r\nContent-Length: 1\r\n\r\nA").
%% API
-export([start/1]).

%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).

-define(SERVER, ?MODULE).

-record(state, {sock}).

configure(Pid) ->
gen_server:call(Pid, configure).

start(Sock) ->
{ok, Pid} = gen_server:start(?MODULE, [Sock], []),
gen_tcp:controlling_process(Sock, Pid),
configure(Pid).

init([Sock]) ->
{ok, #state{sock=Sock}}.


handle_call(configure, _From, #state{sock=Sock}=State) ->
inet:setopts(Sock, [{active, once}, {packet, http}, binary]),
{reply, ok, State};

handle_call(_Request, _From, State) ->
{reply, ignore, State}.

handle_cast(_Msg, State) ->
{noreply, State}.

handle_info({http, Sock, http_eoh}, State) ->
io:format("RESPONSE~n"),
inet:setopts(Sock, [{packet, 0}]),
gen_tcp:send(Sock, list_to_binary(?RESPONSE)),
inet:setopts(Sock, [{packet, http}, {active, once}]),
{noreply, State};

handle_info({http, Sock, {http_header, _, _, _, _}}, State) ->
io:format("HEADER~n"),
inet:setopts(Sock, [{active, once}]),
{noreply, State};

handle_info({http, Sock, {http_request, _, _, _}}, State) ->
io:format("REQUEST~n"),
inet:setopts(Sock, [{active, once}]),
{noreply, State};

handle_info({http, Sock, Data}, #state{sock=Sock}=State) ->
io:format("Data: ~p~n", [Data]),
gen_tcp:close(Sock),
{noreply, State};

handle_info(_Info, State) ->
{noreply, State}.

terminate(_Reason, _State) ->
ok.

code_change(_OldVsn, State, _Extra) ->
{ok, State}.

%% Internal function
Binary file added rebar
Binary file not shown.
4 changes: 0 additions & 4 deletions src/Emakefile

This file was deleted.

19 changes: 17 additions & 2 deletions src/gen_nb_server.erl
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ init([CallbackModule, IpAddr, Port, InitParams]) ->
{ok, ServerState} ->
case listen_on(CallbackModule, IpAddr, Port) of
{ok, Sock} ->
{ok, #state{cb=CallbackModule, sock=Sock, server_state=ServerState}};
maybe_call_listening(CallbackModule, ServerState, Sock);
Error ->
CallbackModule:terminate(Error, ServerState),
Error
Expand Down Expand Up @@ -156,10 +156,25 @@ listen_on(CallbackModule, IpAddr, Port) ->
end.

%% @hidden
%% @spec convert_addr(Addr) -> Result
%% @spec convert(Addr) -> Result
%% Addr = string()
%% Result = {integer(), integer(), integer(), integer()}
%% @doc Converts text IP addresses "0.0.0.0" to tuples {0, 0, 0, 0}
convert(Addr) ->
T = string:tokens(Addr, "."),
list_to_tuple([list_to_integer(X) || X <- T]).

%% @hidden - call listening/2 if it exists and return gen_server response
maybe_call_listening(CallbackModule, ServerState, Sock) ->
case erlang:function_exported(CallbackModule, listening, 2) of
false ->
{ok, #state{cb=CallbackModule, sock=Sock, server_state=ServerState}};
true ->
case CallbackModule:listening(Sock, ServerState) of
{ok, ServerState2} ->
{ok, #state{cb=CallbackModule, sock=Sock, server_state=ServerState2}};
Error ->
CallbackModule:terminate(Error, ServerState),
Error
end
end.

0 comments on commit 2251bfb

Please sign in to comment.