diff -uNr a/udp/libudp/syscall.adb b/udp/libudp/syscall.adb --- a/udp/libudp/syscall.adb false +++ b/udp/libudp/syscall.adb 200b4319b30e299f9e7063a027a3c60b0d0db36f27776399f8f0f8a5475a773c685cd9b9650a8527c1e7ec91040f2adad0a87031aec07c08f2aab0212378f892 @@ -0,0 +1,148 @@ +with System.Machine_Code; use System.Machine_Code; + +package body Syscall is + SYSCALL_CLOSE : constant := 3; + SYSCALL_SOCKET : constant := 41; + SYSCALL_SENDTO : constant := 44; + SYSCALL_RECVFROM : constant := 45; + SYSCALL_BIND : constant := 49; + SYSCALL_SETSOCKOPT : constant := 54; + + function sys_socket + (domain : in Interfaces.C.int; + socket_type : in Interfaces.C.int; + protocol : in Interfaces.C.int) return Interfaces.C.int is + R : Interfaces.C.int := 0; + begin + Asm + ("syscall", + Outputs => (Interfaces.C.int'Asm_Output ("=a", R)), + Inputs => + (Interfaces.C.int'Asm_Input ("a", SYSCALL_SOCKET), + Interfaces.C.int'Asm_Input ("D", domain), + Interfaces.C.int'Asm_Input ("S", socket_type), + Interfaces.C.int'Asm_Input ("d", protocol)), + Clobber => "rcx, r11", + Volatile => True); + return R; + end sys_socket; + + function sys_bind + (sockfd : in Interfaces.C.int; + addr : in System.Address; + addrlen : in Interfaces.C.int) return Interfaces.C.int is + R : Interfaces.C.int; + begin + Asm + ("syscall", + Outputs => (Interfaces.C.int'Asm_Output ("=a", R)), + Inputs => + (Interfaces.C.int'Asm_Input ("a", SYSCALL_BIND), + Interfaces.C.int'Asm_Input ("D", sockfd), + System.Address'Asm_Input ("S", addr), + Interfaces.C.int'Asm_Input ("d", addrlen)), + Clobber => "rcx, r11", + Volatile => True); + return R; + end sys_bind; + + function sys_recvfrom + (sockfd : in Interfaces.C.int; + buf : in System.Address; + len : in Interfaces.C.int; + flags : in Interfaces.Unsigned_64 := 0; + src_addr : in System.Address; + addrlen : in out Interfaces.C.int) return Interfaces.C.int + is + R : Interfaces.C.int; + begin + Asm + ("movq %5, %%r10" & ASCII.LF & + "movq %6, %%r8" & ASCII.LF & + "movq %7, %%r9" & ASCII.LF & + "syscall", + Outputs => (Interfaces.C.int'Asm_Output ("=a", R)), + Inputs => + (Interfaces.C.int'Asm_Input ("a", SYSCALL_RECVFROM), + Interfaces.C.int'Asm_Input ("D", sockfd), + System.Address'Asm_Input ("S", buf), + Interfaces.C.int'Asm_Input ("d", len), + Interfaces.Unsigned_64'Asm_Input ("c", flags), + System.Address'Asm_Input ("g", src_addr), + System.Address'Asm_Input ("g", addrlen'Address)), + Clobber => "r8, r10, r9, r11, memory", + Volatile => True); + return R; + end sys_recvfrom; + + function sys_sendto + (sockfd : in Interfaces.C.int; + buf : in System.Address; + len : in Interfaces.C.int; + flags : in Interfaces.Unsigned_64 := 0; + dest_addr : in System.Address; + addrlen : in Interfaces.C.int) return Interfaces.C.int + is + R : Interfaces.C.int; + begin + Asm + ("movq %5, %%r10" & ASCII.LF & + "movq %6, %%r8" & ASCII.LF & + "movq %7, %%r9" & ASCII.LF & + "syscall", + Outputs => (Interfaces.C.int'Asm_Output ("=a", R)), + Inputs => + (Interfaces.C.int'Asm_Input ("a", SYSCALL_SENDTO), + Interfaces.C.int'Asm_Input ("D", sockfd), + System.Address'Asm_Input ("S", buf), + Interfaces.C.int'Asm_Input ("d", len), + Interfaces.Unsigned_64 'Asm_Input ("c", flags), + System.Address'Asm_Input ("g", dest_addr), + Interfaces.Unsigned_64 'Asm_Input + ("g", Interfaces.Unsigned_64(addrlen))), + Clobber => "r8, r9, r10, r11", + Volatile => True); + return R; + end sys_sendto; + + function sys_close (fd : in Interfaces.C.int) return Interfaces.C.int is + R : Interfaces.C.int; + begin + Asm + ("syscall", + Outputs => (Interfaces.C.int'Asm_Output ("=a", R)), + Inputs => (Interfaces.C.int'Asm_Input ("a", SYSCALL_CLOSE), + Interfaces.C.int'Asm_Input ("D", fd)), + Clobber => "r11, rcx", + Volatile => True); + return R; + end sys_close; + + + function sys_setsockopt + (sockfd : in Interfaces.C.int; + level : in Interfaces.C.int; + optname : in Interfaces.C.int; + optval : in System.Address; + optlen : in Interfaces.Unsigned_64) return Interfaces.C.int + is + R : Interfaces.C.int; + begin + Asm + ("movq %5, %%r10" & ASCII.LF & + "movq %6, %%r8" & ASCII.LF & + "syscall", + Outputs => (Interfaces.C.int'Asm_Output ("=a", R)), + Inputs => + (Interfaces.C.int'Asm_Input ("a", SYSCALL_SETSOCKOPT), + Interfaces.C.int'Asm_Input ("D", sockfd), + Interfaces.C.int'Asm_Input ("S", level), + Interfaces.C.int'Asm_Input ("d", optname), + System.Address'Asm_Input ("c", optval), + Interfaces.Unsigned_64 'Asm_Input ("g", optlen)), + Clobber => "r8, r9, r10, r11", + Volatile => True); + return R; + end sys_setsockopt; + +end Syscall; diff -uNr a/udp/libudp/syscall.ads b/udp/libudp/syscall.ads --- a/udp/libudp/syscall.ads false +++ b/udp/libudp/syscall.ads 1db83cb65cae4630d3010cb0b8b9aefcb6c3c1fae83b343890f13197c3f79369fa2dcb7c17ba7faf1b58abc6fe3eac7ba3f23c7a5db7ccba20d509b10594fd0a @@ -0,0 +1,43 @@ +with Interfaces; +with Interfaces.C; +with System; + +package Syscall is + pragma Preelaborate; + + function sys_socket + (domain : in Interfaces.C.int; + socket_type : in Interfaces.C.int; + protocol : in Interfaces.C.int) return Interfaces.C.int; + + function sys_bind + (sockfd : in Interfaces.C.int; + addr : in System.Address; + addrlen : in Interfaces.C.int) return Interfaces.C.int; + + function sys_recvfrom + (sockfd : in Interfaces.C.int; + buf : in System.Address; + len : in Interfaces.C.int; + flags : in Interfaces.Unsigned_64 := 0; + src_addr : in System.Address; + addrlen : in out Interfaces.C.int) return Interfaces.C.int; + + function sys_sendto + (sockfd : in Interfaces.C.int; + buf : in System.Address; + len : in Interfaces.C.int; + flags : in Interfaces.Unsigned_64 := 0; + dest_addr : in System.Address; + addrlen : in Interfaces.C.int) return Interfaces.C.int; + + function sys_close (fd : in Interfaces.C.int) return Interfaces.C.int; + + function sys_setsockopt + (sockfd : in Interfaces.C.int; + level : in Interfaces.C.int; + optname : in Interfaces.C.int; + optval : in System.Address; + optlen : in Interfaces.Unsigned_64) return Interfaces.C.int; + +end Syscall; diff -uNr a/udp/libudp/udp.adb b/udp/libudp/udp.adb --- a/udp/libudp/udp.adb fac6c1240a87ba4838ee02af197f58392fb7833b40a9841716653d9d468b18c37201585a66bc2133c8f2f5c60bdc0364291a64b91ae301281ecec416dad6c57f +++ b/udp/libudp/udp.adb e2afd89c409dbb2842d21b1336b4435b45ae9485da17aba136dec30859c6425c8329a2ae37dfc467354cf637de74763e80555eedb9dd2de9e680f043aedd4998 @@ -17,6 +17,9 @@ ------------------------------------------------------------------------------ ------------------------------------------------------------------------------ +with Syscall; use Syscall; +with System.Machine_Code; use System.Machine_Code; + package body UDP is -- Generate a human representation of a (local-endian) IP Address @@ -224,5 +227,137 @@ S(I) := Character'Val(Z+C); return I + 1; end write_mod1000_to_string; - + + ----- + function has_syscall_error(E : Interfaces.C.int) return Boolean + is + begin + return E < 0 and E > -(2**12); + end has_syscall_error; + + function Unix_UDP_Socket_Open + (Socket : System.Address; + Local_IP : Unsigned_32; + Local_Port : Unsigned_16) return Interfaces.C.int is + + E : Interfaces.C.Int; + S : Udp.Socket; + One : constant Interfaces.C.Int := 1; + for S'Address use Socket; + begin + S.FD := sys_socket(AF_INET, SOCK_DGRAM, IPROTO_UDP); + if has_syscall_error(S.FD) then + return -1; + end if; + + E := sys_setsockopt + (S.FD, + SOL_SOCKET, SO_REUSEADDR, + One'Address, one'Size / Unsigned_8'Size); + if has_syscall_error(E) then + E := sys_close(S.FD); + return -2; + end if; + + S.SA := ( + family => AF_INET, + sin_addr => ByteSwap32(Local_IP), + port => ByteSwap16(Local_Port), + padding => 0); + + E := sys_bind(S.FD, S.SA'Address, S.SA'Size / Unsigned_8'Size); + if has_syscall_error(E) then + E := sys_close(S.FD); + return -3; + end if; + + return 0; + end Unix_UDP_Socket_Open; + + procedure Unix_UDP_Socket_Close + (Socket : System.Address) is + E : Interfaces.C.Int; + S : Udp.Socket; + for S'Address use Socket; + begin + E := sys_close(S.FD); + end Unix_UDP_Socket_Close; + + function Unix_UDP_Socket_Transmit + (Socket : System.Address; + Remote_IP : Unsigned_32; + Remote_Port : Unsigned_16; + Payload_Buf : System.Address; + Payload_Len : Unsigned_32) return Interfaces.C.int is + A : sockaddr_in := (family=>AF_INET, + sin_addr=>ByteSwap32(Remote_IP), + port=>ByteSwap16(Remote_port), + padding=>0); + S : Udp.Socket; + E : Interfaces.C.Int; + for S'Address use Socket; + begin + E := sys_sendto (S.FD, + Payload_Buf, Interfaces.C.Int(Payload_Len), + 0, -- flags == 0 + A'Address, A'Size / Unsigned_8'Size); + if has_syscall_error(E) then + return -1; + end if; + + return E; + end Unix_UDP_Socket_Transmit; + + function Unix_UDP_Socket_Receive + (Socket : System.Address; + Origin_IP : not null access Unsigned_32; + Origin_Port : not null access Unsigned_16; + Payload_Buf : System.Address; + Payload_Len : Unsigned_32) return Interfaces.C.int is + A : sockaddr_in := (family=>AF_INET, + sin_addr=>0, + port=>0, + padding=>0); + S : Udp.Socket; + E : Interfaces.C.Int; + L : Interfaces.C.Int := A'Size / Unsigned_8'Size; + for S'Address use Socket; + begin + E := sys_recvfrom (S.FD, + Payload_Buf, Interfaces.C.Int(Payload_Len), + 0, + A'Address, L); + + if has_syscall_error(E) then + return -1; + end if; + + Origin_IP.all := ByteSwap32(A.sin_addr); + Origin_Port.all := ByteSwap16(A.port); + + if E < 0 then + return -1; + end if; + + return E; + end Unix_UDP_Socket_Receive; + + + function ByteSwap32 (N : in Unsigned_32) return Unsigned_32 is + R : Unsigned_32; + begin + Asm ("bswap %%eax", + Inputs => Unsigned_32'Asm_Input ("a", N), + Outputs => Unsigned_32'Asm_Output ("=a", R)); + return R; + end ByteSwap32; + + function ByteSwap16 (N : in Unsigned_16) return Unsigned_16 is + R : Unsigned_16; + begin + Asm ("xchg %%ah,%%al", + Inputs => Unsigned_16'Asm_Input ("a", N), + Outputs => Unsigned_16'Asm_Output ("=a", R)); + return R; + end ByteSwap16; end UDP; diff -uNr a/udp/libudp/udp.ads b/udp/libudp/udp.ads --- a/udp/libudp/udp.ads 257085592c6440e74e1f64ce625940e6c61fd1bec56fdef327a8fc17d58578caadbe041a0d4f16c71abeff2192b19a64ff25959d76685509a0c2d3c2b030f502 +++ b/udp/libudp/udp.ads e6a7b2f40ed5716486885c59cd1aaad8b55ebf31c7821bc28d9dc164b38027b3f88e05ac326a5b548f15638610740c9640b615a650b0867ac09e5d4125e74fd7 @@ -107,28 +107,14 @@ end record; pragma Convention(C, Socket); - -- Everything below -- imports from unix_udp.c: - - procedure Unix_UDP_IP_To_String - (IP : Unsigned_32; - Output_Buffer : System.Address; - Output_Buffer_Size : Unsigned_32); - pragma Import(C, Unix_UDP_IP_To_String, "unix_udp_ip_to_string"); - - function Unix_UDP_String_To_IP - (Input_Buffer : System.Address; - IP : not null access Unsigned_32) return Interfaces.C.int; - pragma Import(C, Unix_UDP_String_To_IP, "unix_udp_string_to_ip"); function Unix_UDP_Socket_Open (Socket : System.Address; Local_IP : Unsigned_32; Local_Port : Unsigned_16) return Interfaces.C.int; - pragma Import(C, Unix_UDP_Socket_Open, "unix_udp_socket_open"); procedure Unix_UDP_Socket_Close (Socket : System.Address); - pragma Import(C, Unix_UDP_Socket_Close, "unix_udp_socket_close"); function Unix_UDP_Socket_Transmit (Socket : System.Address; @@ -136,7 +122,6 @@ Remote_Port : Unsigned_16; Payload_Buf : System.Address; Payload_Len : Unsigned_32) return Interfaces.C.int; - pragma Import(C, Unix_UDP_Socket_Transmit, "unix_udp_socket_transmit"); function Unix_UDP_Socket_Receive (Socket : System.Address; @@ -144,7 +129,9 @@ Origin_Port : not null access Unsigned_16; Payload_Buf : System.Address; Payload_Len : Unsigned_32) return Interfaces.C.int; - pragma Import(C, Unix_UDP_Socket_Receive, "unix_udp_socket_receive"); + + function ByteSwap32 (N : in Unsigned_32) return Unsigned_32; + function ByteSwap16 (N : in Unsigned_16) return Unsigned_16; -- Support functions for conversion between a string and an ip-address function read_mod1000_from_string @@ -156,6 +143,12 @@ (V : in IP_Address; S : in out String; INDEX : in Integer) return Integer; - - + + -- Linux or architecture specific constants + AF_INET : constant := 2; + SOCK_DGRAM : constant := 2; + IPROTO_UDP : constant := 17; + SOL_SOCKET : constant := 1; + SO_REUSEADDR : constant := 2; + end UDP; diff -uNr a/udp/libudp/udp.gpr b/udp/libudp/udp.gpr --- a/udp/libudp/udp.gpr 8547b598d4310c0a25ed8feb79159195e97c8b4546f7e5099490e5fdfb83e4f2869eee9efc77a0fd24448308192059252f986fa2b14b7de67ff3686eb422554c +++ b/udp/libudp/udp.gpr a90a346f69a70760b8423b5aa5a9faf47e925a4f75ff9ed17c777751b09495c6bb299c5187ac2c7476e9891fe28776ddbbf385ce473ca9225cc087e7a637ff71 @@ -24,7 +24,7 @@ type Mode_Type is ("debug", "release"); Mode : Mode_Type := external ("mode", "release"); - for Languages use ("Ada", "C"); + for Languages use ("Ada"); for Source_Dirs use ("."); for Library_Dir use "lib"; for Library_Name use "UDP"; diff -uNr a/udp/libudp/unix_udp.c b/udp/libudp/unix_udp.c --- a/udp/libudp/unix_udp.c 575886decfb03275e991dad5372d9f29627e287a3ae29e920b817f7f57f72fd672e09e800bc07166fa6ed97436d66e4c9f0cb06329468b13102758db3b76f90e +++ b/udp/libudp/unix_udp.c bcf56ac882ad981cd0fa74f0f397572c28801c1eb31c1bac4ca703d6f19e9419d693ba6c2b55efbf139777fa6bed9421506f9f27d462e7aacff3202a88ca2389 @@ -1,141 +0,0 @@ -/* ------------------------------------------------------------------------------- ------------------------------------------------------------------------------- --- This file is part of 'UDP', a datagram sockets library. -- --- -- --- (C) 2018 Stanislav Datskovskiy ( www.loper-os.org ) -- --- http://wot.deedbot.org/17215D118B7239507FAFED98B98228A001ABFFC7.html -- --- -- --- You do not have, nor can you ever acquire the right to use, copy or -- --- distribute this software ; Should you use this software for any purpose, -- --- or copy and distribute it to anyone or in any manner, you are breaking -- --- the laws of whatever soi-disant jurisdiction, and you promise to -- --- continue doing so for the indefinite future. In any case, please -- --- always : read and understand any software ; verify any PGP signatures -- --- that you use - for any purpose. -- --- -- --- See also http://trilema.com/2015/a-new-software-licensing-paradigm . -- ------------------------------------------------------------------------------- ------------------------------------------------------------------------------- -*/ - -#include -#include -#include -#include -#include -#include - - -/* Socket state representation: */ -typedef struct _UDP_Socket { - struct sockaddr_in sa_local; - int sock; -} UDP_Socket; - - -/* local-endian ip to string conversion */ -void unix_udp_ip_to_string(uint32_t ip, char *buf, uint32_t buf_size) { - struct in_addr addr; - addr.s_addr = htonl(ip); - char *txt = inet_ntoa(addr); - strncpy(buf, txt, buf_size); -} -/* Should be replaced with native routine */ - - -/* string to local-endian ip conversion */ -int unix_udp_string_to_ip(char *buf, uint32_t *ip) { - struct in_addr addr; - if (inet_aton(buf, &addr) <= 0) - return -1; - *ip = ntohl(addr.s_addr); - return 0; -} -/* Should be replaced with native routine */ - - -int unix_udp_socket_open(UDP_Socket *S, - uint32_t local_ip, uint16_t local_port) { - /* Open the socket FD: */ - if ((S->sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { - return -1; - } - - memset(&S->sa_local, 0, sizeof(struct sockaddr_in)); - - /* Set up emitter endpoint, converting from local endianness: */ - S->sa_local.sin_family = AF_INET; - S->sa_local.sin_addr.s_addr = htonl(local_ip); - S->sa_local.sin_port = htons(local_port); - - /* Cure the asinine linuxism where dead sockets interfere with living: */ - int one = 1; - if (setsockopt(S->sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0) { - close(S->sock); - return -2; - } - - /* Bind the socket */ - if (bind(S->sock, - (struct sockaddr *)&(S->sa_local), sizeof(S->sa_local)) < 0) { - close(S->sock); - return -3; - } - - /* ok */ - return 0; -} - - -void unix_udp_socket_close(UDP_Socket *S) { - close(S->sock); -} - - -int unix_udp_socket_transmit(UDP_Socket *S, - uint32_t remote_ip, uint16_t remote_port, - uint8_t *payload, uint32_t payload_len) { - int bytes_sent = 0; - struct sockaddr_in remote_addr; - memset((char *)&remote_addr, 0, sizeof(remote_addr)); - - /* Set up dest endpoint, converting from local endianness: */ - remote_addr.sin_family = AF_INET; - remote_addr.sin_port = htons(remote_port); - remote_addr.sin_addr.s_addr = htonl(remote_ip); - - /* Transmit Datagram */ - bytes_sent = sendto(S->sock, payload, payload_len, - 0, /* no flags */ - (struct sockaddr*)&remote_addr, - sizeof(remote_addr)); - if (bytes_sent <= 0) - return -1; - - return bytes_sent; -} - - -int unix_udp_socket_receive(UDP_Socket *S, - uint32_t *origin_ip, uint16_t *origin_port, - uint8_t *payload, uint32_t payload_len) { - int bytes_received = 0; - struct sockaddr_in orig_addr; - socklen_t orig_addr_len = sizeof(orig_addr); - memset((char *)&orig_addr, 0, sizeof(orig_addr)); - - /* Receive Datagram (blocking!) */ - bytes_received = recvfrom(S->sock, payload, payload_len, - 0, /* no flags */ - (struct sockaddr *)&orig_addr, - &orig_addr_len); - - if (bytes_received < 0) return -1; - - /* Save the originator's endpoint in ~local~ endianness */ - *origin_ip = ntohl(orig_addr.sin_addr.s_addr); - *origin_port = ntohs(orig_addr.sin_port); - - return bytes_received; -} diff -uNr a/udp/manifest b/udp/manifest --- a/udp/manifest 135461b32061a95d3ab747a510040dbfa72040dd628dc8609fc213ef1c2f74d6c78c72df53f14ea592cd7757a16f14c4f57e89dda9ba9ef738cbee76f3ff6fd1 +++ b/udp/manifest e346d87d1671a3d3ef6c9fdc78a080feaaff540152a796215520deb023b26467a5ccb975aeeccc2ea1dc28ac7e365a7b290d712d82607961db2308f48f1a21ec @@ -1,3 +1,4 @@ 543080 udp_genesis diana_coman Regrind of asciilifeform's UDP lib genesis, to bring it to current format (Keccak hashes, manifest file and standard compliant names for vpatches). A minimal library for UDP communications with fixed-size payloads sent/received over the wire. Uses Ada and C code. 543081 udp_errata_asciilifeform diana_coman Regrind of asciilifeform's errata on his UDP lib: adds closing socket calls, corrects and adds to comments. 543909 custom_conversion_ave1 Use Ada based function to convert from ip address to string and vice versa. +549808 x86_64_asm_ave1 Replace C calls with assembly