Page 10 of 10

Re: atomic web server threads

Posted: Fri Nov 14, 2025 2:57 am
by skinkairewalker
Is it possible for us to create a web server that is compatible with all operating systems using the PureBasic network library?
And if we remove complex structures and leave only the HTTP server for the local network? I think that this way we can make protected web apps with webview — or am I wrong?

in MacOS (ARM) occurs :
Image


in linux (ARM with parallels desktop) occurs :
Image

Re: atomic web server threads

Posted: Fri Nov 14, 2025 4:22 am
by idle
Yes you can use it to serve on localhost to serve to either a web gadget or users browser.
It looks like the static lib is missing a dependency on the linux system.

I haven't tested on arm recently and I don't have access to a Mac to test on.
Did you try with a lower port number like 8081 ?
Also if your not using tls find the usetls() and comment it out as there's no point using tls on localhost or loopback.

Re: atomic web server threads

Posted: Fri Nov 14, 2025 5:26 am
by skinkairewalker
Strange behavior on Linux, the dependency is installed.
What could be calling this dependency?
Image

Re: atomic web server threads

Posted: Sun Nov 16, 2025 4:56 am
by idle
it's missing a dependency. I can't help you with that at the moment though.

Re: atomic web server threads

Posted: Sun Nov 16, 2025 11:30 am
by mk-soft
Mint Linux LMDE 7 (Debian 13)
With TLS Server I always have with TLS functions "Invaild Memory Access", but have an address after importing to the function?

Other thing:
With linux you should not call the MessageRequester from a thread (crash)

Fix for Linux

Code: Select all

CompilerIf #PB_Compiler_OS = #PB_OS_Linux
  Procedure MyMessageRequester(Title.s, Text.s, Flags=0)
    Protected r1
    gdk_threads_enter_();
    r1 = MessageRequester(Title, Text, Flags)
    gdk_flush_()
    gdk_threads_leave_()
    ProcedureReturn r1
  EndProcedure
  
  Macro MessageRequester(Title, Text, Flags=0)
    MyMessageRequester(Title, Text, Flags)
  EndMacro
CompilerEndIf

Re: atomic web server threads

Posted: Mon Nov 17, 2025 9:55 am
by infratec
Maybe you need

libbsd-dev (libbsd)

in ubuntu.

Re: atomic web server threads

Posted: Mon Nov 17, 2025 4:42 pm
by skinkairewalker
infratec wrote: Mon Nov 17, 2025 9:55 am Maybe you need

libbsd-dev (libbsd)

in ubuntu.
I achieved the goal I was aiming for xD
My only concern is that the code is quite "unprofessional" :
viewtopic.php?t=87904

Re: atomic web server threads

Posted: Thu Jan 22, 2026 11:22 am
by tatanas
Hi idle,

I'm testing a TLS client/server with your tlsStatic.pbi (yes I know that since PB 6.20, we can use native network procedures with TLS but crashes when client socket isn't valid anymore forces me to find another solution). I keep getting an error when the server receives data from a client in the procedure TLS_NetworkServerEvent() when calling tls_handshake(). The parameter ctx is equal to 0 and an invalid memory access occurs. Its seems the problem comes from tls_accept_socket() function which returns 0 (ok) but don't fill the ctx parameter as it should.
I'm using PB 6.20.

Here is the client I'm using :

Code: Select all

XIncludeFile "tlsStatic.pbi"

Define.i Con

