indexing description: "[ A specialized UDP socket that can be linked into the event loop such that an event handler will be called if new incomming packets are detected. ]" date: "$Date$" revision: "$Revision$" class EM_UDP_SOCKET inherit EM_SOCKET EM_NETWORK_CONSTANTS export {NONE} all end EM_SHARED_ERROR_HANDLER export {NONE} all end NET2_FUNCTIONS_EXTERNAL export {NONE} all end create make feature -- Initialization make is -- Init do -- make_delayed_procedures create data_received_event create send_failed_event ensure data_received_event_created: data_received_event /= Void end feature -- Access last_packet: EM_UDP_PACKET -- Last received packet feature -- Status setting open is -- Open UDP Socket on `a_port'. do net2_socket_id := net2_udpaccept_on_external (port, Max_udp_packet_size) if net2_socket_id < 0 then error_handler.raise_error (error_handler.Em_error_udp_open,[]) else network_subsystem.sockets.add_socket (Current) is_open := True end ensure then open: is_open end close is -- Close the UDP socket. do network_subsystem.sockets.remove_socket (Current) net2_udpclose_external (net2_socket_id) net2_socket_id := -1 is_open := false end feature -- Basic operations send (a_packet: EM_UDP_PACKET) is -- Send `a_packet' to its destination. require open: is_open local a_transaction_id: INTEGER hostname_data: ANY do if not a_packet.address.is_resolved then -- Add a resolve transaction a_transaction_id := network_subsystem.sockets.next_transaction_id network_subsystem.sockets.add_transaction (a_transaction_id, a_packet.address) -- Only possible to give this pointer to another thread because we keep a refrence on it. hostname_data := a_packet.address.hostname.to_c net2_udpsend_to_threaded_external (net2_socket_id, $hostname_data, a_packet.address.port, a_packet.udp_packet_struct.data,a_packet.udp_packet_struct.len, a_packet.address.ip_address_struct.item, a_transaction_id) else if net2_udpsend_external (net2_socket_id, a_packet.address.ip_address_struct.item, a_packet.udp_packet_struct.data,a_packet.udp_packet_struct.len) = -1 then send_failed_event.publish ([error_handler.Em_error_send_failed]) end end end send_direct (a_destination: EM_INET_SOCKET_ADDRESS; a_string: STRING) is -- Send `a_string' to `a_destination'. local string_data, hostname_data: ANY a_transaction_id: INTEGER do string_data := a_string.to_c if a_destination.is_resolved then if net2_udpsend_external (net2_socket_id, a_destination.ip_address_struct.item, $string_data, a_string.count) = -1 then send_failed_event.publish ([Error_handler.Em_error_send_failed]) end else -- Add a resolve transaction a_transaction_id := network_subsystem.sockets.next_transaction_id network_subsystem.sockets.add_transaction (a_transaction_id, a_destination) -- It's allowed to give this to another thread because we keep a reference to the EM_INET_SOCKET_ADDRESS object. hostname_data := a_destination.hostname.to_c net2_udpsend_to_threaded_external (net2_socket_id, $hostname_data, a_destination.port,$string_data,a_string.count,a_destination.ip_address_struct.item, a_transaction_id) end end feature {EM_SOCKETS} -- Implementation handle_data_received is -- Handle data reveived event. local a_packet_struct: UDPPACKET_STRUCT a_pointer: POINTER do from a_pointer := net2_udpread_external (net2_socket_id) until a_pointer = Default_pointer loop create a_packet_struct.make_shared (a_pointer) create last_packet.make_from_struct (a_packet_struct) net2_udpfree_packet_external (a_packet_struct.item) data_received_event.publish ([last_packet]) a_pointer := net2_udpread_external (net2_socket_id) end end handle_send_failed (an_error: INTEGER) is -- Handle send failed. do send_failed_event.publish ([an_error]) end feature -- Events data_received_event: EM_EVENT_CHANNEL [TUPLE[EM_UDP_PACKET]] -- Handle a received packet. send_failed_event: EM_EVENT_CHANNEL [TUPLE [INTEGER]] -- Send failed event. -- Passed parameter is the error code: Em_error_resolve_ip or Em_error_send_failed feature {NONE} -- Implementation end