Open a TCP stream using Java sockets for communication.
comm
open-tcp-stream-using-java hostspec service &key factory verify direction element-type errorp read-timeout write-timeout timeout ssl-ctx ctx-configure-callback ssl-configure-callback tlsext-host-name local-address ipv6 local-port nodelay keepalive => stream
hostspec⇩ |
An integer or string or an ipv6-address object. |
service⇩ |
A string or a fixnum. |
factory⇩ |
A Java socket factory. |
verify⇩ | |
direction⇩ |
One of :input , :output or :io . |
element-type⇩ | |
errorp⇩ |
A boolean. |
read-timeout⇩ |
A positive number, or nil . |
write-timeout⇩ |
Ignored. |
timeout⇩ |
A positive number, or nil . |
ssl-ctx⇩ |
A generalized boolean. |
ctx-configure-callback⇩ | |
Ignored. | |
ssl-configure-callback⇩ | |
Ignored. | |
tlsext-host-name⇩ |
Ignored. |
local-address⇩ | nil , an integer, a string or a ipv6-address object. |
ipv6⇩ |
Ignored. |
local-port⇩ | nil , a string or a fixnum. |
nodelay⇩ |
A generalized boolean. |
keepalive⇩ |
A generalized boolean. |
stream |
The function open-tcp-stream-using-java
opens a TCP stream using Java sockets for communication.
Note: open-tcp-stream-using-java
does not have any clear advantage over open-tcp-stream. Use it only when you really need it.
open-tcp-stream-using-java
accepts the same service, direction, element-type, errorp, read-timeout, timeout, local-address, local-port, nodelay and keepalive arguments as open-tcp-stream, plus factory and verify, but ignores the values of write-timeout, ipv6, ctx-configure-callback, ssl-configure-callback and tlsext-host-name. It also treats ssl-ctx as a generalized boolean, where any non-nil value means using SSL Java object.
open-tcp-stream-using-java
opens and returns a socket-stream like open-tcp-stream, but the socket object that it uses is a Java object. However, cl:listen is unreliable on such streams, and they cannot be used in wait-for-input-streams. See 25.9 Socket streams with Java sockets and SSL on Android for details.
The keyword argument factory can be used to specify the socket factory to use to create the Java socket. When passed, it must be a Java socket factory, that is a jobject which is an instance of class javax.net.SocketFactory
. In this case the socket is generated from this factory, the factory determines whether it is a SSL socket or not, and the value of ssl-ctx is used only to decide whether to do a handshake. By default, the default factory (the result of "getDefault"
) of javax.net.SocketFactory
(when ssl-ctx is nil
) or javax.net.ssl.SSLSocketFactory
(when ssl-ctx is non-nil) is used.
The keyword argument verify is used only when ssl-ctx is non-nil. It controls verification of hostspec when SSL is used, which means checking that the certificate that was returned by the server is for this server. The default value t
means using SSLCertificateSocketFactory
on Android when factory is not supplied (see below), on other platforms it is the same as :strict
. :strict
mean uses the strict verifier (Java class org.apache.http.conn.ssl.StrictHostnameVerifier
). :browser-compat
means using "browser compatible" verifier (Java class org.apache.http.conn.ssl.BrowserCompatHostnameVerifier
). Verification with :browser-compat
is a little more relaxed than with :strict
.
On Android when verify is t
and factory is nil
, the code uses the socket factory android.net.SSLCertificateSocketFactory
(instead of the default of javax.net.ssl.SSLSocketFactory
), which is doing the verification itself. When factory is non-nil, Android does the same as in the previous paragraph (verify using the strict verifier). The SSLCertificateSocketFactory
has the advantage that it uses SNI (Server Name Indication), which makes verification work better.
When verify is a string, it has to be the hostname to use for verification, instead of hostspec argument. The verification is done using the strict verifier.
When verify is a jobject, it must be a verifier (of class javax.net.ssl.HostnameVerifier
), and it is used as-is.
The verifier classes above are part of httpclient
from apache.org
, and therefore to use them (which is the default when using SSL), you need to have httpclient
. On Android it is always available, so it is not an issue, on another architectures it needs to be added to the class path.
When verify is nil
, hostspec is not verified, which is not recommended. However, there are valid sites which will fail verification, because they return a certificate for the wrong site (that happens due to use of virtual hosts). At the time of writing, "gmail.com"
is one of them, and returns a certificate for "mail.google.com"
. However, if the client uses SNI, which is used by Java socket in Java 1.7 or higher, this server does return the correct certificate, and in general all servers should work when using SNI. On Android the default setting uses the SSLCertificateSocketFactory
(discussed above), which is using SNI. Thus there is a problem only when using Java 1.6 or earlier, and for Android only when you use your own factory. For these cases, you can either use verify nil
, or pass the name in the certificate as verify:
(comm:open-tcp-stream-using-java "gmail.com" 443 :ssl-ctx t :verify "mail.google.com")
Note however that this will fail if SNI is used.
open-tcp-stream-using-java
to work. On Android the JVM always runs, on other architectures it needs to have been started by init-java-interface. When using ssl-ctx, httpclient
must be available too, and again it is always available on Android.open-tcp-stream-using-java
with ssl-ctx non-nil is identical in this case.(make-instance 'socket-stream ...)
. Note that closing such a stream will close the socket, and if you want to avoid that you need to use replace-socket-stream-socket.
25.9 Socket streams with Java sockets and SSL on Android
open-tcp-stream
25 TCP and UDP socket communication and SSL
LispWorks® User Guide and Reference Manual - 01 Dec 2021 19:30:26