indexing description: "[ List of all sockets in system. Use EM_SHARED_SUBSYSTEMS.Network_subsystem to access the only instance of this class. As normal user of EiffelMedia you don't need to worry about this class. Use the various socket classes to access network. ]" date: "$Date$" revision: "$Revision$" class EM_SOCKETS inherit ANY EM_SHARED_ERROR_HANDLER export {NONE} all end create {EM_NETWORK_SUBSYSTEM} make feature {NONE} -- Initialisation make is -- Initialise. do -- Synchronize with 'maxSockets' in '$EM/library/manual_wrapper/c/net2.c' create sockets.make (0, 1023) create tcp_servers.make (30) create waiting_sockets.make create resolve_transactions.make end feature {EM_SOCKET} -- Implementation add_socket (a_socket: EM_SOCKET) is -- Add `a_socket'. require a_socket_not_void: a_socket /= Void socket_not_already_added: not has(a_socket) do sockets.put (a_socket, a_socket.net2_socket_id) ensure socket_added: has(a_socket) end remove_socket (a_socket: EM_SOCKET) is -- Remove `a_socket'. require a_socket_not_void: a_socket /= Void has_a_socket: has (a_socket) do sockets.put (Void, a_socket.net2_socket_id) ensure socket_removed: not has (a_socket) end has (a_socket: EM_SOCKET): BOOLEAN is -- Is `a_socket' present? do Result := sockets.item (a_socket.net2_socket_id) = a_socket end feature {EM_TCP_CLIENT_SOCKET} -- Implementation wait_for_connection (a_socket: EM_TCP_CLIENT_SOCKET) is -- Add 'a_socket' to waiting sockets. require a_socket_not_void: a_socket /= Void do waiting_sockets.force_last (a_socket) ensure socket_added: waiting_sockets.has (a_socket) end feature {EM_TCP_SERVER_SOCKET} -- Implementation is_port_free (a_port: INTEGER): BOOLEAN is -- Is 'a_port' alredy taken? -- This does not guarantee that 'a_port' is not taken by another program. do Result := not tcp_servers.has (a_port) end add_server (a_server: EM_TCP_SERVER_SOCKET) is -- Add 'a_server' to server list. require port_free: is_port_free (a_server.port) a_server_not_void: a_server /= Void do tcp_servers.put (a_server, a_server.port) end remove_server (a_server: EM_TCP_SERVER_SOCKET) is -- Remove 'a_server' from server list. require a_server_not_void: a_server /= Void do tcp_servers.remove (a_server.port) ensure port_freeded: is_port_free (a_server.port) end feature {EM_INET_ADDRESS, EM_SOCKET} -- Implementation add_transaction (transaction_id: INTEGER; an_inet_address: EM_INET_ADDRESS) is -- Add a transaction do resolve_transactions.put_last (create {EM_PAIR[INTEGER,EM_INET_ADDRESS]}.make (transaction_id,an_inet_address)) end next_transaction_id: INTEGER is -- Always a new transaction id do next_transaction_id_internal := next_transaction_id_internal + 1 if next_transaction_id_internal = next_transaction_id_internal.max_value then next_transaction_id_internal := 0 end Result := next_transaction_id_internal end feature {EM_EVENT_LOOP} -- Implementation handle_udp_receive_event (a_socket_id: INTEGER) is -- Handle a receive event on socket `a_socket_id'. local a_socket: EM_SOCKET do a_socket := sockets.item (a_socket_id) if a_socket /= Void then a_socket.handle_data_received else Error_handler.raise_error (Error_handler.Em_error_this_should_never_happen, ["handle_udp_receive_event"]) end end handle_udp_send_event (a_socket_id: INTEGER; an_error: INTEGER) is -- Handle an udp send event on socket `a_socket_id'. local a_socket: EM_SOCKET an_udp_socket: EM_UDP_SOCKET do a_socket := sockets.item (a_socket_id) if a_socket /= Void then an_udp_socket ?= a_socket if an_udp_socket /= Void then an_udp_socket.handle_send_failed (an_error) else Error_handler.raise_error (Error_handler.Em_error_this_should_never_happen, ["handle_udp_send_event 1"]) end else Error_handler.raise_error (Error_handler.Em_error_this_should_never_happen, ["handle_udp_send_event 2"]) end end handle_tcp_connect_event (a_socket_id: INTEGER; an_ip_pointer: POINTER) is -- Handle a connection established to a server. local a_client: EM_TCP_CLIENT_SOCKET do from a_client := Void waiting_sockets.start until waiting_sockets.after or a_client /= Void loop if waiting_sockets.item_for_iteration.address.ip_address_struct.item = an_ip_pointer then a_client := waiting_sockets.item_for_iteration waiting_sockets.remove_at else waiting_sockets.forth end end if a_client = Void then Error_handler.raise_error (Error_handler.Em_error_this_should_never_happen, ["handle_tcp_connect_event"]) else sockets.put (a_client, a_socket_id) a_client.handle_connection_established (a_socket_id) end end handle_tcp_connect_failed_event (an_error: INTEGER; an_ip_pointer: POINTER) is -- Handle a failed connection attempt. local a_client: EM_TCP_CLIENT_SOCKET do from a_client := Void waiting_sockets.start until waiting_sockets.after or a_client /= Void loop if waiting_sockets.item_for_iteration.address.ip_address_struct.item = an_ip_pointer then a_client := waiting_sockets.item_for_iteration waiting_sockets.remove_at else waiting_sockets.forth end end if a_client = Void then Error_handler.raise_error (Error_handler.Em_error_this_should_never_happen, ["handle_tcp_connect_failed_event"]) else a_client.handle_connection_failed (an_error) end end handle_tcp_accept_event (a_port, a_socket_id: INTEGER) is -- Handle a new connection on 'a_port' with 'a_socket_id'. local a_server: EM_TCP_SERVER_SOCKET a_client_socket: EM_TCP_CLIENT_SOCKET do if tcp_servers.has (a_port) then a_server := tcp_servers.item (a_port) create a_client_socket.make_from_socket_id (a_socket_id) sockets.put (a_client_socket, a_socket_id) a_server.handle_connection_accepted (a_client_socket) else Error_handler.raise_error (Error_handler.Em_error_this_should_never_happen, ["handle_tcp_accept_event"]) end end handle_tcp_close_event (a_socket_id: INTEGER) is -- Handle TCP close event. local a_socket: EM_SOCKET a_client: EM_TCP_CLIENT_SOCKET do a_socket := sockets.item (a_socket_id) if a_socket /= Void then a_client ?= a_socket if a_client /= Void then a_client.handle_connection_closed else Error_handler.raise_error (Error_handler.Em_error_this_should_never_happen, ["handle_tcp_close_event 1"]) end else Error_handler.raise_error (Error_handler.Em_error_this_should_never_happen, ["handle_tcp_close_event 2"]) end end handle_tcp_receive_event (a_socket_id: INTEGER) is -- Handle a receive event on socket `a_socket_id'. local a_socket: EM_SOCKET do a_socket := sockets.item (a_socket_id) if a_socket /= Void then a_socket.handle_data_received else Error_handler.raise_error (Error_handler.Em_error_this_should_never_happen, ["handle_tcp_receive_event"]) end end handle_resolve_finished_event (a_transaction_id: INTEGER) is -- Handle resolve trial finished for transaction `a_transaction_id'. do from resolve_transactions.start until resolve_transactions.after loop if resolve_transactions.item_for_iteration.first = a_transaction_id then resolve_transactions.item_for_iteration.second.resolve_finished_event.publish ([]) resolve_transactions.remove_at else resolve_transactions.forth end end end feature {NONE} -- Implementation sockets: ARRAY [EM_SOCKET] -- Sockets array -- maps net2 socket id's to em_socket's tcp_servers: DS_HASH_TABLE [EM_TCP_SERVER_SOCKET, INTEGER] -- TCP servers indexed by port waiting_sockets: DS_LINKED_LIST [EM_TCP_CLIENT_SOCKET] -- Sockets waiting for a connection resolve_transactions: DS_LINKED_LIST [EM_PAIR [INTEGER, EM_INET_ADDRESS]] -- Addresses waiting for resolve finished event next_transaction_id_internal: INTEGER -- Next transaction id internal end