Con = OpenNetworkConnection("127.0.0.1", 20252, #PB_Network_TCP | #PB_Network_IPv4 | #PB_Network_TLSv1)
If Con
			
	SendNetworkString(Con, "message sent by client")
	
	CloseNetworkConnection(Con)
EndIf
And the server :

Code: Select all

XIncludeFile "tlsStatic.pbi"

PrivateKey$ = "-----BEGIN PRIVATE KEY-----"+#LF$+
      "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAPEbSQq/uwESZduPtDd83qXXkSPf6lUNa17xhM2fOZQxGr0Fdmvw6IsC+QGX25EE1TG6TFQkHlM2rW8y6a3WEC/WzCNWaTCPYD/rguiAFG+4eQmwHjiJFVec0InjjSG9SX8xwS/gQeWdQniKROO4DmMJO8N7mdUhdHODSntXdr9zAgMBAAECgYAE+VMgbaQl+YMwbF6DZogRU8kivFPRPV2hr8nVlBtT+09Z5uryfx3NAFqytbdJ3penVviMI9KcVNxvFtXLSEc9KyjzgysorAfUpwFuECCLDbOXX0HlV6rgkqJdhyV6FybcDLvgcvulHQ64QdYRhW+jPx7vXk3h0/JRFqKQJsY7QQJBAPrDLJRPbAw+Mlq1fHBWk8Z1Qn1ivPAmz+2nPAgDya/xdAlb9GbFAMzCS3upIBpxW70uLI04OuTVhwYL194I5C0CQQD2JHtHp25SkIDpBgZGicEC7yAIE/wPC0P9X85UJqXx5dPx4HbEc8lqSKMbCzkbHyvjHonSHu00QxU1W6ZALFYfAkBcPWzphSl+e2Z0XWvPutkS2FFD5A0R3YUAq1J2tEX9NTj0tGF7aB36M8ImU7jeYTJYrWJv8+4d/Ll1LOgT4XtlAkAxofOV5EYTsf28fzF+wcJAtDUyS81Uv0HLcqkpQM3PdDeDm253eJ2Rp+nzxxSRynxQBNVnoELWefxp0Pw6DnajAkBF5h7fQIbwAEPrhDzhjMXU7g9k9KzkkJN/bluLbleqkkAz1kfkGtWXJdGITZuY4K/X2yp1diWQ0utZjmOmhWsl"+#LF$+
      "-----END PRIVATE KEY-----"

Cert$ = "-----BEGIN CERTIFICATE-----"+#LF$+
       "MIICnTCCAgYCCQD0AWy2vzfcpzANBgkqhkiG9w0BAQUFADCBkjELMAkGA1UEBhMCVVMxDjAMBgNVBAgTBVN0YXRlMQ0wCwYDVQQHEwRDaXR5MRUwEwYDVQQKEwxPcmdhbml6YXRpb24xHDAaBgNVBAsTE09yZ2FuaXphdGlvbmFsIFVuaXQxLzAtBgNVBAMTJkNvbW1vbiBOYW1lIChlLmcuLCB5b3VyIHNlcnZlciBkb21haW4pMB4XDTI0MTEwNjE2NTI1N1oXDTI0MTIwNjE2NTI1N1owgZIxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIEwVTdGF0ZTENMAsGA1UEBxMEQ2l0eTEVMBMGA1UEChMMT3JnYW5pemF0aW9uMRwwGgYDVQQLExNPcmdhbml6YXRpb25hbCBVbml0MS8wLQYDVQQDEyZDb21tb24gTmFtZSAoZS5nLiwgeW91ciBzZXJ2ZXIgZG9tYWluKTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA8RtJCr+7ARJl24+0N3zepdeRI9/qVQ1rXvGEzZ85lDEavQV2a/DoiwL5AZfbkQTVMbpMVCQeUzatbzLprdYQL9bMI1ZpMI9gP+uC6IAUb7h5CbAeOIkVV5zQieONIb1JfzHBL+BB5Z1CeIpE47gOYwk7w3uZ1SF0c4NKe1d2v3MCAwEAATANBgkqhkiG9w0BAQUFAAOBgQCprm5a5bg1LqCDdtwDTnRDmVcca6HoUlvbjZLmWdLjltG1McNAATppTy/bF7vT3jXLobA1Vzs2g14POjYQhPnIbRPEnNzvAe+Se3y0YeFOwYarEyFBHKHODGIPaCnXGH8gB9fgcp2SYtLaPKvXdNL44VeYGbD4+fvUcu/zkXqTSg=="+#LF$+
       "-----END CERTIFICATE-----"
  
  
Init_TLS(Cert$, PrivateKey$)

Exit = #False

Server = CreateNetworkServer(#PB_Any, 20252, #PB_Network_TCP | #PB_Network_IPv4 | #PB_Network_TLSv1)
If Server
	*Buffer = AllocateMemory($FFFF, #PB_Memory_NoClear)

	Repeat 

		Select NetworkServerEvent(Server)

			Case #PB_NetworkEvent_Connect
				Debug "client connecté"

			Case #PB_NetworkEvent_Data
				Client = EventClient()
				If *Buffer
					Repeat
						Length = ReceiveNetworkData(Client, *Buffer, MemorySize(*Buffer))
						If Length > 0
							Debug PeekS(*Buffer, Length, #PB_UTF8|#PB_ByteLength)
							Exit = #True
						EndIf
					Until Length = 0 Or (Length > 0 And Length <> MemorySize(*Buffer))
				EndIf	

			Case #PB_NetworkEvent_Disconnect
				Debug "client déconnecté"

			Case #PB_NetworkEvent_None
				Delay(10)

		EndSelect
		
	Until Exit
	CloseNetworkServer(Server)
EndIf
Did I miss something ?

Re: atomic web server threads

Posted: Thu Jan 22, 2026 7:48 pm
by idle
It's a little complicated.
The statictls expects to see file format /certs/domain and /www/domain
Where domain is yourdomain.com

You can test it with self signed certs and add the domain to your hosts file

I will take a look later today.

Re: atomic web server threads

Posted: Thu Jan 22, 2026 8:20 pm
by tatanas
Oh I see. Indeed I'm not using a web server so I didn't think about the domain part.
For this example I was using the private key/certificate code from Purebasic TLS server example but I tested with my own self signed .crt and .key files too and got the same error.

Thanks for your time.

Re: atomic web server threads

Posted: Thu Jan 22, 2026 11:46 pm
by idle
It works here but you need to load the certs from file.
I changed If tls_configure(*ctx, *cfg) < 0 ;= -1
error's supposed to be -1 according to the docs though maybe it changed

save the certs as

path/certs/certificate.crt

Code: Select all

-----BEGIN CERTIFICATE-----
MIICnTCCAgYCCQD0AWy2vzfcpzANBgkqhkiG9w0BAQUFADCBkjELMAkGA1UEBhMCVVMxDjAMBgNVBAgTBVN0YXRlMQ0wCwYDVQQHEwRDaXR5MRUwEwYDVQQKEwxPcmdhbml6YXRpb24xHDAaBgNVBAsTE09yZ2FuaXphdGlvbmFsIFVuaXQxLzAtBgNVBAMTJkNvbW1vbiBOYW1lIChlLmcuLCB5b3VyIHNlcnZlciBkb21haW4pMB4XDTI0MTEwNjE2NTI1N1oXDTI0MTIwNjE2NTI1N1owgZIxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIEwVTdGF0ZTENMAsGA1UEBxMEQ2l0eTEVMBMGA1UEChMMT3JnYW5pemF0aW9uMRwwGgYDVQQLExNPcmdhbml6YXRpb25hbCBVbml0MS8wLQYDVQQDEyZDb21tb24gTmFtZSAoZS5nLiwgeW91ciBzZXJ2ZXIgZG9tYWluKTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA8RtJCr+7ARJl24+0N3zepdeRI9/qVQ1rXvGEzZ85lDEavQV2a/DoiwL5AZfbkQTVMbpMVCQeUzatbzLprdYQL9bMI1ZpMI9gP+uC6IAUb7h5CbAeOIkVV5zQieONIb1JfzHBL+BB5Z1CeIpE47gOYwk7w3uZ1SF0c4NKe1d2v3MCAwEAATANBgkqhkiG9w0BAQUFAAOBgQCprm5a5bg1LqCDdtwDTnRDmVcca6HoUlvbjZLmWdLjltG1McNAATppTy/bF7vT3jXLobA1Vzs2g14POjYQhPnIbRPEnNzvAe+Se3y0YeFOwYarEyFBHKHODGIPaCnXGH8gB9fgcp2SYtLaPKvXdNL44VeYGbD4+fvUcu/zkXqTSg==
-----END CERTIFICATE-----
path/certs/private.key

Code: Select all

-----BEGIN PRIVATE KEY-----
MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAPEbSQq/uwESZduPtDd83qXXkSPf6lUNa17xhM2fOZQxGr0Fdmvw6IsC+QGX25EE1TG6TFQkHlM2rW8y6a3WEC/WzCNWaTCPYD/rguiAFG+4eQmwHjiJFVec0InjjSG9SX8xwS/gQeWdQniKROO4DmMJO8N7mdUhdHODSntXdr9zAgMBAAECgYAE+VMgbaQl+YMwbF6DZogRU8kivFPRPV2hr8nVlBtT+09Z5uryfx3NAFqytbdJ3penVviMI9KcVNxvFtXLSEc9KyjzgysorAfUpwFuECCLDbOXX0HlV6rgkqJdhyV6FybcDLvgcvulHQ64QdYRhW+jPx7vXk3h0/JRFqKQJsY7QQJBAPrDLJRPbAw+Mlq1fHBWk8Z1Qn1ivPAmz+2nPAgDya/xdAlb9GbFAMzCS3upIBpxW70uLI04OuTVhwYL194I5C0CQQD2JHtHp25SkIDpBgZGicEC7yAIE/wPC0P9X85UJqXx5dPx4HbEc8lqSKMbCzkbHyvjHonSHu00QxU1W6ZALFYfAkBcPWzphSl+e2Z0XWvPutkS2FFD5A0R3YUAq1J2tEX9NTj0tGF7aB36M8ImU7jeYTJYrWJv8+4d/Ll1LOgT4XtlAkAxofOV5EYTsf28fzF+wcJAtDUyS81Uv0HLcqkpQM3PdDeDm253eJ2Rp+nzxxSRynxQBNVnoELWefxp0Pw6DnajAkBF5h7fQIbwAEPrhDzhjMXU7g9k9KzkkJN/bluLbleqkkAz1kfkGtWXJdGITZuY4K/X2yp1diWQ0utZjmOmhWsl
-----END PRIVATE KEY-----
compile without debugger #Server = 1
and then recompile with #server = 0

Code: Select all

;V 1.0.4b
;author Hexor,infratec,idle
;* $OpenBSD: tls.h,v 1.58 2020/01/22 06:44:02 beck Exp $ */
;*
;* Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
;*
;* Permission To use, copy, modify, And distribute this software For any
;* purpose With Or without fee is hereby granted, provided that the above
;* copyright notice And this permission notice appear in all copies.
;*
;* THE SOFTWARE IS PROVIDED "AS IS" And THE AUTHOR DISCLAIMS ALL WARRANTIES
;* With REGARD To THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
;* MERCHANTABILITY And FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE For
;* ANY SPECIAL, DIRECT, INDIRECT, Or CONSEQUENTIAL DAMAGES Or ANY DAMAGES
;* WHATSOEVER RESULTING FROM LOSS OF USE, Data Or PROFITS, WHETHER IN AN
;* ACTION OF CONTRACT, NEGLIGENCE Or OTHER TORTIOUS ACTION, ARISING OUT OF
;* Or IN CONNECTION With THE USE Or PERFORMANCE OF THIS SOFTWARE.
;*
; Original from idle => https://www.purebasic.fr/english/viewtopic.php?p=593079#p593079

;/=============
;|
;| Usage:
;| - Include that file here on top of your (existing?!) network application.
;| - make sure a libtls-xx.dll or libtls-xx.a is in the same directory as your app
;|                                               (or set a global variable LIBTLSFILE$ to path and filename of that library BEFORE including this source)
;|   you will find compiled libraries in the dropbox account from idle, see here:
;|   https://www.purebasic.fr/english/viewtopic.php?p=593079#p593079
;|   or just compile newer versions yourself
;| - That's it!
;|   If you now want to initiate a TLS connection, use all known PB commands as usual, but:
;|   Add one of the PB_Network_TLSv1_xx constants to:
;|   OpenNetworkConnection(ServerName$, Port [, Mode  <= here
;|   e.g. OpenNetworkConnection("my.domain.com", 1234, #PB_Network_TCP | #PB_Network_IPv4 | #PB_Network_TLS_DEFAULT, ...)
;|
;|   OR
;|
;|   CreateNetworkServer(Server, Port [, Mode, <== here
;|   e.g. CreateNetworkServer(#PB_Any, 1234, #PB_Network_TCP | #PB_Network_IPv4 | #PB_Network_TLS_DEFAULT, ...)
;|   In case of a server, you would need to call Init_TLS() also most likely.
;|   Because with that procedure you can set the needed TLS certificates (cert and key file typically)
;|
;|   ;/============

#TLS_API = 20200120

#TLS_PROTOCOL_TLSv1_0 = (1 << 1)
#TLS_PROTOCOL_TLSv1_1 = (1 << 2)
#TLS_PROTOCOL_TLSv1_2 = (1 << 3)
#TLS_PROTOCOL_TLSv1_3 = (1 << 4)

#TLS_PROTOCOL_TLSv1 = #TLS_PROTOCOL_TLSv1_0 | #TLS_PROTOCOL_TLSv1_1 | #TLS_PROTOCOL_TLSv1_2 | #TLS_PROTOCOL_TLSv1_3

#TLS_PROTOCOLS_ALL     = #TLS_PROTOCOL_TLSv1
#TLS_PROTOCOLS_DEFAULT = (#TLS_PROTOCOL_TLSv1_2 | #TLS_PROTOCOL_TLSv1_3)

#TLS_WANT_POLLIN  = -2
#TLS_WANT_POLLOUT = -3

;/* RFC 6960 Section 2.3 */
#TLS_OCSP_RESPONSE_SUCCESSFUL    = 0
#TLS_OCSP_RESPONSE_MALFORMED     = 1
#TLS_OCSP_RESPONSE_INTERNALERROR = 2
#TLS_OCSP_RESPONSE_TRYLATER      = 3
#TLS_OCSP_RESPONSE_SIGREQUIRED   = 4
#TLS_OCSP_RESPONSE_UNAUTHORIZED  = 5

;/* RFC 6960 Section 2.2 */
#TLS_OCSP_CERT_GOOD    = 0
#TLS_OCSP_CERT_REVOKED = 1
#TLS_OCSP_CERT_UNKNOWN = 2

;/* RFC 5280 Section 5.3.1 */
#TLS_CRL_REASON_UNSPECIFIED            = 0
#TLS_CRL_REASON_KEY_COMPROMISE         = 1
#TLS_CRL_REASON_CA_COMPROMISE          = 2
#TLS_CRL_REASON_AFFILIATION_CHANGED    = 3
#TLS_CRL_REASON_SUPERSEDED             = 4
#TLS_CRL_REASON_CESSATION_OF_OPERATION = 5
#TLS_CRL_REASON_CERTIFICATE_HOLD       = 6
#TLS_CRL_REASON_REMOVE_FROM_CRL        = 8
#TLS_CRL_REASON_PRIVILEGE_WITHDRAWN    = 9
#TLS_CRL_REASON_AA_COMPROMISE          = 10

#TLS_MAX_SESSION_ID_LENGTH = 32
#TLS_TICKET_KEY_SIZE       = 48

CompilerIf Defined(PB_Network_TLSv1, #PB_Constant) = 0
  
  #PB_Network_TLSv1_0     = #TLS_PROTOCOL_TLSv1_0 << 1
  #PB_Network_TLSv1_1     = #TLS_PROTOCOL_TLSv1_1 << 1
  #PB_Network_TLSv1_2     = #TLS_PROTOCOL_TLSv1_2 << 1
  #PB_Network_TLSv1_3     = #TLS_PROTOCOL_TLSv1_3 << 1 
  #PB_Network_TLSv1       = #PB_Network_TLSv1_0 | #PB_Network_TLSv1_1 | #PB_Network_TLSv1_2 | #PB_Network_TLSv1_3
CompilerEndIf  

  #PB_Network_TLS_DEFAULT = #PB_Network_TLSv1_2 | #PB_Network_TLSv1_3
  #PB_Network_KeepAlive   = $1000
  #PB_Network_Extra       = #PB_Network_TLSv1 | #PB_Network_KeepAlive


CompilerIf Defined(TLS_AUTOINIT, #PB_Constant) = #False
  #TLS_AUTOINIT = #True
CompilerEndIf

PrototypeC tls_read_cb(ctx,*buf,_buflen,*cb_arg);
PrototypeC tls_write_cb(ctx,*buf,_buflen,*cb_arg);

ImportC "" 
  tls_init()                                                                                                   
  tls_config_error(config)                                                                            
  tls_error(ctx)                                                                                      
  tls_config_new()                                                                                             
  tls_config_free(config)                                                                             
  tls_default_ca_cert_file()                                                                                   
  tls_config_add_keypair_file(config,cert_file.p-utf8,key_file.p-utf8)                              
  tls_config_add_keypair_mem(config,cert.p-utf8,certlen.i,key.p-utf8,key_len.i)        
  tls_config_add_keypair_ocsp_file(config,cert_file.p-utf8,key_file.p-utf8,ocsp_staple_file.p-utf8)
  tls_config_add_keypair_ocsp_mem(config,cert.p-utf8,cert_len.i,key.p-utf8,key_len.i,staple.p-utf8,staple_len.i)
  tls_config_set_alpn(config,alpn.p-utf8)                                                                                           
  tls_config_set_ca_file(config,ca_file.p-utf8)                                                                                     
  tls_config_set_ca_path(config,ca_path.p-utf8)                                                                                     
  tls_config_set_ca_mem(config,*ca,len.i)                                                                               
  tls_config_set_cert_file(config,cert_file.p-utf8)                                                                                 
  tls_config_set_cert_mem(config,*cert,len.i)                                                                           
  tls_config_set_ciphers(config,ciphers.p-utf8)                                                                                     
  tls_config_set_crl_file(config,crl_file.p-utf8)                                                                                   
  tls_config_set_crl_mem(config,crl.p-utf8,len.i)                                                                             
  tls_config_set_dheparams(config,params.p-utf8)                                                                                    
  tls_config_set_ecdhecurve(config,curve.p-utf8)                                                                                    
  tls_config_set_ecdhecurves(config,curves.p-utf8)                                                                                  
  tls_config_set_key_file(config,key_file.p-utf8)                                                                                   
  tls_config_set_key_mem(config,*key,len.i)                                                                             
  tls_config_set_keypair_file(config,cert_file.p-utf8,key_file.p-utf8)                                                             
  tls_config_set_keypair_mem(config,cert.p-utf8,cert_len.i,key.p-utf8,key_len.i)                                       
  tls_config_set_keypair_ocsp_file(config,cert_file.p-utf8,key_file.p-utf8,staple_file.p-utf8)                                    
  tls_config_set_keypair_ocsp_mem(config,cert.p-utf8,cert_len.i,key.p-utf8,key_len.i,staple.p-utf8,staple_len.i) 
  tls_config_set_ocsp_staple_mem(config,staple.p-utf8,len.i)                                                                  
  tls_config_set_ocsp_staple_file(config,staple_file.p-utf8)                                                                        
  tls_config_set_protocols(config,protocols.l)                                                                               
  tls_config_set_session_fd(config,session_fd.l)                                                                                  
  tls_config_set_verify_depth(config,verify_depth.l)                                                                              
  tls_config_prefer_ciphers_client(config)                                                                                           
  tls_config_prefer_ciphers_server(config)                                                                                           
  tls_config_insecure_noverifycert(config)                                                                                           
  tls_config_insecure_noverifyname(config)                                                                                           
  tls_config_insecure_noverifytime(config)                                                                                           
  tls_config_verify(config)                                                                                                          
  tls_config_ocsp_require_stapling(config)                                                                                           
  tls_config_verify_client(config)                                                                                                   
  tls_config_verify_client_optional(config)                                                                                          
  tls_config_clear_keys(config)                                                                                                      
  tls_config_parse_protocols(*protocols,protostr.p-utf8)                                                                           
  tls_config_set_session_id(config,session_id.p-utf8,len.i)                                                                   
  tls_config_set_session_lifetime(config,lifetime.l)                                                                              
  tls_config_add_ticket_key(config,keyrev.i,*key,keylen.i)                                                   
  tls_client()                                                                                                                                
  tls_server()                                                                                                                                
  tls_configure(ctx,config)                                                                                                 
  tls_reset(ctx)                                                                                                                     
  tls_free(ctx)                                                                                                                      
  tls_accept_fds(ctx,*cctx,fd_read.l,fd_write.l)                                                                       
  tls_accept_socket(ctx,*cctx,socket.l)                                                                                   
  tls_accept_cbs(ctx,*cctx,*read_cb.tls_read_cb,*write_cb.tls_write_cb,*cb_arg)                                      
  tls_connect(ctx,host.p-utf8,port.p-utf8)                                                                                         
  tls_connect_fds(ctx,fd_read.l,fd_write.l,servername.p-utf8)                                                                 
  tls_connect_servername(ctx,host.p-utf8,port.p-utf8,servername.p-utf8)                                                           
  tls_connect_socket(ctx,s.l,servername.p-utf8)                                                                                  
  tls_connect_cbs(ctx,*read_cb.tls_read_cb,*write_cb.tls_write_cb,*cb_arg,servername.p-utf8)                                
  tls_handshake(ctx)                                                                                                                 
  tls_read(ctx,*buf,buflen.i)                                                                                            
  tls_write(ctx,*buf,buflen.i)                                                                                          
  tls_close(ctx)                                                                                                                     
  tls_peer_cert_provided(ctx)                                                                                                        
  tls_peer_cert_contains_name(ctx,name.p-utf8)                                                                                      
  tls_peer_cert_hash(ctx)                                                                                                            
  tls_peer_cert_issuer(ctx)                                                                                                          
  tls_peer_cert_subject(ctx)                                                                                                         
  tls_peer_cert_notbefore(ctx)                                                                                                       
  tls_peer_cert_notafter(ctx)                                                                                                        
  tls_peer_cert_chain_pem(ctx,*len)                                                                                          
  tls_conn_alpn_selected(ctx)                                                                                                        
  tls_conn_cipher(ctx)                                                                                                               
  tls_conn_cipher_strength(ctx)                                                                                                      
  tls_conn_servername(ctx)                                                                                                           
  tls_conn_session_resumed(ctx)                                                                                                      
  tls_conn_version(ctx)                                                                                                              
  tls_load_file(file.p-utf8,*len,*password)                                                                                    
  tls_unload_file(*buf,len.i)                                                                                                   
  tls_ocsp_process_response(ctx,response.p-utf8,size.i)                                                                       
  tls_peer_ocsp_cert_status(ctx)                                                                                                     
  tls_peer_ocsp_crl_reason(ctx)                                                                                                      
  tls_peer_ocsp_next_update(ctx)                                                                                                     
  tls_peer_ocsp_response_status(ctx)                                                                                                 
  tls_peer_ocsp_result(ctx)                                                                                                          
  tls_peer_ocsp_revocation_time(ctx)                                                                                                 
  tls_peer_ocsp_this_update(ctx)                                                                                                     
  tls_peer_ocsp_url(ctx)                                                                                                             
EndImport

Structure TLS_Certs 
  Path$
  CertFile$
  KeyFile$
  CaCertFile$
  domain$
EndStructure 

Structure TLS_Report 
  host.s
  version.s
  cipher.s
  subject.s
  issuer.s
  validFrom.q
  validUntil.q
  hash.s
EndStructure  

Structure TLS_Connections
  *ctx 
   report.TLS_Report 
EndStructure

Structure TLS_Globals
  CertFile$
  KeyFile$
  CaCertFile$
  List certs.TLS_Certs()
  domain$
  LastError.i
  DLL.i
  muxClient.i
  muxSever.i
  Map Clients.TLS_Connections()
  Map Servers.TLS_Connections()
EndStructure

Global TLSG.TLS_Globals

Procedure __MyInit()
  TLSG\DLL=1
  TLSG\muxClient = CreateMutex()
  TLSG\muxSever = CreateMutex() 
    
EndProcedure

Enumeration TLS_Errors 
  #TLS_Error_InitFailed
  #TLS_Error_None
  #TLS_Error_NewConfig_Failed
  #TLS_Error_CantLoad_CertFile
  #TLS_Error_CantLoad_KeyFile
  #TLS_Error_CantLoad_RootCert
  #TLS_Error_Unsupported_Protocol
  #TLS_Error_Cant_Start_Client
  #TLS_Error_Configure_Error
  #TLS_Error_Cant_Start_Server
  #TLS_Error_Cant_Connect_Socket
EndEnumeration

Global TLSG\LastError = #TLS_Error_None

Procedure TLS_GetLastError()
  ProcedureReturn TLSG\LastError
EndProcedure

Procedure.s _PEEKS(*ptr,len,type) 
  If *PTR 
    ProcedureReturn PeekS(*ptr,len,type)   
  Else 
    ProcedureReturn "" 
  EndIf   
EndProcedure     

Macro TLS_PS(func) 
  _PeekS(func,-1,#PB_UTF8) 
EndMacro 

Procedure TLS_report(*ctx.TLS_Connections)
  
  Protected t, ocsp_url.s,*ptr,*tls_ctx;
  *tls_ctx = *ctx\ctx 
  If *ctx\report\version = "" 
    *ctx\report\version = TLS_PS(tls_conn_version(*tls_ctx)) 
    *ctx\report\cipher =  TLS_PS(tls_conn_cipher(*tls_ctx)) 
    *ctx\report\subject = TLS_PS(tls_peer_cert_subject(*tls_ctx)) 
    *ctx\report\issuer =  TLS_PS(tls_peer_cert_issuer(*tls_ctx))
    *ctx\report\hash =    TLS_PS(tls_peer_cert_hash(*tls_ctx))
    *ctx\report\validFrom = tls_peer_cert_notbefore(*tls_ctx) 
    *ctx\report\validUntil = tls_peer_cert_notafter(*tls_ctx)  
  EndIf 
    
;   CompilerIf #PB_Compiler_Debugger 
;   ;not tested yet and probably not required anymore as it's getting dropped soon  
;   *ptr = tls_peer_ocsp_url(*tls_ctx)
;   If *ptr 
;     ocsp_url = tls_PS(*ptr)
;     
;     Debug "OCSP URL: " + ocsp_url;
;     t = tls_peer_ocsp_response_status(*tls_ctx) 
;     If t = #TLS_OCSP_RESPONSE_SUCCESSFUL   
;       Debug "OCSP Stapling: " + TLS_PS(tls_peer_ocsp_result(*tls_ctx))
;       Debug "response_status= " + TLS_PS(tls_peer_ocsp_response_status(*tls_ctx))
;       Debug "cert_status= "  +  TLS_PS(tls_peer_ocsp_cert_status(*tls_ctx))
;       Debug "crl_reason= " +  TLS_PS(tls_peer_ocsp_crl_reason(*tls_ctx))
;       t = tls_peer_ocsp_this_update(*tls_ctx)                             
;       If t <> - 1 
;         Debug "this update: " + FormatDate("%hh:%dd:%mm:%yy",t)
;       EndIf   
;       t =  tls_peer_ocsp_next_update(*tls_ctx);
;       If t <> - 1
;         Debug "next update: " + FormatDate("%hh:%dd:%mm:%yy",t)
;       EndIf 
;       t =  tls_peer_ocsp_revocation_time(*tls_ctx)
;       If t <> -1 
;         Debug "revocation: " + FormatDate("%hh:%dd:%mm:%yy",t)
;       EndIf                                                 
;     ElseIf t <> -1 
;       Debug "OCSP Stapling:  failure - response_status " + Str(t) + " " + TLS_PS(tls_peer_ocsp_result(*tls_ctx))
;       
;     EndIf
;     
;   EndIf
;   
;   CompilerEndIf 
  
  ProcedureReturn @*ctx\report
  
EndProcedure 

Procedure TLS_ReportClient(clientID) 
  
  If FindMapElement(TLSG\Clients(),Str(clientID)) 
    ProcedureReturn TLS_report(TLSG\Clients())
  EndIf  
  
EndProcedure 

Procedure TLS_CreateNetworkServer(Server, Port, Mode, BindedIP.s)
  Protected TLSMode, ServerID, *ctx, *cfg, *Error, SockOpt.l, SockOptLen.l
  
  CompilerIf #PB_Compiler_Version <= 620 
    tlsmode = ((mode & $ffffff0) >> 1)  
    If mode & $10000000 
      mode = #PB_Network_IPv6 | (mode & 3) 
    Else   
      mode = mode & 3 
    EndIf 
       
  CompilerElse 
    tlsmode = ((mode & $ffffff0) >> 1 )  
    mode = mode & 3  
  CompilerEndIf 
   
  
  If TLSG\DLL And tlsMode 
    
    TLSG\LastError = #TLS_Error_None 
    *ctx = tls_server()
    If *ctx 
      *cfg  = tls_config_new()
      If *cfg = 0
        TLSG\LastError = #TLS_Error_NewConfig_Failed
      Else
        FirstElement(TLSG\certs())
        
       tls_config_set_ca_path(*cfg,TLSG\certs()\Path$)
        
        If tls_config_set_keypair_file(*cfg,tlsg\certs()\CertFile$,tlsg\certs()\KeyFile$) = -1
          TLSG\LastError = #TLS_Error_CantLoad_CertFile
        EndIf 
        
        While NextElement(TLSG\certs()) 
          If tls_config_add_keypair_file(*cfg,tlsg\certs()\CertFile$,tlsg\certs()\KeyFile$) = -1
            TLSG\LastError = #TLS_Error_CantLoad_CertFile
          EndIf   
        Wend   
                
        If tls_config_set_protocols(*cfg, TLSMode) = -1
          TLSG\LastError = #TLS_Error_Unsupported_Protocol
        EndIf
        
        ;If tls_config_verify_client_optional(*cfg) = -1 
        ;  TLSG\LastError = #TLS_Error_Configure_Error 
        ;EndIf   
        
        If tls_configure(*ctx, *cfg) < 0 ;= -1
          TLSG\LastError = #TLS_Error_Configure_Error 
          *Error = tls_config_error(*cfg)
          If *Error
            PrintN("TLS Config error: " + PeekS(*Error, - 1, #PB_UTF8))
          EndIf
        EndIf     
        tls_config_free(*cfg)
      EndIf 
      
      If *ctx 
        ServerID = CreateNetworkServer(Server, Port, mode, BindedIP)
        If ServerID
          Protected iocontext   
          If tls_accept_socket(*ctx,@iocontext,ServerID(ServerID)) = -1
            TLSG\LastError = #TLS_Error_Cant_Connect_Socket
            PrintN("#TLS_Error_Cant_Connect_Socket") 
            *error = tls_error(*ctx) 
            PrintN("error " + PeekS(*Error, - 1, #PB_UTF8)) 
          Else
            LockMutex(TLSG\muxSever) 
            AddMapElement(TLSG\Servers(), Str(ServerID(ServerID)))
            TLSG\Servers()\ctx = *ctx
            FirstElement(TLSG\certs())
            TLSG\Servers()\report\host = TLSG\certs()\domain$ 
            UnlockMutex(TLSG\muxSever) 
          EndIf
        EndIf
      EndIf
    Else 
      TLSG\LastError = #TLS_Error_Cant_Start_Server
    EndIf
  Else
    ServerID = CreateNetworkServer(Server, Port, Mode, BindedIP)
  EndIf
  
  ProcedureReturn ServerID
EndProcedure

Procedure TLS_NetworkServerEvent(ServerID)
  Protected Result, Server, ClientID, ctx,*server.TLS_Connections
  Protected  *client.TLS_Connections,key.s 
  
  Result = NetworkServerEvent(ServerID)
  Select Result
    Case #PB_NetworkEvent_Connect
      
      Server = EventServer()
      Server = ServerID(Server)
      LockMutex(TLSG\muxSever)
      *server = FindMapElement(TLSG\Servers(), Str(Server))
      
      If *server 
        ClientID = EventClient()
        If tls_accept_socket(*server\ctx, @ctx, ConnectionID(ClientID)) = -1
          CloseNetworkConnection(ClientID)
          Result = #PB_NetworkEvent_None
        Else
          LockMutex(TLSG\muxClient) 
          
          AddMapElement(TLSG\Clients(),Str(ClientID))
          TLSG\Clients()\ctx = ctx
          
          If ctx And tls_handshake(ctx) = -1 
           CloseNetworkConnection(ClientID) 
           DeleteMapElement(TLSG\Clients(),Str(ClientID))
           Result = #PB_NetworkEvent_None
          Else 
            TLS_report(@TLSG\Clients())  
          EndIf 
          
          UnlockMutex(TLSG\muxClient)  
        EndIf
      EndIf
       UnlockMutex(TLSG\muxSever)
    Case #PB_NetworkEvent_Disconnect
      
      ClientID = EventClient()
      key = Str(ClientID)
      LockMutex(TLSG\muxClient) 
      *client = FindMapElement(TLSG\Clients(),key) 
      If *client 
        tls_close(*client\ctx)
        tls_free(*client\ctx)
        DeleteMapElement(TLSG\Clients(),key)
      EndIf
      UnlockMutex(TLSG\muxClient)
      
  EndSelect
  
  ProcedureReturn Result
EndProcedure

Procedure TLS_CloseNetworkServer(Server)
  Protected *client.TLS_Connections 
  Protected key.s = Str(Server)
  
  LockMutex(TLSG\muxClient) 
  
  *client = FindMapElement(TLSG\Clients(),key) 
  
  If *client 
    ;is TLS connection!
    CloseNetworkServer(Server)
    tls_close(*Client\ctx)
    tls_free(*client\ctx)
    DeleteMapElement(TLSG\clients(),key)
  Else
    CloseNetworkServer(Server)
  EndIf
  
  UnlockMutex(TLSG\muxClient) 
  
EndProcedure

Procedure TLS_OpenNetworkConnection(ServerName$, Port, Mode, TimeOut, LocaleIP$, LocalePort)
  Protected TLSMode, ClientID, *ctx, *cfg, *Error, SockOpt.l, SockOptLen.l
  
  CompilerIf #PB_Compiler_Version <= 620 
    tlsmode = ((mode & $ffffff0) >> 1)  
    If mode & $10000000 
      mode = #PB_Network_IPv6 | (mode & 3) 
    Else   
      mode = mode & 3 
    EndIf 
  CompilerElse 
    tlsmode = ((mode & $ffffff0) >> 1 )  
    mode = mode & 3  
  CompilerEndIf 
    
  If TLSG\DLL And TLSMode
    *cfg = tls_config_new()
    If *cfg = 0
      TLSG\LastError = #TLS_Error_NewConfig_Failed
    Else
      If TLSG\CertFile$ = "" And TLSG\KeyFile$ = "" And TLSG\CaCertFile$ = ""
        tls_config_insecure_noverifycert(*cfg)
        tls_config_insecure_noverifyname(*cfg)
      Else
        If TLSG\CertFile$
          If tls_config_set_cert_file(*cfg, TLSG\CertFile$) = -1
            TLSG\LastError = #TLS_Error_CantLoad_CertFile
          EndIf
        EndIf
        If TLSG\KeyFile$
          If tls_config_set_key_file(*cfg, TLSG\KeyFile$) = -1
            TLSG\LastError = #TLS_Error_CantLoad_KeyFile
          EndIf
        EndIf
        If TLSG\CaCertFile$
          If tls_config_set_ca_file(*cfg, TLSG\CaCertFile$) = -1
            TLSG\LastError = #TLS_Error_CantLoad_RootCert
          EndIf
        EndIf
      EndIf
      If tls_config_set_protocols(*cfg, TLSMode) = -1
        TLSG\LastError = #TLS_Error_Unsupported_Protocol
      EndIf
      *ctx = tls_client()
      If *ctx = 0
        TLSG\LastError = #TLS_Error_Cant_Start_Client
      ElseIf tls_configure(*ctx, *cfg) = -1
        TLSG\LastError = #TLS_Error_Configure_Error
      Else
        *Error = tls_config_error(*cfg)
        If *Error
          Debug "TLS Config error: " + PeekS(*Error, - 1, #PB_UTF8)
        EndIf
        tls_config_free(*cfg)
        ClientID = OpenNetworkConnection(ServerName$, Port, Mode, TimeOut, LocaleIP$, LocalePort)
        If ClientID
          tls_connect_socket(*ctx, ConnectionID(ClientID), ServerName$)
          tls_handshake(*ctx) 
          LockMutex(TLSG\muxClient) 
          AddMapElement(TLSG\Clients(), Str(ClientID))
          TLSG\Clients()\ctx = *ctx 
          TLSG\Clients()\report\host = ServerName$
          TLS_report(@TLSG\Clients())
          UnlockMutex(TLSG\muxClient) 
        EndIf
      EndIf
    EndIf
  Else
    ClientID = OpenNetworkConnection(ServerName$, Port, Mode, TimeOut, LocaleIP$, LocalePort)
  EndIf
  
  ProcedureReturn ClientID
EndProcedure

Procedure TLS_ReceiveNetworkData(ClientID, Buffer, Length)
  Protected Result,*client.TLS_Connections 
  
  
  LockMutex(TLSG\muxClient) 
  
  *client = FindMapElement(TLSG\Clients(), Str(ClientID))
    
  If *client 
    Result = tls_read(*client\ctx, Buffer, Length)
  Else
    Result = ReceiveNetworkData(ClientID, Buffer, Length)
  EndIf
  
  UnlockMutex(TLSG\muxClient)
   
  ProcedureReturn Result
  
EndProcedure

Procedure TLS_SendNetworkData(ClientID, Buffer, Length)
  Protected Result,*client.TLS_Connections
  
  LockMutex(TLSG\muxClient) 
  
  *client = FindMapElement(TLSG\Clients(), Str(ClientID))
   
  If *client <> 0   
    Result = tls_write(*client\ctx, Buffer, Length)
  Else
    Result = SendNetworkData(ClientID, Buffer, Length)
  EndIf
  
  UnlockMutex(TLSG\muxClient)
  
  ProcedureReturn Result
EndProcedure

Procedure TLS_SendNetworkString(ClientID, String$, Format)
  Protected Result, *Buffer,*client.TLS_Connections
  
  LockMutex(TLSG\muxClient) 
  
  *client = FindMapElement(TLSG\Clients(), Str(ClientID))
  
  If *client 
    Select Format
      Case #PB_Ascii
        *Buffer = Ascii(String$)
        Result  = tls_write(*client\ctx, *Buffer, MemorySize(*Buffer) - 1)
        FreeMemory(*Buffer)
      Case #PB_Unicode
        Result = tls_write(*client\ctx, @String$, StringByteLength(String$))
      Case #PB_UTF8
        *Buffer = UTF8(String$)
        Result  = tls_write(*client\ctx, *Buffer, MemorySize(*Buffer) - 1)
        FreeMemory(*Buffer)
    EndSelect
  Else
    Result = SendNetworkString(ClientID, String$, Format)
  EndIf
  
  UnlockMutex(TLSG\muxClient)
  
  ProcedureReturn Result
EndProcedure

Procedure TLS_CloseNetworkConnection(ClientID)
  Protected *client.TLS_Connections,key.s 
  key =  Str(ClientID)
  
  LockMutex(TLSG\muxClient) 
  
  *client = FindMapElement(TLSG\Clients(), key)
  If *client   
    
    If *client\ctx 
      tls_close(*client\ctx)
      tls_free(*client\ctx)
    EndIf
    CloseNetworkConnection(ClientID)
    
    DeleteMapElement(TLSG\Clients(),key)
  Else
    CloseNetworkConnection(ClientID)
  EndIf
  
  UnlockMutex(TLSG\muxClient)
  
EndProcedure

Procedure Init_TLS(Domain$="",CertFile$ = "", KeyFile$ = "", CaCertFile$ = "",caPath$="")
  
  Protected Result = #TLS_Error_InitFailed
  If tlsg\DLL 
    If tls_init() = 0; TLS_Error_None
      AddElement(TLSG\certs())
      tlsg\certs()\Path$ = caPath$
      TLSG\certs()\domain$ = Domain$ 
      TLSG\certs()\CertFile$ = CertFile$ 
      TLSG\certs()\KeyFile$ = KeyFile$
      TLSG\certs()\CaCertFile$ = CaCertFile$ 
      If TLSG\CertFile$ <> "" 
        TLSG\CertFile$ = CertFile$  
        TLSG\KeyFile$ = KeyFile$ 
        TLSG\CaCertFile$ = CaCertFile$ 
        TLSG\domain$ = Domain$ 
      EndIf   
      Result  = #TLS_Error_None
    EndIf
  EndIf 
  
  ProcedureReturn Result
EndProcedure

Macro OpenNetworkConnection(ServerName, Port, Mode = #PB_Network_TCP | #PB_Network_IPv4, TimeOut = 0, LocaleIP = "", LocalePort = 0)
  TLS_OpenNetworkConnection(ServerName, Port, Mode, TimeOut, LocaleIP, LocalePort)
EndMacro

Macro CloseNetworkConnection(ClientID)
  TLS_CloseNetworkConnection(ClientID)
EndMacro

Macro ReceiveNetworkData(ClientID, Buffer, Length)
  TLS_ReceiveNetworkData(ClientID, Buffer, Length)
EndMacro

Macro SendNetworkData(ClientID, Buffer, Length)
  TLS_SendNetworkData(ClientID, Buffer, Length)
EndMacro

Macro SendNetworkString(ClientID, String, Format = #PB_UTF8)
  TLS_SendNetworkString(ClientID, String, Format)
EndMacro

Macro CreateNetworkServer(Server, Port, Mode = #PB_Network_TCP | #PB_Network_IPv4, BindedIP = "")
  TLS_CreateNetworkServer(Server, Port, Mode, BindedIP)
EndMacro

Macro CloseNetworkServer(Server)
  TLS_CloseNetworkServer(Server)
EndMacro

Macro NetworkServerEvent(ServerID = -1)
  TLS_NetworkServerEvent(ServerID)
EndMacro

CompilerIf #TLS_AUTOINIT
  __MyInit()
CompilerEndIf

#Server = 1 

CompilerIf #Server = 1 

PrivateKey$ = "E:\idle\testtls\certs\private.key.txt"
Cert$ = "E:\idle\testtls\certs\certificate.crt"  
  
Init_TLS("127.0.0.1",Cert$, PrivateKey$)

Exit = #False

OpenConsole()

Server = CreateNetworkServer(#PB_Any, 20252, #PB_Network_TCP | #PB_Network_IPv4 | #PB_Network_TLSv1,"127.0.0.1")
If Server
	*Buffer = AllocateMemory($FFFF, #PB_Memory_NoClear)

	Repeat 

		Select NetworkServerEvent(Server)

			Case #PB_NetworkEvent_Connect
				PrintN("client connecté")

			Case #PB_NetworkEvent_Data
				Client = EventClient()
				If *Buffer
					Repeat
						Length = ReceiveNetworkData(Client, *Buffer, MemorySize(*Buffer))
						If Length > 0
							PrintN(PeekS(*Buffer, Length, #PB_UTF8|#PB_ByteLength))
							Exit = #True
						EndIf
					Until Length = 0 Or (Length > 0 And Length <> MemorySize(*Buffer))
				EndIf	

			Case #PB_NetworkEvent_Disconnect
				PrintN("client déconnecté")

			Case #PB_NetworkEvent_None
				Delay(10)

		EndSelect
		
	Until Exit
	CloseNetworkServer(Server)
EndIf

 Input() 

CompilerElse 
  
  Define.i Con

Con = OpenNetworkConnection("127.0.0.1", 20252, #PB_Network_TCP | #PB_Network_IPv4 | #PB_Network_TLSv1)
If Con
			
	SendNetworkString(Con, "message sent by client")
	
	CloseNetworkConnection(Con)
EndIf

CompilerEndIf