Permalink
Browse files

rebar-ified build;Added optional callback listening/2 for notifying b…

…ehavior impls when a dynamic port is chosen
  • Loading branch information...
1 parent 33f8d12 commit 2251bfba2fde0e4bbb12b51d386f85d58782d50c @kevsmith committed Apr 15, 2010
View
@@ -0,0 +1 @@
+ebin/*.beam
View
@@ -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
View
@@ -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 not shown.
Binary file not shown.
Binary file not shown.
@@ -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}.
@@ -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).
@@ -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}.
@@ -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
View
BIN rebar
Binary file not shown.
View
@@ -1,4 +0,0 @@
-{"*", [warn_obsolete_guard, warn_unused_import,
- warn_shadow_vars, warn_export_vars, debug_info,
- {i, "../include"},
- {outdir, "../ebin"}]}.
View
@@ -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
@@ -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.