Solstice X.25 9.2 Developer's Guide

4.1 Listening for a Single Call

The steps for listening for a single incoming call are:

  1. Send an N_Xlisten message to the X.25 driver.

    This should carry the called address list in which the application is interested.

  2. Wait for the response to the Listen Request.

    The l_result flag will indicate success or failure. If the l_result flag indicates failure, the application can decide either to close the stream or to try again later.

  3. Wait for Connect Indication messages from the X.25 driver.

  4. Decide whether to accept on this or a different stream.

  5. Negotiate facilities and QOS, if required.

    A Connect Confirmation message carrying the appropriate connection identifier is then passed down on the stream on which the connection is being accepted.

  6. Construct the listen message.

    The listen message has two parts. Construct the control part of the message like this:

    struct xlistenf lisreq;
     lisreq.xl_type = XL_CTL;
     lisreq.xl_command = N_XListen;
     lisreq.lmax = 1;

    In this example, lmax has the value of 1, indicating that only one Connect Indication is to be handled at a time.

    The data part of the message contains the sequence of bytes that specify the Call User Data string and address(es) which are to be listened for. The simplest case for this would be to set "Don't Care" values for both the CUD and address:

    int lislen;
     char lisbuf[MAXLIS];
     lisbuf[0] = X25_DONTCARE; /* l_cumode*/
     lisbuf[1] = X25_DONTCARE; /* l_mode*/
     lislen = 2;

    Alternatively, to set the CUD to match exactly the (X.29) value defined in the array cudf[] (0x01000000), and the NSAP to match any sequence starting 0x80, 0x00, the following would be used:

    lislen = 0;
     lisbuf[lislen++] = X25_IDENTITY; /* l_cumode */
     lisbuf[lislen++] = CUDFLEN; /* l_culength */
     memcpy(&(lisbuf[lislen]), cudf, CUDFLEN); /* l_cubytes */
     lislen += CUDFLEN;
     lisbuf[lislen++] = X25_STARTSWITH; /* l_mode */
     lisbuf[lislen++] = X25_NSAP; /* l_type */
     lisbuf[lislen++] = 4; /* l_length */
     lisbuf[lislen++] = 0x80;  /* l_add */
     lisbuf[lislen++] = 0x00; 

    Or, to accept any CUD Field, with a DTE of 2342315656565:

    #define MY_DTE_LEN 13
     #define MY_DTE_OCTETS 7
     char my_dte[MY_DTE_OCTETS] = {0x23,0x42,0x31,0x56,0x56,0x56,0x50};
     lislen = 0;
     lisbuf[lislen++] = X25_DONTCARE;  /* l_cumode */
     lisbuf[lislen++] = X25_IDENTITY; /* l_mode */
     lisbuf[lislen++] = X25_DTE; /* l_type */
     lisbuf[lislen++] = MY_DTE_LEN; /* l_length */
     memcpy(&(lisbuf[lislen]), my_dte, MY_DTE_OCTETS); /* l_add */
     lislen += MY_DTE_OCTETS;

    Note -

    The l_add field uses packed hexadecimal digits and the l_length value is actually the number of semi-octets, whereas the l_culength field specifies the length of the l_cubytes field in octets.


  7. Send the Listen Request down the open stream:

    ctlblk.len = sizeof(struct xlistenf);
     ctlblk.buf = (char *) &lisreq;
     datblk.len = lislen;
     datblk.buf = lisbuf;
     if (putmsg(x25_fd, &ctlblk, &datblk, 0) < 0) {
     	perror("Listen putmsg failure");
     	return -1;
     	}
  8. Wait for the listen response; the result flag indicates success or failure:

    #define DBUFSIZ 128
     #define CBUFSIZ MAX( sizeof(struct xccnff), sizeof(struct xdiscf) )
     struct xlistenf *lis_msg;
     ctlblk.maxlen = CBUFSIZ; /* See 4.1 above for declarations */
     ctlblk.buf = ctlbuf;
     datblk.maxlen = DBUFSIZ;
     datblk.buf = datbuf;
     for(;;) {
     	if (getmsg (x25_fd, &ctlblk, &datblk, &getflags) < 0) {
     		perror("Listen getmsg failure");
     		return -1;
     		}
     	lis_msg = (struct xlistenf *) ctlbuf;
     	if ((lis_msg->xl_type == XL_CTL) &&  (lis_msg->xl_command == N_XListen))
     		if (lis_msg->l_result != 0) {
     			printf("Listen command failed \n");
     			return -1;
     			}
     		else {
     			printf("Listen command succeeded \n");
     			return 0;
     			}
     	} 

    Cancelling a Listen Request is done in the same way, except that no data is passed with the request. It cancels all successful Listens that have been made on that stream.

  9. Once the listening application has received a Listen Response indicating success, it should wait for incoming Connect Indications.

    When an N_CI message arrives, the application should inspect its parameters-- address, call user data, facilities, quality of service, and so on--then decide whether to accept or reject the connection.

    A listening application can accept a call either on the stream the indication arrived on, or on some other stream. This other stream can be one which is already open and free, or the application can open it.

    Whatever method is used for the accept, the identifier conn_id in the Connect Indication message must be copied into the accept message for matching by the X.25 driver. If this identifier in the accept message does not match, a Disconnect is sent to the accepting application. This causes the resource to hang on the stream on which the incoming call was sent, since the connection is never accepted.

    A listening application can reject the call by sending a N_DI message down the stream on which the Connect Indication arrived. A Connect Indication cannot be rejected on a different stream. The connection identifier must be quoted in the message for matching, since there may be several Connect Indications passed to the listening application. If there is no match for the rejection, the message is silently discarded.

    The rejecting listener can request one of two actions in response to the disconnect:

    • Request immediate disconnect. The application sets the reason field to NU_PERMANENT (0xF5).

    • Search for further matching listeners. The application set the reason field to any value except 0xF5.

      The following code example shows how to reject an incoming call:

      struct xcallf  *conind;
       struct xdiscf disc_msg; 
       /* Use getmsg to receive the Connect Indication
        * use conind to point to it
        */
       disc_msg.xl_type = XL_CTL;
       disc_msg.xl_command = N_DI;
       disc_msg.conind = conind->conind;
       disc_msg.cause = cause; /* cause to be returned */
       disc_msg.diag = diag; /* diagnostic to be returned */
       if (disc_immed) /* no more searches */
       	disc_msg.reason = NU_PERMANENT; /* 0xF5 */
       /* Send Rejection down stream with putmsg */

      Note -

      The application must not accept a connection on a listening stream that is capable of handling more than one Connect Indication at one time if there could subsequently be other Connect Indications to be handled on that stream. For example, the application issues a Listen Request to handle three Connect Indications at one time. A Connect Indication is received and sent to the application on the listen stream. The application must not accept this connection on the listen stream because there could be two more Connect Indications that can be sent subsequently.


  10. Negotiate any facilities or OSI CONS QOS parameters required.

    To do this, set the negotiate_qos flag in the Connect Response message. The values received should then be copied into the response, and those facilities and/or parameters (and any related flags) for which a different value is desired should then be altered (see "2.7 Facilities and QOS Parameters"). Copy the entire QOS structure from the indication to the response. This allows for future additions to this structure.

    An example of negotiation is shown below. Here all the values are copied as indicated, except the packet size, which is negotiated down to 256 if it is flagged as negotiable, and is greater than 256:

    struct xcallf *conind;
     struct xccnff conresp;
     /* Do a getmsg etc to receive the Connect Indication,
      * assign conind to point to it.
      */
     conresp.xl_type = XL_CTL;
     conresp.xl_command = N_CC;
     conresp.conn_id = conind->conn_id;  /* Connection identifier */
     conresp.CONS_call = TRUE /* This is a CONS call */
     memset(&conresp.responder, 0, sizeof(struct xaddrf));
     /* Let network fill in responding addr */
     conresp.negotiate_qos = TRUE;
     memcpy (&conresp.rqos, &conind->qos, sizeof (struct qosformat) );
     if (conind->qos.xtras.pwoptions & NEGOT_PKT) {
     	if (conind->qos.xtras.rempacket > 8)
     		conresp.rqos.xtras.rempacket = 8; 
     	if (conind->qos.xtras.locpacket > 8)
     		conresp.rqos.xtras.locpacket = 8;
     	}
     /* Set any other values to be negotiated here,
      * then send the response down with a putmsg.
      */

    Alternatively, the application may decide to accept (agree with) the indicated values, in which case the negotiate_qos flag is set to zero.

    If a connection is never established on a listening stream (using a matching accept) then that stream remains listening on the address list supplied. On the other hand, once an established connection has been disconnected, the stream does not return to a listening state. Instead, it remains open in an idle state. If the application needs to listen again, then the listen message must be re-sent. Rejection does not alter the listening state of the stream.