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.
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.
| Form | Transport | Protocol | Default port |
|---|---|---|---|
host[:port] | TCP/IP | Z39.50 | 210 |
tcp:host[:port] | TCP/IP | Z39.50 | 210 |
ssl:host[:port] | TLS | Z39.50 | 210 |
http://host[:port][/path] | TCP/IP | HTTP | 80 |
https://host[:port][/path] | TLS | HTTP | 443 |
unix:path | UNIX socket | Z39.50 | Not 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);
}
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.
| Target | Proxy | Behavior |
|---|---|---|
| TCP/IP Z39.50 | Unprefixed or tcp: | Z39.50 proxy; mode 1 |
| TCP/IP Z39.50 | http: | HTTP CONNECT tunnel; mode 0 |
| HTTP | Unprefixed, 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.
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.