You are viewing a plain text version of this content. The canonical link for it is here.
Posted to proton@qpid.apache.org by Michael Goulish <mg...@redhat.com> on 2013/09/30 19:46:43 UTC

[doc] I will check these in on Friday the 4th...



I will check this stuff in this coming Friday, 4 Oct,
( at midnight, in the last timezone on Earth...)
if I don't hear any objections / suggestions,
so please take a look before then if you would like to
provide feedback.



These are expanded descriptions that I'd like to add to the C API
documentation.  ( These are the descriptions only -- where the
current info already explains the parameters and returns values
I will just leave those in place. )


These are the only ones I plan to change at this time.




Please take a look to see

  1. whether the description matches your understanding
     of what the functions do, and how they fit together.


  2. whether you, as a developer using this code, would
     find the description useful, sufficient, understandable,
     etc.


Question 2 is still very valuable even if you have no
idea about Question 1.



This is not yet a complete list.  Some of the functions are
clear already, and some I have no clue about as yet.



Here they are:




pn_messenger_accept
{
  Signal the sender that you have received and have acted on the message
  pointed to by the tracker.  If the PN_CUMULATIVE flag is set, all
  messages prior to the tracker will also be accepted, back to the
  beginning of your incoming window.
}



pn_messenger_errno
{
  Return the code for the most recent error.
  Initialized to zero at messenger creation.
  Error numbers are "sticky" i.e. are not reset to 0
  at the end of successful API calls.

  (NOTE! This is the only description that is intentionally false.
   There *is* one API call that resets errno to 0 -- but I think
   it shouldn't, and I will complain about it Real Soon Now.)
}



pn_messenger_error
{
  Return a text description of the most recent error.
  Initialized to null at messenger creation.
  Error text is "sticky" i.e. not reset to null
  at the end of successful API calls.
}



pn_messenger_get
{
  Pop the oldest message off your incoming message queue,
  and copy it into the given message structure.
  If the given pointer to a message structure in NULL,
  the popped message is discarded.
  Returns PN_EOS if there are no messages to get.
  Returns an error code only if there is a problem in
  decoding the message.
}




pn_messenger_get_certificate
{
  Return the certificate path if one has been set,
  by pn_messenger_set_certificate, or null.
}



pn_messenger_get_incoming_window
{
  Returns the size of the incoming window that was
  set with pn_messenger_set_incoming_window.  The
  default is 0.
}


pn_messenger_get_outgoing_window
{
  Returns the size of the incoming window that was
  set with pn_messenger_set_incoming_window.  The
  default is 0.
}



pn_messenger_incoming_subscription
{
  Returns a pointer to the subscription of the message returned by the
  most recent call to pn_messenger_get(), or NULL if pn_messenger_get()
  has never been called.
}



pn_messenger_incoming_tracker
{
  Returns a tracker for the message most recently fetched by
  pn_messenger_get().  The tracker allows you to accept or reject its
  message, or its message plus all prior messages that are still within
  your incoming window.
}



pn_messenger_interrupt
{
  Call this from a non-messenger thread to interrupt
  a messenger that is blocking.
  Return value:  0 if all is well, or -1.
  If -1 is returned, that is not PN_EOS.  It is the return
  value of the system call write(3), and can be printed with
  perror(3).
}



pn_messenger_is_blocking
{
  Accessor for messenger blocking mode.
  Note: this tells you only whether the messenger is in
  blocking mode.  This will not tell you (if called from
  a separate thread) that a messenger is currently blocking
}




pn_messenger_outgoing_tracker
{
  Returns a tracker for the outgoing message most recently given
  to pn_messenger_put.  Use this tracker with pn_messenger_status
  to determine the delivery status of the message, as long as the
  message is still within your outgoing window.
}



pn_messenger_put
{
  Puts the message onto the messenger's outgoing queue.
  The message may also be sent if transmission would not cause
  blocking.  This call will not block.
}



pn_messenger_receiving
{
  Returns the number of messages that
  was requested by the most recent call
  to pn_messenger_recv.
}


pn_messenger_recv
{
  ( add this text to current description )
  After receiving messages onto your incoming queue,
  use pn_messenger_get to bring messages into your application code.
}



pn_messenger_reject
{
  Rejects the message indicated by the tracker.  If the PN_CUMULATIVE
  flag is used this call will also reject all prior messages that
  have not already been settled.  The semantics of message rejection
  are application-specific.  If messages represent work requests,
  then rejection would leave the sender free to try another receiver,
  without fear of having the same task done twice.
}



pn_messenger_rewrite
{
  Similar to pn_messenger_route(), except that the destination of
  the message is determined before the message address is rewritten.
  If a message has an outgoing address of "amqp://0.0.0.0:5678", and a
  rewriting rule that changes its outgoing address to "foo", it will still
  arrive at the peer that is listening on "amqp://0.0.0.0:5678", but when
  it arrives there, its outgoing address will have been changed to "foo".
}



pn_messenger_send
{
  If blocking has been set with pn_messenger_set_blocking, this call
  will block until n messages have been sent.  A value of -1 for n means
  "all messages in the outgoing queue".

  In addition, if a nonzero size has been set for the outgoing window,
  this call will block until all messages within that window have
  been received.  Any blocking will end upon timeout, if one has been
  set by pn_messenger_timeout.

  If blocking has not been set, this call will stop transmitting
  messages when further transmission would require blocking, or when
  the outgoing queue is empty, or when n messages have been sent.
}



pn_messenger_set_blocking
{
  Enable or disable blocking behavior during calls to
  pn_messenger_send and pn_messenger_recv.
}




pn_messenger_set_certificate
{
  Sets the path that will be used to get the certificate
  that will be used to identify this messenger to its
  peers.  The validity of the path is not checked by
  this function.
}



pn_messenger_set_incoming_window
{
  The size of your incoming window limits the number of messages
  that can be accepted or rejected using trackers.  Messages do
  not enter this window when they have been received (pn_messenger_recv)
  onto you incoming queue.  Messages enter this window only when you
  take them into your application using pn_messenger_get.
  If your incoming window size is N, and you get N+1 messages without
  explicitly accepting or rejecting the oldest message, then it will be
  implicitly accepted when it falls off the edge of the incoming window.
}



pn_messenger_set_outgoing_window
{
  The size of your outgoing window limits the number of messages whose
  status you can check on using a tracker, and pn_messenger_status.
  Messages do not enter this window when they are placed on your outgoing
  queue They enter it only when they have been transmitted to the sender.
  If you requested a tracker for an outgoing message, and if it is still
  within this window, you can find the current delivery status of the
  message using pn_messenger_status.
}



pn_messenger_set_timeout
{
  Set timeout, in milliseconds, that will interrupt blocking calls.
}



pn_messenger_start
{
  Currently a no-op placeholder.
  For future compatibility, do not send or receive messages
  before starting the messenger.
}



pn_messenger_status
{
  Find the current delivery status of the outgoing message
  associated with this tracker, as long as the message is still
  within your outgoing window.
}



pn_messenger_stop
{
  Stops a messenger.  A messenger cannot send or
  receive messages after it is stopped.  The messenger may require
  some time to stop if it is busy, and in that case will return
  PN_IN_PROGRESS.  In that case, call pn_messenger_stopped() to see
  if it has fully stopped.
}



pn_messenger_stopped
{
  If a call to pn_messenger_stop returns a non-zero code,
  use this to determine whether the messenger has stopped.
}



Re: [doc] I will check these in on Friday the 4th...

Posted by Rafael Schloming <rh...@alum.mit.edu>.
Comments inline...

On Mon, Sep 30, 2013 at 2:43 PM, Ted Ross <tr...@redhat.com> wrote:

> Comments in-line below...
>
> A general question/comment:  Is the single-threaded nature of this API
> clearly spelled out somewhere?  There's a lot of the use of the "returns X
> associated with the most recent call to Y" pattern, which isn't
> multi-thread-friendly.  Then, there are calls like pn_messenger_interrupt
> and pn_messenger_stopped that suggest multi-threaded use.  What's the
> intent here?
>

This is a good point. We probably need some sort of API level description
that states basic assumptions like this. To answer Ted's question, in
general the API is single threaded. The only exception to that is
pn_messenger_interrupt which can be safely called from another thread to
interrupt a blocking call.


>
> -Ted
>
>
> On 09/30/2013 01:46 PM, Michael Goulish wrote:
>
>>
>>
>> I will check this stuff in this coming Friday, 4 Oct,
>> ( at midnight, in the last timezone on Earth...)
>> if I don't hear any objections / suggestions,
>> so please take a look before then if you would like to
>> provide feedback.
>>
>>
>>
>> These are expanded descriptions that I'd like to add to the C API
>> documentation.  ( These are the descriptions only -- where the
>> current info already explains the parameters and returns values
>> I will just leave those in place. )
>>
>>
>> These are the only ones I plan to change at this time.
>>
>>
>>
>>
>> Please take a look to see
>>
>>    1. whether the description matches your understanding
>>       of what the functions do, and how they fit together.
>>
>>
>>    2. whether you, as a developer using this code, would
>>       find the description useful, sufficient, understandable,
>>       etc.
>>
>>
>> Question 2 is still very valuable even if you have no
>> idea about Question 1.
>>
>>
>>
>> This is not yet a complete list.  Some of the functions are
>> clear already, and some I have no clue about as yet.
>>
>>
>>
>> Here they are:
>>
>>
>> pn_messenger_interrupt
>> {
>>    Call this from a non-messenger thread to interrupt
>>    a messenger that is blocking.
>>    Return value:  0 if all is well, or -1.
>>    If -1 is returned, that is not PN_EOS.  It is the return
>>    value of the system call write(3), and can be printed with
>>    perror(3).
>> }
>>
>
> It appears that the error-space for this function is different from all of
> the other functions.  This call uses the posix errors whereas
> pn_messenger_error uses a Proton-specific error code.


That's not intentional, it's just passing up the driver error code. We
probably should fix this.


>
>
>  pn_messenger_receiving
>> {
>>    Returns the number of messages that
>>    was requested by the most recent call
>>    to pn_messenger_recv.
>> }
>>
>
> I'd like to see a case where this is needed?   When would you use it?


The description isn't quite right. It is supposed to return the number of
messages that could be inbound, i.e. the credit you've given messenger to
use for incoming messages. This does correspond to what was most recently
passed to recv, however it should change as incoming messages arrive.


>
>
>  pn_messenger_reject
>> {
>>    Rejects the message indicated by the tracker.  If the PN_CUMULATIVE
>>    flag is used this call will also reject all prior messages that
>>    have not already been settled.  The semantics of message rejection
>>    are application-specific.  If messages represent work requests,
>>    then rejection would leave the sender free to try another receiver,
>>    without fear of having the same task done twice.
>> }
>>
>
> It is my understanding that rejected messages should never be re-sent.
>  Isn't the above description appropriate for RELEASED, not REJECTED?
>
>
>
>>
>>
>> pn_messenger_rewrite
>> {
>>    Similar to pn_messenger_route(), except that the destination of
>>    the message is determined before the message address is rewritten.
>>    If a message has an outgoing address of "amqp://0.0.0.0:5678", and a
>>    rewriting rule that changes its outgoing address to "foo", it will
>> still
>>    arrive at the peer that is listening on "amqp://0.0.0.0:5678", but
>> when
>>    it arrives there, its outgoing address will have been changed to "foo".
>> }
>>
>
> What is the purpose of this function?  If the to-field has been re-written
> to "foo", how will it then arrive at your intended destination?


It allows a layer of indirection between addresses in your application and
addresses you use on the wire, e.g. you can use "FOOBAR" inside your app
and then configure messenger to rewrite that into "//bar.com/foo" or
something like that. Internally the mechanism is used to rewrite
credentials out of addresses.


>
>
>  pn_messenger_stopped
>> {
>>    If a call to pn_messenger_stop returns a non-zero code,
>>    use this to determine whether the messenger has stopped.
>> }
>>
>
> Does this function block?  Do you need to call it in a loop?  What are the
> multi-threading implications?
>

It doesn't block, it just reports whether a messenger is started/stopped.
There shouldn't be any multi threading implications. I guess it might help
to define what started/stopped means. A stopped messenger has no network
connections and is not allowed to create them (hypothetically, right now
that part is not enforced). A started messenger might not have network
connections, but is allowed to create them if needed.

--Rafael

Re: [doc] I will check these in on Friday the 4th...

Posted by Ted Ross <tr...@redhat.com>.
Comments in-line below...

A general question/comment:  Is the single-threaded nature of this API 
clearly spelled out somewhere?  There's a lot of the use of the "returns 
X associated with the most recent call to Y" pattern, which isn't 
multi-thread-friendly.  Then, there are calls like 
pn_messenger_interrupt and pn_messenger_stopped that suggest 
multi-threaded use.  What's the intent here?

-Ted

On 09/30/2013 01:46 PM, Michael Goulish wrote:
>
>
> I will check this stuff in this coming Friday, 4 Oct,
> ( at midnight, in the last timezone on Earth...)
> if I don't hear any objections / suggestions,
> so please take a look before then if you would like to
> provide feedback.
>
>
>
> These are expanded descriptions that I'd like to add to the C API
> documentation.  ( These are the descriptions only -- where the
> current info already explains the parameters and returns values
> I will just leave those in place. )
>
>
> These are the only ones I plan to change at this time.
>
>
>
>
> Please take a look to see
>
>    1. whether the description matches your understanding
>       of what the functions do, and how they fit together.
>
>
>    2. whether you, as a developer using this code, would
>       find the description useful, sufficient, understandable,
>       etc.
>
>
> Question 2 is still very valuable even if you have no
> idea about Question 1.
>
>
>
> This is not yet a complete list.  Some of the functions are
> clear already, and some I have no clue about as yet.
>
>
>
> Here they are:
>
>
> pn_messenger_interrupt
> {
>    Call this from a non-messenger thread to interrupt
>    a messenger that is blocking.
>    Return value:  0 if all is well, or -1.
>    If -1 is returned, that is not PN_EOS.  It is the return
>    value of the system call write(3), and can be printed with
>    perror(3).
> }

It appears that the error-space for this function is different from all 
of the other functions.  This call uses the posix errors whereas 
pn_messenger_error uses a Proton-specific error code.

> pn_messenger_receiving
> {
>    Returns the number of messages that
>    was requested by the most recent call
>    to pn_messenger_recv.
> }

I'd like to see a case where this is needed?   When would you use it?

> pn_messenger_reject
> {
>    Rejects the message indicated by the tracker.  If the PN_CUMULATIVE
>    flag is used this call will also reject all prior messages that
>    have not already been settled.  The semantics of message rejection
>    are application-specific.  If messages represent work requests,
>    then rejection would leave the sender free to try another receiver,
>    without fear of having the same task done twice.
> }

It is my understanding that rejected messages should never be re-sent.  
Isn't the above description appropriate for RELEASED, not REJECTED?

>
>
>
> pn_messenger_rewrite
> {
>    Similar to pn_messenger_route(), except that the destination of
>    the message is determined before the message address is rewritten.
>    If a message has an outgoing address of "amqp://0.0.0.0:5678", and a
>    rewriting rule that changes its outgoing address to "foo", it will still
>    arrive at the peer that is listening on "amqp://0.0.0.0:5678", but when
>    it arrives there, its outgoing address will have been changed to "foo".
> }

What is the purpose of this function?  If the to-field has been 
re-written to "foo", how will it then arrive at your intended destination?

> pn_messenger_stopped
> {
>    If a call to pn_messenger_stop returns a non-zero code,
>    use this to determine whether the messenger has stopped.
> }

Does this function block?  Do you need to call it in a loop?  What are 
the multi-threading implications?




Re: [doc] I will check these in on Friday the 4th...

Posted by Rafael Schloming <rh...@alum.mit.edu>.
Hey, sorry to take so long getting around to this. Thanks for the prodding.
See comments inline...

On Mon, Sep 30, 2013 at 1:46 PM, Michael Goulish <mg...@redhat.com>wrote:

>
>
>
> I will check this stuff in this coming Friday, 4 Oct,
> ( at midnight, in the last timezone on Earth...)
> if I don't hear any objections / suggestions,
> so please take a look before then if you would like to
> provide feedback.
>
>
>
> These are expanded descriptions that I'd like to add to the C API
> documentation.  ( These are the descriptions only -- where the
> current info already explains the parameters and returns values
> I will just leave those in place. )
>
>
> These are the only ones I plan to change at this time.
>
>
>
>
> Please take a look to see
>
>   1. whether the description matches your understanding
>      of what the functions do, and how they fit together.
>
>
>   2. whether you, as a developer using this code, would
>      find the description useful, sufficient, understandable,
>      etc.
>
>
> Question 2 is still very valuable even if you have no
> idea about Question 1.
>
>
>
> This is not yet a complete list.  Some of the functions are
> clear already, and some I have no clue about as yet.
>
>
>
> Here they are:
>
>
>
>
> pn_messenger_accept
> {
>   Signal the sender that you have received and have acted on the message
>   pointed to by the tracker.  If the PN_CUMULATIVE flag is set, all
>   messages prior to the tracker will also be accepted, back to the
>   beginning of your incoming window.
> }
>

Minor quibble, but I'm not sure it adds much to say that it signals that
you've received the message. That's kind of implicit in having acted upon
the message anyways.


>
> pn_messenger_errno
> {
>   Return the code for the most recent error.
>   Initialized to zero at messenger creation.
>   Error numbers are "sticky" i.e. are not reset to 0
>   at the end of successful API calls.
>
>   (NOTE! This is the only description that is intentionally false.
>    There *is* one API call that resets errno to 0 -- but I think
>    it shouldn't, and I will complain about it Real Soon Now.)
> }
>
>
>
> pn_messenger_error
> {
>   Return a text description of the most recent error.
>   Initialized to null at messenger creation.
>   Error text is "sticky" i.e. not reset to null
>   at the end of successful API calls.
> }
>
>
This is no longer accurate. As of 0.5 pn_messenger_error returns a pointer
to a pn_error_t. There is a pn_error_* API that allows for accessing the
text, error number, and doing things like setting/clearing the error code
explicitly if you wish to do so.


>
> pn_messenger_get
> {
>   Pop the oldest message off your incoming message queue,
>   and copy it into the given message structure.
>   If the given pointer to a message structure in NULL,
>   the popped message is discarded.
>   Returns PN_EOS if there are no messages to get.
>   Returns an error code only if there is a problem in
>   decoding the message.
> }
>

That should probably read "If the given pointer to a message structure *is*
NULL, ..."


>
> pn_messenger_get_certificate
> {
>   Return the certificate path if one has been set,
>   by pn_messenger_set_certificate, or null.
> }
>

This is a little bit ambiguous, maybe "Return the certificate path. This
value may be set by pn_messenger_set_certificate. The default certificate
path is null."


>
> pn_messenger_get_incoming_window
> {
>   Returns the size of the incoming window that was
>   set with pn_messenger_set_incoming_window.  The
>   default is 0.
> }
>
>
> pn_messenger_get_outgoing_window
> {
>   Returns the size of the incoming window that was
>   set with pn_messenger_set_incoming_window.  The
>   default is 0.
> }
>
>
>
> pn_messenger_incoming_subscription
> {
>   Returns a pointer to the subscription of the message returned by the
>   most recent call to pn_messenger_get(), or NULL if pn_messenger_get()
>   has never been called.
> }
>
>
>
> pn_messenger_incoming_tracker
> {
>   Returns a tracker for the message most recently fetched by
>   pn_messenger_get().  The tracker allows you to accept or reject its
>   message, or its message plus all prior messages that are still within
>   your incoming window.
> }
>
>
>
> pn_messenger_interrupt
> {
>   Call this from a non-messenger thread to interrupt
>   a messenger that is blocking.
>   Return value:  0 if all is well, or -1.
>   If -1 is returned, that is not PN_EOS.  It is the return
>   value of the system call write(3), and can be printed with
>   perror(3).
> }
>
>
>
> pn_messenger_is_blocking
> {
>   Accessor for messenger blocking mode.
>   Note: this tells you only whether the messenger is in
>   blocking mode.  This will not tell you (if called from
>   a separate thread) that a messenger is currently blocking
> }
>
>
>
>
> pn_messenger_outgoing_tracker
> {
>   Returns a tracker for the outgoing message most recently given
>   to pn_messenger_put.  Use this tracker with pn_messenger_status
>   to determine the delivery status of the message, as long as the
>   message is still within your outgoing window.
> }
>
>
>
> pn_messenger_put
> {
>   Puts the message onto the messenger's outgoing queue.
>   The message may also be sent if transmission would not cause
>   blocking.  This call will not block.
> }
>
>
>
> pn_messenger_receiving
> {
>   Returns the number of messages that
>   was requested by the most recent call
>   to pn_messenger_recv.
> }
>
>
> pn_messenger_recv
> {
>   ( add this text to current description )
>   After receiving messages onto your incoming queue,
>   use pn_messenger_get to bring messages into your application code.
> }
>
>
>
> pn_messenger_reject
> {
>   Rejects the message indicated by the tracker.  If the PN_CUMULATIVE
>   flag is used this call will also reject all prior messages that
>   have not already been settled.  The semantics of message rejection
>   are application-specific.  If messages represent work requests,
>   then rejection would leave the sender free to try another receiver,
>   without fear of having the same task done twice.
> }
>
>
>
> pn_messenger_rewrite
> {
>   Similar to pn_messenger_route(), except that the destination of
>   the message is determined before the message address is rewritten.
>   If a message has an outgoing address of "amqp://0.0.0.0:5678", and a
>   rewriting rule that changes its outgoing address to "foo", it will still
>   arrive at the peer that is listening on "amqp://0.0.0.0:5678", but when
>   it arrives there, its outgoing address will have been changed to "foo".
> }
>

You could also mention that by default there is a rewrite rule that removes
username and password from addresses before they hit the wire.


>
>
>
> pn_messenger_send
> {
>   If blocking has been set with pn_messenger_set_blocking, this call
>   will block until n messages have been sent.  A value of -1 for n means
>   "all messages in the outgoing queue".
>
>   In addition, if a nonzero size has been set for the outgoing window,
>   this call will block until all messages within that window have
>   been received.  Any blocking will end upon timeout, if one has been
>   set by pn_messenger_timeout.
>
>   If blocking has not been set, this call will stop transmitting
>   messages when further transmission would require blocking, or when
>   the outgoing queue is empty, or when n messages have been sent.
> }
>

It's not that it blocks until messages are received, it blocks until they
are settled, e.g. they could be rejected. Also, it should somehow say all
of the N messages indicated by the argument that fall within the outgoing
window. As stated it sounds like it will block on settlement of all
messages in the outgoing window regardless of the argument passed.


>
>
>
> pn_messenger_set_blocking
> {
>   Enable or disable blocking behavior during calls to
>   pn_messenger_send and pn_messenger_recv.
> }
>
>
>
>
> pn_messenger_set_certificate
> {
>   Sets the path that will be used to get the certificate
>   that will be used to identify this messenger to its
>   peers.  The validity of the path is not checked by
>   this function.
> }
>
>
>
> pn_messenger_set_incoming_window
> {
>   The size of your incoming window limits the number of messages
>   that can be accepted or rejected using trackers.  Messages do
>   not enter this window when they have been received (pn_messenger_recv)
>   onto you incoming queue.  Messages enter this window only when you
>   take them into your application using pn_messenger_get.
>   If your incoming window size is N, and you get N+1 messages without
>   explicitly accepting or rejecting the oldest message, then it will be
>   implicitly accepted when it falls off the edge of the incoming window.
> }
>
>
>
> pn_messenger_set_outgoing_window
> {
>   The size of your outgoing window limits the number of messages whose
>   status you can check on using a tracker, and pn_messenger_status.
>   Messages do not enter this window when they are placed on your outgoing
>   queue They enter it only when they have been transmitted to the sender.
>   If you requested a tracker for an outgoing message, and if it is still
>   within this window, you can find the current delivery status of the
>   message using pn_messenger_status.
> }
>
>
This description of the outgoing window isn't quite right. If the outgoing
window size is N, then messenger will track the status of the last N
messages that have been put. It doesn't really interact with send in the
way you describe. The only interaction with send is that if you have an
outgoing window of 5 and you put 10 messages without calling, then you may
lose information about 5 of your messages because you told messenger to
only remember the last 5.


>
>
> pn_messenger_set_timeout
> {
>   Set timeout, in milliseconds, that will interrupt blocking calls.
> }
>

I would avoid using "interrupt" here since this has nothing to do with
pn_messenger_interrupt. Also, it doesn't quite parse as english. ;-)


>
>
>
> pn_messenger_start
> {
>   Currently a no-op placeholder.
>   For future compatibility, do not send or receive messages
>   before starting the messenger.
> }
>
>
>
> pn_messenger_status
> {
>   Find the current delivery status of the outgoing message
>   associated with this tracker, as long as the message is still
>   within your outgoing window.
> }
>
>
>
> pn_messenger_stop
> {
>   Stops a messenger.  A messenger cannot send or
>   receive messages after it is stopped.  The messenger may require
>   some time to stop if it is busy, and in that case will return
>   PN_IN_PROGRESS.  In that case, call pn_messenger_stopped() to see
>   if it has fully stopped.
> }
>
>
>
That should be PN_INPROGRESS.


>
> pn_messenger_stopped
> {
>   If a call to pn_messenger_stop returns a non-zero code,
>   use this to determine whether the messenger has stopped.
> }
>
>
>
The way you describe this sounds like you need to call stop first and have
it return a non zero code. That isn't the case though,
pn_messenger_stopped() simply reports whether a messenger is started or
stopped. You can call it at any time for whatever reason you wish.

--Rafael