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; }