Show TOC

RFC Server Programming ExampleLocate this document in the navigation structure

Use

In the following section you can find a programming example using basic elements of RFC Server programs such as registering the server, installing a server function, and error handling:

#include <stdlib.h>

#include <stdio.h>

#include "sapnwrfc.h"

static int listening = 1;

/*

Transaction SE37 in the AS ABAP does not yet allow you to set complex inputs, so in order to test

this example, you will probably need to write a short ABAP report, which sets a few

input lines for IMPORT_TAB and then does a


CALL FUNCTION 'STFC_DEEP_TABLE' DESTINATION 'MY_SERVER'
  EXPORTING
    import_tab       = imtab
  IMPORTING
    export_tab       = extab
    resptext         = text
  EXCEPTIONS
    system_failure   = 1  MESSAGE mes.


         

This also allows you to catch the detailed texts for SYSTEM_FAILURES.

Note: STFC_DEEP_TABLE only exists as of SAP_BASIS Release 6.20.


void errorHandling(RFC_RC rc, SAP_UC description[], RFC_ERROR_INFO* errorInfo, RFC_CONNECTION_HANDLE connection){
        printfU(cU("%s: %d\n"), description, rc);
        printfU(cU("%s: %s\n"), errorInfo->key, errorInfo->message);
        // It's better to close the TCP/IP connection cleanly, than to just let the
        // backend get a "Connection reset by peer" error...
        if (connection != NULL) RfcCloseConnection(connection, errorInfo);

        exit(1);
}

RFC_RC SAP_API stfcDeepTableImplementation(RFC_CONNECTION_HANDLE rfcHandle, RFC_FUNCTION_HANDLE funcHandle, RFC_ERROR_INFO* errorInfoP){
        RFC_ATTRIBUTES attributes;
        RFC_TABLE_HANDLE importTab = 0;
        RFC_STRUCTURE_HANDLE tabLine = 0;
        RFC_TABLE_HANDLE exportTab = 0;
        RFC_ERROR_INFO errorInfo ;
        RFC_CHAR buffer[257]; //One for the terminating zero
        RFC_INT intValue;
        RFC_RC rc;
        unsigned tabLen = 0, strLen;
        unsigned  i = 0;
        buffer[256] = 0;

        printfU(cU("\n*** Got request for STFC_DEEP_TABLE from the following system: ***\n"));

/*If you want to include an authorization check for your RFC server according to SAP Note 1058327, insert it now:*/

        RfcGetConnectionAttributes(rfcHandle, , );
        printfU(cU("System ID: %s\n"), attributes.sysId);
        printfU(cU("System No: %s\n"), attributes.sysNumber);
        printfU(cU("Mandant  : %s\n"), attributes.client);
        printfU(cU("Host     : %s\n"), attributes.partnerHost);
        printfU(cU("User     : %s\n"), attributes.user);

        //Print the Importing Parameter
        printfU(cU("\nImporting Parameter:\n"));
        RfcGetTable(funcHandle, cU("IMPORT_TAB"), , );

        RfcGetRowCount(importTab, , );
        printfU(cU("IMPORT_TAB (%d lines)\n"), tabLen);
        for (i=0; i<tabLen; i++){
                RfcMoveTo(importTab, i, );
                printfU(cU("\t\t-line %d\n"), i);

                RfcGetInt(importTab, cU("I"), , );
                printfU(cU("\t\t\t-I:\t%d\n"), intValue);
                RfcGetString(importTab, cU("C"), buffer, 11, , );
                printfU(cU("\t\t\t-C:\t%s\n"), buffer);
                // Check for the stop flag:
                if (i==0 && strncmpU(cU("STOP"), buffer, 4) == 0) listening = 0;
                RfcGetStringLength(importTab, cU("STR"), , );
                if (strLen > 256) printfU(cU("STRING length bigger than 256: %d. Omitting the STR field...\n"), strLen);
                else{
                        RfcGetString(importTab, cU("STR"), buffer, 257, , );
                        printfU(cU("\t\t\t-STR:\t%s\n"), buffer);
                }
                RfcGetStringLength(importTab, cU("XSTR"), , );
                if (strLen > 128) printfU(cU("XSTRING length bigger than 128: %d. Omitting the XSTR field...\n"), strLen);
                else{
                        RfcGetString(importTab, cU("XSTR"), buffer, 257, , );
                        printfU(cU("\t\t\t-XSTR:\t%s\n"), buffer);
                }
        }

        //Now set the Exporting Parameters
        printfU(cU("\nSetting values for Exporting Parameters:\n"));
        printfU(cU("Please enter a value for RESPTEXT:\n> "));
        getsU(buffer);
        RfcSetChars(funcHandle, cU("RESPTEXT"), buffer, strlenU(buffer), );
        printfU(cU("\nPlease enter the number of lines in EXPORT_TAB:\n> ")); 
        getsU(buffer);
        tabLen = atoiU(buffer);
        RfcGetTable(funcHandle, cU("EXPORT_TAB"), , );
        for (i=0; i<tabLen; i++){
                tabLine = RfcAppendNewRow(exportTab, );
                printfU(cU("Line %d\n"), i);
                printfU(cU("\tPlease enter a value for C [CHAR10]:> "));
                getsU(buffer);
                RfcSetChars(tabLine, cU("C"), buffer, strlenU(buffer), );
                printfU(cU("\tPlease enter a value for I [INT4]:> "));
                getsU(buffer);
                RfcSetInt(tabLine, cU("I"), atoiU(buffer), );
                printfU(cU("\tPlease enter a value for STR [STRING]:> "));
                fgetsU(buffer, 257, stdin); // For these fields better make sure, the user doesn't bust our buffer...
                strLen = strlenU(buffer) - 1;
                // In contrast to gets, fgets includes the linebreak... Very consistent...
                RfcSetString(tabLine, cU("STR"), buffer, strLen, );
                mark: printfU(cU("\tPlease enter a value for XSTR [XSTRING]:> "));
                fgetsU(buffer, 257, stdin);
                strLen = strlenU(buffer) - 1;
                // In contrast to gets, fgets includes the linebreak... Very consistent...
                rc = RfcSetString(tabLine, cU("XSTR"), buffer, strLen, );
                if (rc != RFC_OK){
                        printfU(cU("\tInvalid value for XSTR. Please only use hex digits 00 - FF.\n"));
                        goto mark;
                }
        }
        printfU(cU("**** Processing of STFC_DEEP_TABLE finished ***\n\n"));

        return RFC_OK;
}

