Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 207 lines (183 sloc) 7.533 kb
bd5d6fa @nniclausse add option to scan ip aliases on a given interface at runtime on clients
nniclausse authored
1 %%% This program is free software; you can redistribute it and/or modify
2 %%% it under the terms of the GNU General Public License as published by
3 %%% the Free Software Foundation; either version 2 of the License, or
4 %%% (at your option) any later version.
5 %%%
6 %%% This program is distributed in the hope that it will be useful,
7 %%% but WITHOUT ANY WARRANTY; without even the implied warranty of
8 %%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 %%% GNU General Public License for more details.
10 %%%
11 %%% You should have received a copy of the GNU General Public License
12 %%% along with this program; if not, write to the Free Software
13 %%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
14 %%%
15 %%% Created : 9 Aug 2010 by Nicolas Niclausse <nicolas@niclux.org>
16
17 %%% In addition, as a special exception, you have the permission to
18 %%% link the code of this program with any library released under
19 %%% the EPL license and distribute linked combinations including
20 %%% the two.
21
22 %%%-------------------------------------------------------------------
23 %%% @author Nicolas Niclausse <nicolas@niclux.org>
24 %%% @copyright (C) 2010, Nicolas Niclausse
25 %%% @doc
26 %%%
27 %%% @end
28 %%% Created : 9 Aug 2010 by Nicolas Niclausse <>
29 %%%-------------------------------------------------------------------
30 -module(ts_ip_scan).
31
32 -behaviour(gen_server).
33
583ea5e @nniclausse put macros in a separated header file; add NOW macro
nniclausse authored
34 -include("ts_macros.hrl").
bd5d6fa @nniclausse add option to scan ip aliases on a given interface at runtime on clients
nniclausse authored
35
36 %% API
37 -export([start_link/0, get_ip/1]).
38
39 %% gen_server callbacks
40 -export([init/1, handle_call/3, handle_cast/2, handle_info/2,
41 terminate/2, code_change/3]).
42
43 -define(SERVER, ?MODULE).
44
45 -record(state, {ips}).
46
47 %%%===================================================================
48 %%% API
49 %%%===================================================================
50 get_ip(Interface) ->
51 gen_server:call(?MODULE, {get_ip, Interface}).
52
53 %%--------------------------------------------------------------------
54 %% @doc
55 %% Starts the server
56 %%
57 %% @spec start_link() -> {ok, Pid} | ignore | {error, Error}
58 %% @end
59 %%--------------------------------------------------------------------
60 start_link() ->
61 gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
62
63 %%%===================================================================
64 %%% gen_server callbacks
65 %%%===================================================================
66
67 %%--------------------------------------------------------------------
68 %% @private
69 %% @doc
70 %% Initializes the server
71 %%
72 %% @spec init(Args) -> {ok, State} |
73 %% {ok, State, Timeout} |
74 %% ignore |
75 %% {stop, Reason}
76 %% @end
77 %%--------------------------------------------------------------------
78 init([]) ->
79 ?LOG("Starting ~n",?INFO),
80 {ok, #state{}}.
81
82 %%--------------------------------------------------------------------
83 %% @private
84 %% @doc
85 %% Handling call messages
86 %%
87 %% @spec handle_call(Request, From, State) ->
88 %% {reply, Reply, State} |
89 %% {reply, Reply, State, Timeout} |
90 %% {noreply, State} |
91 %% {noreply, State, Timeout} |
92 %% {stop, Reason, Reply, State} |
93 %% {stop, Reason, State}
94 %% @end
95 %%--------------------------------------------------------------------
96 handle_call({get_ip, Interface}, _From, State=#state{ips=undefined}) ->
97 [Val|Rest] = get_intf_aliases(Interface),
98 {reply, Val, State#state{ips=Rest ++ [Val]}};
99 handle_call({get_ip, _}, _From, State=#state{ips=[Val|Rest]}) ->
100 {reply, Val, State#state{ips=Rest ++ [Val]}}.
101
102 %%--------------------------------------------------------------------
103 %% @private
104 %% @doc
105 %% Handling cast messages
106 %%
107 %% @spec handle_cast(Msg, State) -> {noreply, State} |
108 %% {noreply, State, Timeout} |
109 %% {stop, Reason, State}
110 %% @end
111 %%--------------------------------------------------------------------
112 handle_cast(_Msg, State) ->
113 {noreply, State}.
114
115 %%--------------------------------------------------------------------
116 %% @private
117 %% @doc
118 %% Handling all non call/cast messages
119 %%
120 %% @spec handle_info(Info, State) -> {noreply, State} |
121 %% {noreply, State, Timeout} |
122 %% {stop, Reason, State}
123 %% @end
124 %%--------------------------------------------------------------------
125 handle_info(_Info, State) ->
126 {noreply, State}.
127
128 %%--------------------------------------------------------------------
129 %% @private
130 %% @doc
131 %% This function is called by a gen_server when it is about to
132 %% terminate. It should be the opposite of Module:init/1 and do any
133 %% necessary cleaning up. When it returns, the gen_server terminates
134 %% with Reason. The return value is ignored.
135 %%
136 %% @spec terminate(Reason, State) -> void()
137 %% @end
138 %%--------------------------------------------------------------------
139 terminate(_Reason, _State) ->
140 ok.
141
142 %%--------------------------------------------------------------------
143 %% @private
144 %% @doc
145 %% Convert process state when code is changed
146 %%
147 %% @spec code_change(OldVsn, State, Extra) -> {ok, NewState}
148 %% @end
149 %%--------------------------------------------------------------------
150 code_change(_OldVsn, State, _Extra) ->
151 {ok, State}.
152
153 %%%===================================================================
154 %%% Internal functions
155 %%%===================================================================
156
157 %%
158 get_intf_aliases(Interface) ->
e79b768 @nniclausse use 'ip' instead of 'ifconfig' by default (TSUN-187)
nniclausse authored
159 case file:read_file_info("/sbin/ip") of
160 {ok,_} ->
161 Res=os:cmd("LC_ALL=C /sbin/ip -o -f inet addr show dev "++Interface),
162 get_ip_aliases(string:tokens(Res,"\n"), []);
163 {error,Reason} ->
164 ?LOGF("ip command not found (~p), using ifconfig instead~n",[Reason],?NOTICE),
165 Res=os:cmd("LC_ALL=C /sbin/ifconfig "),
166 get_intf_aliases(string:tokens(Res,"\n"), Interface,[],[])
167 end.
168
169
170 get_ip_aliases([], Res) ->
171 Res;
172 get_ip_aliases([Line|Tail], Res) ->
173 [_,_,_,Net|_] =string:tokens(Line," "),
174 [TmpIP|_] =string:tokens(Net,"/"),
175 ?LOGF("found IP: ~p~n",[TmpIP],?DEB),
176 {ok, IP } = inet:getaddr(TmpIP,inet),
177 get_ip_aliases(Tail, [IP|Res]).
178
bd5d6fa @nniclausse add option to scan ip aliases on a given interface at runtime on clients
nniclausse authored
179
180 get_intf_aliases([], _, _, Res) ->
181 Res;
182 get_intf_aliases([" inet addr:"++Line|Tail], Interface, Interface, Res) ->
183 [TmpIP|_] =string:tokens(Line," "),
184 ?LOGF("found IP: ~p~n",[TmpIP],?DEB),
185 {ok, IP } = inet:getaddr(TmpIP,inet),
186 get_intf_aliases(Tail, Interface, Interface, lists:append([IP],Res));
187 get_intf_aliases([" "++_Line|Tail], Interface, Current, Res) ->
188 get_intf_aliases(Tail, Interface, Current, Res);
ec5ee1e @nniclausse scan_intf: handle empty line with a single space in ifconfig output
nniclausse authored
189 get_intf_aliases([" "|Tail], Interface, Old, Res) ->
190 get_intf_aliases(Tail, Interface, Old, Res);
bd5d6fa @nniclausse add option to scan ip aliases on a given interface at runtime on clients
nniclausse authored
191 get_intf_aliases([Line|Tail], Interface, Old, Res) ->
ec5ee1e @nniclausse scan_intf: handle empty line with a single space in ifconfig output
nniclausse authored
192 ?LOGF("scan line : ~p~n",[Line],?DEB),
193 %% ?DebugF("scan line : ~p~n",[Line]),
bd5d6fa @nniclausse add option to scan ip aliases on a given interface at runtime on clients
nniclausse authored
194 case string:str(Line,Interface) of
195 1 ->
196 [Current|_] =string:tokens(Line," "),
197 ?LOGF("found interface (old is ~p): ~p~n",[Old,Current],?DEB),
198 case string:str(Current, Old++":") of
199 1 -> % subinterface, don't change current
200 get_intf_aliases(Tail, Interface, Old, Res);
201 _ ->
202 get_intf_aliases(Tail, Interface, Current, Res)
203 end;
204 _ ->
205 get_intf_aliases(Tail, Interface, "", Res)
206 end.
Something went wrong with that request. Please try again.