This program receives a call over a switched virtual circuit (SVC), accepts it, and then prints any data received. Example program svcxmit is designed to send the data received by this program.
The X.25 program uses the following steps:
/* X.25 Example Program svcrcv. */
#include <stdio.h> #include <stdlib.h> #include <errno.h> #include <NLchar.h> #include <x25sdefs.h>
#define LINK_NAME "x25s0" /* Name of X.25 port. */ #define SAMPLE_NAME "IBMSAMP" /* A name in the X.25 routing list. */
/*****************************************************************************/ /* Function main */ /* Description This program is designed to demonstrate usage of the X.25 */ /* API. It waits for an incoming call, accepts it, and then */ /* prints any data received. */ /* Example program svcxmit is designed to send the data */ /* received by this program. */ /* Note that, in a production program, you should check the */ /* return code from each subroutine call and take appropriate */ /* action. */ /* Returns 0 if successful */ /* 1 if error */ /*****************************************************************************/
int main( int argc, char *argv[]) {
/***************************************************************************/ /* The following structures are defined in the x25sdefs.h file. */ /***************************************************************************/ struct cb_call_struct cb_call; struct ctr_array_struct ctr_array[1]; /* This program waits for only */ /* one counter at a time. */ struct cb_msg_struct cb_msg; struct cb_link_name_struct cb_link_name;
NLchar name[8]; /* 1 longer than SAMPLE_NAME for NULL terminator. */ int listen_id; /* Listen identifier for x25_receive. */ int conn_id; /* Connection identifier to identify the call after */ /* receiving it. */ int listen_ctr_id; /* Counter identifier to associate with incoming calls*/ int call_ctr_id; /* Counter identifier to associate with accepted call */ int ctr_num; /* Number of entries in ctr_array. */ int rc; /* Return code */
/***************************************************************************/ /* Initialize the API for access to a link. */ /***************************************************************************/
cb_link_name.flags = X25FLG_LINK_NAME; cb_link_name.link_name = LINK_NAME; rc = x25_init(&cb_link_name);
if (rc < 0) { (void)printf("%s: x25_init failed : x25_errno = %d errno = %d\n", argv[0],x25_errno,errno); return(1); } else {
/************************************************************************/ /* Prepare to receive incoming calls: */ /* 1. Get a counter to be used to notify us of incoming calls. */ /* 2. Listen for calls that satisfy the criteria specified by a name in */ /* the routing list. */ /************************************************************************/
listen_ctr_id = x25_ctr_get(); /* Get a counter. */ (void)NCdecstr(SAMPLE_NAME,name,8); /* Convert to NLchar. */ listen_id = x25_listen(name,listen_ctr_id); if (listen_id < 0) { (void)printf("%s: x25_listen failed : x25_errno = %d errno = %d\n", argv[0],x25_errno,errno); return(1); } else (void)printf("%s: Awaiting incoming call...\n",argv[0]);
/************************************************************************/ /* Wait for an incoming call. The x25_ctr_wait subroutine returns */ /* when a message arrives. */ /************************************************************************/
ctr_num = 1; ctr_array[0].flags = X25FLG_CTR_ID; ctr_array[0].flags |= X25FLG_CTR_VALUE; ctr_array[0].ctr_id = listen_ctr_id; ctr_array[0].ctr_value = 0; rc = x25_ctr_wait(ctr_num,ctr_array);
/************************************************************************/ /* Receive an incoming call. */ /* In this example, we can assume that the message that has arrived */ /* (causing the counter to be incremented and x25_ctr_wait to return) */ /* is an incoming-call message. Therefore we assign the listen */ /* identifier to the conn_id parameter before invoking x25_receive and */ /* we do not check the return code. */
/* On return, conn_id is set to the connection identifier for this call.*/ /************************************************************************/
conn_id = listen_id; (void)x25_receive(&conn_id,&cb_msg); (void)printf("%s: Incoming call received\n",argv[0]);
/************************************************************************/ /* Get a new counter for handling data from this call before */ /* accepting the call. */ /* No additional information needs to be put into the call-accept */ /* packet, so the flags field is set to zero. */ /************************************************************************/ call_ctr_id = x25_ctr_get(); cb_call.flags = 0; (void)x25_call_accept(conn_id,&cb_call,call_ctr_id); (void)printf("%s: Call accepted.\n",argv[0]);
/************************************************************************/ /* x25_receive allocates storage to return information. Although there */ /* are no storage constraints in this application, the allocated */ /* storage is freed once the information is no longer needed. */ /************************************************************************/ if (cb_msg.msg_point.cb_call != NULL) { cb_msg.msg_point.cb_call -> flags = 0; if (cb_msg.msg_point.cb_call->link_name != NULL) free(cb_msg.msg_point.cb_call->link_name); if (cb_msg.msg_point.cb_call->calling_addr != NULL) free(cb_msg.msg_point.cb_call->calling_addr); if (cb_msg.msg_point.cb_call->called_addr != NULL) free(cb_msg.msg_point.cb_call->called_addr); if (cb_msg.msg_point.cb_call->user_data != NULL) free(cb_msg.msg_point.cb_call->user_data); free(cb_msg.msg_point.cb_call); }
/************************************************************************/ /* The call has now been received and accepted. Now wait for the data. */ /************************************************************************/ do {
/**********************************************************************/ /* Wait for counter to indicate that data is waiting to be received. */ /**********************************************************************/ ctr_num = 1; ctr_array[0].flags = X25FLG_CTR_ID; ctr_array[0].flags |= X25FLG_CTR_VALUE; ctr_array[0].ctr_id = call_ctr_id; ctr_array[0].ctr_value = 0; (void)x25_ctr_wait(ctr_num,ctr_array);
/**********************************************************************/ /* Receive the message that is now ready. The types of message that */ /* the program can handle are data, clear-indication, and */ /* reset-indication; other message types are ignored. */ /**********************************************************************/ (void)x25_receive(&conn_id,&cb_msg); switch (cb_msg.msg_type) { case X25_DATA:
/********************************************************************/ /* Acknowledge the data if the D-bit (delivery confirmation) is set.*/ /********************************************************************/ if ((cb_msg.msg_point.cb_data->flags) & X25FLG_D_BIT) (void)x25_ack(conn_id);
/********************************************************************/ /* Print the received data. Assume it is a normal string. */ /********************************************************************/ if ((cb_msg.msg_point.cb_data -> flags) & X25FLG_DATA) { (void)printf("%s: Incoming Data : ",argv[0]); (void)printf("%s\n",cb_msg.msg_point.cb_data->data); free(cb_msg.msg_point.cb_data->data); /* Free memory allocated */ free(cb_msg.msg_point.cb_data); } break;
case X25_CLEAR_INDICATION: /********************************************************************/ /* When the call has been cleared, do the tidying up: */ /* Remove the counters. */ /* Stop listening for calls. */ /* Terminate the API. */ /********************************************************************/ (void)printf("%s: Call cleared. Cause = 0x%02x Diagnostic = 0x%02x\n", argv[0], cb_msg.msg_point.cb_clear->cause, cb_msg.msg_point.cb_clear->diagnostic); (void)x25_ctr_remove(call_ctr_id); (void)x25_ctr_remove(listen_ctr_id); (void)x25_deafen(listen_id); (void)x25_term(&cb_link_name); break;
case X25_RESET_INDICATION: /********************************************************************/ /* Respond to the arrival of a reset-indication message, by sending */ /* a reset-confirmation message. */ /********************************************************************/ (void)x25_reset_confirm(conn_id); break;
default: /* Ignore packet types other than data, clear-indication, and */ /* reset-indication. */ break; } } while (cb_msg.msg_type != X25_CLEAR_INDICATION); } return(0); }