Subject: [Sipping] Call Completion: In Defense of Explicit Operations

From: Adam Roach <[email-masked]>
Date: Thu, 05 Apr 2007 14:10:14 -0500

Despite what appeared to be early agreement in the working group (and on 
the MIG mailing list) that we wanted to discourage the use of SUBSCRIBE 
and NOTIFY as general purpose RPC mechanisms. This is the primary 
objection that I have raised to draft-poetzl-sipping-call-completion, 
which uses SUBSCRIBE and NOTIFY to manipulate call queue state.

In the spirit of sending text, I described an alternate set of 
mechanisms in draft-roach-sipping-callcomp-bfcp, which performs the same 
task without having implied side effects from the creation of a 
subscription.

I'll further note that the use of SUBSCRIBE to both create a 
subscription and manipulate a call queue falls under the category of 
"one operation with two separate effects." We have a very poor 
institutional memory indeed if we cannot recall why operations of this 
nature are Really Bad Ideas (cf. REFER creating a subscription; REGISTER 
with call processing upload; and BYE with an "Also" header field).

All of this notwithstanding, in Prague, there seemed to be a curious 
indifference to pursuing the path laden with such Really Bad Ideas. I 
suspect that this indifference is a result of the arguments raised so 
far against the mechanism I have proposed, which I have done little to 
refute so far (largely because I believed that the merits of a system 
with explicit operations were self-evident enough that the objections 
would seem trifling in comparison).

As far as I can tell, the objections raised so far have fallen into 
three primary categories:

   1. "The use of BFCP is troubling because, in a decomposed gateway,
      the BFCP goes to the Media Gateway, while the signaling goes to
      the Media Gateway Controller."

      This objection, raised on one of the slides during the SIPPING
      meeting on March 23rd as the official reason TISPAN rejected the
      approach, is based on a simple misconception.

      The BFCP goes wherever the SDP says the BFCP goes. In the case of
      a decomposed gateway, this could be the Media Gateway, the Media
      Gateway Controller, or any other random network-connected server
      that the Media Gateway Controller wants. I agree that it probably
      is most sensible to send it to the Media Gateway Controller, and
      this is trivial to achieve.

   2. "In the case of PSTN interwork, there is no way to guarantee that
      the ISUP (or other) signaling from the PSTN side lands on the same
      gateway that the client has a BFCP connection to."

      This is true, and it is a relatively difficult problem to solve
      (not impossible, though; I proposed several potential solutions in
      San Diego). It is meaningless to raise it in objection to an
      alternate proposal, since it exists in almost precisely the same
      form in draft-poetzl-sipping-call-completion; and any solution
      that can be applied to one solution can be applied to the other.

   3. "We don't want to add another protocol."

      I suspect this argument is the one that is receiving the most
      traction, probably because most of the people involved in the
      discussion are not familiar with BFCP. The protocol itself is very
      straightforward and extremely easy to implement. In fact,
      exclusively for the purpose of answering this email (and
      demonstrating this very point), I threw together a BFCP
      implementation sufficient for implementation of the Call
      Completion service described in draft-roach-sipping-callcomp-bfcp.
      It took me two hours, and compiles down to less than 4 kb of
      object code on an intel processor. It's attached to this message
      to help the participants in the conversation understand just how
      very little is being added to applications by this use of BFCP.

So, is that it? The first two objections are simply red herrings, and 
the third is based on a misconception regarding the level of effort 
required to implement BFCP. Are we really going to down the path of 
doing things incorrectly over what amount to misunderstandings?

/a

P.S. In case anyone wants a more full-featured BFCP stack, I'll point to 
the confiance project on SourceForge, available under the Academic 
Freedom License, which is compatible with commercial development. See 
http://confiance.sourceforge.net/
#include <sys/types.h>

/* Primitives */
#define BFCP_PRIM_FLOOR_REQUEST           1    /*  P -> S            */
#define BFCP_PRIM_FLOOR_RELEASE           2    /*  P -> S            */
#define BFCP_PRIM_FLOOR_REQUEST_QUERY     3    /*  P -> S ; Ch -> S  */
#define BFCP_PRIM_FLOOR_REQUEST_STATUS    4    /*  P <- S ; Ch <- S  */
#define BFCP_PRIM_USER_QUERY              5    /*  P -> S ; Ch -> S  */
#define BFCP_PRIM_USER_STATUS             6    /*  P <- S ; Ch <- S  */
#define BFCP_PRIM_FLOOR_QUERY             7    /*  P -> S ; Ch -> S  */
#define BFCP_PRIM_FLOOR_STATUS            8    /*  P <- S ; Ch <- S  */
#define BFCP_PRIM_CHAIR_ACTION            9    /*  Ch -> S           */
#define BFCP_PRIM_CHAIR_ACTION_ACK        10   /*  Ch <- S           */
#define BFCP_PRIM_HELLO                   11   /*  P -> S ; Ch -> S  */
#define BFCP_PRIM_HELLO_ACK               12   /*  P <- S ; Ch <- S  */
#define BFCP_PRIM_ERROR                   13   /*  P <- S ; Ch <- S  */
#define BFCP_PRIM_FLOOR_REQUEST_PAUSE     20   /*  P -> S            */
#define BFCP_PRIM_FLOOR_REQUEST_RESUME    21   /*  P -> S            */

/* Attributes */
#define BFCP_ATT_BENEFICIARY_ID                1   /*  Unsigned16     */
#define BFCP_ATT_FLOOR_ID                      2   /*  Unsigned16     */
#define BFCP_ATT_FLOOR_REQUEST_ID              3   /*  Unsigned16     */
#define BFCP_ATT_PRIORITY                      4   /*  OctetString16  */
#define BFCP_ATT_REQUEST_STATUS                5   /*  OctetString16  */
#define BFCP_ATT_ERROR_CODE                    6   /*  OctetString    */
#define BFCP_ATT_ERROR_INFO                    7   /*  OctetString    */
#define BFCP_ATT_PARTICIPANT_PROVIDED_INFO     8   /*  OctetString    */
#define BFCP_ATT_STATUS_INFO                   9   /*  OctetString    */
#define BFCP_ATT_SUPPORTED_ATTRIBUTES         10   /*  OctetString    */
#define BFCP_ATT_SUPPORTED_PRIMITIVES         11   /*  OctetString    */
#define BFCP_ATT_USER_DISPLAY_NAME            12   /*  OctetString    */
#define BFCP_ATT_USER_URI                     13   /*  OctetString    */
#define BFCP_ATT_BENEFICIARY_INFORMATION      14   /*  Grouped        */
#define BFCP_ATT_FLOOR_REQUEST_INFORMATION    15   /*  Grouped        */
#define BFCP_ATT_REQUESTED_BY_INFORMATION     16   /*  Grouped        */
#define BFCP_ATT_FLOOR_REQUEST_STATUS         17   /*  Grouped        */
#define BFCP_ATT_OVERALL_REQUEST_STATUS       18   /*  Grouped        */

/* Request Status Codes */
#define BFCP_STATUS_PENDING    1
#define BFCP_STATUS_ACCEPTED   2
#define BFCP_STATUS_GRANTED    3
#define BFCP_STATUS_DENIED     4
#define BFCP_STATUS_CANCELLED  5
#define BFCP_STATUS_RELEASED   6
#define BFCP_STATUS_REVOKED    7
#define BFCP_STATUS_PAUSED     8

/* Message output functions */

ssize_t bfcp_send_floor_request(int socket,
                                int flags,
                                uint32_t conference_id,
                                uint16_t transaction_id, 
                                uint16_t user_id,
                                uint16_t floor_id);

ssize_t bfcp_send_floor_release(int socket,
                                int flags,
                                uint32_t conference_id,
                                uint16_t transaction_id, 
                                uint16_t user_id,
                                uint16_t floor_request_id);

ssize_t bfcp_send_floor_pause(int socket, 
                              int flags,
                              uint32_t conference_id, 
                              uint16_t transaction_id, 
                              uint16_t user_id, 
                              uint16_t floor_request_id);

ssize_t bfcp_send_floor_resume(int socket, 
                               int flags,
                               uint32_t conference_id, 
                               uint16_t transaction_id, 
                               uint16_t user_id, 
                               uint16_t floor_request_id);

ssize_t bfcp_send_floor_request_status(int socket, 
                                       int flags,
                                       uint32_t conference_id, 
                                       uint16_t transaction_id, 
                                       uint16_t user_id,
                                       uint16_t floor_request_id,
                                       uint16_t floor_id,
                                       uint8_t  request_status,
                                       uint8_t  queue_position);

ssize_t bfcp_send_error(int socket, 
                        int flags,
                        uint32_t conference_id, 
                        uint16_t transaction_id, 
                        uint16_t user_id, 
                        uint8_t  error_code,
                        uint16_t detail_length,
                        uint8_t *details);

/* Message input functions */

void bfcp_init_message_for_reading(void *message, size_t max_size);

ssize_t bfcp_read_message(int socket,
                          int flags,
                          void *message,
                          size_t max_size);

uint8_t  bfcp_get_message_primitive(void *message);

/* Functions to get attributes */

void *bfcp_get_attribute(void *message, uint8_t tag);
void *bfcp_get_subattribute(void *attribute, uint8_t tag);

/* Functions to examine attributes */

uint16_t bfcp_get_attribute_length(void *attribute);
uint8_t *bfcp_get_attribute_value(void *attribute);
uint16_t bfcp_get_attribute_value_16(void *attribute);
uint16_t bfcp_get_grouped_attribute_header_value(void *attribute);
#include "bfcp.h"

#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>

/*
  Encodes an arbitrary BFCP attribute.

  @param type      The attribute type.
  @param mandatory Flag indicating whether the attribute is mandatory
                   to understand.
  @param length    The length of the parameter value
  @param value     The value of the parameter to encode
  @param encoded   Buffer into which the encoded attribute is to be written

  @returns         The total length of the encoded attribute

  @note The buffer that "encoded" points to must be at least (length + 5)
        bytes long.
*/
int
bfcp_encode_attribute(uint8_t type,
                      int mandatory,
                      uint16_t length,
                      uint8_t *value, 
                      uint8_t *encoded)
{
  encoded[0] = (type << 1) | (mandatory?1:0);
  encoded[1] = length + 2;
  memmove(encoded + 2, value, length);

  /* ensure the attribute is word aligned */
  length += 2;
  while (length % 4)
  {
    encoded[length] = 0;
    length++;
  }
  return length;
}

/*
  Encodes a groupd BFCP attribute.

  @param type         The attribute type.
  @param mandatory    Flag indicating whether the attribute is mandatory
                      to understand.
  @param header_value The 16-bit value encoded in the grouped attribute header
  @param length       The length of the grouped parameters -- must be
                      an even multiple of 4.
  @param value        The (already encoded) grouped parameters
  @param encoded      Buffer into which the encoded attribute is to be written

  @returns            The total length of the encoded attribute

  @note The buffer that "encoded" points to must be at least (length + 4)
        bytes long.
*/
int
bfcp_encode_attribute_grouped(uint8_t type,
                              int mandatory,
                              uint16_t header_value,
                              uint16_t length,
                              uint8_t *value, 
                              uint8_t *encoded)
{
  encoded[0] = (type << 1) | (mandatory?1:0);
  encoded[1] = length + 2;
  encoded[2] = (header_value >> 8) & 0xff;
  encoded[3] = header_value & 0xff;

  memmove(encoded + 4, value, length);
  return length + 4;
}

/**
  Encodes a 16-bit BFCP attribute.

  @param type      The attribute type.
  @param mandatory Flag indicating whether the attribute is mandatory
                   to understand.
  @param value     The value of the parameter to encode
  @param encoded   Buffer into which the encoded attribute is to be written

  @returns         The total length of the encoded attribute

  @note The buffer that "encoded" points to must be at least 4 bytes long.
*/
int
bfcp_encode_attribute_16(uint8_t type,
                         int mandatory,
                         uint16_t value, 
                         uint8_t *encoded)
{
  encoded[0] = (type << 1) | (mandatory?1:0);
  encoded[1] = 4;
  encoded[2] = (value >> 8) & 0xff;
  encoded[3] = value & 0xff;

  return 4;
}

/**
  Encodes a complete BFCP message.

  @param primitive        The type of BFCP message to send
  @param conference_id    The conference ID for the message
  @param transaction_id   The transaction ID for the message
  @param user_id          The user ID for the message
  @param attribute_length The length of the attributes for this message
  @param attributes       The (already encoded) attributes for this message
  @param encoded          The buffer into which the encoded message is to
                          be written

  @returns                The total length of the BFCP message

  @note The buffer that "encoded" points to must be at least
        (attribute_length + 12) bytes long.
*/
int bfcp_encode_message(uint8_t primitive,
                        uint32_t conference_id,
                        uint16_t transaction_id,
                        uint16_t user_id,
                        uint16_t attribute_length,
                        uint8_t *attributes,
                        uint8_t *encoded)
{
  uint16_t word_length = attribute_length / 4;
  encoded[0] = 0x20; /* BFCP Version 1 */
  encoded[1] = primitive;

  encoded[2] = (word_length >> 8) & 0xff;
  encoded[3] = word_length & 0xff;

  encoded[4] = (conference_id >> 24) & 0xff;
  encoded[5] = (conference_id >> 16) & 0xff;
  encoded[6] = (conference_id >> 8) & 0xff;
  encoded[7] = conference_id & 0xff;

  encoded[8] = (transaction_id >> 8) & 0xff;
  encoded[9] = transaction_id & 0xff;

  encoded[10] = (user_id >> 8) & 0xff;
  encoded[11] = user_id & 0xff;

  memmove(encoded + 12, attributes, attribute_length);

  return attribute_length + 12;
}

/**
  Sends a FloorRequest message.

  @param socket          System-level socket to use to send the message.
  @param flags           Flags passed to send(); see send() documentation.
  @param conference_id   Conference ID for message header
  @param transaction_id  Transaction ID for message header
  @param user_id         User ID for message header
  @param floor_id        Floor ID for floor being requested

  @returns the number of uint8_tacters sent, or -1 if an error occurred.
*/
ssize_t bfcp_send_floor_request(int socket, int flags,
                                uint32_t conference_id,
                                uint16_t transaction_id,
                                uint16_t user_id,
                                uint16_t floor_id)
{
  uint8_t attributes[4];
  uint8_t message[16];
  int length;

  length = bfcp_encode_attribute_16(BFCP_ATT_FLOOR_ID, 0, floor_id, attributes);

  length = bfcp_encode_message(BFCP_PRIM_FLOOR_REQUEST, conference_id,
                      transaction_id, user_id, length, attributes, message);

  return send(socket, message, length, flags);
}

/**
  Sends a FloorRequestRelease message.

  @param socket           System-level socket to use to send the message.
  @param flags            Flags passed to send(); see send() documentation.
  @param conference_id    Conference ID for message header
  @param transaction_id   Transaction ID for message header
  @param user_id          User ID for message header
  @param floor_request_id Floor Request ID for floor being released

  @returns the number of uint8_tacters sent, or -1 if an error occurred.
*/
ssize_t bfcp_send_floor_release(int socket, int flags,
                                uint32_t conference_id,
                                uint16_t transaction_id,
                                uint16_t user_id,
                                uint16_t floor_request_id)
{
  uint8_t attributes[4];
  uint8_t message[16];
  int length;

  length = bfcp_encode_attribute_16(BFCP_ATT_FLOOR_REQUEST_ID, 0, 
                                     floor_request_id, attributes);

  length = bfcp_encode_message(BFCP_PRIM_FLOOR_RELEASE, conference_id,
                      transaction_id, user_id, length, attributes, message);

  return send(socket, message, length, flags);
}

