You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
250 lines
8.2 KiB
250 lines
8.2 KiB
9 years ago
|
/*
|
||
|
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
|
||
|
Copyright (c) 2013 GoPivotal, Inc. All rights reserved.
|
||
|
|
||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||
|
of this software and associated documentation files (the "Software"),
|
||
|
to deal in the Software without restriction, including without limitation
|
||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||
|
and/or sell copies of the Software, and to permit persons to whom
|
||
|
the Software is furnished to do so, subject to the following conditions:
|
||
|
|
||
|
The above copyright notice and this permission notice shall be included
|
||
|
in all copies or substantial portions of the Software.
|
||
|
|
||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||
|
IN THE SOFTWARE.
|
||
|
*/
|
||
|
|
||
|
#include "binproc.h"
|
||
|
#include "sinproc.h"
|
||
|
#include "cinproc.h"
|
||
|
#include "ins.h"
|
||
|
|
||
|
#include "../../utils/err.h"
|
||
|
#include "../../utils/cont.h"
|
||
|
#include "../../utils/fast.h"
|
||
|
#include "../../utils/alloc.h"
|
||
|
|
||
|
#define NN_BINPROC_STATE_IDLE 1
|
||
|
#define NN_BINPROC_STATE_ACTIVE 2
|
||
|
#define NN_BINPROC_STATE_STOPPING 3
|
||
|
|
||
|
#define NN_BINPROC_SRC_SINPROC 1
|
||
|
|
||
|
/* Implementation of nn_epbase interface. */
|
||
|
static void nn_binproc_stop (struct nn_epbase *self);
|
||
|
static void nn_binproc_destroy (struct nn_epbase *self);
|
||
|
static const struct nn_epbase_vfptr nn_binproc_vfptr = {
|
||
|
nn_binproc_stop,
|
||
|
nn_binproc_destroy
|
||
|
};
|
||
|
|
||
|
/* Private functions. */
|
||
|
static void nn_binproc_handler (struct nn_fsm *self, int src, int type,
|
||
|
void *srcptr);
|
||
|
static void nn_binproc_shutdown (struct nn_fsm *self, int src, int type,
|
||
|
void *srcptr);
|
||
|
static void nn_binproc_connect (struct nn_ins_item *self,
|
||
|
struct nn_ins_item *peer);
|
||
|
|
||
|
|
||
|
int nn_binproc_create (void *hint, struct nn_epbase **epbase)
|
||
|
{
|
||
|
int rc;
|
||
|
struct nn_binproc *self;
|
||
|
|
||
|
self = nn_alloc (sizeof (struct nn_binproc), "binproc");
|
||
|
alloc_assert (self);
|
||
|
|
||
|
nn_ins_item_init (&self->item, &nn_binproc_vfptr, hint);
|
||
|
nn_fsm_init_root (&self->fsm, nn_binproc_handler, nn_binproc_shutdown,
|
||
|
nn_epbase_getctx (&self->item.epbase));
|
||
|
self->state = NN_BINPROC_STATE_IDLE;
|
||
|
nn_list_init (&self->sinprocs);
|
||
|
|
||
|
/* Start the state machine. */
|
||
|
nn_fsm_start (&self->fsm);
|
||
|
|
||
|
/* Register the inproc endpoint into a global repository. */
|
||
|
rc = nn_ins_bind (&self->item, nn_binproc_connect);
|
||
|
if (nn_slow (rc < 0)) {
|
||
|
nn_list_term (&self->sinprocs);
|
||
|
|
||
|
/* TODO: Now, this is ugly! We are getting the state machine into
|
||
|
the idle state manually. How should it be done correctly? */
|
||
|
self->fsm.state = 1;
|
||
|
nn_fsm_term (&self->fsm);
|
||
|
|
||
|
nn_ins_item_term (&self->item);
|
||
|
nn_free (self);
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
*epbase = &self->item.epbase;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static void nn_binproc_stop (struct nn_epbase *self)
|
||
|
{
|
||
|
struct nn_binproc *binproc;
|
||
|
|
||
|
binproc = nn_cont (self, struct nn_binproc, item.epbase);
|
||
|
|
||
|
nn_fsm_stop (&binproc->fsm);
|
||
|
}
|
||
|
|
||
|
static void nn_binproc_destroy (struct nn_epbase *self)
|
||
|
{
|
||
|
struct nn_binproc *binproc;
|
||
|
|
||
|
binproc = nn_cont (self, struct nn_binproc, item.epbase);
|
||
|
|
||
|
nn_list_term (&binproc->sinprocs);
|
||
|
nn_fsm_term (&binproc->fsm);
|
||
|
nn_ins_item_term (&binproc->item);
|
||
|
|
||
|
nn_free (binproc);
|
||
|
}
|
||
|
|
||
|
static void nn_binproc_connect (struct nn_ins_item *self,
|
||
|
struct nn_ins_item *peer)
|
||
|
{
|
||
|
struct nn_binproc *binproc;
|
||
|
struct nn_cinproc *cinproc;
|
||
|
struct nn_sinproc *sinproc;
|
||
|
|
||
|
binproc = nn_cont (self, struct nn_binproc, item);
|
||
|
cinproc = nn_cont (peer, struct nn_cinproc, item);
|
||
|
|
||
|
nn_assert_state (binproc, NN_BINPROC_STATE_ACTIVE);
|
||
|
|
||
|
sinproc = nn_alloc (sizeof (struct nn_sinproc), "sinproc");
|
||
|
alloc_assert (sinproc);
|
||
|
nn_sinproc_init (sinproc, NN_BINPROC_SRC_SINPROC,
|
||
|
&binproc->item.epbase, &binproc->fsm);
|
||
|
nn_list_insert (&binproc->sinprocs, &sinproc->item,
|
||
|
nn_list_end (&binproc->sinprocs));
|
||
|
nn_sinproc_connect (sinproc, &cinproc->fsm);
|
||
|
|
||
|
nn_epbase_stat_increment (&binproc->item.epbase,
|
||
|
NN_STAT_ACCEPTED_CONNECTIONS, 1);
|
||
|
}
|
||
|
|
||
|
static void nn_binproc_shutdown (struct nn_fsm *self, int src, int type,
|
||
|
void *srcptr)
|
||
|
{
|
||
|
struct nn_binproc *binproc;
|
||
|
struct nn_list_item *it;
|
||
|
struct nn_sinproc *sinproc;
|
||
|
|
||
|
binproc = nn_cont (self, struct nn_binproc, fsm);
|
||
|
|
||
|
if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) {
|
||
|
|
||
|
/* First, unregister the endpoint from the global repository of inproc
|
||
|
endpoints. This way, new connections cannot be created anymore. */
|
||
|
nn_ins_unbind (&binproc->item);
|
||
|
|
||
|
/* Stop the existing connections. */
|
||
|
for (it = nn_list_begin (&binproc->sinprocs);
|
||
|
it != nn_list_end (&binproc->sinprocs);
|
||
|
it = nn_list_next (&binproc->sinprocs, it)) {
|
||
|
sinproc = nn_cont (it, struct nn_sinproc, item);
|
||
|
nn_sinproc_stop (sinproc);
|
||
|
}
|
||
|
|
||
|
binproc->state = NN_BINPROC_STATE_STOPPING;
|
||
|
goto finish;
|
||
|
}
|
||
|
if (nn_slow (binproc->state == NN_BINPROC_STATE_STOPPING)) {
|
||
|
nn_assert (src == NN_BINPROC_SRC_SINPROC && type == NN_SINPROC_STOPPED);
|
||
|
sinproc = (struct nn_sinproc*) srcptr;
|
||
|
nn_list_erase (&binproc->sinprocs, &sinproc->item);
|
||
|
nn_sinproc_term (sinproc);
|
||
|
nn_free (sinproc);
|
||
|
finish:
|
||
|
if (!nn_list_empty (&binproc->sinprocs))
|
||
|
return;
|
||
|
binproc->state = NN_BINPROC_STATE_IDLE;
|
||
|
nn_fsm_stopped_noevent (&binproc->fsm);
|
||
|
nn_epbase_stopped (&binproc->item.epbase);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
nn_fsm_bad_state(binproc->state, src, type);
|
||
|
}
|
||
|
|
||
|
static void nn_binproc_handler (struct nn_fsm *self, int src, int type,
|
||
|
void *srcptr)
|
||
|
{
|
||
|
struct nn_binproc *binproc;
|
||
|
struct nn_sinproc *peer;
|
||
|
struct nn_sinproc *sinproc;
|
||
|
|
||
|
binproc = nn_cont (self, struct nn_binproc, fsm);
|
||
|
|
||
|
switch (binproc->state) {
|
||
|
|
||
|
/******************************************************************************/
|
||
|
/* IDLE state. */
|
||
|
/******************************************************************************/
|
||
|
case NN_BINPROC_STATE_IDLE:
|
||
|
switch (src) {
|
||
|
|
||
|
case NN_FSM_ACTION:
|
||
|
switch (type) {
|
||
|
case NN_FSM_START:
|
||
|
binproc->state = NN_BINPROC_STATE_ACTIVE;
|
||
|
return;
|
||
|
default:
|
||
|
nn_fsm_bad_action (binproc->state, src, type);
|
||
|
}
|
||
|
|
||
|
default:
|
||
|
nn_fsm_bad_source (binproc->state, src, type);
|
||
|
}
|
||
|
|
||
|
/******************************************************************************/
|
||
|
/* ACTIVE state. */
|
||
|
/******************************************************************************/
|
||
|
case NN_BINPROC_STATE_ACTIVE:
|
||
|
switch (src) {
|
||
|
|
||
|
case NN_SINPROC_SRC_PEER:
|
||
|
switch (type) {
|
||
|
case NN_SINPROC_CONNECT:
|
||
|
peer = (struct nn_sinproc*) srcptr;
|
||
|
sinproc = nn_alloc (sizeof (struct nn_sinproc), "sinproc");
|
||
|
alloc_assert (sinproc);
|
||
|
nn_sinproc_init (sinproc, NN_BINPROC_SRC_SINPROC,
|
||
|
&binproc->item.epbase, &binproc->fsm);
|
||
|
nn_list_insert (&binproc->sinprocs, &sinproc->item,
|
||
|
nn_list_end (&binproc->sinprocs));
|
||
|
nn_sinproc_accept (sinproc, peer);
|
||
|
return;
|
||
|
default:
|
||
|
nn_fsm_bad_action (binproc->state, src, type);
|
||
|
}
|
||
|
|
||
|
case NN_BINPROC_SRC_SINPROC:
|
||
|
return;
|
||
|
|
||
|
default:
|
||
|
nn_fsm_bad_source (binproc->state, src, type);
|
||
|
}
|
||
|
|
||
|
/******************************************************************************/
|
||
|
/* Invalid state. */
|
||
|
/******************************************************************************/
|
||
|
default:
|
||
|
nn_fsm_bad_state (binproc->state, src, type);
|
||
|
}
|
||
|
}
|
||
|
|