Socket streams can now be implemented on top of Java Objects, instead of native sockets. The main purpose of this is to allow using SSL in LispWorks for Android Runtime, because OpenSSL is not available on Android. It may also be useful where you have a Java socket from some source and want to communicate through it using a Lisp stream.
The function switch-open-tcp-stream-with-ssl-to-java is called automatically before delivery for Android by deliver-to-android-project. That causes open-tcp-stream, when it is called with ssl-ctx non-nil, to use Java sockets instead of operating system sockets.
The function open-tcp-stream-using-java can be used to force using a Java socket.
You can also explicitly create a stream using Java sockets by passing a Java socket to
(make-instance 'comm:socket-stream ...) or by setting the socket in an existing stream using
(setf comm:socket-stream-socket) or replace-socket-stream-socket.
Socket streams with Java sockets are limited, mainly because cl:listen cannot be used reliably with them. Specifically, when cl:listen returns
t it is guaranteed that reading will not hang, but when cl:listen returns
nil it does not mean that there is nothing to read. They also do not have a zero timeout: the shortest timeout is 1 millisecond. That means that it is impossible to check whether reading from the stream will hang. The best that you can do is to set the read-timeout to a short time, and then try to read.
There is also no write timeout.
The Asynchronous I/O interface and the server side (start-up-server) do not work at the moment with Java sockets. If you want to create a service with Java sockets, you will need to implement the listening part using Java methods. Once a socket is accepted, you can pass it to
(make-instance 'comm:socket-stream ...) to do the actual communication.
When using Java sockets, the SSL configuration arguments ctx-configure-callback and ssl-configure-callback, as well as the write-timeout and ipv6, are ignored. The ssl-ctx is ignored when passed to cl:make-instance, and when passed to open-tcp-stream or open-tcp-stream-using-java it is interpreted as a boolean, specifying whether to use SSL or not. The only way to configure the socket, and more importantly the SSL settings, is by passing a socket factory (a Java object of class
javax.net.SocketFactory) to open-tcp-stream-using-java. The application needs to set up and configure this factory using Java methods. By default, open-tcp-stream and open-tcp-stream-using-java use the default factory (which they get by the method
javax.net.ssl.SSLSocketFactory). Thus configuring the default factories affects what they do.
cl:listen is unreliable because the only way to check whether there is input on a Java socket is to use the Java method
"available" on the input stream of the Java socket (that is, the result of the method
"available" method is documented as unreliable, and experimentally it is indeed unreliable on SSL sockets (on plain sockets it seems to work properly). If you know that in the implementation that you use the method
"available" on an input stream of a socket is reliable, then you can trust cl:listen on socket streams with Java sockets.
Using Java sockets requires the LispWorks Java interface running Java Virtual Machine (JVM). On Android there is always a running JVM. On other architectures the JVM must be initialized by init-java-interface. To load the LispWorks Java interface, do:
When using Java sockets and SSL, the default behavior is to verify the hostname (not done on the ordinary sockets). To do that it relies on classes from
httpclient must be in the class path for using Java sockets with SSL.
httpclient is always available on Android. See open-tcp-stream-using-java for details of the verification process.
On Android, the OpenSSL library is not available, so if the module "comm" was loaded, deliver-to-android-project switches to using Java sockets for SSL streams. These streams have problems with cl:listen, discussed above. In principle, if you can find OpenSSL library for Android you can switch it back by calling switch-open-tcp-stream-with-ssl-to-java with
nil, and use SSL in the usual way. You need to use set-ssl-library-path to tell the system where to find the library.
Android does not allow doing socket operations on the GUI threads (since Honeycomb SDK), and doing such operations would give a java-exception error with exception
NetworkOnMainThreadException. That applies to socket-stream where the socket is a Java socket. However, it is always a bad idea to do socket operations on the GUI thread, so you should not do socket operations in the GUI thread with ordinary sockets either.
LispWorks® User Guide and Reference Manual - 01 Dec 2021 19:30:24