1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 1999-2021. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20
21%%
22%%-----------------------------------------------------------------
23%%
24%% Purpose:
25%%      Interface the TPKT (TCP/IP) transport module for Megaco/H.248
26%%
27%%-----------------------------------------------------------------
28-module(megaco_tcp).
29
30-behaviour(gen_server).
31
32
33%%-----------------------------------------------------------------
34%% Include files
35%%-----------------------------------------------------------------
36-include_lib("megaco/include/megaco.hrl").
37-include_lib("megaco/src/tcp/megaco_tcp.hrl").
38-include_lib("megaco/src/app/megaco_internal.hrl").
39
40
41-define(d1(F, A), ?d("~p " ++ F, [self()|A])).
42-define(d2(F),    ?d1(F, [])).
43
44
45%%-----------------------------------------------------------------
46%% External exports
47%%-----------------------------------------------------------------
48-export([
49	 start_transport/0, %% Start TPKT transport service
50	 stop_transport/1,  %% Stop TPKT transport service
51	 listen/2,          %% Starts a new listener socket
52	 connect/2,         %% Used on client side to connect server
53	 socket/1,          %% Returns the inet socket
54	 send_message/2,    %% Used to send data on connection
55	 block/1,           %% Used to block the socket for incomming
56	                    %% messages
57	 unblock/1,         %% Used to unblock the node
58	 close/1,           %% Used on both sides to close connection
59
60	 upgrade_receive_handle/2
61	]).
62
63%% Statistics exports
64-export([
65	 get_stats/0, get_stats/1, get_stats/2,
66	 reset_stats/0, reset_stats/1
67	]).
68
69%% -export([tcp_sockets/0]).
70
71
72%%-----------------------------------------------------------------
73%% Internal exports
74%%-----------------------------------------------------------------
75-export([
76	 start_link/1,       %% Start TCP/IP net server
77	 init/1,             %%
78	 terminate/2,
79	 handle_call/3,
80	 handle_cast/2,
81	 handle_info/2,
82	 code_change/3,
83	 start_connection/2
84	]).
85
86
87%%-----------------------------------------------------------------
88%% Server state record
89%%-----------------------------------------------------------------
90-record(state, {supervisor_pid, linkdb}).
91
92
93%%-----------------------------------------------------------------
94%% External interface functions
95%%-----------------------------------------------------------------
96
97%%-----------------------------------------------------------------
98%% Func: get_stats/0, get_stats/1, get_stats/2
99%% Description: Retreive statistics (counters) for TCP
100%%-----------------------------------------------------------------
101get_stats() ->
102    megaco_stats:get_stats(megaco_tcp_stats).
103
104get_stats(Socket) ->
105    megaco_stats:get_stats(megaco_tcp_stats, Socket).
106
107get_stats(Socket, Counter) ->
108    megaco_stats:get_stats(megaco_tcp_stats, Socket, Counter).
109
110
111%%-----------------------------------------------------------------
112%% Func: reset_stats/0, reaet_stats/1
113%% Description: Reset statistics (counters) for TCP
114%%-----------------------------------------------------------------
115reset_stats() ->
116    megaco_stats:reset_stats(megaco_tcp_stats).
117
118reset_stats(Socket) ->
119    megaco_stats:reset_stats(megaco_tcp_stats, Socket).
120
121
122%%-----------------------------------------------------------------
123%% Func: start_transport/0
124%% Description: Starts the TPKT transport service
125%%-----------------------------------------------------------------
126start_transport() ->
127    ?d2("start_transport -> entry"),
128    (catch megaco_stats:init(megaco_tcp_stats)),
129    megaco_tcp_sup:start_link().
130
131
132%%-----------------------------------------------------------------
133%% Func: stop_transport/1, 2
134%% Description: Stop the TPKT transport service
135%%-----------------------------------------------------------------
136stop_transport(Pid) ->
137    (catch unlink(Pid)),
138    stop_transport(Pid, shutdown).
139
140stop_transport(Pid, Reason) ->
141    ?d1("stop_transport -> entry with"
142	"~n   Pid:    ~p"
143	"~n   Reason: ~p", [Pid, Reason]),
144    exit(Pid, Reason).
145
146
147%%-----------------------------------------------------------------
148%% Func: listen/2
149%% Description: Starts new TPKT listener sockets
150%%-----------------------------------------------------------------
151listen(SupPid, Parameters) ->
152    ?d1("listen -> entry with"
153	"~n   SupPid:     ~p"
154	"~n   Parameters: ~p", [SupPid, Parameters]),
155    ProcList = supervisor:which_children(SupPid),
156    case lists:keysearch(megaco_tcp, 1, ProcList) of
157	{value, {_Name, Pid, _Type, _Modules}} ->
158	    ?d1("listen -> found listener: "
159		"~n   Pid: ~p", [Pid]),
160	    call(Pid, {add_listener, Parameters});
161	false ->
162	    {error, no_tcp_server}
163    end.
164
165
166%%-----------------------------------------------------------------
167%% Func: connect
168%% Description: Function is used when opening an TCP socket
169%%              at the MG side when trying to connect an MGC
170%%-----------------------------------------------------------------
171connect(SupPid, Parameters) ->
172    ?d1("connect -> entry with"
173	"~n   SupPid:     ~p"
174	"~n   Parameters: ~p", [SupPid, Parameters]),
175    Mand = [host, port, receive_handle],
176    case parse_options(Parameters, #megaco_tcp{}, Mand) of
177	{ok, Rec} ->
178
179	    ?d1("connect -> options parsed: "
180		"~n   Rec: ~p", [Rec]),
181
182	    #megaco_tcp{host         = Host,
183			port         = Port,
184			options      = Options,
185                        inet_backend = IB} = Rec,
186
187	    IpOpt =
188                case IB of
189                    default ->
190                        [];
191                    _ ->
192                        [{inet_backend, IB}]
193                end ++ [binary, {packet, tpkt}, {active, once} | Options],
194
195            %%------------------------------------------------------
196            %% Connect the other side
197	    case (catch gen_tcp:connect(Host, Port, IpOpt)) of
198		{ok, Socket} ->
199		    ?d1("connect -> connected: "
200			"~n   Socket: ~p", [Socket]),
201                    %%----------------------------------------------
202                    %% Socket up start a new control process
203		    Rec2 = Rec#megaco_tcp{socket = Socket},
204		    case start_connection(SupPid, Rec2) of
205			{ok, Pid} ->
206			    ?d1("connect -> connection started: "
207				"~n   Pid: ~p", [Pid]),
208			    gen_tcp:controlling_process(Socket, Pid),
209			    ?d2("connect -> control transferred"),
210			    {ok, Socket, Pid};
211			{error, Reason} ->
212			    ?d1("connect -> failed starting connection: "
213				"~n   Reason: ~p", [Reason]),
214			    {error, Reason}
215		    end;
216
217		{error, Reason} ->
218		    ?d1("connect -> failed connecting: "
219			"~n   Reason: ~p", [Reason]),
220		    Error = {error, {gen_tcp_connect, Reason}},
221		    ?tcp_debug(Rec, "tcp connect failed", [Error]),
222		    Error;
223
224		{'EXIT', _Reason} = Exit ->
225		    ?d1("connect -> connect exited: "
226			"~n   Exit: ~p", [Exit]),
227		    Error = {error, {gen_tcp_connect, Exit}},
228		    ?tcp_debug(Rec, "tcp connect failed", [Error]),
229		    Error
230
231	    end;
232
233	{error, _Reason} = Error ->
234	    ?d1("connect -> failed parsing options: "
235		"~n   Error: ~p", [Error]),
236	    ?tcp_debug(#megaco_tcp{}, "tcp connect failed",
237		       [Error, {options, Parameters}]),
238	    Error
239    end.
240
241
242%%-----------------------------------------------------------------
243%% Func: send_message
244%% Description: Function is used for sending data on the TCP socket
245%%-----------------------------------------------------------------
246send_message(Socket, Data) ->
247    ?d1("send_message -> entry with"
248	"~n   Socket:     ~p"
249	"~n   size(Data): ~p", [Socket, sz(Data)]),
250    {Size, NewData} = add_tpkt_header(Data),
251    Res = gen_tcp:send(Socket, NewData),
252    case Res of
253	ok ->
254	    incNumOutMessages(Socket),
255	    incNumOutOctets(Socket, Size);
256	_ ->
257	    ok
258    end,
259    Res.
260
261-ifdef(megaco_debug).
262sz(Bin) when is_binary(Bin) ->
263    size(Bin);
264sz(List) when is_list(List) ->
265    length(List).
266-endif.
267
268
269%%-----------------------------------------------------------------
270%% Func: block
271%% Description: Function is used for blocking incomming messages
272%%              on the TCP socket
273%%-----------------------------------------------------------------
274block(Socket) ->
275    ?tcp_debug({socket, Socket}, "tcp block", []),
276    inet:setopts(Socket, [{active, false}]).
277
278
279%%-----------------------------------------------------------------
280%% Func: unblock
281%% Description: Function is used for blocking incomming messages
282%%              on the TCP socket
283%%-----------------------------------------------------------------
284unblock(Socket) ->
285    ?tcp_debug({socket, Socket}, "tcp unblock", []),
286    inet:setopts(Socket, [{active, once}]).
287
288
289%%-----------------------------------------------------------------
290%% Func: close
291%% Description: Function is used for closing the TCP socket
292%%-----------------------------------------------------------------
293close(Socket) ->
294    ?tcp_debug({socket, Socket}, "tcp close", []),
295    gen_tcp:close(Socket).
296
297
298%%-----------------------------------------------------------------
299%% Func: socket
300%% Description: Returns the inet socket
301%%-----------------------------------------------------------------
302socket(Socket) ->
303    Socket.
304
305upgrade_receive_handle(Pid, NewHandle)
306  when is_pid(Pid) andalso is_record(NewHandle, megaco_receive_handle) ->
307    megaco_tcp_connection:upgrade_receive_handle(Pid, NewHandle).
308
309
310%%-----------------------------------------------------------------
311%% Internal Interface functions
312%%-----------------------------------------------------------------
313%%-----------------------------------------------------------------
314%% Func: start_link/1
315%% Description: Starts the net server
316%%-----------------------------------------------------------------
317start_link(Args) ->
318    gen_server:start_link(?MODULE, Args, []).
319
320
321%%-----------------------------------------------------------------
322%% Func: start_connection
323%% Description: Function is used for starting up a connection
324%%              process
325%%-----------------------------------------------------------------
326start_connection(SupPid, #megaco_tcp{socket = Socket} = TcpRec) ->
327    ?d1("start_connection -> entry with"
328	"~n   SupPid: ~p"
329	"~n   Socket: ~p", [SupPid, Socket]),
330
331    case connection_sup(SupPid) of
332	{ok, ConnSupPid} ->
333	    ?d1("start_connection -> found connection supervisor: "
334		"~n   ConnSupPid: ~p", [ConnSupPid]),
335	    ?tcp_debug(TcpRec, "tcp connect", []),
336	    case create_connection(ConnSupPid, TcpRec) of
337		{ok, Pid} ->
338		    ?d1("start_connection -> started: "
339			"~n   Pid: ~p", [Pid]),
340		    ?tcp_debug(TcpRec, "connect handler started", [Pid]),
341		    create_snmp_counters(Socket),
342		    {ok, Pid};
343		{error, Reason} ->
344		    ?d1("start_connection -> failed starting: "
345			"~n   Reason: ~p", [Reason]),
346		    Error = {error, {controlling_process_not_started, Reason}},
347		    ?tcp_debug(TcpRec, "tcp connect failed", [Error]),
348		    Error
349	    end;
350	{error, _Reason} ->
351	    ?d2("start_connection -> could not find connection supervisor"),
352	    Error = {error, no_connection_supervisor},
353	    ?tcp_debug(TcpRec, "tcp connect failed", [Error]),
354	    Error
355    end.
356
357connection_sup(Pid) ->
358    megaco_tcp_sup:which_connection_sup(Pid).
359
360create_connection(Pid, Rec) ->
361    megaco_tcp_connection_sup:start_child(Pid, Rec).
362
363create_snmp_counters(Socket) ->
364    Counters = [medGwyGatewayNumInMessages,
365                medGwyGatewayNumInOctets,
366                medGwyGatewayNumOutMessages,
367                medGwyGatewayNumOutOctets,
368                medGwyGatewayNumErrors],
369    create_snmp_counters(Socket, Counters).
370
371create_snmp_counters(_Socket, []) ->
372    ok;
373create_snmp_counters(Socket, [Counter|Counters]) ->
374    Key = {Socket, Counter},
375    ets:insert(megaco_tcp_stats, {Key, 0}),
376    create_snmp_counters(Socket, Counters).
377
378
379%%-----------------------------------------------------------------
380%% Server functions
381%%-----------------------------------------------------------------
382%%-----------------------------------------------------------------
383%% Func: init/1
384%% Description: Init funcion for the supervisor
385%%-----------------------------------------------------------------
386init({SupPid, _}) ->
387    process_flag(trap_exit, true),
388    {ok, #state{supervisor_pid = SupPid, linkdb = []}}.
389
390%%-----------------------------------------------------------------
391%% Func: terminate/1
392%% Description: Termination function for the generic server
393%%-----------------------------------------------------------------
394terminate(_Reason, _State) ->
395    ok.
396
397
398%%-----------------------------------------------------------------
399%% Internal Functions
400%%-----------------------------------------------------------------
401
402%%-----------------------------------------------------------------
403%% Func: start_tcp_listener/2
404%% Description: Function which parses the list of transport layers
405%%              to start
406%%-----------------------------------------------------------------
407start_tcp_listener(P, State) ->
408    ?d1("start_tcp_listener -> entry with"
409	"~n   P: ~p", [P]),
410    case setup(State#state.supervisor_pid, P) of
411	{ok, Pid, Data} ->
412	    ?d1("start_tcp_listener -> setup ok"
413		"~n   Pid:  ~p"
414		"~n   Data: ~p", [Pid, Data]),
415	    link(Pid),
416	    {reply, ok,
417	     State#state{linkdb=[{Pid, Data} | State#state.linkdb]}};
418	{error, Reason} ->
419	    ?d1("start_tcp_listener -> setup failed"
420		"~n   Reason: ~p", [Reason]),
421            DB       = State#state.linkdb,
422            DBStatus = [{LPid, {LRec, LSock}, inet:info(LSock)} ||
423                           {LPid, {LRec, LSock}} <- DB],
424            Reply = {error, {could_not_start_listener, Reason, DBStatus}},
425	    {reply, Reply, State}
426    end.
427
428
429%%-----------------------------------------------------------------
430%% Func: handle_call/3
431%% Description: Handling call messages (really just garbage)
432%%-----------------------------------------------------------------
433handle_call({add_listener, Parameters}, _From, State) ->
434    ?d1("handle_call(add_listener) -> entry with"
435	"~n   Parameters: ~p", [Parameters]),
436    start_tcp_listener(Parameters, State);
437handle_call(Req, From, State) ->
438    warning_msg("received unexpected request from ~p: "
439		"~n~w", [From, Req]),
440    {noreply, State}.
441
442
443%%------------------------------------------------------------
444%% Func: handle_cast/2
445%% Description: Handling cast messages (really just garbage)
446%%------------------------------------------------------------
447handle_cast(Msg, State) ->
448    warning_msg("received unexpected message: "
449		"~n~w", [Msg]),
450    {noreply,  State}.
451
452
453%%-----------------------------------------------------------------
454%% Func: handle_info/2
455%% Description: Handling non call/cast messages, eg exit messages
456%%-----------------------------------------------------------------
457handle_info({'EXIT', Pid, Reason}, State) when is_pid(Pid) ->
458    %% Accept process died
459    NewState = resetup(Pid, Reason, State),
460    {noreply, NewState};
461handle_info(Info, State) ->
462    warning_msg("received unexpected info: "
463		"~n~w", [Info]),
464    {noreply,  State}.
465
466
467%%-----------------------------------------------------------------
468%% Func: code_change/3
469%% Descrition: Handles code change messages during upgrade.
470%%-----------------------------------------------------------------
471code_change(_Vsn, State, _Extra) ->
472    {ok, State}.
473
474
475%%-----------------------------------------------------------------
476%% Internal functions
477%%-----------------------------------------------------------------
478%%-----------------------------------------------------------------
479%% Func: setup/2
480%% Description: Function is used when setting up an TCP listen
481%%              socket in the MGC
482%%-----------------------------------------------------------------
483setup(SupPid, Options) ->
484    ?d1("setup -> entry with"
485	"~n   SupPid:  ~p"
486	"~n   Options: ~p", [SupPid, Options]),
487    Mand = [port, receive_handle],
488    case parse_options(Options, #megaco_tcp{}, Mand) of
489	{ok, TcpRec} ->
490
491	    ?d1("setup -> options parsed"
492		"~n   TcpRec: ~p", [TcpRec]),
493
494            %%------------------------------------------------------
495            %% Setup the listen socket
496	    IpOpts =
497                case TcpRec#megaco_tcp.inet_backend of
498                    default ->
499                        [];
500                    IB ->
501                        [{inet_backend, IB}]
502                end ++
503                [binary, {packet, tpkt}, {active, once},
504                 {reuseaddr, true} | TcpRec#megaco_tcp.options],
505            Port = TcpRec#megaco_tcp.port,
506	    case catch gen_tcp:listen(Port, IpOpts) of
507		{ok, LSock} ->
508
509		    ?d1("setup -> listen ok"
510			"~n   Listen: ~p", [Listen]),
511
512	            %%-----------------------------------------------
513	            %% Startup the accept process that will wait for
514	            %% connect attempts
515		    case start_accept(SupPid, TcpRec, LSock) of
516			{ok, Pid} ->
517			    ?d1("setup -> accept process started"
518				"~n   Pid: ~p", [Pid]),
519			    ?tcp_debug(TcpRec, "tcp listen setup", []),
520			    {ok, Pid, {TcpRec, LSock}};
521
522			{error, _Reason} = Error ->
523			    ?d1("setup -> failed starting accept process"
524				"~n   Error: ~p", [Error]),
525			    ?tcp_debug(TcpRec, "tcp listen setup failed",
526				       [Error]),
527			    Error
528		    end;
529
530		{error, Reason} ->
531		    ?d1("setup -> listen failed"
532			"~n   Reason: ~p", [Reason]),
533		    Error = {error, {gen_tcp_listen, Reason, [Port, IpOpts]}},
534		    ?tcp_debug(TcpRec, "tcp listen setup failed", [Error]),
535		    Error;
536		{'EXIT', _Reason} = Exit ->
537		    ?d1("setup -> listen exited"
538			"~n   Exit: ~p", [Exit]),
539		    Error = {error, {gen_tcp_listen, Exit, [Port, IpOpts]}},
540		    ?tcp_debug(TcpRec, "tcp listen setup failed", [Error]),
541		    Error
542	    end;
543	{error, _Reason} = Error ->
544	    ?d1("setup -> failed parsing options"
545		"~n   Error: ~p", [Error]),
546	    ?tcp_debug(#megaco_tcp{}, "tcp listen setup failed",
547		       [Error, {options, Options}]),
548	    Error
549    end.
550
551
552%%-----------------------------------------------------------------
553%% Func: resetup
554%% Description: Function is used when restarting the accept process
555%%              if it died for some reason.
556%%-----------------------------------------------------------------
557
558resetup(Pid, Reason, State) ->
559    ?d1("resetup -> entry with"
560	"~n   Pid:    ~p"
561	"~n   Reason: ~p", [Pid, Reason]),
562    case lists:keysearch(Pid, 1, State#state.linkdb) of
563	{value, {Pid, {TcpRec, Listener}}} ->
564	    ?d1("resetup -> found accept process: "
565		"~n   TcpRec:   ~p"
566		"~n   Listener: ~p", [TcpRec, Listener]),
567	    ?tcp_debug(TcpRec, "tcp listen resetup", [{error, Reason}]),
568	    unlink(Pid),
569	    warning_msg("received unexpected 'EXIT' signal "
570			"from accept process ~p: "
571			"~n~w", [Pid, Reason]),
572	    case start_accept(State#state.supervisor_pid, TcpRec, Listener) of
573		{ok, NewPid} ->
574		    ?d1("resetup -> start new accept process ok: "
575			"~n   NewPid: ~p", [NewPid]),
576		    link(NewPid),
577		    NewList = lists:keyreplace(Pid, 1, State#state.linkdb,
578					       {NewPid, {TcpRec, Listener}}),
579		    State#state{linkdb = NewList};
580		{error, Reason} ->
581		    ?d1("resetup -> failed starting new accept process: "
582			"~n   :Reason ~p", [Reason]),
583		    ?tcp_debug(TcpRec,
584			       "tcp listen resetup failed", [{error, Reason}]),
585		    State
586	    end;
587	false ->
588	    warning_msg("received unexpected 'EXIT' signal from ~p: "
589			"~n~w", [Pid, Reason]),
590	    State
591    end.
592
593
594%%-----------------------------------------------------------------
595%% Func: start_accept
596%% Description: Function is used for starting up an TCP accept
597%%              process
598%%-----------------------------------------------------------------
599start_accept(SupPid, TcpRec, Listen) ->
600    ?d1("start_accept -> entry with"
601	"~n   SupPid: ~p"
602	"~n   TcpRec: ~p"
603	"~n   Reason: ~p", [SupPid, TcpRec, Listen]),
604    case accept_sup(SupPid) of
605	{ok, AcceptSupPid} ->
606	    ?d1("start_accept -> found accept supervisor"
607		"~n   AcceptSupPid: ~p", [AcceptSupPid]),
608	    case create_acceptor(AcceptSupPid, TcpRec, SupPid, Listen) of
609		{ok, Pid} ->
610		    ?d1("start_accept -> accept process started"
611			"~n   Pid: ~p", [Pid]),
612		    {ok, Pid};
613		{error, Reason} ->
614		    ?d1("start_accept -> failed starting accept process: "
615			"~n   Reason: ~p", [Reason]),
616		    {error, {accept_not_started, Reason}}
617	    end;
618	{error, Reason} ->
619	    ?d1("start_accept -> could not find acceept supervisor: "
620		"~n   Reason: ~p", [Reason]),
621	    {error, {no_tcp_accept_sup, Reason}}
622    end.
623
624accept_sup(Pid) ->
625    megaco_tcp_sup:which_accept_sup(Pid).
626
627create_acceptor(Pid, Rec, TopSup, Listen) ->
628    megaco_tcp_accept_sup:start_child(Pid, Rec, TopSup, Listen).
629
630
631%%-----------------------------------------------------------------
632%% Func: add_tpkt_header
633%% Description: Function is used to add the TPKT header
634%%-----------------------------------------------------------------
635add_tpkt_header(Data) when is_binary(Data) ->
636    L = size(Data) + 4,
637    {L, [3, 0, ((L) bsr 8) band 16#ff, (L) band 16#ff ,Data]};
638add_tpkt_header(IOList) when is_list(IOList) ->
639    Binary = list_to_binary(IOList),
640    L = size(Binary) + 4,
641    {L, [3, 0, ((L) bsr 8) band 16#ff, (L) band 16#ff , Binary]}.
642
643%%-----------------------------------------------------------------
644%% Func: parse_options
645%% Description: Function that parses the options sent to the TCP
646%%              module.
647%%-----------------------------------------------------------------
648parse_options([{Tag, Val} | T], TcpRec, Mand) ->
649    ?d1("parse_options -> entry with"
650	"~n   Tag: ~p"
651	"~n   Val: ~p", [Tag, Val]),
652    Mand2 = Mand -- [Tag],
653    case Tag of
654	port ->
655	    parse_options(T, TcpRec#megaco_tcp{port = Val}, Mand2);
656	host ->
657	    parse_options(T, TcpRec#megaco_tcp{host = Val}, Mand2);
658	tcp_options when is_list(Val) ->
659	    parse_options(T, TcpRec#megaco_tcp{options = Val}, Mand2);
660	receive_handle ->
661	    parse_options(T, TcpRec#megaco_tcp{receive_handle = Val}, Mand2);
662	module when is_atom(Val) ->
663	    parse_options(T, TcpRec#megaco_tcp{module = Val}, Mand2);
664	serialize when (Val =:= true) orelse (Val =:= false) ->
665	    parse_options(T, TcpRec#megaco_tcp{serialize = Val}, Mand2);
666	inet_backend when (Val =:= default) orelse
667                          (Val =:= inet) orelse
668                          (Val =:= socket)  ->
669	    parse_options(T, TcpRec#megaco_tcp{inet_backend = Val}, Mand2);
670        Bad ->
671	    ?d1("parse_options -> bad option: "
672		"~n   Tag: ~p", [Tag]),
673	    {error, {bad_option, Bad}}
674    end;
675parse_options([], TcpRec, []) ->
676    ?d2("parse_options -> done"),
677    {ok, TcpRec};
678parse_options([], _TcpRec, Mand) ->
679    ?d1("parse_options -> entry with"
680	"~n   Mand: ~p", [Mand]),
681    {error, {missing_options, Mand}};
682parse_options(BadList, _TcpRec, _Mand) ->
683    ?d1("parse_options -> entry with"
684	"~n   BadList: ~p", [BadList]),
685    {error, {bad_option_list, BadList}}.
686
687
688%%-----------------------------------------------------------------
689%% Func: incNumOutMessages/1, incNumOutOctets/2, incNumErrors/1
690%% Description: SNMP counter increment functions
691%%
692%%-----------------------------------------------------------------
693incNumOutMessages(Socket) ->
694    incCounter({Socket, medGwyGatewayNumOutMessages}, 1).
695
696incNumOutOctets(Socket, NumOctets) ->
697    incCounter({Socket, medGwyGatewayNumOutOctets}, NumOctets).
698
699incCounter(Key, Inc) ->
700    ets:update_counter(megaco_tcp_stats, Key, Inc).
701
702% incNumErrors(Socket) ->
703%     ets:update_counter(megaco_tcp_stats,
704% 		       {Socket, medGwyGatewayNumErrors}, 1).
705
706
707%%-----------------------------------------------------------------
708
709
710warning_msg(F, A) ->
711    ?megaco_warning("TCP server: " ++ F, A).
712
713%% error_msg(F, A) ->
714%%     ?megaco_error("TCP server: " ++ F, A).
715
716
717call(Pid, Req) ->
718    gen_server:call(Pid, Req, infinity).
719
720
721%%-----------------------------------------------------------------
722
723%% formated_timestamp() ->
724%%     format_timestamp(os:timestamp()).
725
726%% format_timestamp(TS) ->
727%%     megaco:format_timestamp(TS).
728
729%% d(F) ->
730%%     d(F, []).
731
732%% d(F, A) ->
733%%     io:format("*** [~s] ~p ~w " ++ F ++ "~n",
734%%               [formated_timestamp(), self(), ?MODULE | A]).
735
736
737%%-----------------------------------------------------------------
738
739%% tcp_sockets() ->
740%%     port_list("tcp_inet") ++ gen_tcp_socket:which_sockets().
741
742
743%% %% Return all ports having the name 'Name'
744%% port_list(Name) ->
745%%     lists:filter(
746%%       fun(Port) ->
747%%               case erlang:port_info(Port, name) of
748%%                   {name, Name} -> true;
749%%                   _ -> false
750%%               end
751%%       end, erlang:ports()).
752
753