-- -- EuTcp4u: Wrapper functions for tcp4u -- Ray Smith -- Version 1.03 -- -- History: -- 29/7/2010: V1.03 - Jean-Marc Duro -- added tcp4u_receive_long_sequence and tcp4u_send_long_sequence to allow -- transmission of long sequences (> 65535 which is tcp4u maximum length) -- added constant TCP4U_PARTIAL_SEQUENCE and modified function tcp4u_error_string -- 14/4/2002: V1.02 - Ray Smith -- Changed peek_sequence and added peek_sequence_null. -- peek_sequence_null() returns null terminated strings -- peek_sequence() was changed to always return buff_len bytes. -- This fixes a bug found by Chris re: not being able to transfer 0. -- 22/1/2002: -- Changed tcp4u_receive to only return the number of bytes recieved -- from the socket and not the number of bytes in the buffer -- 15/1/2002: -- Changed data type of Sockets from integer to atom (Thanks Kat and Chris) -- Added a poke2 function for poking port addresses (Thanks Chris) -- 8/8/2000: -- Original release ------------------------------------------- -- Includes ------------------------------------------- include dll.e include machine.e include get.e include misc.e include common.e with trace ------------------------------------------- -- EuTcp4u settings ------------------------------------------- -- User constants, change to appropriate values -- max size of sequence to read using tcp4u_recveive_sequence global integer TCP4U_MAX_MSG_SIZE TCP4U_MAX_MSG_SIZE = 16384 -- a token to use to stop reading data using tcp4u_receive_sequence global sequence TCP4U_STOP_STRING TCP4U_STOP_STRING = "EuTcPsToP" global constant tcp4u_ret = 1, tcp4u_buff = 2, tcp4u_socket = 2, tcp4u_host_name = 1, tcp4u_host_id_quad = 2, tcp4u_host_id = 3, tcp4u_ver_major = 1, tcp4u_ver_minor = 2, tcp4u_ver_string = 3 ------------------------------------------- -- Return Codes for TCP4U Functions ------------------------------------------- global constant TCP4U_SUCCESS = 1 -- function OK global constant TCP4U_ERROR = -1 -- error global constant TCP4U_TIMEOUT = -2 -- timeout has occured global constant TCP4U_BUFFERFREED = -3 -- the buffer has been freed global constant TCP4U_HOSTUNKNOWN = -4 -- connect to unknown host global constant TCP4U_NOMORESOCKET = -5 -- all socket has been used global constant TCP4U_NOMORERESOURCE = -5 -- or no more free resource global constant TCP4U_CONNECTFAILED = -6 -- connect function has failed global constant TCP4U_UNMATCHEDLENGTH = -7 -- TcpPPRecv : Error in length global constant TCP4U_BINDERROR = -8 -- bind failed (Task already started?) global constant TCP4U_OVERFLOW = -9 -- Overflow during TcpPPRecv global constant TCP4U_EMPTYBUFFER = -10 -- TcpPPRecv receives 0 byte global constant TCP4U_CANCELLED = -11 -- Call cancelled by signal global constant TCP4U_INSMEMORY = -12 -- Not enough memory global constant TCP4U_BADPORT = -13 -- Bad port number or alias global constant TCP4U_SOCKETCLOSED = 0 -- Host has closed connection global constant TCP4U_FILE_ERROR = -14 -- A file operation has failed -- wrapper function error numbers global constant TCP4U_CONVERSION_ERROR = -100 -- value failed on receive global constant TCP4U_PARTIAL_SEQUENCE = -99 -- Received sequence is not complete ------------------------------------------- -- Return Codes for HTTP4U Functions ------------------------------------------- global constant HTTP4U_BAD_URL = -100 global constant HTTP4U_TCP_FAILED = -99 global constant HTTP4U_HOST_UNKNOWN = -98 global constant HTTP4U_TCP_CONNECT = -97 global constant HTTP4U_FILE_ERROR = -96 global constant HTTP4U_INSMEMORY = -95 global constant HTTP4U_BAD_PARAM = -94 global constant HTTP4U_OVERFLOW = -93 global constant HTTP4U_CANCELLED = -92 global constant HTTP4U_NO_CONTENT = -90 global constant HTTP4U_MOVED = -89 global constant HTTP4U_BAD_REQUEST = -88 global constant HTTP4U_FORBIDDEN = -87 global constant HTTP4U_NOT_FOUND = -86 global constant HTTP4U_PROTOCOL_ERROR = -85 global constant HTTP4U_UNDEFINED = -84 global constant HTTP4U_TIMEOUT = -83 global constant HTTP4U_SUCCESS = 1 ------------------------------------------- -- Constants for HTTP4U ------------------------------------------- global constant HTTP4U_KBYTES = 1024 global constant HTTP4U_DFLT_TIMEOUT = 60 global constant HTTP4U_DFLT_BUFFERSIZE = 4 * HTTP4U_KBYTES ------------------------------------------- -- GENERAL PURPOSE ROUTINES ------------------------------------------- ------------------------------------------------ -- wait_abort ------------------------------------------------ global procedure wait_abort(sequence msg) integer wait printf(1, "%s\n", {msg} ) wait = wait_key() abort(1) end procedure ------------------------------------------------ -- link_dll - taken from win32lib - thanks David ------------------------------------------------ global function link_dll(sequence name) atom handle handle = open_dll( name ) if handle = NULL then wait_abort("Couldn't find DLL " & name) end if return handle end function ------------------------------------------------ -- link_func - taken from win32lib - thanks David ------------------------------------------------ global function link_func(atom dll, sequence name, sequence args, atom result) integer handle handle = define_c_func(dll, name, args, result) if handle = -1 then wait_abort("Couldn't link to C function " & name) end if return handle end function ------------------------------------------------ -- link_proc - taken from win32lib - thanks David ------------------------------------------------ global function link_proc(atom dll, sequence name, sequence args) integer handle handle = define_c_proc(dll, name, args) if handle = -1 then wait_abort("Couldn't link to C procedure " & name) end if return handle end function ------------------------------------- -- peek_sequence_null ------------------------------------- -- peeks data out of memory and puts it into a sequence -- used for null terminated strings global function peek_sequence_null(atom addr, integer len) integer i, tmp sequence seq seq="" i=0 tmp=peek(addr) while (tmp != 0 and i 0 then buff_seq = peek_sequence(buff_addr, ret) else buff_seq = {} end if free(buff_addr) --puts(f_debug, "tcp4u_receive\n") --analyzeSequence(buff_seq, " buf", f_debug) return {ret, buff_seq} end function ------------------------------------------------ -- tcp4u_receive_until_str ------------------------------------------------ global function tcp4u_receive_until_str(atom socket, integer buff_size, sequence stop_string, integer case_sensitive, integer time_out) integer ret, stop_len atom buff_addr, stop_addr, buff_size_addr sequence buff_seq buff_addr = allocate(buff_size) stop_addr = allocate_string(stop_string) stop_len = length(stop_string) buff_size_addr = allocate(4) poke4(buff_size_addr, buff_size) ret = c_func(myTcpRecvUntilStr, {socket, buff_addr, buff_size_addr, stop_addr, stop_len, case_sensitive, time_out, TCP4U_FILE_ERROR}) buff_size = peek4u(buff_size_addr) buff_seq = peek_sequence(buff_addr, buff_size) free(buff_addr) free(stop_addr) free(buff_size_addr) --puts(f_debug, "tcp4u_receive_until_str\n") --analyzeSequence(buff_seq, " buf", f_debug) return {ret, buff_seq} end function ------------------------------------------------ -- right ------------------------------------------------ function right(sequence s, integer n) -- returns the n characters at the right of string s integer l l = length(s) if (l=0) or (n=0) then return "" end if if n >= l then return s end if return s[l-n+1..l] end function ------------------------------------------------ -- tcp4u_receive_sequence ------------------------------------------------ global function tcp4u_receive_sequence(atom socket, integer time_out) sequence ret sequence seq ret = tcp4u_receive_until_str(socket, TCP4U_MAX_MSG_SIZE, TCP4U_STOP_STRING, 1, time_out) if ret[tcp4u_ret] != TCP4U_SUCCESS then return { ret[tcp4u_ret], {} } else seq = value(ret[tcp4u_buff]) if seq[tcp4u_ret] != GET_SUCCESS then return { TCP4U_CONVERSION_ERROR, {} } else return { ret[tcp4u_ret], seq[tcp4u_buff] } end if end if end function ------------------------------------------------ -- tcp4u_receive_long_sequence ------------------------------------------------ global function tcp4u_receive_long_sequence(atom socket, integer time_out) sequence ret, comp sequence seq integer lg_stop ret = tcp4u_receive(socket, TCP4U_MAX_MSG_SIZE, time_out) if ret[tcp4u_ret] < TCP4U_SUCCESS then return { ret[tcp4u_ret], {} } else -- correct sequence lg_stop = length(TCP4U_STOP_STRING) if compare(right(ret[tcp4u_buff], lg_stop), TCP4U_STOP_STRING) = 0 then -- normal sequence: remove STOP tag and call value() seq = value(ret[tcp4u_buff][1..$-lg_stop]) analyzeSequence(seq, "seq", f_debug) if seq[tcp4u_ret] != GET_SUCCESS then return { TCP4U_CONVERSION_ERROR, {} } else return { TCP4U_SUCCESS, seq[tcp4u_buff] } end if else -- long sequence: append segments before removing STOP tag and calling value() comp = {} while compare(right(ret[tcp4u_buff], lg_stop), TCP4U_STOP_STRING) != 0 do -- while end of sequence not reached comp &= ret[tcp4u_buff] -- append segment to sequence ret = tcp4u_receive(socket, TCP4U_MAX_MSG_SIZE, time_out) if ret[tcp4u_ret] < TCP4U_SUCCESS then return { TCP4U_PARTIAL_SEQUENCE, comp } -- returns a sequence that is not complete end if end while comp &= ret[tcp4u_buff][1..$-lg_stop] -- append segment minus STOP tag to sequence seq = value(comp) analyzeSequence(seq, "seq", f_debug) if seq[tcp4u_ret] != GET_SUCCESS then return { TCP4U_CONVERSION_ERROR, {} } else return { TCP4U_SUCCESS, seq[tcp4u_buff] } end if end if end if end function ------------------------------------------------ -- tcp4u_send ------------------------------------------------ global function tcp4u_send(atom socket, sequence buff) integer ret, high_priority atom buff_addr puts(f_debug, "tcp4u_send\n") analyzeSequence(buff, " buf", f_debug) high_priority = 0 buff_addr = allocate_string(buff) ret = c_func(myTcpSend, {socket, buff_addr, length(buff), high_priority, TCP4U_FILE_ERROR}) free(buff_addr) return ret end function ------------------------------------------------ -- tcp4u_send_sequence ------------------------------------------------ global function tcp4u_send_sequence(atom socket, sequence buff) integer ret sequence conv_buff if length(buff) > TCP4U_MAX_MSG_SIZE - length(TCP4U_STOP_STRING) then return TCP4U_OVERFLOW else conv_buff = sprint(buff) & TCP4U_STOP_STRING ret = tcp4u_send(socket, conv_buff) return ret end if end function ------------------------------------------------ -- tcp4u_send_long_sequence ------------------------------------------------ global function tcp4u_send_long_sequence(atom socket, sequence buff) integer ret, max_length sequence conv_buff, sent integer lg max_length = TCP4U_MAX_MSG_SIZE - length(TCP4U_STOP_STRING) conv_buff = sprint(buff) lg = length(conv_buff) while lg > max_length do if lg > TCP4U_MAX_MSG_SIZE then sent = conv_buff[1..TCP4U_MAX_MSG_SIZE] conv_buff = conv_buff[TCP4U_MAX_MSG_SIZE+1..$] else sent = conv_buff[1..max_length] conv_buff = conv_buff[max_length+1..$] end if ret = tcp4u_send(socket, sent) if ret != TCP4U_SUCCESS then return ret end if lg = length(conv_buff) end while ret = tcp4u_send(socket, conv_buff & TCP4U_STOP_STRING) return ret end function ------------------------------------------------ -- tcp4u_flush ------------------------------------------------ global function tcp4u_flush(atom socket) integer ret ret = c_func(myTcpFlush, {socket}) return ret end function ------------------------------------------------ -- tcp4u_is_data_avail ------------------------------------------------ global function tcp4u_is_data_avail(atom socket) integer ret ret = c_func(myTcpIsDataAvail, {socket}) return ret end function ------------------------------------------------ -- tcp4u_get_remote_id ------------------------------------------------ global function tcp4u_get_remote_id(atom socket) integer ret, name_len atom name_addr, ip_addr sequence name_seq, ip_seq name_len = 100 name_addr = allocate(name_len) ip_addr = allocate(4) ret = c_func(myTcpGetRemoteID, {socket, name_addr, name_len, ip_addr}) name_seq = peek_sequence_null(name_addr, name_len) ip_seq = { peek(ip_addr), peek(ip_addr+1), peek(ip_addr+2), peek(ip_addr+3) } free(name_addr) free(ip_addr) return {name_seq, ip_seq, sprintf("%d.%d.%d.%d", {ip_seq[1], ip_seq[2], ip_seq[3], ip_seq[4]}) } end function ------------------------------------------------ -- http4u_set_buffer_size ------------------------------------------------ global procedure http4u_set_buffer_size(integer buff_size) c_proc(myHttp4uSetBufferSize, {buff_size}) end procedure ------------------------------------------------ -- http4u_set_timeout ------------------------------------------------ global procedure http4u_set_timeout(integer timeout) c_proc(myHttp4uSetTimeout, {timeout}) end procedure ------------------------------------------------ -- http4u_error_string ------------------------------------------------ global function http4u_error_string (integer msg_code) sequence error_string atom addr addr = c_func(myHttp4uErrorString, {msg_code}) error_string = peek_sequence_null(addr, 256) return error_string end function ------------------------------------------------ -- http4u_get_file ------------------------------------------------ global function http4u_get_file(sequence url, object proxy, sequence filename) integer ret atom addr_url, addr_proxy, addr_filename addr_url = allocate_string(url) addr_filename = allocate_string(filename) if sequence(proxy) and length(proxy) > 0 then addr_proxy = allocate_string(proxy) ret = c_func(myHttpGetFile, {addr_url, addr_proxy, addr_filename}) free(addr_proxy) else ret = c_func(myHttpGetFile, {addr_url, NULL, addr_filename}) end if free(addr_url) free(addr_filename) return ret end function