Rework route print command to use newer mdp api, show live updates & deprecate monitor messages

This commit is contained in:
Jeremy Lakeman 2016-05-09 16:21:46 +09:30
parent 6cedb2d0ac
commit 6feaddf24d
12 changed files with 253 additions and 179 deletions

View File

@ -67,6 +67,15 @@ int parse_sid_t(sid_t *sidp, const char *hex, ssize_t hexlen, const char **endp)
return 0;
}
int sid_get_special_type(const sid_t *sid)
{
if (is_all_matching(sid->binary, SID_SIZE -1, 0))
return sid->binary[SID_SIZE -1];
if (is_all_matching(sid->binary, SID_SIZE, 0xFF))
return SID_TYPE_BROADCAST;
return -1;
}
int str_is_subscriber_id(const char *sid)
{
size_t len = 0;

View File

@ -40,6 +40,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "overlay_interface.h"
#include "keyring.h"
#include "serval.h" // for overlay_send_frame()
#include "route_link.h"
__thread struct subscriber *directory_service;
@ -142,3 +143,10 @@ static void interface_change(struct overlay_interface *UNUSED(interface)){
}
DEFINE_TRIGGER(iupdown, interface_change);
static void directory_link_changed(struct subscriber *subscriber, int UNUSED(prior_reachable)){
if (subscriber==directory_service)
directory_registration();
}
DEFINE_TRIGGER(link_change, directory_link_changed);

View File

@ -100,14 +100,7 @@ struct mdp_identity_request {
#define MDP_INTERFACE_DOWN 1
#define MDP_INTERFACE_RECV 2
struct overlay_route_record{
sid_t sid;
char interface_name[256];
int reachable;
int hop_count;
sid_t neighbour;
sid_t prior_hop;
};
#define MDP_ROUTE_TABLE 5
struct overlay_mdp_scan{
struct in_addr addr;
@ -121,7 +114,6 @@ struct overlay_mdp_data_frame {
int ttl;
union{
unsigned char payload[MDP_MTU-100];
struct overlay_route_record route_record;
};
};

View File

@ -394,10 +394,24 @@ void monitor_get_all_supported_codecs(unsigned char *codecs){
}
}
static void monitor_announce_peer(struct subscriber *subscriber, int prior_reachable)
{
monitor_tell_formatted(MONITOR_LINKS, "\nLINK:%d:%s:%s\n",
subscriber->hop_count,
subscriber->prior_hop ? alloca_tohex_sid_t(subscriber->prior_hop->sid) : "",
alloca_tohex_sid_t(subscriber->sid));
if ((prior_reachable & REACHABLE) && (!(subscriber->reachable & REACHABLE)))
monitor_tell_formatted(MONITOR_PEERS, "\nOLDPEER:%s\n", alloca_tohex_sid_t(subscriber->sid));
if ((!(prior_reachable & REACHABLE)) && (subscriber->reachable & REACHABLE))
monitor_tell_formatted(MONITOR_PEERS, "\nNEWPEER:%s\n", alloca_tohex_sid_t(subscriber->sid));
}
DEFINE_TRIGGER(link_change, monitor_announce_peer);
static int monitor_announce_all_peers(struct subscriber *subscriber, void *UNUSED(context))
{
if (subscriber->reachable&REACHABLE)
monitor_announce_peer(&subscriber->sid);
monitor_announce_peer(subscriber, REACHABLE_NONE);
return 0;
}
@ -423,7 +437,7 @@ static int monitor_set(const struct cli_parsed *parsed, struct cli_context *cont
c->flags|=MONITOR_DNAHELPER;
}else if (strcase_startswith(parsed->args[1],"links", NULL)){
c->flags|=MONITOR_LINKS;
link_state_announce_links();
enum_subscribers(NULL, monitor_announce_all_peers, NULL);
}else if (strcase_startswith(parsed->args[1],"quit", NULL)){
c->flags|=MONITOR_QUIT;
}else if (strcase_startswith(parsed->args[1],"interface", NULL)){
@ -627,24 +641,6 @@ static void monitor_announce_bundle(rhizome_manifest *m)
}
DEFINE_TRIGGER(bundle_add, monitor_announce_bundle);
int monitor_announce_peer(const sid_t *sidp)
{
return monitor_tell_formatted(MONITOR_PEERS, "\nNEWPEER:%s\n", alloca_tohex_sid_t(*sidp));
}
int monitor_announce_unreachable_peer(const sid_t *sidp)
{
return monitor_tell_formatted(MONITOR_PEERS, "\nOLDPEER:%s\n", alloca_tohex_sid_t(*sidp));
}
int monitor_announce_link(int hop_count, struct subscriber *transmitter, struct subscriber *receiver)
{
return monitor_tell_formatted(MONITOR_LINKS, "\nLINK:%d:%s:%s\n",
hop_count,
transmitter ? alloca_tohex_sid_t(transmitter->sid) : "",
alloca_tohex_sid_t(receiver->sid));
}
// test if any monitor clients are interested in a particular type of event
int monitor_client_interested(int mask){
int i;

View File

@ -445,21 +445,31 @@ static int app_count_peers(const struct cli_parsed *parsed, struct cli_context *
DEFINE_CMD(app_route_print, 0,
"Print the routing table",
"route","print");
"route","print","[--monitor]");
static int app_route_print(const struct cli_parsed *parsed, struct cli_context *context)
{
int mdp_sockfd;
int opt_monitor = 0 == cli_arg(parsed, "--monitor", NULL, NULL, NULL);
DEBUG_cli_parsed(verbose, parsed);
if ((mdp_sockfd = overlay_mdp_client_socket()) < 0)
if ((mdp_sockfd = mdp_socket()) < 0)
return WHY("Cannot create MDP socket");
overlay_mdp_frame mdp;
bzero(&mdp,sizeof(mdp));
mdp.packetTypeAndFlags=MDP_ROUTING_TABLE;
overlay_mdp_send(mdp_sockfd, &mdp,0,0);
struct mdp_header mdp_header;
bzero(&mdp_header, sizeof mdp_header);
mdp_header.local.sid = SID_INTERNAL;
mdp_header.local.port = MDP_ROUTE_TABLE;
mdp_header.remote.sid = SID_ANY;
mdp_header.remote.port = MDP_ROUTE_TABLE;
if (opt_monitor)
mdp_header.flags = MDP_BIND;
int ret=-1;
if (mdp_send(mdp_sockfd, &mdp_header, NULL, 0))
goto end;
const char *names[]={
"Subscriber id",
"Routing flags",
@ -469,57 +479,98 @@ static int app_route_print(const struct cli_parsed *parsed, struct cli_context *
};
cli_columns(context, 5, names);
size_t rowcount=0;
while(overlay_mdp_client_poll(mdp_sockfd, 200)){
overlay_mdp_frame rx;
int ttl;
if (overlay_mdp_recv(mdp_sockfd, &rx, 0, &ttl))
continue;
int ofs=0;
while(ofs + sizeof(struct overlay_route_record) <= rx.out.payload_length){
struct overlay_route_record *p=&rx.out.route_record;
ofs+=sizeof(struct overlay_route_record);
if (p->reachable==REACHABLE_NONE)
continue;
cli_put_string(context, alloca_tohex_sid_t(p->sid), ":");
char flags[32];
strbuf b = strbuf_local_buf(flags);
switch (p->reachable){
case REACHABLE_SELF:
strbuf_puts(b, "SELF");
sigIntFlag = 0;
signal(SIGINT, sigIntHandler);
uint8_t payload[MDP_MTU];
struct overlay_buffer *buff = ob_static(payload, sizeof payload);
while(!sigIntFlag){
ssize_t recv_len = mdp_poll_recv(mdp_sockfd, gettime_ms()+1000, &mdp_header, payload, sizeof payload);
if (recv_len == -1)
break;
if (recv_len>0){
ob_clear(buff);
ob_limitsize(buff, recv_len);
while(ob_remaining(buff)>0){
sid_t *sid = (sid_t *)ob_get_bytes_ptr(buff, SID_SIZE);
if (!sid)
break;
case REACHABLE_BROADCAST:
strbuf_puts(b, "BROADCAST");
int reachable = ob_get(buff);
if (reachable<0)
break;
case REACHABLE_UNICAST:
strbuf_puts(b, "UNICAST");
break;
case REACHABLE_INDIRECT:
strbuf_puts(b, "INDIRECT");
break;
default:
strbuf_sprintf(b, "%d", p->reachable);
int hop_count =-1;
sid_t *next_hop = NULL;
sid_t *prior_hop = NULL;
int interface_id =-1;
const char *interface_name = NULL;
if (reachable & REACHABLE){
hop_count = ob_get(buff);
if (hop_count<0)
break;
if (hop_count>1){
next_hop = (sid_t *)ob_get_bytes_ptr(buff, SID_SIZE);
if (!next_hop)
break;
if (hop_count>2){
prior_hop = (sid_t *)ob_get_bytes_ptr(buff, SID_SIZE);
if (!prior_hop)
break;
}
}else{
interface_id = ob_get(buff);
if (interface_id<0)
break;
interface_name = ob_get_str_ptr(buff);
if (!interface_name)
break;
}
}
cli_put_string(context, alloca_tohex_sid_t(*sid), ":");
char flags[32];
strbuf b = strbuf_local_buf(flags);
switch (reachable){
case REACHABLE_NONE:
strbuf_puts(b, "UNREACHABLE");
break;
case REACHABLE_SELF:
strbuf_puts(b, "SELF");
break;
case REACHABLE_BROADCAST:
strbuf_puts(b, "BROADCAST");
break;
case REACHABLE_UNICAST:
strbuf_puts(b, "UNICAST");
break;
case REACHABLE_INDIRECT:
strbuf_puts(b, "INDIRECT");
break;
default:
strbuf_sprintf(b, "%d", reachable);
}
cli_put_string(context, strbuf_str(b), ":");
cli_put_string(context, interface_name, ":");
cli_put_string(context, next_hop?alloca_tohex_sid_t(*next_hop):"", ":");
cli_put_string(context, prior_hop?alloca_tohex_sid_t(*prior_hop):"", "\n");
rowcount++;
}
cli_put_string(context, strbuf_str(b), ":");
cli_put_string(context, p->interface_name, ":");
if (is_sid_t_any(p->neighbour))
cli_put_string(context, "", ":");
else
cli_put_string(context, alloca_tohex_sid_t(p->neighbour), ":");
if (is_sid_t_any(p->prior_hop))
cli_put_string(context, "", "\n");
else
cli_put_string(context, alloca_tohex_sid_t(p->prior_hop), "\n");
rowcount++;
}
if (!opt_monitor && (mdp_header.flags & MDP_FLAG_CLOSE))
break;
}
overlay_mdp_client_close(mdp_sockfd);
ob_free(buff);
signal(SIGINT, SIG_DFL);
sigIntFlag = 0;
ret = 0;
cli_row_count(context, rowcount);
return 0;
end:
mdp_close(mdp_sockfd);
return ret;
}
DEFINE_CMD(app_network_scan, 0,

View File

@ -73,15 +73,8 @@ int set_reachable(struct subscriber *subscriber,
/* Pre-emptively send a sas request */
if (!subscriber->sas_valid && reachable&REACHABLE)
keyring_send_sas_request(subscriber);
// Hacky layering violation... send our identity to a directory service
if (subscriber==directory_service)
directory_registration();
if ((old_value & REACHABLE) && (!(reachable & REACHABLE)))
monitor_announce_unreachable_peer(&subscriber->sid);
if ((!(old_value & REACHABLE)) && (reachable & REACHABLE))
monitor_announce_peer(&subscriber->sid);
CALL_TRIGGER(link_change, subscriber, old_value);
return 1;
}

View File

@ -64,6 +64,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "keyring.h"
#include "socket.h"
#include "server.h"
#include "route_link.h"
uint16_t mdp_loopback_port;
@ -99,8 +100,9 @@ struct mdp_binding{
time_ms_t binding_time;
};
struct mdp_binding *mdp_bindings=NULL;
mdp_port_t next_port_binding=256;
static struct mdp_binding *mdp_bindings=NULL;
static mdp_port_t next_port_binding=256;
static struct subscriber internal[0];
static int overlay_saw_mdp_frame(
struct internal_mdp_header *header,
@ -141,6 +143,18 @@ static int free_dead_clients(){
return 0;
}
static int mdp_reply2(struct __sourceloc __whence, const struct socket_address *client, const struct mdp_header *header,
int flags, const uint8_t *payload, size_t payload_len)
{
struct mdp_header response_header;
bcopy(header, &response_header, sizeof(response_header));
response_header.flags = flags;
return mdp_send2(__WHENCE__, client, &response_header, payload, payload_len);
}
#define mdp_reply_error(A,B) mdp_reply2(__WHENCE__,(A),(B),MDP_FLAG_ERROR,NULL,0)
#define mdp_reply_ok(A,B) mdp_reply2(__WHENCE__,(A),(B),MDP_FLAG_CLOSE,NULL,0)
/* Delete all UNIX socket files in instance directory. */
void overlay_mdp_clean_socket_files()
{
@ -555,6 +569,7 @@ static int send_packet_to_client(
case 1:
{
struct mdp_header client_header;
bzero(&client_header, sizeof(client_header));
client_header.local.sid=header->destination?header->destination->sid:SID_BROADCAST;
client_header.local.port=header->destination_port;
client_header.remote.sid=header->source->sid;
@ -1041,37 +1056,60 @@ static int overlay_mdp_address_list(struct overlay_mdp_addrlist *request, struct
}
struct routing_state{
struct mdp_header *header;
struct socket_address *client;
};
static void send_route(struct subscriber *subscriber, struct socket_address *client, struct mdp_header *header)
{
uint8_t payload[MDP_MTU];
struct overlay_buffer *b = ob_static(payload, sizeof payload);
ob_limitsize(b, sizeof payload);
ob_append_bytes(b, subscriber->sid.binary, SID_SIZE);
ob_append_byte(b, subscriber->reachable);
if (subscriber->reachable & REACHABLE){
ob_append_byte(b, subscriber->hop_count);
if (subscriber->hop_count>1){
ob_append_bytes(b, subscriber->next_hop->sid.binary, SID_SIZE);
if (subscriber->hop_count>2){
ob_append_bytes(b, subscriber->prior_hop->sid.binary, SID_SIZE);
}
}else{
ob_append_byte(b, subscriber->destination->interface - overlay_interfaces);
ob_append_str(b, subscriber->destination->interface->name);
}
}
assert(!ob_overrun(b));
mdp_reply2(__WHENCE__, client, header, 0, payload, ob_position(b));
ob_free(b);
}
static int routing_table(struct subscriber *subscriber, void *context)
{
struct routing_state *state = (struct routing_state *)context;
overlay_mdp_frame reply;
bzero(&reply, sizeof(overlay_mdp_frame));
struct overlay_route_record *r=&reply.out.route_record;
reply.packetTypeAndFlags=MDP_TX;
reply.out.payload_length=sizeof(struct overlay_route_record);
r->sid = subscriber->sid;
r->reachable = subscriber->reachable;
r->hop_count = subscriber->hop_count;
if (subscriber->next_hop)
r->neighbour = subscriber->next_hop->sid;
if (subscriber->prior_hop)
r->prior_hop = subscriber->prior_hop->sid;
if (subscriber->reachable & REACHABLE_DIRECT
&& subscriber->destination
&& subscriber->destination->interface)
strcpy(r->interface_name, subscriber->destination->interface->name);
else
r->interface_name[0]=0;
overlay_mdp_reply(mdp_sock.poll.fd, state->client, &reply);
if (subscriber->reachable != REACHABLE_NONE){
struct routing_state *state = (struct routing_state *)context;
send_route(subscriber, state->client, state->header);
}
return 0;
}
static void send_route_changed(struct subscriber *subscriber, int UNUSED(prior_reachable)){
struct mdp_header header;
bzero(&header, sizeof(header));
header.local.sid = SID_INTERNAL;
header.local.port = MDP_ROUTE_TABLE;
header.remote.port = MDP_ROUTE_TABLE;
struct mdp_binding *b = mdp_bindings;
while(b){
if (b->port == MDP_ROUTE_TABLE && b->subscriber == internal){
send_route(subscriber, &b->client, &header);
}
b=b->_next;
}
}
DEFINE_TRIGGER(link_change, send_route_changed);
struct scan_state{
struct sched_ent alarm;
overlay_interface *interface;
@ -1118,18 +1156,6 @@ static void overlay_mdp_scan(struct sched_ent *alarm)
}
}
static int mdp_reply2(struct __sourceloc __whence, const struct socket_address *client, const struct mdp_header *header,
int flags, const unsigned char *payload, size_t payload_len)
{
struct mdp_header response_header;
bcopy(header, &response_header, sizeof(response_header));
response_header.flags = flags;
return mdp_send2(__WHENCE__, client, &response_header, payload, payload_len);
}
#define mdp_reply_error(A,B) mdp_reply2(__WHENCE__,(A),(B),MDP_FLAG_ERROR,NULL,0)
#define mdp_reply_ok(A,B) mdp_reply2(__WHENCE__,(A),(B),MDP_FLAG_CLOSE,NULL,0)
static int mdp_process_identity_request(struct socket_address *client, struct mdp_header *header,
struct overlay_buffer *payload)
{
@ -1382,23 +1408,30 @@ static void mdp_process_packet(struct socket_address *client, struct mdp_header
}
// find local sid
if (is_sid_t_broadcast(header->local.sid)){
// leave source NULL to indicate listening on all local SID's
// note that attempting anything else will fail
}else if (is_sid_t_any(header->local.sid)){
// leaving the sid blank indicates that we should use our main identity
internal_header.source = my_subscriber;
header->local.sid = my_subscriber->sid;
}else{
// find the matching sid from our keyring
internal_header.source = find_subscriber(header->local.sid.binary, sizeof(header->local.sid), 0);
if (!internal_header.source || internal_header.source->reachable != REACHABLE_SELF){
WHY("Subscriber is not local");
mdp_reply_error(client, header);
return;
}
int sid_type;
switch(sid_type=sid_get_special_type(&header->local.sid)){
case SID_TYPE_ANY:
// leaving the sid blank indicates that we should use our main identity
internal_header.source = my_subscriber;
header->local.sid = my_subscriber->sid;
break;
case SID_TYPE_INTERNAL:
internal_header.source = internal;
header->flags |= MDP_FLAG_REUSE;
case SID_TYPE_BROADCAST:
// leave source NULL to indicate listening on all local SID's
// note that attempting anything else will fail
break;
default:
// find the matching sid from our keyring
internal_header.source = find_subscriber(header->local.sid.binary, sizeof(header->local.sid), 0);
if (!internal_header.source || internal_header.source->reachable != REACHABLE_SELF){
WHY("Subscriber is not local");
mdp_reply_error(client, header);
return;
}
}
struct mdp_binding **pclient_binding=NULL;
struct mdp_binding *client_binding=NULL;
struct mdp_binding *conflicting_binding=NULL;
@ -1500,6 +1533,17 @@ static void mdp_process_packet(struct socket_address *client, struct mdp_header
DEBUGF(mdprequests, "Processing MDP_INTERFACE from %s", alloca_socket_address(client));
mdp_interface_packet(client, header, payload);
break;
case MDP_ROUTE_TABLE:
DEBUGF(mdprequests, "Processing MDP_ROUTING_TABLE from %s", alloca_socket_address(client));
{
struct routing_state state={
.client = client,
.header = header
};
enum_subscribers(NULL, routing_table, &state);
mdp_reply_ok(client, header);
}
break;
default:
WHYF("Unknown command port %d", header->remote.port);
mdp_reply_error(client, header);
@ -1507,6 +1551,12 @@ static void mdp_process_packet(struct socket_address *client, struct mdp_header
}
}else{
if (sid_type == SID_TYPE_INTERNAL || sid_type == SID_TYPE_BROADCAST){
WHYF("Can't send data packet from a special SID");
mdp_reply_error(client, header);
return;
}
// double check that you have a binding
if (!client_binding){
WHYF("Can't send data packet, %s:%d is not bound to %s!",
@ -1661,18 +1711,6 @@ static void overlay_mdp_poll(struct sched_ent *alarm)
mark_dead_client(&client);
return;
case MDP_ROUTING_TABLE:
DEBUGF(mdprequests, "MDP_ROUTING_TABLE from %s", alloca_socket_address(&client));
{
struct routing_state state={
.client = &client,
};
enum_subscribers(NULL, routing_table, &state);
}
return;
case MDP_GETADDRS:
DEBUGF(mdprequests, "MDP_GETADDRS from %s", alloca_socket_address(&client));
{

View File

@ -452,30 +452,12 @@ next:
DEBUGF2(overlayrouting, linkstate, "REACHABLE via self %s", alloca_tohex_sid_t(subscriber->sid));
}
if (changed){
monitor_announce_link(best_hop_count, transmitter, subscriber);
if (changed)
state->next_update = now+5;
}
RETURN(best_link);
}
static int monitor_announce(struct subscriber *subscriber, void *UNUSED(context))
{
if (subscriber->reachable & REACHABLE){
struct link_state *state = get_link_state(subscriber);
monitor_announce_link(state->hop_count, state->transmitter, subscriber);
}
return 0;
}
int link_state_announce_links(){
enum_subscribers(NULL, monitor_announce, NULL);
// announce ourselves as unreachable, mainly so that monitor clients will always get one link back
monitor_announce_link(0, NULL, my_subscriber);
return 0;
}
static int append_link_state(struct overlay_buffer *payload, char flags,
struct subscriber *transmitter, struct subscriber *receiver,
int interface, int version, int ack_sequence, uint32_t ack_mask,

View File

@ -28,7 +28,6 @@ struct overlay_frame;
struct decode_context;
struct internal_mdp_header;
int link_state_announce_links();
void link_neighbour_short_status_html(struct strbuf *b, const char *link_prefix);
void link_neighbour_status_html(struct strbuf *b, struct subscriber *neighbour);
int link_has_neighbours();
@ -45,5 +44,6 @@ void link_explained(struct subscriber *subscriber);
int link_state_legacy_ack(struct overlay_frame *frame, time_ms_t now);
DECLARE_TRIGGER(nbr_change, struct subscriber *neighbour, uint8_t found, unsigned count);
DECLARE_TRIGGER(link_change, struct subscriber *subscriber, int prior_reachable);
#endif

View File

@ -243,9 +243,6 @@ int monitor_get_fds(struct pollfd *fds,int *fdcount,int fdmax);
int monitor_setup_sockets();
int monitor_get_fds(struct pollfd *fds,int *fdcount,int fdmax);
int monitor_announce_peer(const sid_t *sidp);
int monitor_announce_unreachable_peer(const sid_t *sidp);
int monitor_announce_link(int hop_count, struct subscriber *transmitter, struct subscriber *receiver);
int monitor_tell_clients(char *msg, int msglen, int mask);
int monitor_tell_formatted(int mask, char *fmt, ...);
int monitor_client_interested(int mask);

View File

@ -41,7 +41,12 @@ typedef struct sid_binary {
unsigned char binary[SID_SIZE];
} sid_t;
#define SID_ANY ((sid_t){{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}})
#define SID_TYPE_ANY (0)
#define SID_TYPE_INTERNAL (1)
#define SID_TYPE_BROADCAST (0xFF)
#define SID_ANY ((sid_t){{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,SID_TYPE_ANY}})
#define SID_INTERNAL ((sid_t){{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,SID_TYPE_INTERNAL}})
#define SID_BROADCAST ((sid_t){{0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}})
// is the SID entirely 0xFF?
@ -57,6 +62,7 @@ int cmp_sid_t(const sid_t *a, const sid_t *b);
int str_to_sid_t(sid_t *sid, const char *hex);
int strn_to_sid_t(sid_t *sid, const char *hex, size_t hexlen);
int parse_sid_t(sid_t *sid, const char *hex, ssize_t hexlen, const char **endp);
int sid_get_special_type(const sid_t *sid);
#define alloca_tohex_sas(sas) alloca_tohex((sas), SAS_SIZE)

View File

@ -46,6 +46,8 @@ setup_StartCreateInstanceDir() {
test_StartCreateInstanceDir() {
executeOk $servald start
assert [ -d "$SERVALINSTANCE_PATH" ]
executeOk $servald stop
tfw_cat --stdout --stderr
}
doc_StartLogfile="Starting server gives no errors"