Reviewed the AppServer code

This commit is contained in:
Pierre Pronchery 2014-03-23 15:32:02 +09:00
parent 2ee7645798
commit becab80217
7 changed files with 145 additions and 523 deletions

View File

@ -64,6 +64,7 @@ dist:
$(PACKAGE)-$(VERSION)/src/transport/common.c \
$(PACKAGE)-$(VERSION)/src/transport/project.conf \
$(PACKAGE)-$(VERSION)/tests/appmessage.c \
$(PACKAGE)-$(VERSION)/tests/appserver.c \
$(PACKAGE)-$(VERSION)/tests/transport.c \
$(PACKAGE)-$(VERSION)/tests/Makefile \
$(PACKAGE)-$(VERSION)/tests/tests.sh \

View File

@ -1,5 +1,5 @@
/* $Id$ */
/* Copyright (c) 2012-2013 Pierre Pronchery <khorben@defora.org> */
/* Copyright (c) 2012-2014 Pierre Pronchery <khorben@defora.org> */
/* This file is part of DeforaOS System libApp */
/* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -25,25 +25,17 @@
/* types */
typedef struct _AppServer AppServer;
typedef enum _AppServerOptions
{
ASO_LOCAL = 1,
ASO_REMOTE = 2
} AppServerOptions;
/* constants */
# define APPSERVER_MAX_ARGUMENTS 4
/* functions */
AppServer * appserver_new(char const * app, int options);
AppServer * appserver_new_event(char const * app, int options, Event * event);
AppServer * appserver_new(char const * app, char const * name);
AppServer * appserver_new_event(char const * app, char const * name,
Event * event);
void appserver_delete(AppServer * appserver);
/* accessors */
void * appserver_get_client_id(AppServer * appserver);
/* useful */
int appserver_loop(AppServer * appserver);

View File