/**
  Sends a FloorRequestPause message.

  @param socket           System-level socket to use to send the message.
  @param flags            Flags passed to send(); see send() documentation.
  @param conference_id    Conference ID for message header
  @param transaction_id   Transaction ID for message header
  @param user_id          User ID for message header
  @param floor_request_id Floor Request ID for floor request being paused

  @returns the number of uint8_tacters sent, or -1 if an error occurred.
*/
ssize_t bfcp_send_floor_pause(int socket, int flags,
                              uint32_t conference_id,
                              uint16_t transaction_id,
                              uint16_t user_id,
                              uint16_t floor_request_id)
{
  uint8_t attributes[4];
  uint8_t message[16];
  int length;

  length = bfcp_encode_attribute_16(BFCP_ATT_FLOOR_REQUEST_ID, 0, 
                                     floor_request_id, attributes);

  length = bfcp_encode_message(BFCP_PRIM_FLOOR_REQUEST_PAUSE, conference_id,
                      transaction_id, user_id, length, attributes, message);

  return send(socket, message, length, flags);
}

/**
  Sends a FloorRequestResume message.

  @param socket           System-level socket to use to send the message.
  @param flags            Flags passed to send(); see send() documentation.
  @param conference_id    Conference ID for message header
  @param transaction_id   Transaction ID for message header
  @param user_id          User ID for message header
  @param floor_request_id Floor Request ID for floor request being resumed

  @returns the number of uint8_tacters sent, or -1 if an error occurred.
*/
ssize_t bfcp_send_floor_resume(int socket, int flags,
                               uint32_t conference_id,
                               uint16_t transaction_id,
                               uint16_t user_id,
                               uint16_t floor_request_id)
{
  uint8_t attributes[4];
  uint8_t message[16];
  int length;

  length = bfcp_encode_attribute_16(BFCP_ATT_FLOOR_REQUEST_ID, 0, 
                                     floor_request_id, attributes);

  length = bfcp_encode_message(BFCP_PRIM_FLOOR_REQUEST_RESUME, conference_id,
                      transaction_id, user_id, length, attributes, message);

  return send(socket, message, length, flags);
}

/**
  Sends a FloorRequestStatus message.

  @param socket           System-level socket to use to send the message.
  @param flags            Flags passed to send(); see send() documentation.
  @param conference_id    Conference ID for message header
  @param transaction_id   Transaction ID for message header
  @param user_id          User ID for message header
  @param floor_request_id Floor Request ID for floor request
  @param floor_id         Floor ID for floor request
  @param request_status   Floor request status
  @param queue_position   Position of request in queue

  @returns the number of uint8_tacters sent, or -1 if an error occurred.
*/
ssize_t bfcp_send_floor_request_status(int socket, int flags,
                                       uint32_t conference_id,
                                       uint16_t transaction_id,
                                       uint16_t user_id,
                                       uint16_t floor_request_id,
                                       uint16_t floor_id,
                                       uint8_t  request_status,
                                       uint8_t  queue_position)
{
  /*
  The attributes for this message are nested as follows:

    FLOOR-REQUEST-INFORMATION (floor-request-id)
      FLOOR-REQUEST-STATUS (floor-id)
        REQUEST-STATUS (status, queue position)
  */

  uint8_t request_status_attribute[4];
  uint8_t floor_request_status_attribute[8];
  uint8_t attributes[12];
  uint8_t message[32];
  int length;

  length = bfcp_encode_attribute_16(BFCP_ATT_REQUEST_STATUS, 0, 
                                    (floor_id << 8) | queue_position,
                                    request_status_attribute);

  length = bfcp_encode_attribute_grouped(BFCP_ATT_FLOOR_REQUEST_STATUS, 0,
                                         floor_id, length,
                                         request_status_attribute,
                                         floor_request_status_attribute);

  length = bfcp_encode_attribute_grouped(BFCP_ATT_FLOOR_REQUEST_INFORMATION, 0,
                                         floor_request_id, length,
                                         floor_request_status_attribute,
                                         attributes);

  length = bfcp_encode_message(BFCP_PRIM_FLOOR_REQUEST_RESUME, conference_id,
                      transaction_id, user_id, length, attributes, message);

  return send(socket, message, length, flags);
}

/**
  Sends an Error message.

  @param socket           System-level socket to use to send the message.
  @param flags            Flags passed to send(); see send() documentation.
  @param conference_id    Conference ID for message header
  @param transaction_id   Transaction ID for message header
  @param user_id          User ID for message header
  @param error_code       Error code indicating what happened
  @param detail_length    Length of error details (often 0)
  @param details          error details

  @returns the number of uint8_tacters sent, or -1 if an error occurred.
*/
ssize_t bfcp_send_error(int socket, int flags,
                        uint32_t conference_id,
                        uint16_t transaction_id,
                        uint16_t user_id,
                        uint8_t error_code,
                        uint16_t detail_length,
                        uint8_t *details)
{
  uint8_t attributes[4];
  uint8_t message[16];
  int length;

  uint8_t *attribute_value;
  uint8_t *detail_attributes;
  uint8_t *detail_message;
  ssize_t status;

  /* Special case for less-common "error with details" case */
  if (detail_length != 0)
  {
    attribute_value = malloc(1 + detail_length);
    attribute_value[0] = error_code;
    memmove(attribute_value + 1, details, detail_length);

    detail_attributes = malloc(1 + detail_length + 5);

    length = bfcp_encode_attribute(BFCP_ATT_ERROR_CODE, 0, 
                                   1, attribute_value, detail_attributes);
    free(attribute_value);

    detail_message = malloc(1 + detail_length + 5 + 20);

    length = bfcp_encode_message(BFCP_PRIM_ERROR, conference_id, transaction_id,
                                 user_id, length, 
                                 detail_attributes, detail_message);

    free(detail_attributes);

    status = send(socket, detail_message, length, flags);
    free(detail_message);
    return status;
  }

  length = bfcp_encode_attribute(BFCP_ATT_ERROR_CODE, 0, 
                                 1, &error_code, attributes);

  length = bfcp_encode_message(BFCP_PRIM_ERROR, conference_id, transaction_id,
                               user_id, length, attributes, message);

  return send(socket, message, length, flags);
}

/**
  Initializes a message buffer so it can be read into. Buffers must be
  initialized for every message read into them.

  @param message  Buffer into which message will be read
  @param max_size Size of message buffer
*/
void bfcp_init_message_for_reading(void *message, size_t max_size)
{
  int *bytes_read = (int *)message;
  if (max_size < 12 + sizeof(int))
  {
    return;
  }
  *bytes_read = 0;
}

/**
  Reads a BFCP message from a socket.

  @param socket   System-level socket used to read the message
  @param flags    Flags passed to recv(); see recv() documentation
  @param message  Buffer into which message is to be read
  @param max_size Size of message buffer

  @returns The size of the message actually read

  @retval -1  An error has occured
  @retval 0   There is not enough data to form a complete message.
              The caller is required to call bfcp_read_message
              again WITH THE SAME MESSAGE BUFFER when the descriptor
              is ready for reading.
*/

ssize_t bfcp_read_message(int socket,
                          int flags,
                          void *message,
                          size_t max_size)
{
  int *bytes_read = (int *)message;
  uint8_t *buffer = (uint8_t *) message;
  uint16_t attribute_length;

  buffer += sizeof(int);

  /* We need enough space to read in at least a message header */
  if (max_size < 12 + sizeof(int))
  {
    return -1;
  }

  /* Read in the header */
  if (*bytes_read < 12)
  {
    *bytes_read += recv(socket, buffer, 12 - (*bytes_read), flags);
  }

  if (*bytes_read < 12)
  {
    return 0;
  }

  /* Check for a valid version number */
  if (buffer[1] & 0xE0 != 0x20)
  {
    return -1;
  }

  attribute_length = ((buffer[2]<<8) | buffer[3]) * 4;

  /* Check that there is enough room in the buffer */
  if (attribute_length + 12 + sizeof(int) > max_size)
  {
    return -1;
  }

  /* Read in the remainder of the message */
  *bytes_read += recv(socket, buffer, attribute_length - (*bytes_read) - 12,
                      flags);

  if (*bytes_read < attribute_length + 12)
  {
    return 0;
  }

  return (*bytes_read);
}

/**
  Reads the primitive from a BFCP message

  @param message The BFCP message to get the primive from

  @returns       The primitive of the BFCP message
*/
uint8_t bfcp_get_message_primitive(void *message)
{
  uint8_t *buffer = (uint8_t *) message;
  buffer += sizeof(int);

  return buffer[1];
}

/**
  Private function used to find an attribute in a block of
  attributes.

  @param buffer    Buffer to find the attribute in
  @param size      Size of the buffer
  @param tag       Tag indicating which attribute to find

  @returns pointer to the attribute, NULL if not found.
*/
void *bfcp_private_find_attribute (void *buffer, size_t size, uint8_t tag)
{
  uint8_t *attributes = (uint8_t *)buffer;
  size_t i = 0;
  tag <<= 1;

  while (i < size)
  {
    if (attributes[i] & 0xFE == tag)
    {
      return attributes + i;
    }

    if (i + 1 < size)
    {
      i += attributes[i+1];
    }
    else
    {
      return NULL;
    }
  }

  return NULL;
}

/**
  Finds the specified attribute in a message.

  @param message  The message to find the attribute in
  @param tag      The tag for the attribute to find

  @returns pointer to the attribute, NULL if not found.
*/
void *bfcp_get_attribute(void *message, uint8_t tag)
{
  uint8_t *buffer = (uint8_t *) message;
  unsigned int attribute_length;
  buffer += sizeof(int);
  attribute_length = ((buffer[2]<<8) | buffer[3]) * 4;

  return bfcp_private_find_attribute(buffer + 12, attribute_length, tag);
}

/**
  Finds the specified subattribute in a grouped attribute.

  @param attribute  The grouped attribute to find the subattribute in
  @param tag        The tag for the attribute to find

  @returns pointer to the attribute, NULL if not found.
*/
void *bfcp_get_subattribute(void *attribute, uint8_t tag)
{
  uint8_t *buffer = (uint8_t *) attribute;
  uint8_t attribute_length;

  attribute_length = buffer[1];

  if (attribute_length < 4)
  {
    return NULL;
  }

  return bfcp_private_find_attribute(buffer + 4, attribute_length - 4, tag);
}

/**
  Gets the length of an attribute

  @param attribute  Pointer to the attribute

  @returns Length of the attribute
*/
uint16_t bfcp_get_attribute_length(void *attribute)
{
  uint8_t *buffer = (uint8_t *) attribute;
  uint8_t attribute_length;

  attribute_length = buffer[1];
  if (attribute_length < 2)
  {
    return 0;
  }
  return (attribute_length - 2);
}

/**
  Gets the value of an arbitrary attribute

  @param attribute  Pointer to the attribute

  @returns 16-bit value for the indicated attribute; NULL if attribute
           has no value.
*/

uint8_t *bfcp_get_attribute_value(void* attribute)
{
  uint8_t *buffer = (uint8_t *) attribute;
  if (bfcp_get_attribute_length(attribute) == 0)
  {
    return NULL;
  }
  return buffer + 2;
}

/**
  Gets the value of a 16-bit attribute

  @param attribute  Pointer to the attribute

  @returns 16-bit value for the indicated attribute
*/
uint16_t bfcp_get_attribute_value_16(void* attribute)
{
  uint8_t *buffer = (uint8_t *) attribute;
  if (bfcp_get_attribute_length(attribute) < 2)
  {
    return 0;
  }
  return (buffer[2] << 8) | buffer[3];
}

/**
  Gets the 16-bit value from a grouped attribute header

  @param attribute

  @returns the 16-bit value from the grouped attribute header
*/

uint16_t bfcp_get_grouped_attribute_header_value(void* attribute)
{
  return bfcp_get_attribute_value_16(attribute);
}
_______________________________________________
Sipping mailing list  https://www1.ietf.org/mailman/listinfo/sipping
This list is for NEW development of the application of SIP
Use [email-masked] for questions on current sip
Use [email-masked] for new developments of core SIP

---

From: "Francois Audet" <[email-masked]>
Date: Thu, 5 Apr 2007 17:18:20 -0500

Wouldn't it be possible to do this CCBS/CCNR stuff with a simple
dialog package, and ditch this "queue management" mechanism?

This seems to me to be a classic case of Engineers-gone-wild.

I see this in the poetzl draft:

    Completion of Calls on no Reply (CCNR) provides the caller with the 
    ability to complete a requested call to a callee without having to 
    make a new call attempt when the callee becomes not busy after 
    having initiated an activity.  The CCNR service description is 
    defined in ETSI EN 301 134 [6]. 

    The call completion services provide the capability to queue 
    several CCBS/CCNR requests to the same callee on a FIFO basis. It 
    therefore requires functionalities like notifying changes of queue 
    states and managing queues.  

In other words, we are defining this really complex stuff just because
it
used to work like this in some ETSI standard for PSTN.

Is there a better justification than that? What am I missing?

Couldn't we handle some basic level of queueing at the endpoints
themselves,
and use a simple dialog package, and avoid all this stuff that creates
all
the complexity?

This CCBS/CCNR feature is one of the feature that has the most variation

in implementations in PSTN that I know of. To me, picking a really
complicated
variant and replicating it in SIP (either by bastardizing the protocol,
or
by using an entirely different protocol altogether) is not a good idea.
My take is
that there will be such a small uptake in implementation that it will
effectively
useful only in a few confined environments where the it can be mandated
by law.

I'd must rather have a simpler easier to implement version of the
service.

> -----Original Message-----
> From: Adam Roach [mailto:[email-masked]] 
> Sent: Thursday, April 05, 2007 12:10
> To: SIPPING WG
> Subject: [Sipping] Call Completion: In Defense of Explicit Operations
> 
> Despite what appeared to be early agreement in the working 
> group (and on the MIG mailing list) that we wanted to 
> discourage the use of SUBSCRIBE and NOTIFY as general purpose 
> RPC mechanisms. This is the primary objection that I have 
> raised to draft-poetzl-sipping-call-completion,
> In the spirit of sending text, I described an alternate set 
> of mechanisms in draft-roach-sipping-callcomp-bfcp, which 
> performs the same task without having implied side effects 
> from the creation of a subscription.
> 
> subscription and manipulate a call queue falls under the 
> category of "one operation with two separate effects." We 
> have a very poor institutional memory indeed if we cannot 
> recall why operations of this nature are Really Bad Ideas 
> (cf. REFER creating a subscription; REGISTER with call 
> processing upload; and BYE with an "Also" header field).
> 
> All of this notwithstanding, in Prague, there seemed to be a 
> curious indifference to pursuing the path laden with such 
> Really Bad Ideas. I suspect that this indifference is a 
> result of the arguments raised so far against the mechanism I 
> have proposed, which I have done little to refute so far 
> (largely because I believed that the merits of a system with 
> explicit operations were self-evident enough that the 
> objections would seem trifling in comparison).
> 
> As far as I can tell, the objections raised so far have 
> fallen into three primary categories:
> 
> So, is that it? The first two objections are simply red 
> herrings, and the third is based on a misconception regarding 
> the level of effort required to implement BFCP. Are we really 
> going to down the path of doing things incorrectly over what 
> amount to misunderstandings?
> 
> /a
> 
> 
>

