nickva commented on PR #4729:
URL: https://github.com/apache/couchdb/pull/4729#issuecomment-1689241307

   A bit more of a cleaned up connection script version which should work on 
macos, linux and freebsd:
   
   ```erlang
   #!/usr/bin/env escript
   
   is_closed(Sock) ->
       OsType = os:type(),
       case tcp_info_opt(OsType) of
           {raw, _, _, _} = TcpInfoOpt ->
               case inet:getopts(Sock, [TcpInfoOpt]) of
                   {ok, [{raw, _, _, <<State:8/native, _/binary>>}]} ->
                       tcp_fsm_state(State, OsType);
                   {ok, []} ->
                       false;
                   {error, einval} ->
                       % Already cleaned up
                       true;
                   {error, _} ->
                       false
               end;
           undefined ->
               false
       end.
   
   % All OS-es have the tcpi_state (uint8) as first member of tcp_info struct
   
   tcp_info_opt({unix, linux}) ->
       %% include/netinet/in.h
       %%   IPPROTO_TCP = 6
       %%
       %% include/netinet/tcp.h
       %%   #define TCP_INFO 11
       %%
       {raw, 6, 11, 1};
   tcp_info_opt({unix, darwin}) ->
       %% include/netinet/in.h
       %%   #define IPPROTO_TCP   6
       %%
       %% netinet/tcp.h
       %%   #define TCP_CONNECTION_INFO  0x106
       %%
       {raw, 6, 16#106, 1};
   tcp_info_opt({unix, freebsd}) ->
       %% sys/netinet/in.h
       %%  #define  IPPROTO_TCP  6 /* tcp */
       %%
       %% sys/netinet/tcp.h
       %%  #define  TCP_INFO    32 /* retrieve tcp_info structure */
       %%
       {raw, 6, 32, 1};
   tcp_info_opt({_, _}) ->
       undefined.
   
   tcp_fsm_state(State, {unix, linux}) ->
       %% netinet/tcp.h
       %%   enum
       %%   {
       %%     TCP_ESTABLISHED = 1,
       %%     TCP_SYN_SENT,
       %%     TCP_SYN_RECV,
       %%     TCP_FIN_WAIT1,
       %%     TCP_FIN_WAIT2,
       %%     TCP_TIME_WAIT,
       %%     TCP_CLOSE,
       %%     TCP_CLOSE_WAIT,
       %%     TCP_LAST_ACK,
       %%     TCP_LISTEN,
       %%     TCP_CLOSING
       %%   }
       %%
       lists:member(State, [4, 5, 6, 7, 8, 9, 10]);
   tcp_fsm_state(State, {unix, darwin}) ->
       %% netinet/tcp_fsm.h
       %%   #define TCPS_CLOSED             0       /* closed */
       %%   #define TCPS_LISTEN             1       /* listening for connection 
*/
       %%   #define TCPS_SYN_SENT           2       /* active, have sent syn */
       %%   #define TCPS_SYN_RECEIVED       3       /* have send and received 
syn */
       %%   #define TCPS_ESTABLISHED        4       /* established */
       %%   #define TCPS_CLOSE_WAIT         5       /* rcvd fin, waiting for 
close */
       %%   #define TCPS_FIN_WAIT_1         6       /* have closed, sent fin */
       %%   #define TCPS_CLOSING            7       /* closed xchd FIN; await 
FIN ACK */
       %%   #define TCPS_LAST_ACK           8       /* had fin and close; await 
FIN ACK */
       %%   #define TCPS_FIN_WAIT_2         9       /* have closed, fin is 
acked */
       %%   #define TCPS_TIME_WAIT          10      /* in 2*msl quiet wait 
after close */
       %%
       lists:member(State, [0, 5, 6, 7, 8, 9, 10]);
   tcp_fsm_state(State, {unix, freebsd}) ->
       %% netinet/tcp_fsm.h
       %%   #define TCPS_CLOSED 0 /* closed */
       %%   #define TCPS_LISTEN 1 /* listening for connection */
       %%   #define TCPS_SYN_SENT 2  /* active, have sent syn */
       %%   #define TCPS_SYN_RECEIVED 3 /* have sent and received syn */
       %%   #define TCPS_ESTABLISHED 4 /* established */
       %%   #define TCPS_CLOSE_WAIT 5 /* rcvd fin, waiting for close */
       %%   #define TCPS_FIN_WAIT_1 6 /* have closed, sent fin */
       %%   #define TCPS_CLOSING 7/* closed xchd FIN; await FIN ACK */
       %%   #define TCPS_LAST_ACK 8/* had fin and close; await FIN ACK */
       %%   #define TCPS_FIN_WAIT_2 9/* have closed, fin is acked */
       %%   #define TCPS_TIME_WAIT 10 /* in 2*msl quiet wait after close */
       %%
       lists:member(State, [0, 5, 6, 7, 8, 9, 10]).
   
   monitor_loop(Sock) ->
       timer:sleep(1000),
       io:format("[mon] is_closed: ~p~n", [is_closed(Sock)]),
       monitor_loop(Sock).
   
   client(Port) ->
       timer:sleep(1000),
       io:format("[client] connecting on ~p~n", [Port]),
       {ok, ClientSock} = gen_tcp:connect("127.0.0.1", Port, [{active, false}, 
binary]),
       io:format("[client] connected ~p sleeping for 5 seconds and exiting~n", 
[ClientSock]),
       timer:sleep(5000),
       io:format("[client] exiting ~n", []),
       ok.
   
   main(_) ->
       {ok, ListenSocket} = gen_tcp:listen(0, [binary, {active, false}]),
       {ok, Port} = inet:port(ListenSocket),
       io:format("[srv] spawning client to connect to port ~p~n", [Port]),
       spawn_link(fun() -> client(Port) end),
       {ok, ClientSocket} = gen_tcp:accept(ListenSocket),
       io:format("[srv] accepted a connection ~p, sleeping for 10 seconds then 
exiting ~n", [ClientSocket]),
       spawn_link(fun() -> monitor_loop(ClientSocket) end),
       timer:sleep(10000).
   ```
   
   ```
   ./tcp_server_erlang.escript
   [srv] spawning client to connect to port 59121
   [client] connecting on 59121
   [srv] accepted a connection #Port<0.8>, sleeping for 10 seconds then exiting
   [client] connected #Port<0.7> sleeping for 5 seconds and exiting
   [mon] is_closed: false
   [mon] is_closed: false
   [mon] is_closed: false
   [mon] is_closed: false
   [client] exiting
   [mon] is_closed: true
   [mon] is_closed: true
   [mon] is_closed: true
   [mon] is_closed: true
   [mon] is_closed: true
   ```
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to