int mainU(int argc, SAP_UC** argv){
        RFC_RC rc;
        RFC_FUNCTION_DESC_HANDLE stfcDeepTableDesc;
        RFC_CONNECTION_PARAMETER repoCon[8], serverCon[3];
        RFC_CONNECTION_HANDLE repoHandle, serverHandle;
        RFC_ERROR_INFO errorInfo;

        serverCon[0].name = cU("program_id");   serverCon[0].value = cU("MY_SERVER");
        serverCon[1].name = cU("gwhost");       serverCon[1].value = cU("binmain");
        serverCon[2].name = cU("gwserv");       serverCon[2].value = cU("sapgw53");

        repoCon[0].name = cU("client"); repoCon[0].value = cU("000");
        repoCon[1].name = cU("user");   repoCon[1].value = cU("user");
        repoCon[2].name = cU("passwd"); repoCon[2].value = cU("****");
        repoCon[3].name = cU("lang");   repoCon[3].value = cU("DE");
        repoCon[4].name = cU("ashost"); repoCon[4].value = cU("binmain");
        repoCon[5].name = cU("sysnr");  repoCon[5].value = cU("53");

        printfU(cU("Logging in..."));
        repoHandle = RfcOpenConnection (repoCon, 6, );
        if (repoHandle == NULL) errorHandling(errorInfo.code, cU("Error in RfcOpenConnection()"), , NULL);
        printfU(cU(" ...done\n"));

        printfU(cU("Fetching metadata..."));
        stfcDeepTableDesc = RfcGetFunctionDesc(repoHandle, cU("STFC_DEEP_TABLE"), );
        // Note: STFC_DEEP_TABLE exists only from SAP_BASIS release 6.20 on
        if (stfcDeepTableDesc == NULL) errorHandling(errorInfo.code, cU("Error in Repository Lookup"), , repoHandle);
        printfU(cU(" ...done\n"));

        printfU(cU("Logging out..."));
        RfcCloseConnection(repoHandle, );
        printfU(cU(" ...done\n"));

        rc = RfcInstallServerFunction(NULL, stfcDeepTableDesc, stfcDeepTableImplementation, );
        if (rc != RFC_OK) errorHandling(rc, cU("Error Setting "), , repoHandle);

        printfU(cU("Registering Server..."));
        serverHandle = RfcRegisterServer(serverCon, 3, );
        if (serverHandle == NULL) errorHandling(errorInfo.code, cU("Error Starting RFC Server"), , NULL);
        printfU(cU(" ...done\n"));

        printfU(cU("Starting to listen...\n\n"));
        while(RFC_OK == rc || RFC_RETRY == rc || RFC_ABAP_EXCEPTION == rc){
                rc = RfcListenAndDispatch(serverHandle, 120, );
                printfU(cU("RfcListenAndDispatch() returned %s\n"), RfcGetRcAsString(rc));
                switch (rc){
                        case RFC_RETRY: // This only notifies us, that no request came in within the timeout period.
                                                        // We just continue our loop.
                                printfU(cU("No request within 120s.\n"));
                                break;
                        case RFC_ABAP_EXCEPTION:        // Our function module implementation has returned RFC_ABAP_EXCEPTION.
                                                                // This is equivalent to an ABAP function module throwing an ABAP Exception.
                                                                // The Exception has been returned to the SAP system and our connection is still open.
                                                                // So we just loop around.
                                printfU(cU("ABAP_EXCEPTION in implementing function: %s\n"), errorInfo.key);
                                break;
                        case RFC_NOT_FOUND:     // The SAP system tried to invoke a function module, for which we did not supply
                                                                // an implementation. The SAP system has been notified of this through a SYSTEM_FAILURE,
                                                                // so we need to refresh our connection.
                                printfU(cU("Unknown function module: %s\n"), errorInfo.message);
                        case RFC_EXTERNAL_FAILURE:      // Our function module implementation raised a SYSTEM_FAILURE. In this case
                                                                // the connection needs to be refreshed as well.
                                printfU(cU("SYSTEM_FAILURE has been sent to backend.\n\n"));
                        case RFC_ABAP_MESSAGE:          // And in this case a fresh connection is needed as well
                                serverHandle = RfcRegisterServer(serverCon, 3, );
                                rc = errorInfo.code;
                                break;
                }

                // This allows us to shutdown the RFC Server from the SAP system. The implementation of STFC_DEEP_TABLE
                // will set listening to false, if IMPORT_TAB-C == STOP.
                if (!listening){
                        RfcCloseConnection(serverHandle, NULL);
                        break;
                }
        }

        return 0;
}