---

From: Adam Roach <[email-masked]>
Date: Thu, 05 Apr 2007 20:43:30 -0500

Francois:

You are correct that the specific inclusion of a requirement for strict 
call queuing to handle the once-in-a-lifetime situation in which two 
people attempt to perform call completion against the same destination 
is at the root of the complexity. Without this requirement, call 
completion services could be implemented using already-defined mechanisms.

Not only do I agree with your analysis; it's exactly what I was trying 
to convey at the Dallas meeting. If I recall, the pushback took the form 
of, "TISPAN has defined these requirements, and none of them are 
negotiable."

It would be nice if we could get some kind of liaison statement from 
TISPAN confirming that the use of strict queuing is considered a 
sufficiently critical requirement to warrant the relatively ridiculous 
complexity it introduces. (Relative, that is, to the impact on user 
experience.)

/a

---

From: "Francois Audet" <[email-masked]>
Date: Fri, 6 Apr 2007 12:10:41 -0500

Thanks, it's good to see I'm not the only one puzzled by this.

I think what would be useful is a document that explains how to do
CCBS/CCNR using standard existing mechanisms (i.e., a subscription to
the dialog package), combine with recommendations on how to handle
basic queuing at the endpoint. 

That is probably very simple, and something that is easily implementable
by
clients. 

Then we can think of "is it worth it to ADD queue management to this by
either 
mucking around with SUBSCRIBE (like the poetzl draft) or by using BFCP".

TISPAN will have to think about the tradeoffs:
- I really believe that the vast majority of implementations will not
  do this queue management stuff. It will be confined to places where
  it is somehow mandatory (if there are such places).
- The reality of the market is that the simple version will then be
  widely supported, and the complicated one will not.

So again, I'd advocate doing the simple basic stuff as the baseline, and
then
decice if it needs to be expanded with optional enhancements specific
for TISPAN.

> Sent: Thursday, April 05, 2007 18:44
> To: Audet, Francois (SC100:3055)
> Cc: SIPPING WG
> Subject: Re: [Sipping] Call Completion: In Defense of 
> Explicit Operations
> 
> Francois:
> 
> You are correct that the specific inclusion of a requirement 
> for strict call queuing to handle the once-in-a-lifetime 
> situation in which two people attempt to perform call 
> completion against the same destination is at the root of the 
> complexity. Without this requirement, call completion 
> services could be implemented using already-defined mechanisms.
> 
> Not only do I agree with your analysis; it's exactly what I 
> was trying to convey at the Dallas meeting. If I recall, the 
> pushback took the form of, "TISPAN has defined these 
> requirements, and none of them are negotiable."
> 
> It would be nice if we could get some kind of liaison 
> statement from TISPAN confirming that the use of strict 
> queuing is considered a sufficiently critical requirement to 
> warrant the relatively ridiculous complexity it introduces. 
> (Relative, that is, to the impact on user
> experience.)
> 
> /a

---

From: [email-masked]
Date: Sun, 8 Apr 2007 19:51:25 -0400

There's more to this issue than meets the eye.

First, what is the objection?

The semantic model presented in RFC 3265 is fairly simple:  There is a
"resource" whose state is a time-changing document.  UACs subscribe to
the resource to track the contents of the state document.  From this
follows various features, including (1) the state is logically prior
to the subscriptions, so the presence or absence of subscriptions does
not affect the state, (2) all subscribers see the same information,
and (3) if the machinery of a subscription (at either end) becomes
disrupted, that UA can terminate the subscription and either establish
a new one (if it is the subscriber), or force the subscriber to
establish a new one (if it is the notifier), with only momentary
interruption in functionality.  (Of course, this is a simplification.)

Other than the matter of conceptual coherence of the design of SIP, we
could ignore this if it weren't for the fact that implementations
implicitly incorporate the semantic models of the features they
implement.  E.g., in the sipX code base, there is an event server
system whose purpose is to handle all the machinery of being a
notifier.  The "application" delivers to the event server revisions to
the state documents for the resources it supports, and the event
server handles notifying the appropriate subscribers.  But this
architecture demands properties (1) and (2) above.

Another possibility is that of a proxy-like service that aggregates
and caches subscriptions, so that it can be a notifier for several
subscribers to the same resource, but it needs to make only one
subscription to the "real" notifier for the resource.  This behavior
requires (2), and may require (3) as part of its strategy for
recovering from failures.

At this point I will note that most event package definitions violate
(2) in that they incorporate a sequence number *of the NOTIFYs
delivered within a subscription* into an XML document which is
otherwise common state information.  This has turned out to add
substantial complexity and difficulty to the sipX event server.  This
is another example of why maintaining simple and consistent semantic
models is important for good software.

However, there are some escapes from these limitations by using clever
design.  For instance, subscriptions are allowed to carry attributes
that filter the information seen.  Clever definitions of filters may
be used to avoid limitation (2).

Similarly, careful design of the event package may make (2) less of a
problem than appears.  For instance, if we wish to report to each of
several UAs where it appears in a queue, without revealing to each UA
where the others are in the queue, we can represent each UA's place in
the queue by a hash of the dialog identifiers of its subscription.
Generally, each UA will be able to recognize the hash that represents
it, but it will not be able to identify the UAs represented by the
other hashes.

Dale

---

From: "Michael Hammer \(mhammer\)" <[email-masked]>
Date: Mon, 9 Apr 2007 13:55:07 -0400

Adam,

I am confused about the disconnect between the true state of the call in
the solution you proprose.  In the case of CCBS or CCNR, in fact no call
is in progress.  The initial call has failed and the service is all
about state of a queue for managing priority of the next call attempt
that should be made with the targetted party.  Your reference to a "call
queue" is off the mark.  Only one call is in progress, the one that
caused the target to be busy.  (Or none if NR)  The other callers are
free to call elsewhere or not.  Their lines are not busy with the caller
"hanging on".  That is the whole point of the feature.

Also, I thought binary floor control was about manage sessions/media
*after* a call is completed.  In this way, it seems to be tainted by the
dual operational effects you assert for a subscription-based mechanism.
If floor control for failed as well as completed calls?

And yes, interworking with the TDM version of the feature is important.

To me the Subscription model was exactly called for since this is all
about learning the state of the priority order or not only who called,
but who called and wanted to be notified in order to call again.

Mike

> Sent: Thursday, April 05, 2007 3:10 PM
> To: SIPPING WG

---

From: Adam Roach <[email-masked]>
Date: Mon, 09 Apr 2007 13:18:15 -0500

Michael Hammer (mhammer) wrote:
> queue" is off the mark.

I was being imprecise, and I apologize. Anywhere I used that term, you 
can interpret it to mean "queue of pending but not ongoing calls."

> Only one call is in progress, the one that

That was exactly my understanding, and I think this fact is relatively 
well represented in the current document.

> If floor control for failed as well as completed calls?

I believe you misunderstand what I was saying. The issue isn't that it's 
a single operation that can mean different things when used in different 
contexts -- that's okay if it's designed correctly. The place where we 
get into trouble is where we have a single instance of an operation -- 
one transaction, as it were -- that does two things simultaneously.

> And yes, interworking with the TDM version of the feature is important.

I took great pains in my proposal to preserve this quality. The problem 
could be solved in a far simpler fashion otherwise.

/a

---

From: "Michael Hammer \(mhammer\)" <[email-masked]>
Date: Mon, 9 Apr 2007 15:32:41 -0400

Adam,

My intent is not to advocate the solution as exactly like the poetzl
draft proposes, but to suggest that the SUB/NOT approach is not
inherently wrong.  The problem with the existing draft is that it tries
to treat the Subscribe like an ISUP message.

I was thinking that the set of subscriptions is state.
The in arrival order of that state is a queue.
Reaching the top of the queue (and still being able to make the call) is
an Event.
Events can be Notified.

How does the application managing the subscriptions and queue know the
caller is able to make the call?  
That could be Presence state learned through the called application
subscribing to those callers who subscribed to the CCBS/NR Top of queue
Event.

Yes, it is reciprocal.  But, in such a case SUB/NOT operates exactly as
proscribed.

The tricky part about matching the TDM CCBS is the ability to suspend
and resume without losing place in line.  The algorithm for deciding who
is next at top of queue and when to cancel the subscription would be
straight forward.

Mike

> Sent: Monday, April 09, 2007 2:18 PM
> To: Michael Hammer (mhammer)
> Cc: SIPPING WG
> > I am confused about the disconnect between the true state 
> of the call 
> > in the solution you proprose.  In the case of CCBS or CCNR, 
> in fact no 
> > call is in progress.  The initial call has failed and the 
> service is 
> > all about state of a queue for managing priority of the next call 
> > attempt that should be made with the targetted party.  Your 
> reference 
> > to a "call queue" is off the mark.
> 
> I was being imprecise, and I apologize. Anywhere I used that 
> term, you can interpret it to mean "queue of pending but not 
> ongoing calls."
> 
> > Only one call is in progress, the one that caused the target to be 
> > busy.  (Or none if NR)  The other callers are free to call 
> elsewhere 
> > or not.  Their lines are not busy with the caller "hanging 
> on".  That 
> > is the whole point of the feature.
> >   
> 
> That was exactly my understanding, and I think this fact is 
> relatively well represented in the current document.
> 
> > *after* a call is completed.  In this way, it seems to be 
> tainted by 
> > the dual operational effects you assert for a 
> subscription-based mechanism.
> I believe you misunderstand what I was saying. The issue 
> isn't that it's a single operation that can mean different 
> things when used in different contexts -- that's okay if it's 
> designed correctly. The place where we get into trouble is 
> where we have a single instance of an operation -- one 
> transaction, as it were -- that does two things simultaneously.
> 
> 
> I took great pains in my proposal to preserve this quality. 
> The problem could be solved in a far simpler fashion otherwise.
> 
> /a
>

---

From: Adam Roach <[email-masked]>
Date: Mon, 09 Apr 2007 14:54:32 -0500

> Reaching the top of the queue (and still being able to make the call) is

That's an interesting way of looking at it -- but I'm pretty sure that 
what you're describing would require two subscriptions from each caller 
to make things work.

So, basically, the caller would subscribe to the callee (or their agent) 
for some event package -- perhaps presence, perhaps dialog state, 
perhaps something else. For the sake of discussion, we'll call this 
event package "foo" for the time being.

Then, for this service, we would define a new template event package 
that deals with the relative order of subscribers' subscriptions to a 
resource. Let's call this template event package ".queue".

Then, to activate the service, your proposal basically boils down to the 
caller first subscribing to foo (which may usefully provide the calling 
party some kind of progress information about the called party -- as 
would be the case with the two example event packages I name above.) 
After this subscription succeeds, the caller would additionally 
subscribe to the event package "foo.queue", which would allow the caller 
to find out about the order in which these subscriptions... umm... 
occurred? expire? refresh? I have to admit that I get a bit lost here 
when you talk about "reaching the top of the queue is an event," since 
it's not clear where this queue comes from. It's not something that's 
inherently part of a subscription, as far as I can tell.

In any case, I concede that they might be a solution down this path, but 
you'd need to identify something that's inherently part of a 
subscription's state that has the queuing properties you want. I'm not 
convinced that such a thing exists.

And here's the crux of the matter: adding such a property to an event 
package inherently means that you're now taking "SUBSCRIBE" from meaning 
"create a subscription" to meaning "create a subscription *and* insert 
my user into a queue;" these need to be separate, explicit operations 
that succeed or fail independently.

/a

---

From: Adam Roach <[email-masked]>
Date: Mon, 09 Apr 2007 14:58:31 -0500

Michael:

Since we're having this discussion, and you seem to be one of the 
parties that has a distinctly different opinion on
the topic than I, I'd like you to comment on whether my note at the 
beginning of this thread accurately described the objections that have 
been raised to my BFCP-based proposal -- and whether my explanations 
regarding why I believe such objections are invalid contains any obvious 
fallacies.

Thanks.

/a

Michael Hammer (mhammer) wrote:
>>> And yes, interworking with the TDM version of the feature 
>>>       
>> is important.
>>     
>>>   
>>>

---

From: "Michael Hammer \(mhammer\)" <[email-masked]>
Date: Mon, 9 Apr 2007 16:47:52 -0400

Adam,

One potential weakness in your arguments is a possible assumption that
there are no intermediate boxes that have to handle the SDP and the
subsequent BFCP.  Having the additional protocol may mean additional
programming for the SBCs and other things that like to muck with the
signaling. :(  In a purer SIP world this might not be so bad.  Every new
protocol probably means asking a host of vendors:  "Do you handle
protocol X too?"

While we are at it, when I read the draft my impression was that you
never sent a 486 to end the call as busy, but kept all callers on as
early dialogs.  Did I read that right?  In some situations a client may
be able to only make one call at a time due to interface constraints.

Also, it seemed very strange to me that an INVITE would set up a session
(the BFCP) that did not end with the final response to the INVITE (a
486).  Did I read that correctly?  If so, some middleboxes would likley
shut down such connections when the INVITE gets non-success response.

Mike

> Sent: Monday, April 09, 2007 3:59 PM
> Since we're having this discussion, and you seem to be one of 
> the parties that has a distinctly different opinion on the 
> topic than I, I'd like you to comment on whether my note at 
> the beginning of this thread accurately described the 
> objections that have been raised to my BFCP-based proposal -- 
> and whether my explanations regarding why I believe such 
> objections are invalid contains any obvious fallacies.
> 
> Thanks.
> 
> /a
> 
> > inherently wrong.  The problem with the existing draft is that it 
> > tries to treat the Subscribe like an ISUP message.
> >
> > Reaching the top of the queue (and still being able to make 
> the call) 
> > is an Event.
> > Events can be Notified.
> >
> > subscribing to those callers who subscribed to the CCBS/NR Top of 
> > queue Event.
> >
> > Yes, it is reciprocal.  But, in such a case SUB/NOT 
> operates exactly 
> > as proscribed.
> >
> > and resume without losing place in line.  The algorithm for 
> deciding 
> > who is next at top of queue and when to cancel the 
> subscription would 
> > be straight forward.
> >
> > Mike
> >  
> >
> >   
> >> Subject: Re: [Sipping] Call Completion: In Defense of Explicit 
> >> Operations
> >>
> >> I was being imprecise, and I apologize. Anywhere I used that term, 
> >> you can interpret it to mean "queue of pending but not ongoing 
> >> calls."
> >>
> >>     
> isn't that 
> >> it's a single operation that can mean different things 
> when used in 
> >> different contexts -- that's okay if it's designed correctly. The 
> >> place where we get into trouble is where we have a single 
> instance of 
> >> an operation -- one transaction, as it were -- that does 
> two things 
> >> simultaneously.
> >>
> >>
> >>

---

From: Adam Roach <[email-masked]>
Date: Mon, 09 Apr 2007 15:59:52 -0500

> protocol probably means asking a host of vendors:  "Do you handle

An interesting point; however, such middleboxes typically need 
modification to handle *any* new service semantics (including, most 
probably, the SUB/NOT proposal in draft-poetzl), so I don't think it's 
that much of a differentiator.

> early dialogs.  Did I read that right?

No; the original (failed) call attempt is terminated with a 486 in this 
case. A *new* dialog is set up for the queue management.

> 486).  Did I read that correctly?

