1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2018-2020. 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-module(socket_server).
22
23-export([
24         start/0, start/5,
25         start_tcp/0,  start_tcp/1,  start_tcp/3,
26         start_tcp4/0, start_tcp4/1, start_tcp4/2,
27         start_tcp6/0, start_tcp6/1, start_tcp6/2,
28         start_udp/0,  start_udp/1,  start_udp/3,
29         start_udp4/0, start_udp4/1, start_udp4/2,
30         start_udp6/0, start_udp6/1, start_udp6/2,
31         start_sctp/0, start_sctp/1
32        ]).
33
34-define(LIB, socket_lib).
35
36-record(manager,  {socket, msg, peek, acceptors, handler_id, handlers}).
37-record(acceptor, {id, socket, manager,
38                   atimeout = 5000}).
39-record(handler,  {socket, peek, msg, type, manager,
40                   stimeout = 5000, rtimeout = 5000}).
41
42-define(NUM_ACCEPTORS, 5).
43
44start() ->
45    start_tcp().
46
47start_tcp() ->
48    start_tcp4().
49
50start_tcp(Peek) ->
51    start_tcp4(Peek).
52
53start_tcp4() ->
54    start_tcp4(false).
55
56start_tcp4(Peek) ->
57    start_tcp4(false, Peek).
58
59start_tcp4(UseMsg, Peek) ->
60    start_tcp(inet, UseMsg, Peek).
61
62start_tcp6() ->
63    start_tcp6(false).
64
65start_tcp6(Peek) ->
66    start_tcp6(false, Peek).
67
68start_tcp6(UseMsg, Peek) ->
69    start_tcp(inet6, UseMsg, Peek).
70
71start_tcp(Domain, UseMsg, Peek) when is_boolean(UseMsg) andalso is_boolean(Peek) ->
72    start(Domain, stream, tcp, UseMsg, Peek).
73
74start_udp() ->
75    start_udp4().
76
77start_udp(Peek) ->
78    start_udp4(Peek).
79
80start_udp4() ->
81    start_udp4(false).
82
83start_udp4(Peek) ->
84    start_udp4(false, Peek).
85
86start_udp4(UseMsg, Peek) ->
87    start_udp(inet, UseMsg, Peek).
88
89start_udp6() ->
90    start_udp6(false, false).
91
92start_udp6(Peek) ->
93    start_udp6(false, Peek).
94
95start_udp6(UseMsg, Peek) ->
96    start_udp(inet6, UseMsg, Peek).
97
98start_udp(Domain, UseMsg, Peek) when is_boolean(UseMsg) andalso is_boolean(Peek) ->
99    start(Domain, dgram, udp, UseMsg, Peek).
100
101
102start_sctp() ->
103    start_sctp(inet).
104
105start_sctp(Domain) when ((Domain =:= inet) orelse (Domain =:= inet6)) ->
106    start(Domain, seqpacket, sctp, true, false).
107
108start(Domain, Type, Proto, UseMsg, Peek) ->
109    put(sname, "starter"),
110    i("try start manager"),
111    {Pid, MRef} = manager_start(Domain, Type, Proto, UseMsg, Peek),
112    i("manager (~p) started", [Pid]),
113    loop(Pid, MRef).
114
115loop(Pid, MRef) ->
116    receive
117        {'DOWN', MRef, process, Pid, Reason} ->
118            i("manager process exited: "
119              "~n   ~p", [Reason]),
120            ok
121    end.
122
123
124%% =========================================================================
125
126manager_start(Domain, Type, Proto, UseMsg, Peek) ->
127    spawn_monitor(fun() -> manager_init(Domain, Type, Proto, UseMsg, Peek) end).
128
129manager_start_handler(Pid, Sock) ->
130    manager_request(Pid, {start_handler, Sock}).
131
132manager_stop(Pid, Reason) ->
133    manager_request(Pid, {stop, Reason}).
134
135manager_request(Pid, Request) ->
136    ?LIB:request(manager, Pid, Request).
137
138manager_reply(Pid, Ref, Reply) ->
139    ?LIB:reply(manager, Pid, Ref, Reply).
140
141
142manager_init(Domain, Type, Proto, UseMsg, Peek) ->
143    put(sname, "manager"),
144    do_manager_init(Domain, Type, Proto, UseMsg, Peek).
145
146do_manager_init(Domain, stream = Type, Proto, UseMsg, Peek) ->
147    i("try start acceptor(s)"),
148    {Sock, Acceptors} = manager_stream_init(Domain, Type, Proto),
149    manager_loop(#manager{socket     = Sock,
150                          msg        = UseMsg,
151                          peek       = Peek,
152                          acceptors  = Acceptors,
153                          handler_id = 1,
154                          handlers   = []});
155do_manager_init(Domain, dgram = Type, Proto, UseMsg, Peek) ->
156    i("try open socket"),
157    case socket:open(Domain, Type, Proto) of
158        {ok, Sock} ->
159            F = fun(X) -> case socket:getopt(Sock, socket, X) of
160                              {ok, V} ->    f("~p", [V]);
161                              {error, R} -> f("error: ~p", [R])
162                          end
163                end,
164            i("socket opened (~s,~s,~s): "
165              "~n   broadcast: ~s"
166              "~n   dontroute: ~s"
167              "~n   keepalive: ~s"
168              "~n   reuseaddr: ~s"
169              "~n   linger:    ~s"
170              "~n   debug:     ~s"
171              "~n   prio:      ~s"
172              "~n   rcvbuf:    ~s"
173              "~n   rcvtimeo:  ~s"
174              "~n   sndbuf:    ~s"
175              "~n   sndtimeo:  ~s"
176              "~n   => try find (local) address",
177              [F(domain), F(type), F(protocol),
178               F(broadcast), F(dontroute), F(keepalive), F(reuseaddr), F(linger),
179               F(debug), F(priority),
180               F(rcvbuf), F(rcvtimeo), F(sndbuf), F(sndtimeo)]),
181            Addr = which_addr(Domain),
182            SA = #{family => Domain,
183                   addr   => Addr},
184            i("try bind to: "
185              "~n   ~p", [Addr]),
186            case socket:bind(Sock, SA) of
187                {ok, _P} ->
188                   ok;
189                {error, BReason} ->
190                    throw({bind, BReason})
191            end,
192            i("bound to: "
193              "~n   ~s"
194              "~n   => try start handler",
195              [case socket:sockname(Sock) of
196                   {ok, Name} -> f("~p", [Name]);
197                   {error, R} -> f("error: ~p", [R])
198               end]),
199            case handler_start(1, Sock, UseMsg, Peek) of
200                {ok, {Pid, MRef}} ->
201                    i("handler (~p) started", [Pid]),
202                    handler_continue(Pid),
203                    manager_loop(#manager{peek       = Peek,
204                                          msg        = UseMsg,
205                                          handler_id = 2, % Just in case
206                                          handlers   = [{1, Pid, MRef}]});
207                {error, SReason} ->
208                    e("Failed starting handler: "
209                      "~n   ~p", [SReason]),
210                    exit({failed_start_handler, SReason})
211            end;
212        {error, OReason} ->
213            e("Failed open socket: "
214              "~n   ~p", [OReason]),
215            exit({failed_open_socket, OReason})
216    end;
217do_manager_init(Domain, seqpacket = Type, sctp = Proto, _UseMsg, _Peek) ->
218    %% This is as far as I have got with SCTP at the moment...
219    case socket:open(Domain, Type, Proto) of
220        {ok, Sock} ->
221            i("(sctp) socket opened: "
222              "~n   ~p", [Sock]),
223            EXP = fun(_Desc, Expect, Expect) ->
224                          Expect;
225                     (Desc, Expect, Actual) ->
226                          e("Unexpected result ~w: "
227                            "~n   Expect: ~p"
228                            "~n   Actual: ~p", [Desc, Expect, Actual]),
229                          exit({Desc, Expect, Actual})
230                  end,
231            GO = fun(O) -> case socket:getopt(Sock, sctp, O) of
232                               {ok, V}    -> f("~p", [V]);
233                               {error, R} -> f("error: ~p", [R])
234                           end
235                 end,
236            %% ok = socket:setopt(Sock, otp, debug, true),
237
238            i("Miscellaneous options: "
239              "~n   associnfo:         ~s"
240              "~n   autoclose:         ~s"
241              "~n   disable-fragments: ~s"
242              "~n   initmsg:           ~s"
243              "~n   maxseg:            ~s"
244              "~n   nodelay:           ~s"
245              "~n   rtoinfo:           ~s",
246              [GO(associnfo),
247               GO(autoclose),
248               GO(disable_fragments),
249               GO(initmsg),
250               GO(maxseg),
251               GO(nodelay),
252               GO(rtoinfo)]),
253
254            Events = #{data_in          => true,
255                       association      => true,
256                       address          => true,
257                       send_failure     => true,
258                       peer_error       => true,
259                       shutdown         => true,
260                       partial_delivery => true,
261                       adaptation_layer => true,
262                       authentication   => true,
263                       sender_dry       => true},
264            EXP(set_sctp_events, ok, socket:setopt(Sock, sctp, events, Events)),
265            EXP(close_socket, ok, socket:close(Sock));
266        {error, Reason} ->
267            exit({failed_open, Reason})
268    end;
269do_manager_init(Domain, raw = Type, Proto, UseMsg, Peek) when is_integer(Proto) ->
270    do_manager_init(Domain, Type, {raw, Proto}, UseMsg, Peek);
271do_manager_init(Domain, raw = Type, Proto, _UseMsg, _Peek) ->
272    case socket:open(Domain, Type, Proto) of
273        {ok, Sock} ->
274            i("(sctp) socket opened: "
275              "~n   ~p", [Sock]),
276            socket:close(Sock);
277        {error, Reason} ->
278            exit({failed_open, Reason})
279    end.
280
281
282
283manager_stream_init(Domain, Type, Proto) ->
284    i("try (socket) open"),
285    Sock = case socket:open(Domain, Type, Proto) of
286               {ok, S} ->
287                   S;
288               {error, OReason} ->
289                   throw({open, OReason})
290           end,
291    F = fun(X) -> case socket:getopt(Sock, socket, X) of
292                      {ok, V} ->    f("~p", [V]);
293                      {error, R} -> f("error: ~p", [R])
294                  end
295        end,
296    i("(socket) open (~s,~s,~s): "
297      "~n   debug:     ~s"
298      "~n   prio:      ~s"
299      "~n   => try find (local) address",
300      [F(domain), F(type), F(protocol), F(debug), F(priority)]),
301    Addr = which_addr(Domain),
302    SA = #{family => Domain,
303           addr   => Addr},
304    i("found: "
305      "~n   ~p"
306      "~n   => try (socket) bind", [Addr]),
307    %% ok = socket:setopt(Sock, otp, debug, true),
308    %% ok = socket:setopt(Sock, socket, debug, 1), %% must have rights!!
309    Port = case socket:bind(Sock, SA) of
310               {ok, P} ->
311                   %% ok = socket:setopt(Sock, socket, debug, 0), %% must have rights!!
312                   %% ok = socket:setopt(Sock, otp, debug, false),
313                   P;
314               {error, BReason} ->
315                   throw({bind, BReason})
316           end,
317    i("bound to: "
318      "~n   ~p"
319      "~n   => try (socket) listen (acceptconn: ~s)",
320      [Port, F(acceptconn)]),
321    case socket:listen(Sock) of
322        ok ->
323            i("listening (acceptconn: ~s)",
324              [F(acceptconn)]),
325            manager_stream_init(Sock, 1, ?NUM_ACCEPTORS, []);
326        {error, LReason} ->
327            throw({listen, LReason})
328    end.
329
330which_addr(Domain) ->
331    Iflist = case inet:getifaddrs() of
332                 {ok, IFL} ->
333                     IFL;
334                 {error, Reason} ->
335                     throw({inet,getifaddrs,Reason})
336             end,
337    which_addr(Domain, Iflist).
338
339which_addr(_Domain, []) ->
340    throw(no_address);
341which_addr(Domain, [{Name, IFO}|_IFL]) when (Name =/= "lo") ->
342    which_addr2(Domain, IFO);
343which_addr(Domain, [_|IFL]) ->
344    which_addr(Domain, IFL).
345
346which_addr2(_, []) ->
347    throw(no_address);
348which_addr2(inet = _Domain, [{addr, Addr}|_IFO]) when (size(Addr) =:= 4) ->
349    Addr;
350which_addr2(inet6 = _Domain, [{addr, Addr}|_IFO]) when (size(Addr) =:= 8) ->
351    Addr;
352which_addr2(Domain, [_|IFO]) ->
353    which_addr2(Domain, IFO).
354
355
356manager_stream_init(Sock, ID, NumAcceptors, Acc)
357  when (NumAcceptors > 0) ->
358    i("try start acceptor"),
359    case acceptor_start(Sock, ID) of
360        {ok, {Pid, MRef}} ->
361            i("acceptor ~w (~p) started", [ID, Pid]),
362            ?LIB:sleep(2000),
363            manager_stream_init(Sock, ID+1, NumAcceptors-1,
364                                [{ID, Pid, MRef}|Acc]);
365        {error, Reason} ->
366            exit({failed_starting_acceptor, Reason})
367    end;
368manager_stream_init(Sock, _ID, 0, Acc) ->
369    %% Req = {kill_acceptor, length(Acc)}, % Last in the queue
370    %% Req = {kill_acceptor, 3},           % In the "middle" of the queue
371    %% Req = {kill_acceptor, 2},           % The first in the queue
372    %% Req = {kill_acceptor, 1},           % Current acceptor
373    %% Msg = {manager, self(), make_ref(), Req},
374    %% erlang:send_after(timer:seconds(10), self(), Msg),
375    {Sock, lists:reverse(Acc)}.
376
377
378manager_loop(M) ->
379    receive
380        {'DOWN', MRef, process, Pid, Reason} ->
381            M2 = manager_handle_down(M, MRef, Pid, Reason),
382            manager_loop(M2);
383
384        {manager, Pid, Ref, Request} ->
385            M2 = manager_handle_request(M, Pid, Ref, Request),
386            manager_loop(M2)
387    end.
388
389
390manager_handle_down(#manager{acceptors = Acceptors,
391                             handlers  = Handlers} = M, MRef, Pid, Reason) ->
392    case lists:keysearch(Pid, 2, Acceptors) of
393        {value, {ID, Pid, MRef}} when (Reason =:= normal) ->
394            i("acceptor ~w exited (normally)", [ID]),
395            case lists:keydelete(Pid, 2, Acceptors) of
396                [] ->
397                    %% We are done
398                    i("the last acceptor - we are done"),
399                    exit(normal);
400                Acceptors2 ->
401                    M#manager{acceptors = Acceptors2}
402            end;
403        {value, {ID, Pid, MRef}} ->
404            e("acceptor ~w crashed: "
405              "~n   ~p", [ID, Reason]),
406            exit({acceptor_died, Reason});
407
408        false -> %% handler!
409            if
410                (Reason =/= normal) ->
411                    e("handler ~p died: "
412                      "~n   ~p", [Pid, Reason]);
413                true ->
414                    i("handler ~p terminated", [Pid])
415            end,
416            Handlers2 = lists:keydelete(Pid, 2, Handlers),
417            M#manager{handlers = Handlers2}
418    end.
419
420
421manager_handle_request(#manager{peek       = Peek,
422                                msg        = UseMsg,
423                                handler_id = HID,
424                                handlers   = Handlers} = M, Pid, Ref,
425                       {start_handler, Sock}) ->
426    i("try start handler (~w)", [HID]),
427    case handler_start(HID, Sock, UseMsg, Peek) of
428        {ok, {HPid, HMRef}} ->
429            i("handler ~w started", [HID]),
430            manager_reply(Pid, Ref, {ok, HPid}),
431            M#manager{handler_id = HID+1,
432                      handlers   = [{HID, HPid, HMRef}|Handlers]};
433        {error, Reason} = ERROR ->
434            e("Failed starting new handler: "
435              "~n   Sock:   ~p"
436              "~n   Reason: ~p", [Sock, Reason]),
437            manager_reply(Pid, Ref, ERROR),
438            M
439    end;
440manager_handle_request(#manager{socket    = Sock,
441                                acceptors = [{AID, APid, AMRef}]} = M, _Pid, _Ref,
442                       {kill_acceptor, AID}) ->
443    i("try kill (only remeining) acceptor ~w", [AID]),
444    socket:setopt(Sock, otp, debug, true),
445    manager_stop_acceptor(APid, AMRef, AID, kill),
446    M#manager{acceptors = []};
447manager_handle_request(#manager{socket    = Sock,
448                                acceptors = Acceptors} = M, _Pid, _Ref,
449                       {kill_acceptor, AID}) ->
450    i("try kill acceptor ~w", [AID]),
451    case lists:keysearch(AID, 1, Acceptors) of
452        {value, {AID, APid, AMRef}} ->
453            socket:setopt(Sock, otp, debug, true),
454            manager_stop_acceptor(APid, AMRef, AID, kill),
455            Acceptors2 = lists:keydelete(AID, 1, Acceptors),
456            M#manager{acceptors = Acceptors2};
457        false ->
458            e("no such acceptor"),
459            M
460    end;
461manager_handle_request(#manager{acceptors = Acceptors,
462                                handlers  = Handlers}, Pid, Ref,
463                       {stop, Reason}) ->
464    i("stop"),
465    manager_reply(Pid, Ref, ok),
466    manager_stop_handlers(Handlers, Reason),
467    manager_stop_acceptors(Acceptors, Reason),
468    i("stopped", []),
469    exit(Reason).
470
471manager_stop_acceptors(Acceptors, Reason) ->
472    lists:foreach(fun({ID,P,M}) ->
473                          manager_stop_acceptor(P, M, ID, Reason)
474                  end, Acceptors).
475
476manager_stop_acceptor(Pid, MRef, ID, Reason) ->
477    i("try stop acceptor ~w (~p): ~p", [ID, Pid, Reason]),
478    erlang:demonitor(MRef, [flush]),
479    acceptor_stop(Pid, Reason),
480    ok.
481
482manager_stop_handlers(Handlers, Reason) ->
483    lists:foreach(fun({ID,P,M}) ->
484                          manager_stop_handler(P, M, ID, Reason)
485                  end, Handlers).
486
487manager_stop_handler(Pid, MRef, ID, Reason) ->
488    i("try stop handler ~w (~p): ~p", [ID, Pid, Reason]),
489    erlang:demonitor(MRef, [flush]),
490    handler_stop(Pid, Reason),
491    ok.
492
493
494
495%% =========================================================================
496
497acceptor_start(Sock, ID) ->
498    Self = self(),
499    A = {Pid, _} = spawn_monitor(fun() ->
500                                         acceptor_init(Self, Sock, ID)
501                                 end),
502    receive
503        {acceptor, Pid, ok} ->
504            {ok, A};
505        {acceptor, Pid, {error, _} = Error} ->
506            exit(Pid, kill), % Just in case
507            Error;
508        {'DOWN', _MRef, process, Pid, Reason} ->
509            {error, {crashed, Reason}}
510    end.
511
512acceptor_stop(Pid, _Reason) ->
513    %% acceptor_request(Pid, {stop, Reason}).
514    exit(Pid, kill).
515
516%% acceptor_request(Pid, Request) ->
517%%     request(acceptor, Pid, Request).
518
519%% acceptor_reply(Pid, Ref, Reply) ->
520%%     reply(acceptor, Pid, Ref, Reply).
521
522
523acceptor_init(Manager, Sock, ID) ->
524    put(sname, f("acceptor[~w]", [ID])),
525    Manager ! {acceptor, self(), ok},
526    %% ok = socket:setopt(Sock, otp, debug, true),
527    acceptor_loop(#acceptor{id      = ID,
528                            manager = Manager,
529                            socket  = Sock}).
530
531acceptor_loop(#acceptor{socket = LSock, atimeout = Timeout} = A) ->
532    i("try accept"),
533    case socket:accept(LSock, Timeout) of
534        {ok, Sock} ->
535            i("accepted: "
536              "~n   ~p"
537              "~nwhen"
538              "~n   ~p", [Sock, socket:info()]),
539            case acceptor_handle_accept_success(A, Sock) of
540                ok ->
541                    acceptor_loop(A);
542                {error, Reason} ->
543                    e("Failed starting handler: "
544                      "~n   ~p", [Reason]),
545                    socket:close(Sock),
546                    exit({failed_starting_handler, Reason})
547            end;
548        {error, timeout} ->
549            i("timeout"),
550            acceptor_loop(A);
551        {error, Reason} ->
552            e("accept failure: "
553              "~n   ~p", [Reason]),
554            exit({accept, Reason})
555    end.
556
557acceptor_handle_accept_success(#acceptor{manager = Manager}, Sock) ->
558    i("try start handler for peer"
559      "~n   ~p", [case socket:peername(Sock) of
560                      {ok, Peer} -> Peer;
561                      {error, _} = E -> E
562                  end]),
563    case manager_start_handler(Manager, Sock) of
564        {ok, Pid} ->
565            i("handler (~p) started - now change 'ownership'", [Pid]),
566            case socket:setopt(Sock, otp, controlling_process, Pid) of
567                ok ->
568                    %% Normally we should have a msgs collection here
569                    %% (of messages we receive before the control was
570                    %% handled over to Handler), but since we don't
571                    %% have active implemented yet...
572                    i("new handler (~p) now controlling process", [Pid]),
573                    handler_continue(Pid),
574                    ok;
575                {error, _} = ERROR ->
576                    exit(Pid, kill),
577                    ERROR
578            end;
579        {error, Reason2} ->
580            e("failed starting handler: "
581              "~n   (new) Socket: ~p"
582              "~n   Reason:       ~p", [Sock, Reason2]),
583            exit({failed_starting_handler, Reason2})
584    end.
585
586
587
588%% =========================================================================
589
590handler_start(ID, Sock, UseMsg, Peek) ->
591    Self = self(),
592    H = {Pid, _} = spawn_monitor(fun() ->
593                                         handler_init(Self, ID, UseMsg, Peek, Sock)
594                                 end),
595    receive
596        {handler, Pid, ok} ->
597            {ok, H};
598        {handler, Pid, {error, _} = ERROR} ->
599            exit(Pid, kill), % Just in case
600            ERROR
601    end.
602
603handler_stop(Pid, _Reason) ->
604    %% handler_request(Pid, {stop, Reason}).
605    exit(Pid, kill).
606
607handler_continue(Pid) ->
608    handler_request(Pid, continue).
609
610handler_request(Pid, Request) ->
611    ?LIB:request(handler, Pid, Request).
612
613handler_reply(Pid, Ref, Reply) ->
614    ?LIB:reply(handler, Pid, Ref, Reply).
615
616
617handler_init(Manager, ID, Msg, Peek, Sock) ->
618    put(sname, f("handler:~w", [ID])),
619    i("starting"),
620    Manager ! {handler, self(), ok},
621    receive
622        {handler, Pid, Ref, continue} ->
623            i("got continue"),
624            handler_reply(Pid, Ref, ok),
625            G = fun(L, O) -> case socket:getopt(Sock, L, O) of
626                                {ok, Val} ->
627                                    f("~p", [Val]);
628                                {error, R} when is_atom(R) ->
629                                    f("error: ~w", [R]);
630                                {error, {T, R}} when is_atom(T) ->
631                                    f("error: ~w, ~p", [T, R]);
632                                {error, R} ->
633                                    f("error: ~p", [R])
634                          end
635                end,
636            GSO  = fun(O) -> G(socket, O) end,
637            GIP4 = fun(O) -> G(ip,     O) end,
638            GIP6 = fun(O) -> G(ipv6,   O) end,
639            {ok, Domain} = socket:getopt(Sock, socket, domain),
640            {ok, Type}   = socket:getopt(Sock, socket, type),
641            {ok, Proto}  = socket:getopt(Sock, socket, protocol),
642            B2D          = GSO(bindtodevice),
643            RA           = GSO(reuseaddr),
644            RP           = GSO(reuseport),
645            OOBI         = GSO(oobinline),
646            RcvBuf       = GSO(rcvbuf),
647            RcvLW        = GSO(rcvlowat),
648            RcvTO        = GSO(rcvtimeo),
649            SndBuf       = GSO(sndbuf),
650            SndLW        = GSO(sndlowat),
651            SndTO        = GSO(sndtimeo),
652            Linger       = GSO(linger),
653            Timestamp    = GSO(timestamp),
654            FreeBind     = GIP4(freebind),
655            MTU          = GIP4(mtu),
656            MTUDisc      = GIP4(mtu_discover),
657            MALL         = GIP4(multicast_all),
658            MIF4         = GIP4(multicast_if),
659            MLoop4       = GIP4(multicast_loop),
660            MTTL         = GIP4(multicast_ttl),
661            NF           = GIP4(nodefrag), % raw only
662            PktInfo      = GIP4(pktinfo),  % dgram only
663            RecvErr4     = GIP4(recverr),
664            RecvIF       = GIP4(recvif),   % Only dgram and raw (and FreeBSD)
665            RecvOPTS     = GIP4(recvopts), % Not stream
666            RecvOrigDstAddr = GIP4(recvorigdstaddr),
667            RecvTOS      = GIP4(recvtos),
668            RecvTTL      = GIP4(recvttl),  % not stream
669            RetOpts      = GIP4(retopts),  % not stream
670            SendSrcAddr  = GIP4(sendsrcaddr),
671            TOS          = GIP4(tos),
672            Transparent  = GIP4(transparent),
673            TTL          = GIP4(ttl),
674            MHops        = GIP6(multicast_hops),
675            MIF6         = GIP6(multicast_if), % Only dgram and raw
676            MLoop6       = GIP6(multicast_loop),
677            RecvErr6     = GIP6(recverr),
678            RecvPktInfo  = GIP6(recvpktinfo),
679            RtHdr        = GIP6(rthdr),
680            AuthHdr      = GIP6(authhdr),
681            HopLimit     = GIP6(hoplimit),
682            HopOpts      = GIP6(hopopts),
683            DstOpts      = GIP6(dstopts),
684            FlowInfo     = GIP6(flowinfo),
685            UHops        = GIP6(unicast_hops),
686            i("got continue when: "
687              "~n   (socket) Domain:             ~p"
688              "~n   (socket) Type:               ~p"
689              "~n   (socket) Protocol:           ~p"
690              "~n   (socket) Reuse Address:      ~s"
691              "~n   (socket) Reuse Port:         ~s"
692              "~n   (socket) Bind To Device:     ~s"
693              "~n   (socket) OOBInline:          ~s"
694              "~n   (socket) RcvBuf:             ~s"
695              "~n   (socket) RcvLW:              ~s"
696              "~n   (socket) RcvTO:              ~s"
697              "~n   (socket) SndBuf:             ~s"
698              "~n   (socket) SndLW:              ~s"
699              "~n   (socket) SndTO:              ~s"
700              "~n   (socket) Linger:             ~s"
701              "~n   (socket) Timestamp:          ~s"
702              "~n   (ip)     FreeBind:           ~s"
703              "~n   (ip)     MTU:                ~s"
704              "~n   (ip)     MTU Discovery:      ~s"
705              "~n   (ip)     Multicast ALL:      ~s"
706              "~n   (ip)     Multicast IF:       ~s"
707              "~n   (ip)     Multicast Loop:     ~s"
708              "~n   (ip)     Multicast TTL:      ~s"
709              "~n   (ip)     Node Frag:          ~s"
710              "~n   (ip)     Pkt Info:           ~s"
711              "~n   (ip)     Recv Err:           ~s"
712              "~n   (ip)     Recv IF:            ~s"
713              "~n   (ip)     Recv OPTS:          ~s"
714              "~n   (ip)     Recv Orig Dst Addr: ~s"
715              "~n   (ip)     Recv TOS:           ~s"
716              "~n   (ip)     Recv TTL:           ~s"
717              "~n   (ip)     Ret Opts:           ~s"
718              "~n   (ip)     Send Src Addr:      ~s"
719              "~n   (ip)     TOS:                ~s"
720              "~n   (ip)     Transparent:        ~s"
721              "~n   (ip)     TTL:                ~s"
722              "~n   (ipv6)   Multicast Hops:     ~s"
723              "~n   (ipv6)   Multicast IF:       ~s"
724              "~n   (ipv6)   Multicast Loop:     ~s"
725              "~n   (ipv6)   Recv Err:           ~s"
726              "~n   (ipv6)   Recv Pkt Info:      ~s"
727              "~n   (ipv6)   RT Hdr:             ~s"
728              "~n   (ipv6)   Auth Hdr:           ~s"
729              "~n   (ipv6)   Hop Limit:          ~s"
730              "~n   (ipv6)   Hop Opts:           ~s"
731              "~n   (ipv6)   Dst Opts:           ~s"
732              "~n   (ipv6)   Flow Info:          ~s"
733              "~n   (ipv6)   Unicast Hops:       ~s",
734              [Domain, Type, Proto,
735               RA, RP, B2D, OOBI,
736               RcvBuf, RcvLW, RcvTO, SndBuf, SndLW, SndTO,
737               Linger, Timestamp,
738               FreeBind, MTU, MTUDisc, MALL, MIF4, MLoop4, MTTL,
739               NF, PktInfo,RecvErr4,
740               RecvIF, RecvOPTS, RecvOrigDstAddr, RecvTOS, RecvTTL, RetOpts,
741               SendSrcAddr, TOS, Transparent, TTL,
742               MHops, MIF6, MLoop6, RecvErr6, RecvPktInfo,
743               RtHdr, AuthHdr, HopLimit, HopOpts, DstOpts, FlowInfo,
744               UHops]),
745
746            %% ok = socket:setopt(Sock, otp, debug, true),
747            %% case socket:getopt(Sock, 0, {13, int}) of
748            %%     {ok, Val} ->
749            %%         i("PktOpts ok:  ~p", [Val]);
750            %%     {error, Reason} ->
751            %%         e("PktOpts err: ~p", [Reason])
752            %% end,
753            %% ok = socket:setopt(Sock, otp, debug, false),
754            SSO = fun(O, V) -> soso(Sock, O, V) end,
755            SIP4 =
756                fun(O, V) ->
757                        if
758                            (Type =:= dgram) ->
759                                ok = soip(Sock, O,  V);
760                            true ->
761                                ok
762                        end
763                end,
764            SSO(timestamp, true),
765            SIP4(pktinfo, true),
766            ok = soip(Sock, recvtos,  true),
767            SIP4(recvttl,  true),
768            ok = soip(Sock, recvorigdstaddr,  true),
769
770            handler_loop(#handler{msg     = Msg,
771                                  peek    = Peek,
772                                  manager = Manager,
773                                  type    = Type,
774                                  socket  = Sock})
775    end.
776
777so(Sock, Lvl, Opt, Val) ->
778    ok = socket:setopt(Sock, Lvl, Opt, Val).
779
780soso(Sock, Opt, Val) ->
781    so(Sock, socket, Opt, Val).
782
783soip(Sock, Opt, Val) ->
784    so(Sock, ip, Opt, Val).
785
786%% soipv6(Sock, Opt, Val) ->
787%%     so(Sock, ipv6, Opt, Val).
788
789handler_loop(H) ->
790    i("try read message"),
791    case recv(H) of
792        {ok, {Source, Msg}} ->
793            i("received ~w bytes of data~s",
794              [size(Msg), case Source of
795                              undefined -> "";
796                              _ -> f(" from:~n   ~p", [Source])
797                          end]),
798            case ?LIB:dec_msg(Msg) of
799                {request, N, Req} ->
800                    i("received request ~w: "
801                      "~n   ~p", [N, Req]),
802                    Reply = ?LIB:enc_rep_msg(N, "hoppsan"),
803                    case send(H, Reply, Source) of
804                        ok ->
805                            i("successfully sent reply ~w", [N]),
806                            handler_loop(H);
807                        {error, SReason} ->
808                            e("failed sending reply ~w:"
809                              "~n   ~p", [N, SReason]),
810                            exit({failed_sending_reply, SReason})
811                    end
812            end;
813
814        {error, closed} ->
815            i("closed when"
816              "~n   ~p", [socket:info()]),
817            exit(normal);
818
819        {error, RReason} ->
820            e("failed reading request: "
821              "~n   ~p", [RReason]),
822            exit({failed_reading_request, RReason})
823    end.
824
825
826recv(#handler{peek = true, socket = Sock, type = stream}) ->
827    peek_recv(Sock);
828recv(#handler{socket = Sock, msg = true, type = stream}) ->
829    case socket:recvmsg(Sock) of
830        {ok, #{addr  := undefined = Source,
831               iov   := [Data],
832               ctrl  := CMsgHdrs,
833               flags := Flags}} ->
834            i("received message: "
835              "~n   CMsgHdrs: ~p"
836              "~n   Flags:    ~p", [CMsgHdrs, Flags]),
837            {ok, {Source, Data}};
838        {ok, X} ->
839            e("received *unexpected* message: "
840              "~n   ~p", [X]),
841            {error, {unexpected, X}};
842        {error, _} = ERROR ->
843            ERROR
844    end;
845recv(#handler{socket = Sock, msg = true, type = dgram}) ->
846    case socket:recvmsg(Sock) of
847        {ok, #{addr  := Source,
848               iov   := [Data],
849               ctrl  := CMsgHdrs,
850               flags := Flags}} ->
851            i("received message: "
852              "~n   CMsgHdrs: ~p"
853              "~n   Flags:    ~p", [CMsgHdrs, Flags]),
854            {ok, {Source, Data}};
855        {ok, X} ->
856            {error, {unexpected, X}};
857        {error, _} = ERROR ->
858            ERROR
859    end;
860recv(#handler{peek = false, socket = Sock, type = stream}) ->
861    do_recv(Sock);
862recv(#handler{peek = Peek, socket = Sock, type = dgram})
863  when (Peek =:= true) ->
864    %% ok  = socket:setopt(Sock, otp, debug, true),
865    RES = peek_recvfrom(Sock, 5),
866    %% ok  = socket:setopt(Sock, otp, debug, false),
867    RES;
868recv(#handler{peek = Peek, socket = Sock, type = dgram})
869  when (Peek =:= false) ->
870    %% ok = socket:setopt(Sock, otp, debug, true),
871    socket:recvfrom(Sock).
872
873do_recv(Sock) ->
874    case socket:recv(Sock) of
875        {ok, Msg} ->
876            {ok, {undefined, Msg}};
877        {error, _} = ERROR ->
878            ERROR
879    end.
880
881peek_recv(Sock) ->
882    i("try peek on the message type (expect request)"),
883    Type = ?LIB:req(),
884    case socket:recv(Sock, 4, [peek]) of
885        {ok, <<Type:32>>} ->
886            i("was request - do proper recv"),
887            do_recv(Sock);
888        {error, _} = ERROR ->
889            ERROR
890    end.
891
892peek_recvfrom(Sock, BufSz) ->
893    i("try peek recvfrom with buffer size ~w", [BufSz]),
894    case socket:recvfrom(Sock, BufSz, [peek]) of
895        {ok, {_Source, Msg}} when (BufSz =:= size(Msg)) ->
896            %% i("we filled the buffer: "
897            %%   "~n   ~p", [Msg]),
898            %% It *may not* fit => try again with double size
899            peek_recvfrom(Sock, BufSz*2);
900        {ok, _} ->
901            %% It fits => read for real
902            i("we did *not* fill the buffer - do the 'real' read"),
903            socket:recvfrom(Sock);
904        {error, _} = ERROR ->
905            ERROR
906    end.
907
908
909send(#handler{socket = Sock, msg = true, type = stream, stimeout = Timeout},
910     Msg, _) ->
911    CMsgHdr  = #{level => ip, type => tos, data => reliability},
912    CMsgHdrs = [CMsgHdr],
913    MsgHdr   = #{iov => [Msg], ctrl => CMsgHdrs},
914    %% socket:setopt(Sock, otp, debug, true),
915    Res = socket:sendmsg(Sock, MsgHdr, Timeout),
916    %% socket:setopt(Sock, otp, debug, false),
917    Res;
918send(#handler{socket = Sock, type = stream, stimeout = Timeout}, Msg, _) ->
919    socket:send(Sock, Msg, Timeout);
920send(#handler{socket = Sock, msg = true, type = dgram, stimeout = Timeout},
921     Msg, Dest) ->
922    CMsgHdr  = #{level => ip, type => tos, data => reliability},
923    CMsgHdrs = [CMsgHdr],
924    MsgHdr   = #{addr => Dest,
925                 ctrl => CMsgHdrs,
926                 iov  => [Msg]},
927    %% ok = socket:setopt(Sock, otp, debug, true),
928    Res = socket:sendmsg(Sock, MsgHdr, Timeout),
929    %% ok = socket:setopt(Sock, otp, debug, false),
930    Res;
931send(#handler{socket = Sock, type = dgram, stimeout = Timeout}, Msg, Dest) ->
932    socket:sendto(Sock, Msg, Dest, Timeout).
933
934%% filler() ->
935%%     list_to_binary(lists:duplicate(2048, " FILLER ")).
936
937
938
939%% =========================================================================
940
941f(F, A) ->
942    ?LIB:f(F, A).
943
944e(F) ->
945    e(F, []).
946e(F, A) ->
947    ?LIB:e(F, A).
948
949i(F) ->
950    ?LIB:i(F).
951
952i(F, A) ->
953    ?LIB:i(F, A).
954
955