aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeffrey Armstrong <jeff@approximatrix.com>2020-04-29 17:39:05 -0400
committerJeffrey Armstrong <jeff@approximatrix.com>2020-04-29 17:39:05 -0400
commit537ff39898992c3915bcf01e3840becc6750520f (patch)
tree0e0883ac2c10c88c7c79d4149a2db474c4a7daab
parentdfd21b695107fc01941e3218b60d360ee38fb150 (diff)
downloadLR-87-537ff39898992c3915bcf01e3840becc6750520f.tar.gz
LR-87-537ff39898992c3915bcf01e3840becc6750520f.zip
Added some very low-level network code
-rw-r--r--gemini.prj29
-rw-r--r--jessl.f90163
-rw-r--r--network.f90201
-rw-r--r--test_ssl.f9033
4 files changed, 418 insertions, 8 deletions
diff --git a/gemini.prj b/gemini.prj
index 7a52da9..8306deb 100644
--- a/gemini.prj
+++ b/gemini.prj
@@ -4,33 +4,46 @@
"Folders":[],
"Name":"+samples",
"Files":[{
- "filename":".\\samples\\sample1.gmi",
+ "filename":"samples/sample1.gmi",
+ "enabled":"1"
+ }]
+ },{
+ "Folders":[],
+ "Name":"+ssl",
+ "Files":[{
+ "filename":"jessl.f90",
+ "enabled":"1"
+ },{
+ "filename":"network.f90",
+ "enabled":"1"
+ },{
+ "filename":"test_ssl.f90",
"enabled":"1"
}]
}],
"Name":"+gemini (target.exe)",
"Files":[{
- "filename":".\\dumb_render.f90",
+ "filename":"dumb_render.f90",
"enabled":"1"
},{
- "filename":".\\files.f90",
+ "filename":"files.f90",
"enabled":"1"
},{
- "filename":".\\layout.f90",
+ "filename":"layout.f90",
"enabled":"1"
},{
- "filename":".\\render.f90",
+ "filename":"render.f90",
"enabled":"1"
},{
- "filename":".\\test.f90",
- "enabled":"1"
+ "filename":"test.f90",
+ "enabled":"0"
}]
},
"Name":"gemini (target.exe)",
"Options":{
"Compiler Options":{
"Fortran Flags":"",
- "Link Flags":"",
+ "Link Flags":"-lssl -lcrypto -lpthread -ldl",
"C Flags":""
},
"Architecture":1,
diff --git a/jessl.f90 b/jessl.f90
new file mode 100644
index 0000000..a27803e
--- /dev/null
+++ b/jessl.f90
@@ -0,0 +1,163 @@
+! Just Enough SSL...
+
+module jessl
+implicit none
+
+ interface
+
+ subroutine library_init() bind(c, name="SSL_library_init")
+ end subroutine library_init
+
+ subroutine add_ssl_algorithms() bind(c, name="SSLeay_add_ssl_algorithms")
+ end subroutine add_ssl_algorithms
+
+ subroutine load_error_strings() bind(c, name="SSL_load_error_strings")
+ end subroutine load_error_strings
+
+ function tls_v1_3_client_method() bind(c, name="TLSv1_2_client_method")
+ use iso_c_binding
+ type(c_ptr)::tls_v1_3_client_method
+ end function tls_v1_3_client_method
+
+ function ctx_new(meth) bind(c, name="SSL_CTX_new")
+ use iso_c_binding
+ type(c_ptr)::ctx_new
+ type(c_ptr), value::meth
+ end function ctx_new
+
+ function ssl_new(ctx) bind(c, name="SSL_new")
+ use iso_c_binding
+ type(c_ptr)::ssl_new
+ type(c_ptr), value::ctx
+ end function ssl_new
+
+ function get_fd(ssl) bind(c, name="SSL_get_fd")
+ use iso_c_binding
+ integer(kind=c_int)::get_fd
+ type(c_ptr), value::ssl
+ end function get_fd
+
+ function set_fd(ssl, fd) bind(c, name="SSL_set_fd")
+ use iso_c_binding
+ integer(kind=c_int)::set_fd
+ integer(kind=c_int), value::fd
+ type(c_ptr), value::ssl
+ end function set_fd
+
+ function ssl_connect(ssl) bind(c, name="SSL_connect")
+ use iso_c_binding
+ integer(kind=c_int)::connect
+ type(c_ptr), value::ssl
+ end function ssl_connect
+
+ ! Actually a macro...
+ !function get_cipher_c(ssl) bind(c, name="SSL_get_cipher_name")
+ !use iso_c_binding
+ !type(c_ptr)::get_cipher_c
+ !type(c_ptr), value::ssl
+ !end function get_cipher_c
+
+ function read_c(ssl, buf, length) bind(c, name="SSL_read")
+ use iso_c_binding
+ type(c_ptr), value::ssl
+ character(kind=c_char), dimension(*), intent(inout)::buf
+ integer(kind=c_int), value::length
+ integer(kind=c_int)::read_c
+ end function read_c
+
+ function write_c(ssl, buf, length) bind(c, name="SSL_write")
+ use iso_c_binding
+ type(c_ptr), value::ssl
+ character(kind=c_char), dimension(*), intent(inout)::buf
+ integer(kind=c_int), value::length
+ integer(kind=c_int)::write_c
+ end function write_c
+
+ function get_error(ssl, retcode) bind(c, name="SSL_get_error")
+ use iso_c_binding
+ type(c_ptr), value::ssl
+ integer(kind=c_int), value::retcode
+ integer(kind=c_int)::get_error
+ end function get_error
+
+ end interface
+
+contains
+
+ function ssl_read(ssl, buf)
+ use iso_c_binding
+ implicit none
+
+ type(c_ptr)::ssl
+ character, dimension(:), intent(inout)::buf
+ integer::ssl_read
+
+ character(kind=c_char), dimension(:), allocatable::cbuf
+
+ allocate(cbuf(size(buf)))
+
+ ssl_read = read_c(ssl, cbuf, size(buf))
+ buf = cbuf
+
+ deallocate(cbuf)
+
+ end function ssl_read
+
+ function ssl_write(ssl, buf)
+ use iso_c_binding
+ implicit none
+
+ type(c_ptr)::ssl
+ character, dimension(:), intent(in)::buf
+ integer::ssl_write
+
+ character(kind=c_char), dimension(:), allocatable::cbuf
+
+ allocate(cbuf(size(buf)))
+
+ cbuf = buf
+ ssl_write = write_c(ssl, cbuf, size(buf))
+
+ deallocate(cbuf)
+
+ end function ssl_write
+
+ function get_cipher(ssl)
+ use iso_c_binding
+ implicit none
+
+ character(:), allocatable::get_cipher
+ type(c_ptr)::ssl
+
+ type(c_ptr)::cptr
+
+ character(kind=c_char), dimension(:), pointer::cstring
+
+ integer::i
+
+ cptr = c_null_ptr
+ if(.not. c_associated(cptr)) then
+
+ allocate(character(len=1)::get_cipher)
+ get_cipher = " "
+
+ else
+
+ call c_f_pointer(cptr, cstring, [1])
+
+ i = 1
+ do while(cstring(i) /= c_null_char)
+ i = i + 1
+ end do
+ allocate(character(len=(i-1))::get_cipher)
+
+ i = 1
+ do while(cstring(i) /= c_null_char)
+ get_cipher(i:i) = cstring(i)
+ end do
+
+ end if
+
+ end function get_cipher
+
+end module jessl
diff --git a/network.f90 b/network.f90
new file mode 100644
index 0000000..a4a3ddc
--- /dev/null
+++ b/network.f90
@@ -0,0 +1,201 @@
+module network
+use iso_c_binding
+implicit none
+
+ integer(kind=c_int), parameter::AF_INET = 2
+ integer(kind=c_int), parameter::AF_INET6 = 10
+ integer(kind=c_int), parameter::AF_UNIX = 1
+
+ integer(kind=c_int), parameter::SOCK_STREAM = 1
+
+ type, bind(c) :: in_addr
+ integer(kind=c_int32_t)::s_addr
+ end type
+
+ type, bind(c) :: sockaddr_in
+ integer(kind=c_short)::sin_family
+ integer(kind=c_int16_t)::sin_port
+ type(in_addr)::sin_addr
+ !integer(kind=c_int32_t)::s_addr
+ end type
+
+ type, bind(c) :: hostent_c
+ type(c_ptr)::h_name !official name of host */
+ type(c_ptr)::h_aliases !alias list */
+ integer(kind=c_int):: h_addrtype !host address type */
+ integer(kind=c_int):: h_length !length of address */
+ type(c_ptr)::h_addr_list !list of addresses */
+ end type
+
+ ! Let's keep this simple...
+ type :: simple_hostent
+ character(len=:), allocatable::h_name
+ integer::h_addrtype
+ integer(kind=c_int32_t)::h_addr4
+ integer(kind=c_int64_t)::h_addr6
+ end type
+
+ integer(kind=c_size_t), parameter::sockaddr_size = 56
+
+ interface
+ function socket_c(i, j, k) bind(c, name="socket")
+ use iso_c_binding
+ integer(kind=c_int), value::i, j, k
+ integer(kind=c_int)::socket_c
+ end function socket_c
+
+ function inet_addr_c(str) bind(c, name="inet_addr")
+ use iso_c_binding
+ type(c_ptr), value::str
+ integer(c_int32_t)::inet_addr_c
+ end function inet_addr_c
+
+ function htons(i) bind(c)
+ use iso_c_binding
+ integer(kind=c_int32_t), value::i
+ integer(kind=c_int32_t)::htons
+ end function htons
+
+ function connect_c(sockfd, sock_addr, socklen) bind(c, name="connect")
+ use iso_c_binding
+ import::sockaddr_in
+ integer(kind=c_int), value::sockfd
+ type(c_ptr), value::sock_addr
+ integer(kind=c_size_t), value::socklen
+ integer(kind=c_int)::connect_c
+ end function connect_c
+
+ function gethostbyname_c(host) bind(c, name="gethostbyname")
+ use iso_c_binding
+ type(c_ptr), value::host
+ type(c_ptr)::gethostbyname_c
+ end function gethostbyname_c
+
+ end interface
+
+ contains
+
+ function socket(domain, stype, protocol)
+ use iso_c_binding, only: c_int
+ implicit none
+
+ integer::socket
+ integer, intent(in)::domain, stype, protocol
+
+ socket = socket_c(int(domain, c_int), int(stype, c_int), int(protocol, c_int))
+
+ end function socket
+
+ function inet_addr(str)
+ use iso_c_binding
+ implicit none
+
+ character(*), intent(in)::str
+ integer(c_int32_t)::inet_addr
+
+ character(kind=c_char), dimension(:), allocatable, target::cstr
+ integer::i
+
+ allocate(cstr(len_trim(str)+1))
+
+ do i=1, len_trim(str)
+ cstr(i) = str(i:i)
+ end do
+ cstr(len_trim(str)+1) = c_null_char
+
+ inet_addr = inet_addr_c(c_loc(cstr))
+
+ deallocate(cstr)
+
+ end function inet_addr
+
+ function connect(sockfd, sock_addr)
+ use iso_c_binding
+ implicit none
+
+ integer::sockfd
+ type(sockaddr_in), target::sock_addr
+ logical::connect
+
+ !print *, c_sizeof(sock_addr)
+
+ connect = (connect_c(int(sockfd, kind=c_int), &
+ c_loc(sock_addr), &
+ sockaddr_size) .eq. 0)
+
+ end function connect
+
+ function gethostbyname(host, success) result(res)
+ use iso_c_binding
+ implicit none
+
+ character(*)::host
+ type(simple_hostent)::res
+
+ type(hostent_c), pointer::cres
+ type(c_ptr)::callres
+
+ logical, intent(out), optional::success
+
+ ! To get the host to C
+ character(kind=c_char), dimension(:), allocatable, target::chost
+ integer::i
+
+ ! To process h_name
+ character(kind=c_char), dimension(:), pointer::h_name
+
+ ! To process h_addr
+ type(c_ptr), dimension(:), pointer::addrptr
+ integer(kind=c_int32_t), pointer::addr32
+ integer(kind=c_int64_t), pointer::addr64
+
+ allocate(chost(len_trim(host)+1))
+
+ do i=1, len_trim(host)
+ chost(i) = host(i:i)
+ end do
+ chost(len_trim(host)+1) = c_null_char
+
+ callres = gethostbyname_c(c_loc(chost))
+ if(c_associated(callres)) then
+ call c_f_pointer(callres, cres)
+
+ ! Extract the name
+ call c_f_pointer(cres%h_name, h_name, [1])
+ i = 1
+ do while(h_name(i) /= c_null_char)
+ i = i + 1
+ end do
+ allocate(character(len=i) :: res%h_name)
+ i = 1
+ do while(h_name(i) /= c_null_char)
+ res%h_name(i:i) = h_name(i)
+ i = i + 1
+ end do
+
+ ! And address
+ res%h_addr4 = 0
+ res%h_addr6 = 0
+
+ res%h_addrtype = cres%h_addrtype
+ call c_f_pointer(cres%h_addr_list, addrptr, [1])
+ if(res%h_addrtype == AF_INET) then
+ call c_f_pointer(addrptr(1), addr32)
+ res%h_addr4 = addr32
+ else if(res%h_addrtype == AF_INET6) then
+ call c_f_pointer(addrptr(1), addr64)
+ res%h_addr6 = addr64
+ end if
+
+ if(present(success)) then
+ success = .TRUE.
+ end if
+ else
+ if(present(success)) then
+ success = .FALSE.
+ end if
+ end if
+
+ end function gethostbyname
+
+end module network \ No newline at end of file
diff --git a/test_ssl.f90 b/test_ssl.f90
new file mode 100644
index 0000000..0e169c1
--- /dev/null
+++ b/test_ssl.f90
@@ -0,0 +1,33 @@
+program test_ssl
+use jessl
+use network
+implicit none
+
+ type(sockaddr_in), target::sa
+ integer::s
+
+ type(simple_hostent)::hent
+
+ hent = gethostbyname("google.com")
+ if(allocated(hent%h_name)) then
+ !Print *, "host: ", hent%h_name
+ !Print *, "addr: ", hent%h_addr4
+ else
+ Print *, "Failure"
+ stop
+ end if
+
+ sa%sin_family = AF_INET
+ sa%sin_addr%s_addr = hent%h_addr4 !inet_addr("192.168.2.90")
+ sa%sin_port = htons(80)
+
+ s = socket(AF_INET, SOCK_STREAM, 0);
+ if(.not. connect(s, sa)) then
+ Print *, "Connection failed", IERRNO()
+ stop
+ end if
+
+ Print *, "socket opened!"
+
+
+end program test_ssl \ No newline at end of file