The BFCP dialog is established normally with a 200, and ends normally 
with a BYE.

For both of these cases, look at section 8.1 -- messages 1 through 6 are 
a normal failed call attempt due to a called-party-busy situation 
(INVITE/180/PRACK/200/486/ACK). Messages 7 though 9 are a normal session 
establishment for a BFCP-only session (INVITE/200/ACK). Messages 15 
through 20 are the call re-attempt, which establishes a normal voice 
call (INVITE/180/PRACK/200/200/ACK). Messages 22 and 23 tear down the 
BFCP-only session (BYE/200).

Does that make the proposed mechanism clearer?

/a

---

From: "Michael Hammer \(mhammer\)" <[email-masked]>
Date: Mon, 9 Apr 2007 17:13:36 -0400

Ok, that makes things clearer.

BTW, do you release the floor before you finish the call that got
through because of the floor request?

Mike

> Sent: Monday, April 09, 2007 5:00 PM
> > signaling. :(  In a purer SIP world this might not be so 
> bad.  Every 
> > new protocol probably means asking a host of vendors:  "Do 
> you handle 
> > protocol X too?"
> >   
> 
> An interesting point; however, such middleboxes typically 
> need modification to handle *any* new service semantics 
> (including, most probably, the SUB/NOT proposal in 
> draft-poetzl), so I don't think it's that much of a differentiator.
> 
> No; the original (failed) call attempt is terminated with a 
> 486 in this case. A *new* dialog is set up for the queue management.
> 
> > Also, it seemed very strange to me that an INVITE would set up a 
> > session (the BFCP) that did not end with the final response to the 
> > INVITE (a 486).  Did I read that correctly?
> 
> The BFCP dialog is established normally with a 200, and ends 
> normally with a BYE.
> 
> For both of these cases, look at section 8.1 -- messages 1 
> through 6 are a normal failed call attempt due to a 
> called-party-busy situation (INVITE/180/PRACK/200/486/ACK). 
> Messages 7 though 9 are a normal session establishment for a 
> BFCP-only session (INVITE/200/ACK). Messages 15 through 20 
> are the call re-attempt, which establishes a normal voice 
> call (INVITE/180/PRACK/200/200/ACK). Messages 22 and 23 tear 
> down the BFCP-only session (BYE/200).
>

---

From: Adam Roach <[email-masked]>
Date: Mon, 09 Apr 2007 16:20:06 -0500

> through because of the floor request?

That's an interesting question. Currently, the document shows the floor 
being released by the caller as soon as the call re-attempt succeeds. It 
would probably be more semantically correct to have the caller hold the 
floor until the call is concluded. In practice, this strikes me as a 
fairly minor detail that can be ironed out later (and I believe one can 
make reasonable arguments both ways).

/a

>>> One potential weakness in your arguments is a possible 
>>>       
>> assumption that 
>>     
>>> subsequent BFCP.  Having the additional protocol may mean 
>>>       
>> additional 
>>     
>>> programming for the SBCs and other things that like to muck 
>>>       
>> with the 
>>     
>>> While we are at it, when I read the draft my impression was 
>>>       
>> that you 
>>     
>>> never sent a 486 to end the call as busy, but kept all 
>>>       
>> callers on as 
>>

---

From: "Xavier Marjou" <[email-masked]>
Date: Tue, 10 Apr 2007 15:08:59 +0200

>    3. "We don't want to add another protocol."

Although I understand motivations to re-use BFCP, I am in favor of a
SIP-only solution, based on the following considerations:

- First, as some people raised it, there's also some analogy between
CCBS and Presence. Should Presence have been integrated into a media
stream (eg: XMPP stream negotiated by SIP) or based on SIP signalling
only? This was debatable as the 2 choices seem technically feasible.
Nevertheless, the situation is that Presence is definitely possible
with SIP signalling only. Now, can we blame a CCBS solution based on a
similar approach?

- BFCP used as a media stream makes sense to control media streams.
Using a media stream (BFCP) to implement CCBS, the media stream would
control SIP signalling actions. I'm not sure wether we want to go in
that direction. You already gave 2 issues that have been raised.
Though I have no other example coming to my mind, we may encounter
more interaction issues of this kind by dispatching controlling
between SIP and a media stream.

- With a SIP only approach, we can hope for a single draft. With a
BFCP approach, we will probably need drafts in XCON, MMUSIC, and
perhaps also in SIPPING and MEDIACTRL, which means a lot of time and
efforts before having a solution for this nice feature.

Xavier

---

From: Adam Roach <[email-masked]>
Date: Tue, 10 Apr 2007 08:23:03 -0500

Xavier Marjou wrote:
> CCBS and Presence.

Inasmuch as a system that properly utilizes presence doesn't need a call 
completion service, this is true. That's where the analogy lies, and one 
shouldn't read too much into it in terms of what a solution might look 
like that implements call completion *without* presence information.

> Should Presence have been integrated into a media
> with SIP signalling only.

Yes, and we did so by adding a set of methods -- because none of the 
existing SIP methods had appropriate semantics for subscriptions.

> Now, can we blame a CCBS solution based on a
> similar approach?

Yes, we can. In early conversations on the call completion service, I 
clearly pointed out that adding a new method (or set of methods) to SIP 
for queue manipulation would be a potential solution to the problem.

The key point being that none of the existing SIP methods have 
appropriate semantics for queue manipulation. If you want to do this in 
SIP, you'll need to add one or more new methods.

> that direction. You already gave 2 issues that have been raised.

I gave two _misconceptions_ that have been voiced and corrected. They 
are not valid objections.

> between SIP and a media stream.

And we know for a *fact* that implicit side effects and crafting single 
operations with multiple, disjoint effects *does* cause problems, with a 
track record of exactly how. (I cited these in my initial mail on this 
thread; you can go back to read them there).

> efforts before having a solution for this nice feature.

XCON: probably not. I'll talk to the XCON chairs about whether this 
would fall under their charter. :)  BFCP isn't limited to XCON for 
extensions; this could (and probably would) be done in SIPPING.

MMUSIC: True.

SIPPING: True.

MEDIACTRL: Um.... no.

So, yes, we do end up adding one more working group to the mix -- but 
that hardly seems a valid reason to head down a path that we know is 
technically wrong.

/a

---

From: "Michael Hammer \(mhammer\)" <[email-masked]>
Date: Tue, 10 Apr 2007 10:07:29 -0400

Adam,

One final comment from me.  I originally went with presence because when
you step back and look at what the CCBS or CCNR features are all about
it is about the presence of the caller and called parties and the
ability to accept a call.  Although you have shown that media control
can be used to achieve the same effect, I think that there has not been
sufficient thought put into a presence-based approach.

Mike

> Sent: Tuesday, April 10, 2007 9:23 AM
> To: Xavier Marjou
> Cc: SIPPING WG
> Inasmuch as a system that properly utilizes presence doesn't 
> need a call completion service, this is true. That's where 
> the analogy lies, and one shouldn't read too much into it in 
> terms of what a solution might look like that implements call 
> completion *without* presence information.
> 
> > Should Presence have been integrated into a media stream (eg: XMPP 
> > stream negotiated by SIP) or based on SIP signalling only? This was 
> > debatable as the 2 choices seem technically feasible.
> Yes, and we did so by adding a set of methods -- because none 
> of the existing SIP methods had appropriate semantics for 
> subscriptions.
> 
> > Now, can we blame a CCBS solution based on a similar approach?
> 
> Yes, we can. In early conversations on the call completion 
> service, I clearly pointed out that adding a new method (or 
> set of methods) to SIP for queue manipulation would be a 
> potential solution to the problem.
> 
> The key point being that none of the existing SIP methods 
> have appropriate semantics for queue manipulation. If you 
> want to do this in SIP, you'll need to add one or more new methods.
> 
> I gave two _misconceptions_ that have been voiced and 
> corrected. They are not valid objections.
> 
> And we know for a *fact* that implicit side effects and 
> crafting single operations with multiple, disjoint effects 
> *does* cause problems, with a track record of exactly how. (I 
> cited these in my initial mail on this thread; you can go 
> back to read them there).
> 
> 
> XCON: probably not. I'll talk to the XCON chairs about 
> whether this would fall under their charter. :)  BFCP isn't 
> limited to XCON for extensions; this could (and probably 
> would) be done in SIPPING.
> 
> MMUSIC: True.
> 
> SIPPING: True.
> 
> MEDIACTRL: Um.... no.
> 
> So, yes, we do end up adding one more working group to the 
> mix -- but that hardly seems a valid reason to head down a 
> path that we know is technically wrong.
> 
> /a
> 
> Use [email-masked] for questions on current 
> sip Use [email-masked] for new developments of core SIP
>

---

From: [email-masked]
Date: Tue, 10 Apr 2007 11:48:55 -0400

From: Adam Roach <[email-masked]>

Worse, we're talking about adding side effects to a method that
previously did not have them.  That pretty much guarantees that any
generic implementation of SUBSCRIBE/NOTIFY will have to be changed.

Dale

---

From: Adam Roach <[email-masked]>
Date: Tue, 10 Apr 2007 12:35:19 -0500

Michael Hammer (mhammer) wrote:
> ability to accept a call.

I agree wholeheartedly. If there were a way to reliably subscribe to the 
presence state of a PSTN user, that would be the incontestable, obvious 
way to implement this. While my TCAP knowledge is rusty, I don't think 
there's a way to do this directly.

>   Although you have shown that media control

As Francois and I discussed earlier, it would be a rather 
straightforward exercise to define this service using existing tools, 
*except* for the queue management aspect of the service. That's why I've 
been making arguments that an alternate way to clear the logjam would be 
removal of the queueing requirement.

If we can't do that, we need some mechanism to handle the queueing -- 
and SUBSCRIBE/NOTIFY aren't queue management methods.

/a

---

From: "Vijay K. Gurbani" <[email-masked]>
Date: Tue, 10 Apr 2007 12:43:18 -0500

> there's a way to do this directly.

There was work done in the SPIRITS WG that enabled presence
state of a PSTN user using SUBS/NOT event packages in rfc3910.

- vijay
-- 
Vijay K. Gurbani, Bell Laboratories, Alcatel-Lucent
2701 Lucent Lane, Rm. 9F-546, Lisle, Illinois 60532 (USA)
Email: vkg@{alcatel-lucent.com,bell-labs.com,acm.org}
WWW:   http://www.alcatel-lucent.com/bell-labs

---

From: Adam Roach <[email-masked]>
Date: Tue, 10 Apr 2007 12:59:05 -0500

Vijay K. Gurbani wrote:
> Adam Roach wrote:
>> I agree wholeheartedly. If there were a way to reliably subscribe to 
>> the presence state of a PSTN user, that would be the incontestable, 
>> obvious way to implement this. While my TCAP knowledge is rusty, I 
>> don't think there's a way to do this directly.
>

Ah, yes. By hooking into an SCP, it would certainly be possible to 
determine this information. Somehow I doubt that such a solution would 
be acceptable to TISPAN, since it requires significant software upgrades 
of the called-party end office equipment (even assuming it already has 
generic IN capabilities). Of course, we *could* ask our TISPAN or ETSI 
liaison whether this approach would meet their requirements -- except 
that we don't seem to have one.

  http://www.ietf.org/liaisonActivities.html

/a

---

From: Dean Willis <[email-masked]>
Date: Tue, 10 Apr 2007 13:40:55 -0500

On Apr 10, 2007, at 12:35 PM, Adam Roach wrote:

>
> If we can't do that, we need some mechanism to handle the queueing  
> -- and SUBSCRIBE/NOTIFY aren't queue management methods.
>

I've been pondering that assertion, and can't see why the queue  
modeled as a document with filtering on what part of the document is  
visible isn't a reasonable approach to an event package.

--
Dean

---

From: Adam Roach <[email-masked]>
Date: Tue, 10 Apr 2007 14:09:00 -0500

> visible isn't a reasonable approach to an event package.

Interesting. Continue.

No, really -- what state is the user subscribing to? What changes this 
state? How is the filter being specified? How does a user's position in 
the queue get suspended? Resumed?

I'm not 100% convinced that it can't be done, but I've spent hours 
trying to figure out some way of doing this without having implicit 
operations invoked. It's gonna take someone smarter than I to figure out 
how to make this work in a way that is consistent with the defined 
semantics of SUBSCRIBE and NOTIFY -- so maybe your proposal makes sense; 
but, without more detail, it's not clear how.

Because, on the surface, the problem seems intractable without new 
operations for queue management.

/a

---

From: "Huelsemann, Martin" <[email-masked]>
Date: Wed, 11 Apr 2007 11:46:47 +0200

I think the part of the solution where are no doubts is that we can use SUB/NOT to inform the user about his call-completion state (queued, or he is the one who shall start the recall). IF we decide for a SIP solution, which I think we should do if there are no technical reasons against, because BFCP seem to be easy to implement with the necassary knowledge, but it is still another protocol. 

The question is, when SUBSCRIBEs are used anyway, why can't we reuse them for queue manipulation actions? Why put another RFC into the terminal, when RFC 3265 would be enough. The simpler those terminals are, the cheaper they will be, and the more people will use them. 

Yes, using the SUBSCRIBE also for queue manipulations would be one operation with two effects, but where is the harm? There is a similar use in the policy package, which submits an SDP in the SUBSCRIBE request and gets back a policy for that SDP in the NOTIFY request.

Adam, you are of course the expert for RFC 3265, and if you say such a usage breaks SUB/NOT because of certain reasons, then we certainly have to look for another solution. But if SUB/NOT was not intended for such a use, but it can be done, I think we can keep things simpler if we consider the solution of the Poetzl draft.

Regards, Martin

> -----Ursprüngliche Nachricht-----
> Von: Adam Roach [mailto:[email-masked]] 
> Gesendet: Dienstag, 10. April 2007 21:09
> An: Dean Willis
> Cc: SIPPING WG; Xavier Marjou; Michael Hammer (mhammer)
> Betreff: Re: [Sipping] Call Completion: In Defense of 
> Explicit Operations
> 
> 
> Dean Willis wrote:

---

From: Paul Kyzivat <[email-masked]>
Date: Wed, 11 Apr 2007 10:15:43 -0400

> Yes, using the SUBSCRIBE also for queue manipulations would be one operation with two effects, but where is the harm? There is a similar use in the policy package, which submits an SDP in the SUBSC…

Lets go through this again:

Suppose it does work that way. Then conceptually what is the event state 
that is being subscribed to? Apparently it is the queue of potential 
callers. In principle, every time this state changes there should be a 
notification sent to *all* the subscribers.

Now it could be that policy is used to restrict how much visibility 
subscribers have to the event state. So the views of some may be such 
that they can't see the change, and so get no notification of it. But 
arranging things that way requires structuring the state very carefully. 
For instance, the policy might state that a subscriber can only see 
entries that refer to them. But this wouldn't be very interesting unless 
their entry included "position in queue". That would result in getting a 
notification each time your entry advanced in the queue. If that is 
annoying there could be a filter that says to only display entries that 
are "first in queue".

