From 0b56a98366fc152c0fa5d5398220ac31866114d5 Mon Sep 17 00:00:00 2001
From: Micael Karlberg
One way to handle this is to use the
-
Set options on a socket.
+What properties are valid depend both on
Not all options are valid on all platforms. That is, + even if "we" support an option, that does not mean that the + underlying OS does.
Sockets are set 'non-blocking' when created, so this option + is *not* available (as it would adversely effect the Erlang VM + to set a socket 'blocking').
TBD: Need to implement a receiver process in order to be able to - implement active!
-x_tcp.erl:
-
-listen(Addr, Port) ->
- try
- begin
- Socket = case socket:open(inet, stream, tcp) of
- {ok, Socket} ->
- Socket;
- {error, _} = OERROR ->
- throw(OERROR)
- end,
- SockAddr = #in4_sockaddr{port = Port,
- addr = Addr},
- ok = case socket:bind(Socket, SockAddr) of
- ok ->
- ok;
- {error, _} = BERROR ->
- throw(BERROR)
- end,
- case socket:listen(Socket, 10) of
- ok ->
- {ok, Socket};
- {error, _} = LERROR ->
- throw(LERROR)
- end
- end
- catch
- throw:ERROR ->
- ERROR
-end.
-
-
-
-connect(Addr, Port) ->
- try
- begin
- Socket = case socket:open(inet, stream, tcp) of
- {ok, Socket} ->
- Socket;
- {error, _} = OERROR ->
- throw(OERROR)
- end,
- BSockAddr = #in4_sockaddr{port = 0,
- addr = any},
- ok = case socket:bind(Socket, BSockAddr) of
- ok ->
- ok;
- {error, _} = BERROR ->
- throw(BERROR)
- end,
- CSockAddr = #in4_sockaddr{port = Port,
- addr = Addr},
- Socket = case socket:connect(Socket, CSockAddr) of
- {ok, Sock} ->
- Sock;
- {error, _} = CERROR ->
- throw(CERROR)
- end,
- case start_receiver(Socket) of
- {ok, Pid} ->
- ok = socket:ts_add(Socket, receiver, Pid),
- {ok, Socket};
- {error, _} = RERROR ->
- socket:close(Socket),
- throw(RERROR)
- end
- end
- catch
- throw:ERROR ->
- ERROR
-end.
-
-
-
-accept(LSocket) ->
- case socket:accept(LSocket) of
- {ok, Socket} ->
- case start_receiver(Socket) of
- {ok, Pid} ->
- ok = socket:ts_add(Socket, receiver, Pid),
- {ok, Socket};
- {error, _} = RERROR ->
- socket:close(Socket),
- throw(RERROR)
- end,
- {error, _} = AERROR ->
- AERROR
- end.
-
-
-
-send(Socket, Data) ->
- socket:send(Socket, Data).
-
-
-
-setopt(Socket, controlling_process = Item, Pid) when is_pid(Pid) ->
- case socket:setopt(Socket, otp, Item, Pid) of
- ok ->
- {ok, Receiver} = socket:ts_get(Socket, receiver),
- update_receiver(Receiver, {controlling_process, Pid),
- ok;
- {error, _} = ERROR ->
- ERROR
- end;
-setopt(Socket, active, Active) ->
- {ok, Receiver} = socket:ts_get(Socket, receiver),
- receiver_active(Receiver, Active),
- ok;
-%% This is just to indicate that there will be more options
-%% that needs to be handled
-setopt(Socket, Item, Pid) when is_pid(Pid) ->
- socket:setopt(Socket, which_level(Item), Item, Pid).
-
-
- The receiver process:
-
-start_receiver(Socket) ->
- CtrlProc = self(),
- Ref = make_ref(),
- Receiver = proc_lib:spawn_link(fun() -> receiver_init(CtrlProc, Ref) end),
- receive
- {?MODULE, started, Ref} ->
- Receiver ! {?MODULE, receiver, Ref, Sock, true},
- unlink(Receiver),
- {ok, Receiver};
- {'EXIT', Receiver, Reason} ->
- {error, Reason}
- end.
-
-receiver_active(Receiver, Active)
- when (Active =:= false) orelse
- (Active =:= true) orelse
- (Active =:= once) orelse
- is_integer(Active) ->
- Receiver ! {?MODULE, active, What}.
-
-receiver_update(Receiver, What) ->
- Ref = make_ref(),
- Receiver ! {?MODULE, receiver_update, Ref, What},
- receive
- {?MODULE, receiver_upadate, Ref, Result} ->
- Result
- end.
-
--record(receiver, {sock :: socket:socket(),
- ctrl :: pid(),
- num_packages :: infinity | non_neg_ineteger()}).
-
-receiver_init(Pid, Ref) ->
- receive
- {?MODULE, receiver, Ref, stop} ->
- i("received stop"),
- exit(normal);
-
- {?MODULE, receiver, Ref, Sock, InitialMode} ->
- i("received socket: ~p", [Sock]),
- NumPackages = mode2pkgcount(InitialMode),
- receiver(#receiver{sock = Sock, ctrl = Pid})
- end.
-
-mode2pkgcount(true) ->
- infinity;
-mode2pkgcount(false) ->
- 0;
-mode2pkgcount(N) when is_integer(N) andalso (N >= 0) ->
- N.
-
-receiver(#receiver{num_packages = 0} = State) ->
- receive
- {?MODULE, active, false} ->
- receiver(State);
- {?MODULE, active, true} ->
- receiver(State#receiver{num_packages = infinity});
- {?MODULE, active, once} ->
- receiver(State#receiver{num_packages = 1});
- {?MODULE, active, N} when (N > 0) ->
- receiver(State#receiver{num_packages = N})
- end;
-receiver(#receiver{num_packages = N, sock = Sock, ctrl = Pid} = State) ->
- case socket:recv(Sock, 0) of
- {ok, Package} when size(Package) > 0 ->
- Pid ! {tcp, Sock, Packege},
- case next_active(N) of
- 0 ->
- Pid ! {tcp_passive, Sock},
- receiver(State#{num_packages = 0});
- NextN ->
- receiver(State#{num_packages = NextN})
- end;
- {ok, Package} when size(Package) =:= 0 ->
- receiver(State);
-
- {error, closed} ->
- i("closed"),
- Pid ! {tcp_closed, Sock},
- exit(normal);
-
- {error, Reason} ->
- i("error: ~p", [Reason]),
- Pid ! {tcp_error, Sock, Reason},
- exit(normal)
- end.
-
-
+ TBD