static int sp_inproc_ctx_connect (const char *addr, void *hint, struct sp_epbase **epbase) { int rc; struct sp_list_item *it; struct sp_inprocc *inprocc; struct sp_inprocb *inprocb; struct sp_msgpipe *pipe; /* Insert the entry into the endpoint repository. */ inprocc = sp_alloc (sizeof (struct sp_inprocc), "inprocc"); alloc_assert (inprocc); rc = sp_inprocc_init (inprocc, addr, hint); if (sp_slow (rc != 0)) return rc; sp_list_insert (&self.connected, &inprocc->list, sp_list_end (&self.connected)); /* During this process a pipe may be created. */ for (it = sp_list_begin (&self.bound); it != sp_list_end (&self.bound); it = sp_list_next (&self.bound, it)) { inprocb = sp_cont (it, struct sp_inprocb, list); if (strcmp (addr, inprocb->addr) == 0) { pipe = sp_alloc (sizeof (struct sp_msgpipe), "msgpipe"); alloc_assert (pipe); sp_msgpipe_init (pipe, inprocb, inprocc); break; } } sp_assert (epbase); *epbase = &inprocc->epbase; return 0; }
void sp_stream_init (struct sp_stream *self, struct sp_epbase *epbase, struct sp_usock *usock) { int rc; /* Redirect the underlying socket's events to this state machine. */ self->usock = usock; self->sink = &sp_stream_state_start; self->original_sink = sp_usock_setsink (usock, &self->sink); /* Initialise the pipe to communicate with the user. */ /* TODO: Socket type may reject the pipe. What then? */ rc = sp_pipebase_init (&self->pipebase, &sp_stream_pipebase_vfptr, epbase); sp_assert (rc == 0); /* Start the header timeout timer. */ sp_timer_init (&self->hdr_timeout, &self->sink, usock->cp); sp_timer_start (&self->hdr_timeout, 1000); /* Send the protocol header. */ sp_usock_send (usock, "\0\0SP\0\0\0\0", 8); /* Receive the protocol header from the peer. */ sp_usock_recv (usock, self->hdr, 8); }
static void sp_stream_received (const struct sp_cp_sink **self, struct sp_usock *usock) { int rc; struct sp_stream *stream; uint64_t size; stream = sp_cont (self, struct sp_stream, sink); switch (stream->instate) { case SP_STREAM_INSTATE_HDR: size = sp_getll (stream->inhdr); rc = sp_msgref_init (&stream->inmsg, (size_t) size); errnum_assert (rc == 0, -rc); if (!size) { sp_pipebase_received (&stream->pipebase); break; } stream->instate = SP_STREAM_INSTATE_BODY; sp_usock_recv (stream->usock, sp_msgref_data (&stream->inmsg), (size_t) size); break; case SP_STREAM_INSTATE_BODY: sp_pipebase_received (&stream->pipebase); break; default: sp_assert (0); } }
int sp_pipe_recv (struct sp_pipe *self, void *buf, size_t *len) { struct sp_pipebase *pipebase; pipebase = (struct sp_pipebase*) self; sp_assert (pipebase->instate == SP_PIPEBASE_INSTATE_IDLE); pipebase->instate = SP_PIPEBASE_INSTATE_RECEIVING; pipebase->vfptr->recv (pipebase, buf, len); if (sp_fast (pipebase->instate == SP_PIPEBASE_INSTATE_RECEIVED)) { pipebase->instate = SP_PIPEBASE_INSTATE_IDLE; return 0; } sp_assert (pipebase->instate == SP_PIPEBASE_INSTATE_RECEIVING); pipebase->instate = SP_PIPEBASE_INSTATE_ASYNC; return SP_PIPEBASE_RELEASE; }
int sp_pipe_send (struct sp_pipe *self, const void *buf, size_t len) { struct sp_pipebase *pipebase; pipebase = (struct sp_pipebase*) self; sp_assert (pipebase->outstate == SP_PIPEBASE_OUTSTATE_IDLE); pipebase->outstate = SP_PIPEBASE_OUTSTATE_SENDING; pipebase->vfptr->send (pipebase, buf, len); if (sp_fast (pipebase->outstate == SP_PIPEBASE_OUTSTATE_SENT)) { pipebase->outstate = SP_PIPEBASE_OUTSTATE_IDLE; return 0; } sp_assert (pipebase->outstate == SP_PIPEBASE_OUTSTATE_SENDING); pipebase->outstate = SP_PIPEBASE_OUTSTATE_ASYNC; return SP_PIPEBASE_RELEASE; }
void spec_string_with_escaped_quotes(void) { const char *json_string = "[\"The Word \\\"Foo\\\" is so damn bar!\"]"; struct jzon *jzon = jzon_parse(json_string); sp_assert(jzon != NULL); jzon_free(jzon); }
int sp_pipebase_init (struct sp_pipebase *self, const struct sp_pipebase_vfptr *vfptr, struct sp_epbase *epbase) { sp_assert (epbase->sock); self->vfptr = vfptr; self->instate = SP_PIPEBASE_INSTATE_DEACTIVATED; self->outstate = SP_PIPEBASE_OUTSTATE_DEACTIVATED; self->epbase = epbase; return sp_sock_add (self->epbase->sock, (struct sp_pipe*) self); }
void sp_pipebase_received (struct sp_pipebase *self) { if (sp_fast (self->instate == SP_PIPEBASE_INSTATE_RECEIVING)) { self->instate = SP_PIPEBASE_INSTATE_RECEIVED; return; } sp_assert (self->instate == SP_PIPEBASE_INSTATE_ASYNC); self->instate = SP_PIPEBASE_INSTATE_IDLE; if (self->epbase->sock) sp_sock_in (self->epbase->sock, (struct sp_pipe*) self); }
void sp_pipebase_sent (struct sp_pipebase *self) { if (sp_fast (self->outstate == SP_PIPEBASE_OUTSTATE_SENDING)) { self->outstate = SP_PIPEBASE_OUTSTATE_SENT; return; } sp_assert (self->outstate == SP_PIPEBASE_OUTSTATE_ASYNC); self->outstate = SP_PIPEBASE_OUTSTATE_IDLE; if (self->epbase->sock) sp_sock_out (self->epbase->sock, (struct sp_pipe*) self); }
void worker (void *arg) { int rc; int s; char buf [3]; s = sp_socket (AF_SP, SP_PAIR); errno_assert (s != -1); rc = sp_recv (s, buf, sizeof (buf), 0); sp_assert (rc == -1 && sp_errno () == ETERM); rc = sp_close (s); errno_assert (rc == 0); }
int sp_term (void) { #if defined SP_HAVE_WINDOWS int rc; #endif int i; sp_glock_lock (); /* If there are still references to the library, do nothing, just decrement the reference count. */ --sp_ctx_refcount; if (sp_ctx_refcount) { sp_glock_unlock (); return 0; } /* Notify all the open sockets about the process shutdown and wait till all of them are closed. */ sp_mutex_lock (&self.sync); if (self.nsocks) { for (i = 0; i != self.max_socks; ++i) if (self.socks [i]) sp_sock_zombify (self.socks [i]); self.zombie = 1; sp_cond_wait (&self.termcond, &self.sync); } sp_mutex_unlock (&self.sync); /* Final deallocation of the global resources. */ sp_cond_term (&self.termcond); sp_list_term (&self.socktypes); sp_list_term (&self.transports); sp_mutex_term (&self.sync); sp_free (self.socks); self.socks = NULL; /* Shut down the memory allocation subsystem. */ sp_alloc_term (); /* On Windows, uninitialise the socket library. */ #if defined SP_HAVE_WINDOWS rc = WSACleanup (); sp_assert (rc == 0); #endif sp_glock_unlock (); return 0; }
int sp_shutdown (int s, int how) { int rc; SP_BASIC_CHECKS; rc = sp_sock_shutdown (self.socks [s], how); if (sp_slow (rc < 0)) { errno = -rc; return -1; } sp_assert (rc == 0); return 0; }
static void sp_stream_err (const struct sp_cp_sink **self, struct sp_usock *usock, int errnum) { struct sp_stream *stream; const struct sp_cp_sink **original_sink; stream = sp_cont (self, struct sp_stream, sink); original_sink = stream->original_sink; /* Terminate the session object. */ sp_stream_term (stream); /* Notify the parent state machine about the failure. */ sp_assert ((*original_sink)->err); (*original_sink)->err (original_sink, usock, errnum); }
static void sp_stream_hdr_timeout (const struct sp_cp_sink **self, struct sp_timer *timer) { struct sp_stream *stream; const struct sp_cp_sink **original_sink; /* The initial protocol header exchange have timed out. */ stream = sp_cont (self, struct sp_stream, sink); original_sink = stream->original_sink; /* Terminate the session object. */ sp_stream_term (stream); /* Notify the parent state machine about the failure. */ sp_assert ((*original_sink)->err); (*original_sink)->err (original_sink, stream->usock, ETIMEDOUT); }
static void sp_stream_activate (struct sp_stream *self) { self->sink = &sp_stream_state_active; sp_timer_stop (&self->hdr_timeout); /* Check the header. */ /* TODO: If it does not conform, drop the connection. */ if (memcmp (self->hdr, "\0\0SP\0\0\0\0", 8) != 0) sp_assert (0); /* Connection is ready for sending. Make outpipe available to the SP socket. */ sp_pipebase_activate (&self->pipebase); /* Start waiting for incoming messages. First, read the 8-byte size. */ self->instate = SP_STREAM_INSTATE_HDR; sp_usock_recv (self->usock, self->inhdr, 8); }
void spec_simple_array(void) { struct jzon *jzon = jzon_parse("[1, 2, 3]"); sp_assert(jzon != NULL); sp_assert(jzon->type == JZON_ARRAY); sp_assert(jzon->array != NULL); sp_assert_equal_i(jzon->array->capacity, 3); sp_assert(jzon_get_number(jzon->array->elements[0]) == 1.0); sp_assert(jzon_get_number(jzon->array->elements[1]) == 2.0); sp_assert(jzon_get_number(jzon->array->elements[2]) == 3.0); jzon_free(jzon); }
static int sp_inproc_ctx_bind (const char *addr, void *hint, struct sp_epbase **epbase) { int rc; struct sp_list_item *it; struct sp_inprocb *inprocb; struct sp_inprocc *inprocc; struct sp_msgpipe *pipe; /* Check whether the endpoint isn't already bound. */ /* TODO: This is an O(n) algorithm! */ for (it = sp_list_begin (&self.bound); it != sp_list_end (&self.bound); it = sp_list_next (&self.bound, it)) { inprocb = sp_cont (it, struct sp_inprocb, list); if (strncmp (addr, inprocb->addr, SP_INPROCB_NAMELEN_MAX) == 0) return -EADDRINUSE; } /* Insert the entry into the endpoint repository. */ inprocb = sp_alloc (sizeof (struct sp_inprocb), "inprocb"); alloc_assert (inprocb); rc = sp_inprocb_init (inprocb, addr, hint); if (sp_slow (rc != 0)) return rc; sp_list_insert (&self.bound, &inprocb->list, sp_list_end (&self.bound)); /* During this process new pipes may be created. */ for (it = sp_list_begin (&self.connected); it != sp_list_end (&self.connected); it = sp_list_next (&self.connected, it)) { inprocc = sp_cont (it, struct sp_inprocc, list); if (strncmp (addr, inprocc->addr, SP_INPROCC_NAMELEN_MAX) == 0) { pipe = sp_alloc (sizeof (struct sp_msgpipe), "msgpipe"); alloc_assert (pipe); sp_msgpipe_init (pipe, inprocb, inprocc); } } sp_assert (epbase); *epbase = &inprocb->epbase; return 0; }
int sp_recv (int s, void *buf, size_t len, int flags) { int rc; SP_BASIC_CHECKS; if (sp_slow (!buf && len)) { errno = EFAULT; return -1; } rc = sp_sock_recv (self.socks [s], buf, &len, flags); if (sp_slow (rc < 0)) { errno = -rc; return -1; } sp_assert (rc == 0); return (int) len; }
static void sp_stream_hdr_sent (const struct sp_cp_sink **self, struct sp_usock *usock) { struct sp_stream *stream; stream = sp_cont (self, struct sp_stream, sink); if (stream->sink == &sp_stream_state_received) { sp_stream_activate (stream); return; } if (stream->sink == &sp_stream_state_start) { stream->sink = &sp_stream_state_sent; return; } /* This event is not defined in other states. */ sp_assert (0); }
void sp_epbase_init (struct sp_epbase *self, const struct sp_epbase_vfptr *vfptr, const char *addr, void *hint) { /* Set up the virtual functions table. */ self->vfptr = vfptr; /* Remember which socket the endpoint belongs to. */ self->sock = (struct sp_sock*) hint; /* Store the textual for of the address. */ sp_assert (strlen (addr) <= SP_SOCKADDR_MAX); #if defined _MSC_VER #pragma warning (push) #pragma warning (disable:4996) #endif strcpy (self->addr, addr); #if defined _MSC_VER #pragma warning (pop) #endif }
static void sp_stream_sent (const struct sp_cp_sink **self, struct sp_usock *usock) { struct sp_stream *stream; size_t size; stream = sp_cont (self, struct sp_stream, sink); switch (stream->outstate) { case SP_STREAM_OUTSTATE_HDR: size = sp_msgref_size (&stream->outmsg); stream->outstate = SP_STREAM_OUTSTATE_BODY; if (!size) { sp_pipebase_sent (&stream->pipebase); break; } sp_usock_send (stream->usock, sp_msgref_data (&stream->outmsg), size); break; case SP_STREAM_OUTSTATE_BODY: sp_pipebase_sent (&stream->pipebase); break; default: sp_assert (0); } }
void sp_msgqueue_term (struct sp_msgqueue *self) { int rc; size_t sz; /* Deallocate messages in the pipe. */ while (1) { sz = 0; rc = sp_msgqueue_recv (self, NULL, &sz); if (rc == -EAGAIN) break; } /* There are no more messages in the pipe so there's at most one chunk in the queue. Deallocate it. */ sp_assert (self->in.chunk == self->out.chunk); sp_free (self->in.chunk); /* Deallocate the cached chunk, if any. */ if (self->cache) sp_free (self->cache); sp_mutex_term (&self->sync); }
int main () { int rc; int rep; int req1; int req2; int resend_ivl; char buf [7]; /* Test req/rep with raw socket types. */ rc = sp_init (); errno_assert (rc == 0); rep = sp_socket (AF_SP_RAW, SP_REP); errno_assert (rep != -1); rc = sp_bind (rep, "inproc://a"); errno_assert (rc >= 0); req1 = sp_socket (AF_SP_RAW, SP_REQ); errno_assert (req1 != -1); rc = sp_connect (req1, "inproc://a"); errno_assert (rc >= 0); req2 = sp_socket (AF_SP_RAW, SP_REQ); errno_assert (req2 != -1); rc = sp_connect (req2, "inproc://a"); errno_assert (rc >= 0); rc = sp_send (req2, "ABC", 3, 0); errno_assert (rc >= 0); sp_assert (rc == 3); rc = sp_recv (rep, buf, sizeof (buf), 0); errno_assert (rc >= 0); sp_assert (rc == 7); rc = sp_send (rep, buf, 7, 0); errno_assert (rc >= 0); sp_assert (rc == 7); rc = sp_recv (req2, buf, sizeof (buf), 0); errno_assert (rc >= 0); sp_assert (rc == 3); rc = sp_send (req1, "ABC", 3, 0); errno_assert (rc >= 0); sp_assert (rc == 3); rc = sp_recv (rep, buf, sizeof (buf), 0); errno_assert (rc >= 0); sp_assert (rc == 7); rc = sp_send (rep, buf, 7, 0); errno_assert (rc >= 0); sp_assert (rc == 7); rc = sp_recv (req1, buf, sizeof (buf), 0); errno_assert (rc >= 0); sp_assert (rc == 3); rc = sp_close (rep); errno_assert (rc == 0); rc = sp_close (req1); errno_assert (rc == 0); rc = sp_close (req2); errno_assert (rc == 0); rc = sp_term (); errno_assert (rc == 0); /* Test req/rep with full socket types. */ rc = sp_init (); errno_assert (rc == 0); rep = sp_socket (AF_SP, SP_REP); errno_assert (rep != -1); rc = sp_bind (rep, "inproc://a"); errno_assert (rc >= 0); req1 = sp_socket (AF_SP, SP_REQ); errno_assert (req1 != -1); rc = sp_connect (req1, "inproc://a"); errno_assert (rc >= 0); req2 = sp_socket (AF_SP, SP_REQ); errno_assert (req2 != -1); rc = sp_connect (req2, "inproc://a"); errno_assert (rc >= 0); rc = sp_send (rep, "ABC", 3, 0); sp_assert (rc == -1 && sp_errno () == EFSM); rc = sp_recv (req1, buf, sizeof (buf), 0); sp_assert (rc == -1 && sp_errno () == EFSM); rc = sp_send (req2, "ABC", 3, 0); errno_assert (rc >= 0); sp_assert (rc == 3); rc = sp_recv (rep, buf, sizeof (buf), 0); errno_assert (rc >= 0); sp_assert (rc == 3); rc = sp_send (rep, buf, 3, 0); errno_assert (rc >= 0); sp_assert (rc == 3); rc = sp_recv (req2, buf, sizeof (buf), 0); errno_assert (rc >= 0); sp_assert (rc == 3); rc = sp_send (req1, "ABC", 3, 0); errno_assert (rc >= 0); sp_assert (rc == 3); rc = sp_recv (rep, buf, sizeof (buf), 0); errno_assert (rc >= 0); sp_assert (rc == 3); rc = sp_send (rep, buf, 3, 0); errno_assert (rc >= 0); sp_assert (rc == 3); rc = sp_recv (req1, buf, sizeof (buf), 0); errno_assert (rc >= 0); sp_assert (rc == 3); rc = sp_close (rep); errno_assert (rc == 0); rc = sp_close (req1); errno_assert (rc == 0); rc = sp_close (req2); errno_assert (rc == 0); rc = sp_term (); errno_assert (rc == 0); /* Test re-sending of the request. */ rc = sp_init (); errno_assert (rc == 0); rep = sp_socket (AF_SP, SP_REP); errno_assert (rep != -1); rc = sp_bind (rep, "inproc://a"); errno_assert (rc >= 0); req1 = sp_socket (AF_SP, SP_REQ); errno_assert (req1 != -1); rc = sp_connect (req1, "inproc://a"); errno_assert (rc >= 0); resend_ivl = 100; rc = sp_setsockopt (req1, SP_REQ, SP_RESEND_IVL, &resend_ivl, sizeof (resend_ivl)); errno_assert (rc == 0); rc = sp_send (req1, "ABC", 3, 0); errno_assert (rc >= 0); sp_assert (rc == 3); rc = sp_recv (rep, buf, sizeof (buf), 0); errno_assert (rc >= 0); sp_assert (rc == 3); rc = sp_recv (rep, buf, sizeof (buf), 0); errno_assert (rc >= 0); sp_assert (rc == 3); rc = sp_close (req1); errno_assert (rc == 0); rc = sp_close (rep); errno_assert (rc == 0); rc = sp_term (); errno_assert (rc == 0); return 0; }
void spec_sample_one(void) { sp_assert(42); sp_assert_equal_i(23, 23); }
int sp_freemsg (void *msg) { sp_assert (0); }
int sp_sock_setopt (struct sp_sock *self, int level, int option, const void *optval, size_t optvallen) { int rc; struct sp_sockbase *sockbase; int *dst; sockbase = (struct sp_sockbase*) self; sp_cp_lock (&sockbase->cp); /* If sp_term() was already called, return ETERM. */ if (sp_slow (sockbase->flags & SP_SOCK_FLAG_ZOMBIE)) { sp_cp_unlock (&sockbase->cp); return -ETERM; } /* Generic socket-level options. */ if (level == SP_SOL_SOCKET) { switch (option) { case SP_LINGER: dst = &sockbase->linger; break; case SP_SNDBUF: dst = &sockbase->sndbuf; break; case SP_RCVBUF: dst = &sockbase->rcvbuf; break; case SP_SNDTIMEO: dst = &sockbase->sndtimeo; break; case SP_RCVTIMEO: dst = &sockbase->rcvtimeo; break; case SP_RECONNECT_IVL: dst = &sockbase->reconnect_ivl; break; case SP_RECONNECT_IVL_MAX: dst = &sockbase->reconnect_ivl_max; break; default: sp_cp_unlock (&sockbase->cp); return -ENOPROTOOPT; } if (optvallen != sizeof (int)) { sp_cp_unlock (&sockbase->cp); return -EINVAL; } *dst = *(int*) optval; sp_cp_unlock (&sockbase->cp); return 0; } /* Protocol-specific socket options. */ if (level > SP_SOL_SOCKET) { rc = sockbase->vfptr->setopt (sockbase, level, option, optval, optvallen); sp_cp_unlock (&sockbase->cp); return rc; } /* Transport-specific options. */ if (level < SP_SOL_SOCKET) { sp_cp_unlock (&sockbase->cp); return -ENOPROTOOPT; } sp_assert (0); }
void spec_sample_two(void) { sp_assert(23); }
int sp_sendmsg (int s, void *msg, int flags) { sp_assert (0); }
int sp_sock_getopt (struct sp_sock *self, int level, int option, void *optval, size_t *optvallen, int internal) { int rc; struct sp_sockbase *sockbase; int *src; sockbase = (struct sp_sockbase*) self; if (!internal) sp_cp_lock (&sockbase->cp); /* If sp_term() was already called, return ETERM. */ if (!internal && sp_slow (sockbase->flags & SP_SOCK_FLAG_ZOMBIE)) { sp_cp_unlock (&sockbase->cp); return -ETERM; } /* Generic socket-level options. */ if (level == SP_SOL_SOCKET) { switch (option) { case SP_LINGER: src = &sockbase->linger; break; case SP_SNDBUF: src = &sockbase->sndbuf; break; case SP_RCVBUF: src = &sockbase->rcvbuf; break; case SP_SNDTIMEO: src = &sockbase->sndtimeo; break; case SP_RCVTIMEO: src = &sockbase->rcvtimeo; break; case SP_RECONNECT_IVL: src = &sockbase->reconnect_ivl; break; case SP_RECONNECT_IVL_MAX: src = &sockbase->reconnect_ivl_max; break; default: if (!internal) sp_cp_unlock (&sockbase->cp); return -ENOPROTOOPT; } memcpy (optval, src, *optvallen < sizeof (int) ? *optvallen : sizeof (int)); *optvallen = sizeof (int); if (!internal) sp_cp_unlock (&sockbase->cp); return 0; } /* Protocol-specific socket options. */ if (level > SP_SOL_SOCKET) { rc = sockbase->vfptr->getopt (sockbase, level, option, optval, optvallen); if (!internal) sp_cp_unlock (&sockbase->cp); return rc; } /* Transport-specific options. */ if (level < SP_SOL_SOCKET) { if (!internal) sp_cp_unlock (&sockbase->cp); return -ENOPROTOOPT; } sp_assert (0); }
int sp_recvmsg (int s, void **msg, int flags) { sp_assert (0); }