None of that says anything about queue manipulation - just using sub/not 
to observer a queue in a useful way for this purpose.

Note that we do have an example where the act of subscribing creates 
state that can itself be subscribed to. It is watcherinfo. But in that 
case there are two event packages in use - e.g. presence and 
presence.watcherinfo. Subscribing to presence creates watcher state that 
can be observed by subscribing to presence.watcherinfo. Having a 
SUBSCRIBE modify the state of the event being subscribed to introduces a 
sort of Heisenberg Uncertainty Principle - you can't observe the event 
without affecting it.

Specifically, it becomes impossible to observe the queue without 
becoming one of the requesters. For instance, suppose the queue was 
managed on a server separate from the UAs that receive calls to the 
target AOR. They may want to observe the queue themselves. But 
attempting to do so would seem to cause them to become candidates to 
call themself. This could be mitigated by requesting that the entry be 
suspended, but the point remains.

Further manipulation of the queue, such as suspend and resume, also 
doesn't seem to fit the sub/not model very well. If its done as part of 
the body (as the current draft specifies) then it should be considered a 
filter, but filters don't change state of the event - only the view of 
it. There isn't any good place to specify this kind of action in a 
subscribe request, for the obvious reason that SUBSCRIBE isn't intended 
to be used in that way.

I have seen reference to the policy event package as precedent for using 
bodies to create the state being subscribed to. I think that case is 
less of a problem because it does fall into a suitable conceptual model 
as a filter. In theory one is subscribing to all policies. Supplying a 
body can be viewed as simply a filter restricting notifications to ones 
pertaining to a particular set of media, etc.

	Paul

---

From: Adam Roach <[email-masked]>
Date: Wed, 11 Apr 2007 09:55:18 -0500

Thank you, Paul. You've summarized the key points in a very coherent 
fashion.

/a

Paul Kyzivat wrote:
>> I think the part of the solution where are no doubts is that we can 
>> use SUB/NOT to inform the user about his call-completion state 
>> (queued, or he is the one who shall start the recall). IF we decide 
>> for a SIP solution, which I think we should do if there are no 
>> technical reasons against, because BFCP seem to be easy to implement 
>> with the necassary knowledge, but it is still another protocol.
>> The question is, when SUBSCRIBEs are used anyway, why can't we reuse 
>> them for queue manipulation actions? Why put another RFC into the 
>> terminal, when RFC 3265 would be enough. The simpler those terminals 
>> are, the cheaper they will be, and the more people will use them.
>> Yes, using the SUBSCRIBE also for queue manipulations would be one 
>> operation with two effects, but where is the harm? There is a similar 
>> use in the policy package, which submits an SDP in the SUBSCRIBE 
>> request and gets back a policy for that SDP in the NOTIFY request.
>
> Suppose it does work that way. Then conceptually what is the event 
> state that is being subscribed to? Apparently it is the queue of 
> potential callers. In principle, every time this state changes there 
> should be a notification sent to *all* the subscribers.
>
> arranging things that way requires structuring the state very 
> carefully. For instance, the policy might state that a subscriber can 
> only see entries that refer to them. But this wouldn't be very 
> interesting unless their entry included "position in queue". That 
> would result in getting a notification each time your entry advanced 
> in the queue. If that is annoying there could be a filter that says to 
> only display entries that are "first in queue".
>
> None of that says anything about queue manipulation - just using 
> sub/not to observer a queue in a useful way for this purpose.
>
> presence.watcherinfo. Subscribing to presence creates watcher state 
> that can be observed by subscribing to presence.watcherinfo. Having a 
> SUBSCRIBE modify the state of the event being subscribed to introduces 
> a sort of Heisenberg Uncertainty Principle - you can't observe the 
> event without affecting it.
>
> doesn't seem to fit the sub/not model very well. If its done as part 
> of the body (as the current draft specifies) then it should be 
> considered a filter, but filters don't change state of the event - 
> only the view of it. There isn't any good place to specify this kind 
> of action in a subscribe request, for the obvious reason that 
> SUBSCRIBE isn't intended to be used in that way.
>
> I have seen reference to the policy event package as precedent for 
> using bodies to create the state being subscribed to. I think that 
> case is less of a problem because it does fall into a suitable 
> conceptual model as a filter. In theory one is subscribing to all 
> policies. Supplying a body can be viewed as simply a filter 
> restricting notifications to ones pertaining to a particular set of 
> media, etc.
>
>     Paul

---

From: Dean Willis <[email-masked]>
Date: Wed, 11 Apr 2007 11:18:52 -0500

On Apr 10, 2007, at 2:09 PM, Adam Roach wrote:

> Dean Willis wrote:
>>> If we can't do that, we need some mechanism to handle the  
>>> queueing -- and SUBSCRIBE/NOTIFY aren't queue management methods.
>>>
>>
>>
>> modeled as a document with filtering on what part of the document  
>> is visible isn't a reasonable approach to an event package.
>
> Interesting. Continue.
>
> No, really -- what state is the user subscribing to? What changes  
> this state? How is the filter being specified? How does a user's  
> position in the queue get suspended? Resumed?
>

It's not all that different from sip config.

The state is the content of a document describing the queue, which  
could certainly be modeled in XML, versioned with etag, and so on.

The document is modified by the queue manager, for example by adding  
a queue element, changing the pointer to the "current" queue element,  
or deleting a queue element. It might contain explicit ordering or  
priority rankings.

One can envision that the queue manager's operations on the document  
would be driven by events outside of subscriptions to the queue  
state, just as changes in sip-config documents or resource lists are  
driven by events outside of subscriptions to those documents.

Filtering is the tricky question. Let's step back and see what the  
requirements are:

1) The watcher needs to know when they're the "current" element and  
should make a call.

2) We MAY have a requirement to give the watcher some sense of  
position in the queue, as in "There are currently 487 callers ahead  
of you".

3) We MUST NOT disclose the identity of other pending callers.

4) We need to be able to change the state of the queue to "suspended"  
when the queue target is busy, either in dealing with a queued call  
or an outside call.

5) We probably have a need to correlate incoming calls against the  
queue set, so that callers who are not currently pending can be  
enqueued instead of preempting the queue.

So let's take a simplistic approach for initial analysis: the queue  
consists of an ordered set of elements (a vector), each of which  
represents either one pending call or the "suspended" state. The  
first element is the "active" element. If a watcher of this document  
sees that the first element corresponds to them, they launch a new  
INVITE, using some component of the element as a parameter so that  
the queue manager can match them up. If the queue is in a suspended  
state, the first element is one which encodes "suspended".

This seems to satisfy requirements 1,2,4, and 5 above.

Let's play a bit with #4 -- disclosing of identity of pending call  
sources.

One possibility is to use an opaque token per caller (which might be  
the same token that is used in the call setup). Alice calls into Bob,  
gets a response containing a queue URI and a token for her position.  
She watches the queue until her token comes up to the top, then calls  
in.

The above works just fine, but raises the possibility of "queue  
jumping" -- an aggressive watcher might just take whatever token is  
currently at the top and use it.

We could offset this by adding a filter. One approach might be for  
the queue-watching subscription to include the token-of-interest,  
which would be applied by the queue manager (which is serving as the  
event source). On a per-subscription basis, the queue manager would  
"mask" tokens other than the "token of interest" for that  
subscription with a dummy value.

So Alice, who is subscribed to the callback queue for Bob, might  
receive a NOTIFY containing a queue document with a "suspended"  
element, three "dummy" elements, an element containing her token, and  
two more "dummy" elements. From this she would know that the queue is  
currently blocked, there are three callers ahead of her, and two  
callers behind her. Moments later, she might see a new NOTIFY without  
the "suspended" element at its head, and deduce that the last caller  
is now off the line and a new one likely to be calling in. Eventually  
she receives a NOTIFY with a queue document with her token at the  
head, and calls in.

Myriad other queue representations and filtration strategies seem  
feasible depending on what constraints one wishes to adopt.

The important thing is to keep in mind that the queue is a document  
being edited by an application whose operation is driven by  
information (perhaps other subscriptions, such as presence) that is  
EXTERNAL to the queue itself.

I think this fits into the basic SUBSCRIBE/NOTIFY framework.

--
Dean

---

From: Dean Willis <[email-masked]>
Date: Wed, 11 Apr 2007 11:29:21 -0500

On Apr 11, 2007, at 9:15 AM, Paul Kyzivat wrote:

>> I think the part of the solution where are no doubts is that we  
>> can use SUB/NOT to inform the user about his call-completion state  
>> (queued, or he is the one who shall start the recall). IF we  
>> decide for a SIP solution, which I think we should do if there are  
>> no technical reasons against, because BFCP seem to be easy to  
>> implement with the necassary knowledge, but it is still another  
>> protocol. The question is, when SUBSCRIBEs are used anyway, why  
>> can't we reuse them for queue manipulation actions? Why put  
>> another RFC into the terminal, when RFC 3265 would be enough. The  
>> simpler those terminals are, the cheaper they will be, and the  
>> more people will use them. Yes, using the SUBSCRIBE also for queue  
>> manipulations would be one operation with two effects, but where  
>> is the harm? There is a similar use in the policy package, which  
>> submits an SDP in the SUBSCRIBE request and gets back a policy for  
>> that SDP in the NOTIFY request.
>
> potential callers. In principle, every time this state changes  
> there should be a notification sent to *all* the subscribers.
>
> subscribers have to the event state. So the views of some may be  
> such that they can't see the change, and so get no notification of  
> it. But arranging things that way requires structuring the state  
> very carefully. For instance, the policy might state that a  
> subscriber can only see entries that refer to them. But this  
> wouldn't be very interesting unless their entry included "position  
> in queue". That would result in getting a notification each time  
> your entry advanced in the queue. If that is annoying there could  
> be a filter that says to only display entries that are "first in  
> queue".
>

Yes, that's the model my previous post expanded on.

> Note that we do have an example where the act of subscribing  
> creates state that can itself be subscribed to. It is watcherinfo.  
> But in that case there are two event packages in use - e.g.  
> presence and presence.watcherinfo. Subscribing to presence creates  
> watcher state that can be observed by subscribing to  
> presence.watcherinfo. Having a SUBSCRIBE modify the state of the  
> event being subscribed to introduces a sort of Heisenberg  
> Uncertainty Principle - you can't observe the event without  
> affecting it.
>

So the open question is how does one get into the queue without  
having that insertion be a side-effect of the subscription itself?

Two options:

1) Automatically enqueue all callers when there is a queue.

2) Redirect (or indirect via a new header field) callers to a queue  
factory when there is a queue. If they follow the indirection, they  
get enqueued.

> attempting to do so would seem to cause them to become candidates  
> to call themself. This could be mitigated by requesting that the  
> entry be suspended, but the point remains.

I concur that insertion into the queue and subscription to the queue  
must be different things. That seems obvious, so I must have missed  
the idea that they were intertwingled (or dismissed it as just silly).

> doesn't seem to fit the sub/not model very well. If its done as  
> part of the body (as the current draft specifies) then it should be  
> only the view of it. There isn't any good place to specify this  
> kind of action in a subscribe request, for the obvious reason that  

Operations on the queue data itself are clearly outside of the  
"watcher" package. If the queue notification is handled on a node  
that is different from the node with the data that drives the queue,  
then we have XCAP to manipulate the queue document and make  
insertions, etc.

--
Dean

---

From: "Huelsemann, Martin" <[email-masked]>
Date: Wed, 11 Apr 2007 18:33:46 +0200

So what is really meant by (and explained really badly in) the Poetzl draft is that a user subscribes to his own call-completion state, and the events he is informed of are the transition of his state from any state to the 'queued' state and from any state to the 'start the recall' state.
The notifier has to derive this state from the state of the call-completion queue. The nature of the queue and how the call-completion state for a user is derived from the queue are not explained, but it is assumed that the queue and the notifier are collocated and can interact. A FIFO queue could be a suitable basis for the queue, although other models are not precluded.
 
True is that the user's subscription also creates the resource, which is his own call-completion state. The question is, is that problematical, and why? 

The next question of course would be, is it problematical to transport bodies with queue manipulation information within the SUBSCRIBEs. 
On the other hand, you can interprete suspending and resuming as something like a filter, too. Nothing changes, neither the call-completion queue, the user's position remains the same, nor the resource, the call-completion state of a user remains 'queued'. The user just doesn't receive NOTIFYs for a certain time. Only after resuming the call-completion state might change, but then because of B has become not busy again.

Martin

> Von: Paul Kyzivat [mailto:[email-masked]] 
> Gesendet: Mittwoch, 11. April 2007 16:16
> An: Hülsemann, Martin
> Cc: [email-masked]; [email-masked]
> Betreff: Re: AW: [Sipping] Call Completion: In Defense of 
> Explicit Operations
> 
> 
> 
> 
> > I think the part of the solution where are no doubts is 
> that we can use SUB/NOT to inform the user about his 
> call-completion state (queued, or he is the one who shall 
> start the recall). IF we decide for a SIP solution, which I 
> think we should do if there are no technical reasons against, 
> because BFCP seem to be easy to implement with the necassary 
> knowledge, but it is still another protocol. 
> > 
> > The question is, when SUBSCRIBEs are used anyway, why can't 
> we reuse them for queue manipulation actions? Why put another 
> RFC into the terminal, when RFC 3265 would be enough. The 
> simpler those terminals are, the cheaper they will be, and 
> the more people will use them. 
> > 
> > Yes, using the SUBSCRIBE also for queue manipulations would 
> be one operation with two effects, but where is the harm? 
> There is a similar use in the policy package, which submits 
> an SDP in the SUBSCRIBE request and gets back a policy for 
> carefully.

---

From: Paul Kyzivat <[email-masked]>
Date: Wed, 11 Apr 2007 12:51:56 -0400

> The notifier has to derive this state from the state of the call-completion queue. The nature of the queue and how the call-completion state for a user is derived from the queue are not explained,…

Yes, this is one way to look at the proposal. I posted an earlier reply 
with a similar interpretation.

> True is that the user's subscription also creates the resource, which is his own call-completion state. The question is, is that problematical, and why? 

Agreed.

I think it is problematical. For instance, if the subscription gets 
terminated for some reason, position in queue is lost. One may be able 
to establish a new subscription, but then goes to the end of the line. 
This could be a problem for instance with a mobile device that loses 
connectivity for a period of time.

> On the other hand, you can interprete suspending and resuming as something like a filter, too. Nothing changes, neither the call-completion queue, the user's position remains the same, nor the reso…

Suspending has more of an effect that that. If I understand the intent, 
calls are only to be accepted from the currently selected candidate, 
which is the entry nearest to the top of the queue that is not 
suspended. So suspending has effect on the state of the queue, rather 
than simply being a filter on the subscription.

	Paul

---

From: Adam Roach <[email-masked]>
Date: Wed, 11 Apr 2007 12:49:44 -0500

Dean:

Yes, yes, yes!

What you say below is absolutely correct. Defining an event package that 
subscribes -- unobtrusively -- to a queue state is a perfectly valid 
**part** of a solution. (It's not what I proposed in my draft because 
such notification would be redundant with BFCP mechanisms -- but if 
there were some other sensible way to manipulate the queue, it would 
have been exactly what I would have proposed).

