6. Addresses

The low-level format of the addresses are different depending on the mode of communication you have chosen. A function is provided by each of the lower layers to map a user-friendly string-form address to the binary form required by the lower layers.

    void *cs_straddr(COMSTACK handle, const char *str);
   

The format for TCP/IP and SSL addresses is:

    <host> [ ':' <portnum> ]
   

The hostname can be either a domain name or an IPv4 address, or an IPv6 address enclosed in square brackets, for example [::1]:210. The port, if omitted, defaults to 210 for Z39.50, 80 for HTTP, and 443 for HTTPS. A service name accepted by the system resolver may also be used instead of a port number. A suffix beginning with / or ? is ignored when resolving the network address; the application interprets database names, HTTP paths, and queries.

For TCP/IP and SSL, the special hostnames @, maps to IN6ADDR_ANY_INIT with IPV4 binding as well (bindv6only=0), The special hostname @4 binds to INADDR_ANY (IPV4 only listener). The special hostname @6 binds to IN6ADDR_ANY_INIT with bindv6only=1 (IPV6 only listener).

For UNIX sockets, the format of an address is the socket filename.

When a connection has been established, you can use

    const char *cs_addrstr(COMSTACK h);
   

to retrieve the host name of the peer system. The function returns a pointer to a static area, which is overwritten on the next call to the function.

6.1. Host and URI syntax

     COMSTACK cs_create_host(const char *vhost, int flags, void **vp);
    

This function creates an endpoint and converts its address, combining cs_create and cs_straddr. It does not establish a connection. The vhost selects the transport, protocol, and address using the following case-sensitive prefixes.

FormTransportProtocolDefault port
host[:port]TCP/IPZ39.50210
tcp:host[:port]TCP/IPZ39.50210
ssl:host[:port]TLSZ39.50210
http://host[:port][/path]TCP/IPHTTP80
https://host[:port][/path]TLSHTTP443
unix:pathUNIX socketZ39.50Not applicable

Square brackets above denote optional parts, except for the literal brackets required around IPv6 addresses. For example, tcp:[2001:db8::1]:9999/database selects Z39.50 over TCP/IP, and https://[::1]/sru selects HTTPS. Only http: and https: strip leading slashes from the host part, so http:localhost is also accepted, but tcp://localhost is not the TCP form. An unrecognized prefix is treated as part of an unprefixed Z39.50 address, not as a new URI scheme. TLS forms require a build with GnuTLS support; UNIX sockets are unavailable on Windows.

These strings are COMSTACK address specifications, not a general URI parser. Host names and paths are not percent-decoded, and URI user information and fragments are not interpreted. In particular, user:password@host is not supported for a direct connection. Proxy authentication has a separate syntax described below.

For a UNIX socket, unix:/tmp/yaz.sock names the socket directly. The extended form unix:path:target uses path as the socket address and obtains the protocol and application arguments from target. For example, unix:/tmp/yaz.sock:http://localhost/sru selects HTTP over a UNIX socket, and unix:/tmp/yaz.sock:database selects Z39.50. Use an unencrypted target: ssl: and https: select the TLS transport instead of the UNIX transport. The first colon after unix: separates the socket address from the target, so it cannot be part of the socket filename.

A UNIX socket address may also be a comma-separated list containing file=path and optional user=name-or-id, group=name-or-id, and umask=mode. For example, unix:file=/tmp/yaz.sock,umask=0660. The file is required in this form; unknown or repeated keys are errors. User and group IDs are decimal, and the mode is octal. These options control ownership and permissions when binding a server socket. Despite its name, umask specifies the mode passed to chmod, not a mask to subtract; the default mode is 0666.

For TCP/IP and TLS, a local source address can follow the first space in vhost, for example tcp:server.example:210/ 192.0.2.10. Include a / before the space (or use an existing path or query suffix), so the network address parser does not include the source address in the destination host or port. The source port is forced to zero, allowing the operating system to choose it. For an IPv6 source, include an explicit port placeholder, for example http://[::1]/ [::1]:0.

The flags are the same as for cs_create; use zero for nonblocking operation or CS_FLAGS_BLOCKING for blocking operation. CS_FLAGS_CHECK_CERT enables TLS peer certificate checking. CS_FLAGS_DNS_NO_BLOCK requests asynchronous name resolution when resolver thread support is available, so resolution errors may occur during connection establishment. CS_FLAGS_NUMERICHOST requests numeric peer addresses from cs_addrstr.

