text: /*
      Copyright (c) 2012-2013 250bpm s.r.o.  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.
  */
  
  #ifndef NN_TRANSPORT_INCLUDED
  #define NN_TRANSPORT_INCLUDED
  
  #include "nn.h"
  
  #include "aio/fsm.h"
  
  #include "utils/list.h"
  #include "utils/msg.h"
  
  #include <stddef.h>
  #include <stdint.h>
  
  /*  This is the API between the nanomsg core and individual transports. */
  
  struct nn_sock;
  struct nn_cp;
  
  /******************************************************************************/
  /*  Container for transport-specific socket options.                          */
  /******************************************************************************/
  
  struct nn_optset;
  
  struct nn_optset_vfptr {
      void (*destroy) (struct nn_optset *self);
      int (*setopt) (struct nn_optset *self, int option, const void *optval,
          size_t optvallen);
      int (*getopt) (struct nn_optset *self, int option, void *optval,
          size_t *optvallen);
  };
  
  struct nn_optset {
      const struct nn_optset_vfptr *vfptr;
  };
  
  /******************************************************************************/
  /*  The base class for endpoints.                                             */
  /******************************************************************************/
  
  /*  The best way to think about endpoints is that endpoint is an object created
      by each nn_bind() or nn_connect() call. Each endpoint is associated with
      exactly one address string (e.g. "tcp://127.0.0.1:5555"). */
  
  struct nn_epbase;
  
  struct nn_epbase_vfptr {
  
      /*  Ask the endpoint to stop itself. The endpoint is allowed to linger
          to send the pending outbound data. When done, it reports the fact by
          invoking nn_epbase_stopped() function. */
      void (*stop) (struct nn_epbase *self);
  
      /*  Deallocate the endpoint object. */
      void (*destroy) (struct nn_epbase *self);
  };
  
  struct nn_epbase {
      const struct nn_epbase_vfptr *vfptr;
      struct nn_ep *ep;
  };
  
  /*  Creates a new endpoint. 'hint' parameter is an opaque value that
      was passed to transport's bind or connect function. */
  void nn_epbase_init (struct nn_epbase *self,
      const struct nn_epbase_vfptr *vfptr, void *hint);
  
  /*  Notify the user that stopping is done. */
  void nn_epbase_stopped (struct nn_epbase *self);
  
  /*  Terminate the epbase object. */
  void nn_epbase_term (struct nn_epbase *self);
  
  /*  Returns the AIO context associated with the endpoint. */
  struct nn_ctx *nn_epbase_getctx (struct nn_epbase *self);
  
  /*  Returns the address string associated with this endpoint. */
  const char *nn_epbase_getaddr (struct nn_epbase *self);
  
  /*  Retrieve value of a socket option. */
  void nn_epbase_getopt (struct nn_epbase *self, int level, int option,
      void *optval, size_t *optvallen);
  
  /*  Returns 1 is the specified socket type is a valid peer for this socket,
      or 0 otherwise. */
  int nn_epbase_ispeer (struct nn_epbase *self, int socktype);
  
  /******************************************************************************/
  /*  The base class for pipes.                                                 */
  /******************************************************************************/
  
  /*  Pipe represents one "connection", i.e. perfectly ordered uni- or
      bi-directional stream of messages. One endpoint can create multiple pipes
      (for example, bound TCP socket is an endpoint, individual accepted TCP
      connections are represented by pipes. */
  
  struct nn_pipebase;
  
  /*  This value is returned by pipe's send and recv functions to signalise that
      more sends/recvs are not possible at the moment. From that moment on,
      the core will stop invoking the function. To re-establish the message
      flow nn_pipebase_received (respectively nn_pipebase_sent) should
      be called. */
  #define NN_PIPEBASE_RELEASE 1
  
  /*  Specifies that received message is already split into header and body.
      This flag is used only by inproc transport to avoid merging and re-splitting
      the messages passed with a single process. */
  #define NN_PIPEBASE_PARSED 2
  
  struct nn_pipebase_vfptr {
  
      /*  Send a message to the network. The function can return either error
          (negative number) or any combination of the flags defined above. */
      int (*send) (struct nn_pipebase *self, struct nn_msg *msg);
  
      /*  Receive a message from the network. The function can return either error
          (negative number) or any combination of the flags defined above. */
      int (*recv) (struct nn_pipebase *self, struct nn_msg *msg);
  };
  
  /*  The member of this structure are used internally by the core. Never use
      or modify them directly from the transport. */
  struct nn_pipebase {
      struct nn_fsm fsm;
      const struct nn_pipebase_vfptr *vfptr;
      uint8_t state;
      uint8_t instate;
      uint8_t outstate;
      struct nn_sock *sock;
      void *data;
      struct nn_fsm_event in;
      struct nn_fsm_event out;
  };
  
  /*  Initialise the pipe.  */
  void nn_pipebase_init (struct nn_pipebase *self,
      const struct nn_pipebase_vfptr *vfptr, struct nn_epbase *epbase);
  
  /*  Terminate the pipe. */
  void nn_pipebase_term (struct nn_pipebase *self);
  
  /*  Call this function once the connection is established. */
  int nn_pipebase_start (struct nn_pipebase *self);
  
  /*  Call this function once the connection is broken. */
  void nn_pipebase_stop (struct nn_pipebase *self);
  
  /*  Call this function when new message was fully received. */
  void nn_pipebase_received (struct nn_pipebase *self);
  
  /*  Call this function when current outgoing message was fully sent. */
  void nn_pipebase_sent (struct nn_pipebase *self);
  
  /*  Retrieve value of a socket option. */
  void nn_pipebase_getopt (struct nn_pipebase *self, int level, int option,
      void *optval, size_t *optvallen);
  
  /*  Returns 1 is the specified socket type is a valid peer for this socket,
      or 0 otherwise. */
  int nn_pipebase_ispeer (struct nn_pipebase *self, int socktype);
  
  /******************************************************************************/
  /*  The transport class.                                                      */
  /******************************************************************************/
  
  /*
   * 协议结构体, 包括一些协议的操作接口
   */
  struct nn_transport {
  
      /*  Name of the transport as it appears in the connection strings ("tcp",
          "ipc", "inproc" etc. */
      const char *name;
  
      /*  ID of the transport. */
      int id;
  
      /*  Following methods are guarded by a global critical section. Two of these
          function will never be invoked in parallel. The first is called when
          the library is initialised, the second one when it is terminated, i.e.
          when there are no more open sockets. Either of them can be set to NULL
          if no specific initialisation/termination is needed. */
      void (*init) (void);
      void (*term) (void);
  
      /*  Each of these functions creates an endpoint and returns the newly
          created endpoint in 'epbase' parameter. 'hint' is in opaque pointer
          to be passed to nn_epbase_init(). The epbase object can then be used
          to retrieve the address to bind/connect to. These functions are guarded
          by a socket-wide critical section. Two of these function will never be
          invoked in parallel on the same socket. */
      int (*bind) (void *hint, struct nn_epbase **epbase);
      int (*connect) (void *hint, struct nn_epbase **epbase);
  
      /*  Create an object to hold transport-specific socket options.
          Set this member to NULL in case there are no transport-specific
          socket options available. */
      struct nn_optset *(*optset) (void);
  
      /*  This member is used exclusively by the core. Never touch it directly
          from the transport. */
      struct nn_list_item item;
  };
  
  #endif
  