In particular, you make a point that is precisely congruent with the key 

> EXTERNAL to the queue itself.

Yes! Absolutely! That is completely and utterly correct! And that is 
what is primarily wrong with draft-poetzl.

/a

Dean Willis wrote:
> The document is modified by the queue manager, for example by adding a 
> queue element, changing the pointer to the "current" queue element, or 
> deleting a queue element. It might contain explicit ordering or 
> priority rankings.
>
> would be driven by events outside of subscriptions to the queue state, 
> just as changes in sip-config documents or resource lists are driven 
> by events outside of subscriptions to those documents.
>
> position in the queue, as in "There are currently 487 callers ahead of 
> you".
>
> when the queue target is busy, either in dealing with a queued call or 
> an outside call.
>
> represents either one pending call or the "suspended" state. The first 
> element is the "active" element. If a watcher of this document sees 
> that the first element corresponds to them, they launch a new INVITE, 
> using some component of the element as a parameter so that the queue 
> manager can match them up. If the queue is in a suspended state, the 
> first element is one which encodes "suspended".
>
> She watches the queue until her token comes up to the top, then calls in.
>
> We could offset this by adding a filter. One approach might be for the 
> queue-watching subscription to include the token-of-interest, which 
> would be applied by the queue manager (which is serving as the event 
> source). On a per-subscription basis, the queue manager would "mask" 
> tokens other than the "token of interest" for that subscription with a 
> dummy value.
>

---

From: Dean Willis <[email-masked]>
Date: Wed, 11 Apr 2007 13:16:24 -0500

On Apr 11, 2007, at 12:49 PM, Adam Roach wrote:

> Dean:
>
> Yes, yes, yes!
>
> What you say below is absolutely correct. Defining an event package  
> that subscribes -- unobtrusively -- to a queue state is a perfectly  
> valid **part** of a solution. (It's not what I proposed in my draft  
> because such notification would be redundant with BFCP mechanisms  
> -- but if there were some other sensible way to manipulate the  
> queue, it would have been exactly what I would have proposed).
>
> In particular, you make a point that is precisely congruent with  
> the key point that I've been trying to make; to wit:
>
>> The important thing is to keep in mind that the queue is a  
>> document being edited by an application whose operation is driven  
>> by information (perhaps other subscriptions, such as presence)  
>> that is EXTERNAL to the queue itself.
>
> Yes! Absolutely! That is completely and utterly correct! And that  
> is what is primarily wrong with draft-poetzl.
>

So it would be reasonable to say that it is not the concept of an  
event package for call completion that bothers you. It's the  
intertwingling of "subscription to the events" and "enrollment in the  
queue" that bothers you. That would bother me too -- I think I simply  
assumed that aspect of the Poetzl draft was a misunderstanding that  
remained to be worked out, because it clearly doesn't work right.

This should be resolvable, because it's relatively straightforward to  
use an INVITE side-effect (aka a "factory") to enqueue. The cleanest  
approach might require an additional 4xx response code, semantic  
"enqueued", along with a new header field for returning the queue  
URI. I suppose one could simply use the new header field along with a  
480 (Temporarily Unavailable) response code as an even lighter solution.

What's the remaining problem? Manipulating the queue itself? Why is  
that a problem?

--
Dean

---

From: Adam Roach <[email-masked]>
Date: Wed, 11 Apr 2007 13:29:02 -0500

Dean Willis wrote:
> So the open question is how does one get into the queue without having 
> that insertion be a side-effect of the subscription itself?
>
> Two options:
>

Interesting approach -- I'm not sure how well it will work in practice, 
because you'll end up having to wait for the queue of missed calls from 
disinterested parties to drain before your position percolates to the 
top of the queue. It's probably solvable, but we'd need to come up with 
something.

> factory when there is a queue. If they follow the indirection, they 

Ooh. Run this one by Dave Oran. Perhaps we can get him to give his 
"To-Explode-My-Phone:" speech again.

> the idea that they were intertwingled (or dismissed it as just silly).

Yes, they must be different things. Yes, this is obvious. Yes, it is 
silly to propose that they be combined into the same operation. Yes, 
this very silly thing is at the core of the draft-poetzl proposal.

> "watcher" package. If the queue notification is handled on a node that 
> is different from the node with the data that drives the queue, then 
> we have XCAP to manipulate the queue document and make insertions, etc.

_That's_ interesting. I hadn't thought of that. So, instead of using 
BFCP (as my current proposal suggests), we could use an event package to 
unobtrusively subscribe to a queue, and XCAP to place ourselves in, 
pause, resume, and remove ourselves from the queue.

That seems quite reasonable. I'd be interested to see what other people 
have to say about it.

/a

---

From: David R Oran <[email-masked]>
Date: Wed, 11 Apr 2007 14:56:01 -0400

On Apr 11, 2007, at 2:29 PM, Adam Roach wrote:

> Interesting approach -- I'm not sure how well it will work in  
> practice, because you'll end up having to wait for the queue of  
> missed calls from disinterested parties to drain before your  
> position percolates to the top of the queue. It's probably  
> solvable, but we'd need to come up with something.
>
>> 2) Redirect (or indirect via a new header field) callers to a  
>> queue factory when there is a queue. If they follow the  
>> indirection, they get enqueued.
>
I'm not sure I'd use a 305 redirect. If we had hexadecimal response  
codes, I'd suggest assigning 3-C4.

Seriously though, if we make "holding queues" first-class objects  
(i.e. they have URIs) then one might instead think of this  
analogously to call park, where you can park yourself and get  
notified through the queue/park agent by REFER to try they original  
call again. What does seem common to any SIP-only approach is the  
notion that the caller has an active dialog with *something* until  
such time as he gets to re-try the call to the original callee or  
abandon the operation.

>> I concur that insertion into the queue and subscription to the  
>> queue must be different things. That seems obvious, so I must have  
>> missed the idea that they were intertwingled (or dismissed it as  
>> just silly).
>
> Yes, they must be different things. Yes, this is obvious. Yes, it  
> is silly to propose that they be combined into the same operation.  
> Yes, this very silly thing is at the core of the draft-poetzl  
> proposal.
>
This seems to be one point which is common to the objections to using  
the subscribe/notify machinery. I agree too.

>> that is different from the node with the data that drives the  
>> queue, then we have XCAP to manipulate the queue document and make  
>> insertions, etc.
>
> _That's_ interesting. I hadn't thought of that. So, instead of  
> using BFCP (as my current proposal suggests), we could use an event  
> package to unobtrusively subscribe to a queue, and XCAP to place  
> ourselves in, pause, resume, and remove ourselves from the queue.
>
> That seems quite reasonable. I'd be interested to see what other  
> people have to say about it.
>
If what we want to model is a queue, this makes sense. On the other  
hand, the externally visible behavior does not inherently require a  
queue, in the sense of allowing operations such as head(), tail(),  
count(), enqueue_head(), enqueue_tail(), etc.

---

From: Adam Roach <[email-masked]>
Date: Wed, 11 Apr 2007 14:48:19 -0500

Dean Willis wrote:
> queue" that bothers you.

Reasonable and accurate.

> That would bother me too -- I think I simply assumed that aspect of 
> the Poetzl draft was a misunderstanding that remained to be worked 
> out, because it clearly doesn't work right.
>
> "enqueued", along with a new header field for returning the queue URI. 
> I suppose one could simply use the new header field along with a 480 
> (Temporarily Unavailable) response code as an even lighter solution.

There's probably a mechanism in that direction -- somehow communicating 
a factory URI for the purpose of enqueueing, using INVITE (open issue: 
to what kind of session? Media-free?) to enqueue, and tearing down the 
session to dequeue.

(The "new header field with a URI for activating a feature" proposal is 
why I invoked Dave Oran, referring to his impassioned speech at the 
London IETF SIP meeting arguing _against_ the use of feature-specific 
header fields containing URIs for activating the corresponding feature. 
The reductio ad absurdum he used was a header field called 
"To-Explode-My-Phone:", containing a request URI, presumably used for 
that purpose. At the time, I thought he had a good point, but I can't 
seem to reconstitute the argument at the moment.)

> What's the remaining problem? Manipulating the queue itself? Why is 

Your question implies that you think this is a solved problem. Great! In 
that case, it would be no problem for you to answer the following two 
questions:

   1. How does the queued caller pause their position in the queue?
   2. How does the queued caller un-pause their position in the queue?

/a

---

From: [email-masked]
Date: Wed, 11 Apr 2007 17:21:44 -0400

From: "Huelsemann, Martin" <[email-masked]>

   True is that the user's subscription also creates the resource,
   which is his own call-completion state. The question is, is that
   problematical, and why? 

   The next question of course would be, is it problematical to
   transport bodies with queue manipulation information within the
   SUBSCRIBEs. 

Both are problematical in the same way -- The original defintion of
the subscription mechanism makes subscriptions to be passive observers
of the resource; they inherently could not affect the resource
itself.  And this passivity could now be enshrined as an architectural
principle of implementations.  The change is that the existence of
subscriptions (and the event-type parameters and possibly request
bodies) become operations on the resource.

Indeed, we need to split that previous sentence -- the existence of
subscriptions becomes part of the state that is observed, and (even
messier) features of re-SUBSCRIBE messages become operations on the
state.

Dale

---

From: "Xavier Marjou" <[email-masked]>
Date: Thu, 12 Apr 2007 09:30:15 +0200

> this very silly thing is at the core of the draft-poetzl proposal.

I think the disagreement between people stems from Section 4.4.3 of
RFC3265 that indicates "SUBSCRIBE method bodies [...] will typically
modify, expand, filter, throttle, and/or set thresholds for the class
of events being requested."  Many people understood "modify" as a
"set" operation on the state of the event, whereas the meaning of
"modify" is a "get" operation that can filters - but not modify - the
state parameters being returned to the user. (I admit the analogy with
setters and getters is not perfectly accurate as there are no setters
and getters within our XML documents)

> That seems quite reasonable. I'd be interested to see what other people

XCAP is for configuration data; typically this data is stored as
received within a file. In our case, if a user removes himself from a
queue, it would not make sense to store this information in a file. To
continue the analogy with Presence, we may also consider another
alternative: A user PUBLISHes its state ("in/out queue") via an
input-queue event package, the server side makes the aggregration of
all existing inputs to build the queue, and any user can perform a
SUBscription to an output-queue event package to be NOTified of its
position within the queue. (I think someone, perhaps Mike, proposed
this some time ago).

---

From: "Huelsemann, Martin" <[email-masked]>
Date: Thu, 12 Apr 2007 14:51:59 +0200

Would it then look like as follows?

--- Activation and retention

A calls B, B is busy, B has queueing function, A gets provisionally queued,
 
Timer for A's queueing confirmation starts, 

resource "A's call-completion state" is created (would be instance or function of the queue), 

Allow-events:call-completion is inserted in 486 (this would be the cc-possible indication for A), 

A subscribes to his call-completion state, A gets notification cc-state=idle,

A uses XCAP to add himself to the queue (queueing is confirmed at B queue, confirmation timer stops), A gets notification cc-state=queued

B becomes not busy, A gets notification cc-state=start-recall

recall fails for some reasons, retention option is fulfilled, A gets notification cc-state=queued

--- Deactivation

call-completion activated

A uses XCAP to remove himself from the queue, A gets notification cc-state=idle,

A terminates subscription 

Are this roughly the procedures you are thinking of? 

Martin

> Gesendet: Mittwoch, 11. April 2007 20:29
> An: Dean Willis
> Cc: Paul Kyzivat; Hülsemann, Martin; [email-masked]
> practice,

---

From: Dean Willis <[email-masked]>
Date: Thu, 12 Apr 2007 08:30:46 -0500

> That seems quite reasonable. I'd be interested to see what other people 

I didn't mean to suggest that the caller enqueue themselves with XCAP, 
but that if the queue manager and the event server were on different 
nodes that the queue manager could manipulate the queue state document 
using XCAP.

I still think that being enqueued as a result of an INVITE is a 
reasonable thing.

--
Dean

---

From: Dean Willis <[email-masked]>
Date: Thu, 12 Apr 2007 08:35:04 -0500

>   2. How does the queued caller un-pause their position in the queue?

Ah, so you want the CALLER to manipulate the queue. Not on my original 
list of requirements, which were around the queue manager manipulating it.

But if you're maintaining an INVITE dialog, suspend sounds a lot like hold.

--
Dean

---

From: Paul Kyzivat <[email-masked]>
Date: Thu, 12 Apr 2007 10:06:26 -0400

Dean Willis wrote:
>> BFCP (as my current proposal suggests), we could use an event package 
>> to unobtrusively subscribe to a queue, and XCAP to place ourselves in, 

Dean,

The ultimate goal seems to be to give the potential caller at the top of 
the queue a window of opportunity to attempt a call. During that time, 
you don't want to allow the other pending callers, or new callers, to 
establish a call to the callee.

But if you enroll everybody that attempts a call, without knowing that 
they will use the queue to retry, then you have a problem. You don't 
want to give a window of opportunity to someone who isn't waiting.

I guess you could go ahead and enroll the caller of every failed call, 
but only give a window of opportunity to a candidate that has been 
notified that it is at the head of the queue.

That also suggests a way to handle suspend/resume: to suspend you simply 
cancel your subscription. And to resume you make a new subscription.

That seems somewhat interesting. But it presents a new problem - a 
subscriber needs to know if they even have an entry in the queue. If you 
only get notified when you get to the top, then you could wait forever 
if you aren't in the queue.

I guess that could be handled by having an initial notification report 
your queue entry even if you are not first - perhaps giving position in 
queue. Then a subsequent notifications could be filtered unless the 
entry is first in queue, if it is considered undesirable to notify of 
every change in position. That would take some peculiar language around 
the design of a filter, but seems like it should be possible.

	Paul

---

From: Adam Roach <[email-masked]>
Date: Thu, 12 Apr 2007 09:49:41 -0500

> list of requirements, which were around the queue manager manipulating it.

No, *I* don't want it. TISPAN wants it. *I* think it's silly.

/a

---

From: Adam Roach <[email-masked]>
Date: Thu, 12 Apr 2007 10:49:22 -0500

> But if you're maintaining an INVITE dialog, suspend sounds a lot like 