@ -1,5 +1,5 @@
/* $Id$ */
/* Copyright (c) 2011-2012 Pierre Pronchery <khorben@defora.org> */
/* Copyright (c) 2011-2014 Pierre Pronchery <khorben@defora.org> */
/* This file is part of DeforaOS System libApp */
/* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -15,7 +15,6 @@
#include <assert.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
@ -24,467 +23,44 @@
#endif
#include <string.h>
#include <errno.h>
#ifdef __WIN32__
# include <Winsock2.h>
#else
# include <sys/socket.h>
# include <netinet/in.h>
# include <arpa/inet.h>
#endif
#ifdef WITH_SSL
# include <openssl/ssl.h>
# include <openssl/err.h>
#endif
#include <System.h>
#include "App/appmessage.h"
#include "App/appserver.h"
#include "apptransport.h"
#include "appinterface.h"
#include "common.h"
#include "../config.h"
/* portability */
#ifdef __WIN32__
# define close(fd) closesocket(fd)
#endif
/* AppServerClient */
/* private */
/* types */
typedef enum _AppServerClientState
{
ASCS_NEW,
ASCS_LOGGED
} AppServerClientState;
typedef struct _AppServerClient
{
AppServerClientState state;
int fd;
uint32_t addr; /* FIXME uint8_t[4] instead? */
uint16_t port;
#define ASC_BUFSIZE 65536 /* FIXME */
char buf_read[ASC_BUFSIZE];
size_t buf_read_cnt;
char buf_write[ASC_BUFSIZE];
size_t buf_write_cnt;
/* callbacks */
ssize_t (*read)(struct _AppServerClient * asc, char * buffer,
size_t count);
ssize_t (*write)(struct _AppServerClient * asc, char const * buffer,
size_t count);
#ifdef WITH_SSL
/* ssl-specific */
SSL * ssl;
#endif
} AppServerClient;
/* prototypes */
static AppServerClient * _appserverclient_new(int fd, uint32_t addr,
uint16_t port
#ifdef WITH_SSL
, SSL_CTX * ssl_ctx
#endif
);
static void _appserverclient_delete(AppServerClient * appserverclient);
/* AppServer */
/* private */
/* types */
ARRAY(AppServerClient *, AppServerClient)
struct _AppServer
{
AppInterface * interface;
Event * event;
int event_free;
#ifdef WITH_SSL
SSL_CTX * ssl_ctx;
#endif
AppServerClientArray * clients;
AppServerClient * current;
AppTransport * transport;
AppTransportHelper helper;
};
/* prototypes */
static int _appserver_client_add(AppServer * appserver, AppServerClient * asc);
static int _appserver_client_remove(AppServer * appserver,
AppServerClient * asc);
static int _appserver_accept(int fd, AppServer * appserver);
static int _appserver_read(int fd, AppServer * appserver);
static int _appserver_write(int fd, AppServer * appserver);
#ifdef WITH_SSL
static char const * _appserver_error_ssl(void);
#endif
/* callbacks */
static ssize_t _callback_read(AppServerClient * asc, char * buffer,
size_t count);
static ssize_t _callback_write(AppServerClient * asc, char const * buffer,
size_t count);
#ifdef WITH_SSL
static ssize_t _callback_read_ssl(AppServerClient * asc, char * buffer,
size_t count);
static ssize_t _callback_write_ssl(AppServerClient * asc, char const * buffer,
size_t count);
#endif
/* AppServerClient */
/* private */
/* functions */
/* appserverclient_new */
static AppServerClient * _appserverclient_new(int fd, uint32_t addr,
uint16_t port
#ifdef WITH_SSL
, SSL_CTX * ssl_ctx
#endif
)
{
AppServerClient * asc;
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s()\n", __func__);
#endif
if((asc = object_new(sizeof(*asc))) == NULL)
return NULL;
asc->state = ASCS_NEW;
asc->addr = addr;
asc->port = port;
asc->buf_read_cnt = 0;
asc->buf_write_cnt = 0;
asc->read = _callback_read;
asc->write = _callback_write;
#ifdef WITH_SSL
if(addr != INADDR_LOOPBACK)
{
if((asc->ssl = SSL_new(ssl_ctx)) == NULL
|| SSL_set_fd(asc->ssl, fd) != 1)
{
error_set_code(1, "%s", _appserver_error_ssl());
_appserverclient_delete(asc);
return NULL;
}
asc->read = _callback_read_ssl;
asc->write = _callback_write_ssl;
SSL_set_accept_state(asc->ssl);
}
#endif
asc->fd = fd;
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s(%d, %x, %u) => %p\n", __func__, fd, addr,
port, (void *)asc);
#endif
common_socket_set_nodelay(fd, 1);
return asc;
}
/* appserverclient_delete */
static void _appserverclient_delete(AppServerClient * appserverclient)
{
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s(%p)\n", __func__, (void *)appserverclient);
#endif
#ifdef WITH_SSL
if(appserverclient->ssl != NULL)
SSL_free(appserverclient->ssl);
#endif
if(appserverclient->fd != -1)
close(appserverclient->fd);
object_delete(appserverclient);
}
/* AppServer */
/* private */
/* functions */
/* appserver_client_add */
static int _appserver_client_add(AppServer * appserver, AppServerClient * asc)
/* FIXME check for errors */
{
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s()\n", __func__);
#endif
array_append(appserver->clients, &asc);
event_register_io_read(appserver->event, asc->fd,
(EventIOFunc)_appserver_read, appserver);
return 0;
}
/* appserver_client_remove */
static int _appserver_client_remove(AppServer * appserver,
AppServerClient * asc)
/* FIXME check for errors */
{
AppServerClient * p;
unsigned int i;
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s(%p, %p)\n", __func__, (void *)appserver,
(void *)asc);
#endif
for(i = 0; i < array_count(appserver->clients); i++)
{
if(array_get_copy(appserver->clients, i, &p) != 0)
break;
if(p == asc)
break;
}
if(asc->buf_write_cnt > 0)
event_unregister_io_write(appserver->event, asc->fd);
event_unregister_io_read(appserver->event, asc->fd);
_appserverclient_delete(asc);
array_remove_pos(appserver->clients, i);
return 0;
}
/* appserver_accept */
static int _appserver_accept(int fd, AppServer * appserver)
{
struct sockaddr_in sa;
socklen_t sa_size = sizeof(sa);
int newfd;
AppServerClient * asc;
if((newfd = accept(fd, (struct sockaddr *)&sa, &sa_size)) == -1)
return error_set_code(1, "%s%s", "accept: ", strerror(errno));
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s() %s%d%s%d %s:%u\n", __func__, "accept(",
fd, ") => ", newfd, inet_ntoa(sa.sin_addr),
ntohs(sa.sin_port));
#endif
if((asc = _appserverclient_new(newfd, htonl(sa.sin_addr.s_addr),
htons(sa.sin_port)
#ifdef WITH_SSL
, appserver->ssl_ctx
#endif
)) == NULL)
{
#ifdef DEBUG
error_print("DEBUG");
#endif
close(newfd);
return 0;
}
return _appserver_client_add(appserver, asc);
}
/* appserver_read */
static int _read_error(AppServer * appserver, AppServerClient * asc);
static int _read_eof(AppServer * appserver, AppServerClient * asc);
static int _read_process(AppServer * appserver, AppServerClient * asc);
static int _read_logged(AppServer * appserver, AppServerClient * asc);
static int _appserver_read(int fd, AppServer * appserver)
{
AppServerClient * asc = NULL;
unsigned int i;
ssize_t len;
for(i = 0; i < array_count(appserver->clients); i++)
{
if(array_get_copy(appserver->clients, i, &asc))
break;
if(fd == asc->fd)
break;
asc = NULL;
}
if(asc == NULL)
return 1;
len = sizeof(asc->buf_read) - asc->buf_read_cnt;
assert(len > 0 && asc->fd == fd);
if((len = asc->read(asc, &asc->buf_read[asc->buf_read_cnt], len)) < 0)
return _read_error(appserver, asc);
else if(len == 0)
return _read_eof(appserver, asc);
asc->buf_read_cnt += len;
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s() %s%d%s%ld%s", __func__, "read(", fd,
") => ", len, "\n");
#endif
if(_read_process(appserver, asc) != 0)
{
_appserver_client_remove(appserver, asc);
return 1;
}
return 0;
}
static int _read_error(AppServer * appserver, AppServerClient * asc)
{
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s(%p, %p)\n", __func__, (void *)appserver,
(void *)asc);
#endif
#ifdef WITH_SSL
error_set_code(1, "%s", _appserver_error_ssl());
SSL_shutdown(asc->ssl);
#else
error_set_code(1, "%s", strerror(errno));
#endif
#ifdef DEBUG
error_print("DEBUG");
#endif
_appserver_client_remove(appserver, asc);
return 1;
}
static int _read_eof(AppServer * appserver, AppServerClient * asc)
{
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s(%p, %p)\n", __func__, (void *)appserver,
(void *)asc);
#endif
_appserver_client_remove(appserver, asc);
return 1;
}
static int _read_process(AppServer * appserver, AppServerClient * asc)
{
switch(asc->state)
{
case ASCS_NEW:
/* FIXME authenticate */
asc->state = ASCS_LOGGED;
case ASCS_LOGGED:
return _read_logged(appserver, asc);
}
return 1;
}
static int _read_logged(AppServer * appserver, AppServerClient * asc)
{
ssize_t i;
int32_t ret;
appserver->current = asc;
i = appinterface_receive(appserver->interface, &ret, asc->buf_read,
asc->buf_read_cnt, asc->buf_write,
sizeof(asc->buf_write), &asc->buf_write_cnt);
appserver->current = NULL;
if(i <= 0 || (size_t)i > asc->buf_read_cnt)
return 1;
asc->buf_read_cnt -= i;
memmove(asc->buf_read, &asc->buf_read[i], asc->buf_read_cnt);
/* FIXME should it be done in AppInterface? */
if(asc->buf_write_cnt + sizeof(ret) > sizeof(asc->buf_write))
return error_set_code(1, "%s", strerror(ENOBUFS));
ret = htonl(ret);
memcpy(&(asc->buf_write[asc->buf_write_cnt]), &ret, sizeof(ret));
asc->buf_write_cnt += sizeof(ret);
event_register_io_write(appserver->event, asc->fd,
(EventIOFunc)_appserver_write, appserver);
return (asc->fd != -1) ? 0 : 1;
}
/* appserver_write */
static int _write_error(AppServerClient * asc);
static int _appserver_write(int fd, AppServer * appserver)
{
AppServerClient * asc;
ssize_t len;
unsigned int i;
/* FIXME factorize this code */
for(i = 0; i < array_count(appserver->clients); i++)
{
if(array_get_copy(appserver->clients, i, &asc))
break;
if(fd == asc->fd)
break;
asc = NULL;
}
if(asc == NULL)
return 1;
if((len = asc->write(asc, asc->buf_write, asc->buf_write_cnt)) <= 0)
return _write_error(asc);
#ifdef DEBUG
fprintf(stderr, "DEBUG: write(%d, %lu) => %ld\n", fd,
asc->buf_write_cnt, len);
#endif
memmove(asc->buf_write, &asc->buf_write[len], len);
asc->buf_write_cnt -= len;
return (asc->buf_write_cnt == 0) ? 1 : 0;
}
static int _write_error(AppServerClient * asc)
{
#ifdef WITH_SSL
error_set_code(1, "%s", _appserver_error_ssl());
#else
error_set_code(1, "%s", strerror(errno));
#endif
close(asc->fd);
asc->fd = -1;
return 1;
}
#ifdef WITH_SSL
/* appserver_error_ssl */
static char const * _appserver_error_ssl(void)
{
return ERR_error_string(ERR_get_error(), NULL);
}
#endif
/* callbacks */
/* callback_read */
static ssize_t _callback_read(AppServerClient * asc, char * buffer,
size_t count)
{
return recv(asc->fd, buffer, count, 0);
}
/* callback_write */
static ssize_t _callback_write(AppServerClient * asc, char const * buffer,
size_t count)
{
return send(asc->fd, buffer, count, 0);
}
#ifdef WITH_SSL
/* callback_read_ssl */
static ssize_t _callback_read_ssl(AppServerClient * asc, char * buffer,
size_t count)
{
return SSL_read(asc->ssl, buffer, count);
}
/* callback_write_ssl */
static ssize_t _callback_write_ssl(AppServerClient * asc, char const * buffer,
size_t count)
{
return SSL_write(asc->ssl, buffer, count);
}
#endif
/* helpers */
static int _appserver_helper_message(void * data, AppTransport * transport,
AppTransportClient * client, AppMessage * message);
/* public */
/* functions */
/* appserver_new */
AppServer * appserver_new(const char * app, int options)
AppServer * appserver_new(const char * app, char const * name)
{
AppServer * appserver;
Event * event;
if((event = event_new()) == NULL)
return NULL;
if((appserver = appserver_new_event(app, options, event)) == NULL)
if((appserver = appserver_new_event(app, name, event)) == NULL)
{
event_delete(event);
return NULL;
@ -495,84 +71,85 @@ AppServer * appserver_new(const char * app, int options)
/* appserver_new_event */
static int _new_server(AppServer * appserver, char const * app, int options);
static AppTransport * _new_event_transport(AppTransportHelper * helper,
Event * event, char const * app, char const * name);
static String * _new_server_name(char const * app, char const * name);
static String * _new_server_transport(String ** name);
AppServer * appserver_new_event(char const * app, int options, Event * event)
AppServer * appserver_new_event(char const * app, char const * name,
Event * event)
{
AppServer * appserver;
#ifdef WITH_SSL
char crt[256];
if(snprintf(crt, sizeof(crt), "%s%s%s", PREFIX "/etc/AppServer/", app,
".crt") >= (int)sizeof(crt))
return NULL;
#endif
if((appserver = object_new(sizeof(*appserver))) == NULL)
return NULL;
appserver->interface = NULL;
appserver->interface = appinterface_new_server(app);
appserver->helper.data = appserver;
appserver->helper.message = _appserver_helper_message;
appserver->transport = _new_event_transport(&appserver->helper, event,
app, name);
appserver->event = event;
appserver->event_free = 0;
#ifdef WITH_SSL
appserver->ssl_ctx = NULL;
#endif
if((appserver->clients = AppServerClientarray_new()) == NULL
|| _new_server(appserver, app, options) != 0)
/* check for errors */
if(appserver->interface == NULL || appserver->transport == NULL)
{
appserver_delete(appserver);
return NULL;
}
#ifdef WITH_SSL
# ifdef DEBUG
fprintf(stderr, "DEBUG: Using certificate \"%s\"\n", crt);
# endif
if(options & ASO_REMOTE)
if((appserver->ssl_ctx = SSL_CTX_new(SSLv3_server_method())) == NULL
|| SSL_CTX_set_cipher_list(appserver->ssl_ctx,
SSL_DEFAULT_CIPHER_LIST) != 1
|| SSL_CTX_use_certificate_file(
appserver->ssl_ctx, crt,
SSL_FILETYPE_PEM) == 0
|| SSL_CTX_use_PrivateKey_file(
appserver->ssl_ctx, crt,
SSL_FILETYPE_PEM) == 0)
{
error_set_code(1, "%s", _appserver_error_ssl());
appserver_delete(appserver);
return NULL;
}
#endif
appserver->current = NULL;
return appserver;
}
static int _new_server(AppServer * appserver, char const * app, int options)
static AppTransport * _new_event_transport(AppTransportHelper * helper,
Event * event, char const * app, char const * name)
{
int fd;
struct sockaddr_in sa;
AppTransport * ret;
String * n;
String * transport;
if((appserver->interface = appinterface_new_server(app)) == NULL)
return -1;
if((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
return -error_set_code(1, "%s%s", "socket: ", strerror(errno));
sa.sin_family = AF_INET;
sa.sin_port = htons(appinterface_get_port(appserver->interface));
sa.sin_addr.s_addr = htonl((options & ASO_REMOTE) ? INADDR_ANY
: INADDR_LOOPBACK);
if(bind(fd, (struct sockaddr *)&sa, sizeof(sa)) == 0)
if((n = _new_server_name(app, name)) == NULL)
return NULL;
if((transport = _new_server_transport(&n)) == NULL)
{
if(listen(fd, SOMAXCONN) == 0)
{
event_register_io_read(appserver->event, fd,
(EventIOFunc)_appserver_accept,
appserver);
return 0;
}
error_set_code(1, "%s%s", "listen: ", strerror(errno));
string_delete(n);
return NULL;
}
else
error_set_code(1, "%s%s", "bind: ", strerror(errno));
close(fd);
return -1;
ret = apptransport_new(ATM_SERVER, helper, transport, n, event);
string_delete(transport);
string_delete(n);
return ret;
}
static String * _new_server_name(char const * app, char const * name)
{
String * var;
if(name != NULL)
return string_new(name);
/* obtain the desired transport and name from the environment */
if((var = string_new_append("APPSERVER_", app, NULL)) == NULL)
return NULL;
name = getenv(var);
string_delete(var);
return string_new(name);
}
static String * _new_server_transport(String ** name)
{
String * p;
String * transport;
if((p = strchr(*name, ':')) == NULL)
/* XXX hard-coded default value */
return string_new("tcp");
/* XXX */
*(p++) = '\0';
transport = *name;
if((*name = string_new(p)) == NULL)
{
string_delete(transport);
return NULL;
}
return transport;
}
@ -586,23 +163,10 @@ void appserver_delete(AppServer * appserver)
appinterface_delete(appserver->interface);
if(appserver->event_free != 0)
event_delete(appserver->event);
array_delete(appserver->clients);
#ifdef WITH_SSL
if(appserver->ssl_ctx != NULL)
SSL_CTX_free(appserver->ssl_ctx);
#endif
object_delete(appserver);
}
/* accessors */
/* appserver_get_client_id */
void * appserver_get_client_id(AppServer * appserver)
{
return appserver->current;
}
/* useful */
/* appserver_loop */
int appserver_loop(AppServer * appserver)
@ -612,3 +176,15 @@ int appserver_loop(AppServer * appserver)
#endif
return event_loop(appserver->event);
}
/* private */
/* appserver_helper_message */
static int _appserver_helper_message(void * data, AppTransport * transport,
AppTransportClient * client, AppMessage * message)
{
AppServer * appserver = data;
/* FIXME implement */
return 0;
}

View File

@ -1,4 +1,4 @@
TARGETS = appmessage tests.log transport
TARGETS = appmessage appserver tests.log transport
PREFIX = /usr/local
DESTDIR =
BINDIR = $(PREFIX)/bin
@ -25,7 +25,14 @@ appmessage_LDFLAGS = $(LDFLAGSF) $(LDFLAGS) ../src/libApp.a
appmessage: $(appmessage_OBJS)
$(CC) -o appmessage $(appmessage_OBJS) $(appmessage_LDFLAGS)
tests.log: appmessage tests.sh transport ../src/transport/tcp.c ../src/transport/udp.c
appserver_OBJS = appserver.o
appserver_CFLAGS = $(CPPFLAGSF) $(CPPFLAGS) $(CFLAGSF) $(CFLAGS)
appserver_LDFLAGS = $(LDFLAGSF) $(LDFLAGS) ../src/libApp.a
appserver: $(appserver_OBJS)
$(CC) -o appserver $(appserver_OBJS) $(appserver_LDFLAGS)
tests.log: appmessage appserver tests.sh transport ../src/transport/tcp.c ../src/transport/udp.c
./tests.sh -P "$(PREFIX)" -- "tests.log"
transport_OBJS = transport.o
@ -38,11 +45,14 @@ transport: $(transport_OBJS)
appmessage.o: appmessage.c ../src/libApp.a
$(CC) $(appmessage_CFLAGS) -c appmessage.c
appserver.o: appserver.c ../src/libApp.a
$(CC) $(appserver_CFLAGS) -c appserver.c
transport.o: transport.c ../src/libApp.a
$(CC) $(transport_CFLAGS) -c transport.c
clean:
$(RM) -- $(appmessage_OBJS) $(tests.log_OBJS) $(transport_OBJS)
$(RM) -- $(appmessage_OBJS) $(appserver_OBJS) $(tests.log_OBJS) $(transport_OBJS)
distclean: clean
$(RM) -- $(TARGETS)

34
tests/appserver.c Normal file
View File

@ -0,0 +1,34 @@
/* $Id$ */
/* Copyright (c) 2014 Pierre Pronchery <khorben@defora.org> */
/* This file is part of DeforaOS System libApp */
/* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "App/appserver.h"
/* public */
/* main */
int main(int argc, char * argv[])
{
AppServer * appserver;
if((appserver = appserver_new("VFS", "tcp")) == NULL)
{
error_print("appserver");
return 2;
}
appserver_delete(appserver);
return 0;
}

View File

@ -1,4 +1,4 @@
targets=appmessage,tests.log,transport
targets=appmessage,appserver,tests.log,transport
cppflags_force=-I ../include
cflags_force=-W `pkg-config --cflags libSystem`
cflags=-Wall -g -O2
@ -14,10 +14,18 @@ ldflags=../src/libApp.a
[appmessage.c]
depends=../src/libApp.a
[appserver]
type=binary
sources=appserver.c
ldflags=../src/libApp.a
[appserver.c]
depends=../src/libApp.a
[tests.log]
type=script
script=./tests.sh
depends=appmessage,tests.sh,transport,../src/transport/tcp.c,../src/transport/udp.c
depends=appmessage,appserver,tests.sh,transport,../src/transport/tcp.c,../src/transport/udp.c
[transport]
type=binary

View File

@ -112,6 +112,7 @@ FAILED=
(echo "Performing tests:" 1>&2
$DATE
_test "appmessage"
_test "appserver"
_test "transport" -p tcp4 127.0.0.1:4242
_test "transport" -p tcp4 localhost:4242
_test "transport" -p tcp6 ::1.4242