On success the return value is a COMSTACK and *vp is its transport-specific address, suitable for cs_connect or cs_bind. Pass the address of a void * variable; the vp argument must not be NULL. The address is owned by the COMSTACK and must not be freed by the caller. A later cs_straddr call may replace it. On failure the function returns NULL; do not use the address output. Release a successful endpoint with cs_close.

     void *address = 0;
     COMSTACK cs = cs_create_host("tcp:localhost:9999", CS_FLAGS_BLOCKING,
                                  &address);
     if (cs) {
         int result = cs_connect(cs, address);
         /* Check result before exchanging protocol messages. */
         cs_close(cs);
     }

6.2. Proxies and cs_create_host2

     COMSTACK cs_create_host2(const char *vhost, int flags, void **vp,
                             const char *proxy_host, int *proxy_mode);
     COMSTACK cs_create_host_proxy(const char *vhost, int flags, void **vp,
                                  const char *proxy_host);
    

cs_create_host2 is the general form of cs_create_host. Its first three arguments and return value have the same meaning. vhost describes the target; proxy_host is either NULL for a direct connection or a proxy address using the same host syntax. proxy_mode must point to an integer. On success it is zero for a direct connection or an HTTP CONNECT tunnel, and one for application-level proxying. cs_create_host supplies no proxy; cs_create_host_proxy accepts a proxy but discards the mode output.

TargetProxyBehavior
TCP/IP Z39.50Unprefixed or tcp:Z39.50 proxy; mode 1
TCP/IP Z39.50http:HTTP CONNECT tunnel; mode 0
HTTPUnprefixed, tcp:, or http:HTTP proxy; mode 1
TLS (ssl: or https:)Unprefixed, tcp:, or http:HTTP CONNECT tunnel, then TLS to target; mode 0

The proxy must use TCP/IP; TLS and UNIX socket proxies, and nested proxy specifications, are rejected. In mode one the application must implement the proxy protocol, for example by sending an absolute request URI to an HTTP proxy or supplying the target to a Z39.50 proxy. COMSTACK does not rewrite application messages. In mode zero, COMSTACK performs any CONNECT exchange during cs_connect/cs_rcvconnect.

A tunnel can also be specified directly in vhost:

     connect:[user:password@]proxy-host:proxy-port,target
    

For example, connect:proxy.example:8080,tcp:target.example:210/database tunnels Z39.50, and connect:user:password@proxy.example:8080,https://target.example:443/sru tunnels HTTPS. The proxy part is a host and port, without a scheme; the target uses the normal TCP/IP or TLS syntax. The first comma separates proxy and target. Credentials before the first @ generate a Basic Proxy-Authorization header; they are not percent-decoded. This authentication is supported for CONNECT, not automatically for mode-one proxy requests.

Always give explicit proxy and target ports for CONNECT. The CONNECT request uses the target authority as supplied, removing the suffix starting at /, but does not add a default target port. When a proxy port is omitted, address resolution uses the target transport and protocol's default port, not the proxy scheme's default. This also applies to proxy_host. For example, use http://proxy.example:8080 to avoid ambiguity. CONNECT credentials may also be supplied in proxy_host, for example http://user:password@proxy.example:8080, when the selected behavior is a tunnel.

An explicit connect: specification takes precedence over proxy_host. The extended unix:path:target form likewise supplies its own connection address and ignores proxy_host.

6.3. Host parsing helpers

     int cs_parse_host(const char *uri, const char **host, CS_TYPE *t,
                       enum oid_proto *proto, char **connect_host);
     void cs_get_host_args(const char *type_and_host, const char **args);
    

cs_parse_host performs prefix parsing without creating an endpoint or resolving a host. It returns one on success and zero for an unavailable transport. All output pointer arguments are required. *host points into the input after the recognized prefixes, *t is the transport, and *proto is PROTO_Z3950 or PROTO_HTTP. *connect_host is either NULL or an allocated proxy/socket address from connect: or unix:path:target; free this value with xfree.

cs_get_host_args returns the portion after the first path slash, skipping a leading :// separator. For unix:path:args it returns args directly if that part contains no colon; otherwise it extracts the path from the target. For example, tcp:localhost:210/books yields books, and http://localhost/sru?version=1.2 yields sru?version=1.2. If there are no arguments it returns an empty string through args. The result is borrowed storage and must not be freed. This helper does not decode or interpret the arguments.