I agree -- but I'm having a hard time understanding what you're 
proposing. From what you've said so far, it sounds like you're thinking 
something like:

       Caller                        Callee
          |(1) INVITE                   |
          |---------------------------->|
          |(2) 486                      |
          |<----------------------------|
          |(3) ACK                      |
          |---------------------------->|
          |                             |
          |Caller activates service     |
          |                             |
          |(4) SUBSCRIBE                |
          |---------------------------->|
          |(5) 200                      |
          |<----------------------------|
          |(6) NOTIFY                   |
          |<----------------------------|
          |(7) 200                      |
          |---------------------------->|
          |(8) INVITE                   |
          |---------------------------->|
          |(9) 200                      |
          |<----------------------------|
          |(10) ACK                     |
          |---------------------------->|
          |                             |
          |Caller pauses position       |
          |                             |
          |(11) INVITE                  |
          |---------------------------->|
          |(12) 200                     |
          |<----------------------------|
          |(13) ACK                     |
          |---------------------------->|
          |(14) NOTIFY                  |
          |<----------------------------|
          |(15) 200                     |
          |---------------------------->|
          |                             |
          |Caller resumes position      |
          |                             |
          |(16) INVITE                  |
          |---------------------------->|
          |(17) 200                     |
          |<----------------------------|
          |(18) ACK                     |
          |---------------------------->|
          |(19) NOTIFY                  |
          |<----------------------------|
          |(20) 200                     |
          |---------------------------->|
          |                             |
          |Callee becomes available     |
          |                             |
          |(21) NOTIFY                  |
          |<----------------------------|
          |(22) 200                     |
          |---------------------------->|
          |(23) BYE                     |
          |---------------------------->|
          |(24) 200                     |
          |<----------------------------|
          |                             |
          |Callee re-initiates call     |
          |                             |
          |(25) INVITE                  |
          |---------------------------->|
          |(26) 180                     |
          |<----------------------------|
          |(27) 200                     |
          |<----------------------------|
          |(28) ACK                     |
          |---------------------------->|

(You may find it easier to follow along using the image at 
<http://www.nostrum.com/~adam/images/callcomp-invite.png>)

Most of this should be self-explanatory. Messages 1 - 3 are the failed 
call setup attempt. Messages 4 - 7, 14, 15, 19, 20, 21, and 22 relate to 
the subscription to queue state. Messages 8 - 10 are the INVITE that the 
caller uses to place themselves in the "pending call" queue.

And that's where things start to get confusing for me. What kind of 
session is being set up here? Specifically, what goes in the SDP for 
messages 8 and 9 (or 9 and 10, if that's how you want to do it)? Are 
there any m= lines? What do they indicate?

Semantically, messages 11 through 13 are a re-invite sequence to put the 
session on hold. Hold is enacted by marking a media stream 
appropriately. There are (as far as I understand things) no media 
streams. How do we indicate hold? (Messages 16 through 18 are similarly 
un-hold, and have an identical series of questions). Again, what does 
the SDP look like?

Don't get me wrong -- this approach seems well positioned to address 
everyone's concerns (explicit operations, semantically correct use of 
SUB/NOT, no introduction of additional protocols) -- I'm just poking 
around the edges to try to figure out whether the details can be worked 
out in a sensible fashion. Right now the bugaboo seems to be that you 
want to set up a session to mark a place in the queue, but that this 
"session" doesn't actually exist, since there isn't any media being 
exchanged. (Remember, in SIP, the SIP protocol construct is a dialog; 
the "session" itself is a stream of media).

/a

---

From: "GARCIN Sébastien AERM" <[email-masked]>
Date: Thu, 12 Apr 2007 17:55:53 +0200

A lot of the confusion here comes from the fact that the flows show "caller" and "callee" exchangin SUB/NOT message whereas the call completion service transactions we are talking are to take place between Application Servers serving the caller and callee parties.

sébastien

> But if you're maintaining an INVITE dialog, suspend sounds a lot like 

I agree -- but I'm having a hard time understanding what you're proposing. From what you've said so far, it sounds like you're thinking something like:

       Caller                        Callee
          |(1) INVITE                   |

Most of this should be self-explanatory. Messages 1 - 3 are the failed call setup attempt. Messages 4 - 7, 14, 15, 19, 20, 21, and 22 relate to the subscription to queue state. Messages 8 - 10 are the INVITE that the caller uses to place themselves in the "pending call" queue.

And that's where things start to get confusing for me. What kind of session is being set up here? Specifically, what goes in the SDP for messages 8 and 9 (or 9 and 10, if that's how you want to do it)? Are there any m= lines? What do they indicate?

Semantically, messages 11 through 13 are a re-invite sequence to put the session on hold. Hold is enacted by marking a media stream appropriately. There are (as far as I understand things) no media streams. How do we indicate hold? (Messages 16 through 18 are similarly un-hold, and have an identical series of questions). Again, what does the SDP look like?

Don't get me wrong -- this approach seems well positioned to address everyone's concerns (explicit operations, semantically correct use of SUB/NOT, no introduction of additional protocols) -- I'm just poking around the edges to try to figure out whether the details can be worked out in a sensible fashion. Right now the bugaboo seems to be that you want to set up a session to mark a place in the queue, but that this "session" doesn't actually exist, since there isn't any media being exchanged. (Remember, in SIP, the SIP protocol construct is a dialog; the "session" itself is a stream of media).

/a

_______________________________________________
Sipping mailing list  https://www1.ietf.org/mailman/listinfo/sipping
This list is for NEW development of the application of SIP Use [email-masked] for questions on current sip Use [email-masked] for new developments of core SIP

*********************************
This message and any attachments (the "message") are confidential and intended solely for the addressees. Any unauthorised
use or dissemination is prohibited.
Messages are susceptible to alteration. France Telecom Group shall not be liable for the message if altered, changed or
falsified.
If you are not the intended addressee of this message, please cancel it immediately and inform the sender.
********************************

---

From: Dean Willis <[email-masked]>
Date: Thu, 12 Apr 2007 10:58:32 -0500

On Apr 12, 2007, at 9:06 AM, Paul Kyzivat wrote:

>>> using BFCP (as my current proposal suggests), we could use an  
>>> event package to unobtrusively subscribe to a queue, and XCAP to  
>>> place ourselves in, pause, resume, and remove ourselves from the  
>>> queue.
>>>
>> I didn't mean to suggest that the caller enqueue themselves with  
>> XCAP, but that if the queue manager and the event server were on  
>> different nodes that the queue manager could manipulate the queue  
>> state document using XCAP.
> The ultimate goal seems to be to give the potential caller at the  
> top of the queue a window of opportunity to attempt a call. During  
> that time, you don't want to allow the other pending callers, or  
> new callers, to establish a call to the callee.
>

That's easy. The queue manager uses something like watcherinfo to  
know whether that caller is watching the queue and waiting for his  
turn to come up.

> But if you enroll everybody that attempts a call, without knowing  
> that they will use the queue to retry, then you have a problem. You  
> don't want to give a window of opportunity to someone who isn't  
> waiting.

Those who watch and wait are also served . . .

>
> I guess you could go ahead and enroll the caller of every failed  
> call, but only give a window of opportunity to a candidate that has  
> been notified that it is at the head of the queue.
>

That would work too -- if the NOTIFY times out, expunge. But it does  
add about 32s of latency.

> That also suggests a way to handle suspend/resume: to suspend you  
> simply cancel your subscription. And to resume you make a new  
> subscription.

yeah, that works. The requirement is that the queue-place is not  
purged as a side effect of canceling the subscription. Rather, the  
watcherinfo is used to determine the duration for which that queue- 
place will be held at the top of the queue.

What happens if you "suspend" and your place comes and goes during  
the interval? Sounds like we'd also have to have a little more  
complex queue management to give a recovery window, but it is very  
doable.

> subscriber needs to know if they even have an entry in the queue.  
> If you only get notified when you get to the top, then you could  
> wait forever if you aren't in the queue.
>

Right. Would it be reasonable to have a server-side cancel on the  
subscription if your token goes stale?

--
Dean

---

From: Dean Willis <[email-masked]>
Date: Thu, 12 Apr 2007 10:59:45 -0500

On Apr 12, 2007, at 10:49 AM, Adam Roach wrote:

> proposing. From what you've said so far, it sounds like you're  
> thinking something like:

yeah, that's what I was thinking, but I don't like it. I like the  
watcherinfo model as came out of Paul's ideas a lot better.

--
Dean

---

From: Dean Willis <[email-masked]>
Date: Thu, 12 Apr 2007 11:01:37 -0500

On Apr 12, 2007, at 10:55 AM, GARCIN Sébastien AERM wrote:

>
> A lot of the confusion here comes from the fact that the flows show  
> "caller" and "callee" exchangin SUB/NOT message whereas the call  
> completion service transactions we are talking are to take place  
> between Application Servers serving the caller and callee parties.

Don't try and complicate our world by pretending that B2BUAs are  
anything but UAs.

We don't care WHERE your user agent is or what kind of bastardized  
protocol it uses to present a user. From the SIP perspective, it's  
just a UA.

--
Dean

---

From: Adam Roach <[email-masked]>
Date: Thu, 12 Apr 2007 12:50:24 -0500

You're getting close -- but you really don't want resources to be 
popping in and out of existence ephemerally, if at all possible. What 
people have been discussing so far is that user A subscribes to user B's 
"pending queue of calls" state, not user A's own "my call completion state."

Additionally, the former kind of information has a much broader 
application (think of, for example, the ability for a supervisor to 
watch a queue of pending calls for a call center), while the latter is 
extremely service-specific.

We're still floundering on the queue manipulation bit; it sounds like 
people don't quite like the XCAP approach.

/a

Huelsemann, Martin wrote:
>>> So the open question is how does one get into the queue 
>>>       
>> without having 
>>     
>>> I concur that insertion into the queue and subscription to 
>>>       
>> the queue 
>>     
>>> the idea that they were intertwingled (or dismissed it as 
>>>       
>> just silly).
>>
>>> "watcher" package. If the queue notification is handled on 
>>>       
>> a node that 
>>     
>>> is different from the node with the data that drives the 
>>>       
>> queue, then 
>>     
>>> we have XCAP to manipulate the queue document and make 
>>>       
>> insertions, etc.
>>

---

From: Adam Roach <[email-masked]>
Date: Thu, 12 Apr 2007 13:14:27 -0500

Dean Willis wrote:
>> The ultimate goal seems to be to give the potential caller at the top 
>> of the queue a window of opportunity to attempt a call. During that 
>> time, you don't want to allow the other pending callers, or new 
>> callers, to establish a call to the callee.
>>
>
> That's easy. The queue manager uses something like watcherinfo to know 
> whether that caller is watching the queue and waiting for his turn to 
> come up.
>
>> don't want to give a window of opportunity to someone who isn't waiting.
>

An interesting approach, to be sure. You're using the subscription 
itself in a similar fashion to the INVITE session from before. You're 
modeling the queue controller as an external third party using stock 
winfo to receive information. I think modeling this as an external 
network element will do a reasonably good job of keeping us out of trouble.

Co-location of the 3265 server and the queue handler would, of course, 
always be possible -- but once we go down a path that *requires* 
co-location, it's pretty clear that we've strayed into dangerous 
territory. This means that subscription to the queue is necessarily 
non-atomic with being added to the queue, and that nothing in the 
subscription itself can modify one's position in the queue.

Great! This defines semantics for putting one's self into the queue, for 
removing one's self from a queue, and for discovering when one is at the 
front of the queue. That's three out of five; so now I have to re-ask my 
two questions:

/a

---

From: Adam Roach <[email-masked]>
Date: Thu, 12 Apr 2007 13:54:59 -0500

Adam Roach wrote:
>
> Great! This defines semantics for putting one's self into the queue, 
> for removing one's self from a queue, and for discovering when one is 
> at the front of the queue. That's three out of five; so now I have to 
> re-ask my two questions:
>

Whoops. Sorry; I missed your suggestion that the subscription also 
controls whether the entry is held at the top of the queue for an 
allowed callback period or merely discarded. I guess that works, so long 
as the service definition is such that a "paused" entry continues to 
advance in the queue, and is discarded if it reaches the front while paused.

Or I guess the queue controller could take note of the fact that a 
subscription from that user existed at some point in the past, so it 
will freeze advancing it for a reasonable period of time (say, one 
hour), at which point it gets discarded. In fact, I'm not certain the 
queue controller's behavior would even be appropriate for 
standardization here, as long as the caller had a way to learn, upon 
resubscription, whether he still has a position in the queue.

So, what it's shaping up to look like is something like this: the event 
package itself has an underlying state that would look something like this:

    <queue target="sip:[email-masked]">

      <user name="Bob Smith"
            uri="sip:[email-masked]"
            position="1"
            state="active"
           
    callback="sip:[email-masked]"
            expires="60" />

      <user name="Alice Jones"
            uri="sip:[email-masked]"
            position="2"
            state="pending" />

      <user name="Charlie Farmer"
            uri="sip:[email-masked]"
            position="3"
            state="void" />

      <user name="Dave Little"
            uri="sip:[email-masked]"
            position="4"
            state="paused" />

      <user name="Ed Gardner"
            uri="sip:[email-masked]"
            position="5"
            state="pending" />

    </queue>

In theory, there may be users (e.g., administrative assistants, call 
center supervisors) who have access to this complete state document, but 
*most* people will receive an administratively-filtered view of its.

For example, if Ed subscribes to this state, the authorization policy at 
the server might be such that he is filtered from seeing any information 
but his own; meaning that he would receive notification similar to:

    <queue target="sip:[email-masked]">
      <user name="Ed Gardner"
            uri="sip:[email-masked]"
            position="5"
            state="pending" />
    </queue>

So, Ed knows he is in the queue, and that there are 4 people in front of 
him. He'll be notified whenever he advances in the queue, and (most 
importantly) when he gets to the head of the queue. He'll also get 
another notification when he is removed from the queue. I think that all 
works exactly like we need it to.

Bob, on the other hand, would see only *his* own entry, which contains 
the information he needs to re-attempt his call (i.e., a callback URI, 
along with some indication of how long the URI will remain valid):

    <queue target="sip:[email-masked]">
      <user name="Bob Smith"
            uri="sip:[email-masked]"
            position="1"
            state="active"
           
    callback="sip:[email-masked]"
            expires="60" />
    </queue>

Dave has apparently unsubscribed from the state. The queue handler 
received notification of this fact (via callqueue.winfo), and 
consequently paused his entry. The queue handler will keep the entry 
paused until it gets a callqueue.winfo notification that Dave has 
subscribed again, or until it reaches its administratively-provisioned 
timeout that sets how long it is willing to hold on to a paused user.

Charlie has never subscribed to the queue state. The queue handler will 
either remove his entry after a implementation-specific timeout or when 
it reaches the top of the queue.

If Fred (not listed above) attempts to subscribe to the queue state, 
he'll find out that he's not in the queue because he won't be in the 
queue...

    <queue target="sip:[email-masked]" />

I think that covers all the vagaries of getting people in and out of the 
queue, pausing them and unpausing them, and making sure they know 
whether they'll be notified of their chance to call back in the future.

Sound reasonable? Any obvious holes?

/a

---

From: Adam Roach <[email-masked]>
Date: Thu, 12 Apr 2007 13:57:14 -0500

Responding to myself *yet* *again*...

After a few seconds' more thought, I'm not sure this is what we want -- 
mostly because there's no distinction between "pause my entry in the 
queue" and "remove my entry from the queue."

*sigh*

/a

Adam Roach wrote:
> allowed callback period or merely discarded. I guess that works, so 
> long as the service definition is such that a "paused" entry continues 
> to advance in the queue, and is discarded if it reaches the front 
> while paused.
>
> So, what it's shaping up to look like is something like this: the 
> event package itself has an underlying state that would look something 
> like this:
>
> center supervisors) who have access to this complete state document, 
> but *most* people will receive an administratively-filtered view of its.
>
> For example, if Ed subscribes to this state, the authorization policy 
> at the server might be such that he is filtered from seeing any 
> information but his own; meaning that he would receive notification 
> similar to:
>
>
> So, Ed knows he is in the queue, and that there are 4 people in front 
> of him. He'll be notified whenever he advances in the queue, and (most 
> another notification when he is removed from the queue. I think that 
> all works exactly like we need it to.
>
> Charlie has never subscribed to the queue state. The queue handler 
> will either remove his entry after a implementation-specific timeout 
> or when it reaches the top of the queue.
>
> I think that covers all the vagaries of getting people in and out of 
> the queue, pausing them and unpausing them, and making sure they know

---

From: Paul Kyzivat <[email-masked]>
Date: Thu, 12 Apr 2007 17:04:19 -0400

My comments below were off the cuff in response to what had been said. 
But what I ended up at seems like an almost complete and workable 
approach. So let me try to explain it again directly:

1) A calls B.
2) B decides to reject the call (say busy)
3) B adds the caller A to the call completion queue
4) B returns a 486 response with some indication that
    the caller has been queued (how is TBD)
5) if A wants to use the call completion feature,
    it subscribes to the event package.
6) B sends an initial notify, with queue status.
    Policy most likely limits the information to
    entries naming the subscriber. (Presumably there
    is only one.) With the entry is a status, which
    can be either "waiting" or "selected". Assume it
    is "waiting" because others are in the queue.
7) When B becomes available for a call, it selects the
    oldest entry in the queue for which there is a watcher.
    It changes the state of that entry to "selected".
    As a result of the change, a notification is sent
    to any watchers that can see the change. That includes
    at least A.
8) Perhaps while that is happening B may receive a call
    from C. B knows what is going on, notes that the caller
    is not the selected caller B, and so rejects the call.
    (Same actions as above.)
9) When A receives the notify, it alerts its user. When
    the user is ready, it places the call to B again.
10) When B receives the call from A, it notes it is the
    selected caller and answers. It also then removes the
    entry for A from the queue. This results in a notify
    to A that there is no entry for it in the queue.
11) When A receives that notify, it cancels its subscription.

If, following (4), A had not bothered to subscribe, its entry would 
remain in the queue for awhile. Entries will age out of the queue 
eventually.

If, following (6), enters a state where it won't be able to complete the 
call to B (e.g. A gets a call from C), then A simply unsubscribes. When 
A is again ready to try, it again subscribes. (Being subscribed or not 
is the means of doing suspend and resume.)

For CCNA (no answer) I think B will have to put the caller into the 
queue any time a call is abandoned by the caller. I think that is ok.

	Paul

Paul Kyzivat wrote:
>>> to unobtrusively subscribe to a queue, and XCAP to place ourselves 
>>> in, pause, resume, and remove ourselves from the queue.
>>>

---

From: Adam Roach <[email-masked]>
Date: Thu, 12 Apr 2007 16:10:42 -0500

Paul:

You ended up describing pretty much the same system as I did. Look over 
my earlier mail on the topic, paying close attention to the importance 
of modeling the queue controller as a third party. Any comments on this 
aspect? How about the differentiation between suspend and cancel? It 
might not be important for a pure SIP service, but I can see this 
potentially causing problems in the PSTN interwork case.

One more comment below.

> queue any time a call is abandoned by the caller. I think that is ok.

Yes; it's almost exactly the same solution. The primary difference is a 
matter of a 486 response code versus a 487 response code.

/a

---

From: Paul Kyzivat <[email-masked]>
Date: Thu, 12 Apr 2007 17:16:38 -0400

I replied separately before seeing this. My reply describes something 
pretty much equivalent to this.

One nuance of mine (would work with yours too) is that the <state> can 
be sufficient to tell the watcher that it is time for it to call - he 
doesn't have to see the position. The position could be filtered out by 
policy (because the callee doesn't want people to know it), or it could 
be filtered out by a caller-supplied filter (because the caller doesn't 
want to get the extraneous notifications.

	Paul

---

From: Paul Kyzivat <[email-masked]>
Date: Thu, 12 Apr 2007 17:18:31 -0400

> queue" and "remove my entry from the queue."

Why does it matter? As long as it is paused it won't bother other 
people, and it will eventually age out of the queue. Its no worse that 
the people who are added and have no intention of ever requesting call 
completion.

	Paul

---

From: Adam Roach <[email-masked]>
Date: Thu, 12 Apr 2007 16:20:24 -0500

Paul Kyzivat wrote:
> be sufficient to tell the watcher that it is time for it to call

That's what I meant state="active" to mean. The position attribute 
could, indeed, be optional.

     <user name="Bob Smith"
-------->  state="active"

/a

---

From: Adam Roach <[email-masked]>
Date: Thu, 12 Apr 2007 16:21:43 -0500

Paul Kyzivat wrote:
>> After a few seconds' more thought, I'm not sure this is what we want 
>> -- mostly because there's no distinction between "pause my entry in 
>> the queue" and "remove my entry from the queue."
>

My concern here is PSTN interop. I believe that you *do* tie up very 
real and limited resources in that case. I could be mistaken.

/a

---

From: Paul Kyzivat <[email-masked]>
Date: Thu, 12 Apr 2007 18:32:11 -0400

> real and limited resources in that case. I could be mistaken.

Perhaps that is a problem. But if so then I think the whole scheme is 
kaput, since it currently has callers being added with no overt action 
on their part. If we need an overt action to cause addition to the queue 
then we are back to the same old problem.

	Paul

---

From: Dean Willis <[email-masked]>
Date: Thu, 12 Apr 2007 17:43:33 -0500

On Apr 12, 2007, at 1:57 PM, Adam Roach wrote:

> After a few seconds' more thought, I'm not sure this is what we  
> want -- mostly because there's no distinction between "pause my  
> entry in the queue" and "remove my entry from the queue."

Do we need one?

The question is whether a position in the queue to which no one is  
going to listen is different from not being in the queue at all.

While this is something like "If a tree falls where there is nobody  
to hear, does it still make a sound?", there is one subtle  
difference. The queue state uses up a resource. Is this resource  
costly enough that waiting a reasonable period with no watcher (which  
could be locally tuned) before discarding it would be too expensive?

For example, I might make a DOS attack by enqueueing calls as fast as  
I can send INVITEs.

Of course, a reasonable queue manager could probably defend itself  
from this as well as it could defend itself against an INVITE flood  
DOS, and using the same mechanisms, so why worry?

--
Dean

---

From: Adam Roach <[email-masked]>
Date: Thu, 12 Apr 2007 17:53:53 -0500

Dean Willis wrote:
> While this is something like "If a tree falls where there is nobody to 
> hear, does it still make a sound?", there is one subtle difference. 
> The queue state uses up a resource. Is this resource costly enough 
> that waiting a reasonable period with no watcher (which could be 
> locally tuned) before discarding it would be too expensive?
>

Because there are TCAP operations and PSTN resources tied up for these 
abandoned (but not explicitly deleted) queue positions.

/a

---

From: Paul Kyzivat <[email-masked]>
Date: Thu, 12 Apr 2007 19:31:18 -0400

Replying to myself. :-(

> then we are back to the same old problem.

Maybe these aren't the same problem.

One problem is the caller who never subscribes. The other problem is the 
caller who subscribes and then changes his mind wants to be entirely 
dequeued.

If we automatically queue callers whenever their call attempt fails, 
then the the first kind is likely to be a substantially worse problem 
than the second kind. I'd venture a guess that overt cancellations are 
very rare, since it is an extra action that provides no benefit to the 
caller.

In a pure sip environment I don't think we care much about either kind. 
Its the PSTN case that seems a potential problem. When the queue is 
being managed on behalf of a PSTN gateway, it seems like the TCAP action 
could be deferred until a subscription is first received for a queue 
entry. And then I propose that the second problem simply be ignored.

	Paul

---

From: Dean Willis <[email-masked]>
Date: Thu, 12 Apr 2007 18:42:35 -0500

On Apr 12, 2007, at 5:53 PM, Adam Roach wrote:

> Because there are TCAP operations and PSTN resources tied up for  
> these abandoned (but not explicitly deleted) queue positions.
>

I don't see that. The TCAP/PSTN resources don't get pulled back into  
play until the caller reaches the top of the queue.

If you're thinking about a TCAP based WATCHER losing resources, if  
the TCAP side knows that the caller has abandoned, it abandons its  
subscription so the only resource cost is at the queue manager and  
the event server (And possibly depending on filtering, at the other  
watchers).

--
Dean

---

From: Paul Kyzivat <[email-masked]>
Date: Thu, 12 Apr 2007 20:04:28 -0400

> play until the caller reaches the top of the queue.

I think that if the callee is in the PSTN, and supports the TCAP version 
of this service, then the gateway will need to allow the queuing to use 
the TCAP mechanism and fake it to the sip caller. If the queuing is only 
done on the sip side then it will only be for the sip callers.

	Paul

> If you're thinking about a TCAP based WATCHER losing resources, if the 
> TCAP side knows that the caller has abandoned, it abandons its 
> subscription so the only resource cost is at the queue manager and the 
> event server (And possibly depending on filtering, at the other watchers).
> 
> -- 
> Dean
>

---

From: Dean Willis <[email-masked]>
Date: Thu, 12 Apr 2007 23:17:13 -0500

> I think that if the callee is in the PSTN, and supports the TCAP 
> version of this service, then the gateway will need to allow the 
> queuing to use the TCAP mechanism and fake it to the sip caller. If 
> the queuing is only done on the sip side then it will only be for the 
> sip callers.
>
Well, clearly I was thinking of the use case in the other direction.

But then, I don't understand the user experience in the PSTN. If you 
call into a line that is queuing, how do you indicate whether you wish 
to camp on it? Wouldn't exercise of this mechanism determine whether the 
caller was expecting to watch the queue or not?

IIRC correctly, one dials a number, gets a "busy", and then enters a 
digit sequence to activate call-back to that target. This "digit sequence"
 is the analog of  both inserting into the queue AND subscribing to 
notifications on that queue. If it happens, then we allocate resources 
in the PSTN gateway to make it happen. If it doesn't, we don't. So in 
any case, the resources are only allocated when there really is a watcher.

The proposed SIP model breaks the process into two discrete steps -- 1) 
inserting into the queue, and 2) subscribing to events on the queue.

You're positing that if a SIP  to PSTN call completes step 1 but doesn't 
go to step 2 that resources are wasted "watching" the TCAP changes in 
order to send an event that will never be sent. But as we've already 
described, the queue manager is fully able to make some reasonable 
time-out decision, like "It's been ten seconds since I offered callback 
and I haven't had a subscription, so I'll assume this guy wasn't serious 
about callback and drop him".

And in any case, this seems like a good fit for "If it hurts, don't do 
it!". That is, don't engage the resources on the TCP side until both the 
insertion and at least one subscription have occurred.

--
Dean

---

From: "GARCIN Sébastien AERM" <[email-masked]>
Date: Fri, 13 Apr 2007 09:45:53 +0200

As matter of fact the "bastardized protocol" that we have in mind is "SIP", and I wasn't pretending anything. 

sébastien   

-----Message d'origine-----
De : Dean Willis [mailto:[email-masked]] 
Envoyé : jeudi 12 avril 2007 18:02
À : GARCIN Sébastien AERM
Cc : Adam Roach; SIPPING WG
Objet : Re: [Sipping] Call Completion: In Defense of Explicit Operations

> between Application Servers serving the caller and callee parties.

Don't try and complicate our world by pretending that B2BUAs are anything but UAs.

We don't care WHERE your user agent is or what kind of bastardized protocol it uses to present a user. From the SIP perspective, it's just a UA.

--
Dean

---

From: Paul Kyzivat <[email-masked]>
Date: Fri, 13 Apr 2007 09:24:31 -0400

Dean Willis wrote:
> notifications on that queue.

Yes, that is my understanding too.

> If it happens, then we allocate resources 

> insertion and at least one subscription have occurred.

I proposed something similar in a separate response.

	Paul

---

From: Dean Willis <[email-masked]>
Date: Wed, 18 Apr 2007 10:55:12 -0500

On Apr 13, 2007, at 2:45 AM, GARCIN Sébastien AERM wrote:

> As matter of fact the "bastardized protocol" that we have in mind  
> is "SIP", and I wasn't pretending anything.

Well, the tone on my post came out all wrong. My apologies.

The point I'm trying to make is that much of the difficulty in  
understanding POC comes from the idea that the protocol is user-to- 
user SIP. It isn't. The POC controllers are the UAs. It's SIP (as we  
know it) from controller to controller.

Instead of:

UA----Proxy----Proxy----UA

we have:

UA--Proxy--UA/UA---Proxy----Proxy-----UA/UA--Proxy--UA

In addition to SIP between the controllers (which possibly transits  
proxies), there are almost unrelated controller-to-terminal protocols  
on each side (which may also transit proxies)

The controller-to-terminal protocol is currently defined in terms of  
SIP. However, it could be replaced by some entirely different  
protocol, and neither the controller nor the terminal "on the other  
side" would be able to tell.

So to understand the environment, one has to be very clearly thinking  
about either the terminal-to-controller protocol or about the  
controller-to-controller protocol. When you're working with the  
controller-to-controller protocol (as would be the case when one POC  
controller is queued by another), then it is both irrelevant and  
confusing to bring "the terminal as a UA" into the discussion.

When I was participating in POC (or helping participants deal with  
complexities outside of meetings) I frequently had to say something  
like "Pretend the POC controllers are the final endpoints and that  
they have microphones, speakers, and a talk button. What has to  
happen between them for this to work?" This approach as necessitated  
because people kept getting the dialog state on the controller- 
terminal link mixed up with the dialog state on the controller- 
controller link.

The other mistake people frequently made in POC was asserting that  
the POC controller was somehow "special" and therefore exempt from  
the rules of SIP processing at a user agent. It isn't -- it is a SIP  
user agent, and it has to play by all the rules of a SIP user agent  
or things aren't going to work right.

--
Dean

---

From: "Huelsemann, Martin" <[email-masked]>
Date: Thu, 19 Apr 2007 13:22:50 +0200

Hi,

one open question seems to be, how can you differentiate between cancelling a subsription for suspension and cancelling it for deactivation?

I think because of performance reasons it's necessary to remove an entry from the queue if the queueing is not needed anymore.

Regards, Martin

> Von: Dean Willis [mailto:[email-masked]] 
> Gesendet: Donnerstag, 12. April 2007 17:59
> An: Paul Kyzivat
> Cc: Adam Roach; Hülsemann, Martin; [email-masked]

---

From: Paul Kyzivat <[email-masked]>
Date: Thu, 19 Apr 2007 08:52:54 -0400

> I think because of performance reasons it's necessary to remove an entry from the queue if the queueing is not needed anymore.

In theory this might be significant. But will it be in practice? Under 
what circumstances would the cancellation for deactivation actually take 
place? What percentage of all queued requests will ever be canceled in 
this way?

If a simple mechanism will be sufficient without this capability, and a 
more complex mechanism will be required simply to support removing from 
the queue in this one case, is it worth it?

	Paul

---

From: Dean Willis <[email-masked]>
Date: Thu, 19 Apr 2007 16:13:07 -0500

On Apr 19, 2007, at 6:22 AM, Huelsemann, Martin wrote:

> Hi,
>
> one open question seems to be, how can you differentiate between  
> cancelling a subsription for suspension and cancelling it for  
> deactivation?
>

By how long the resources goes unwatched? That is, a matter of time.

--
Dean