In the following section you can find a programming example using basic elements of RFC Server programs like 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 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 to catch the detail texts for SYSTEM_FAILURES.
Note: STFC_DEEP_TABLE exists only from SAP_BASIS release 6.20 on.
*/
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, &attributes, &errorInfo);
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"), &importTab, &errorInfo);
RfcGetRowCount(importTab, &tabLen, &errorInfo);
printfU(cU("IMPORT_TAB (%d lines)\n"), tabLen);
for (i=0; i<tabLen; i++){
RfcMoveTo(importTab, i, &errorInfo);
printfU(cU("\t\t-line %d\n"), i);
RfcGetInt(importTab, cU("I"), &intValue, &errorInfo);
printfU(cU("\t\t\t-I:\t%d\n"), intValue);
RfcGetString(importTab, cU("C"), buffer, 11, &strLen, &errorInfo);
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"), &strLen, &errorInfo);
if (strLen > 256) printfU(cU("STRING length bigger than 256: %d. Omitting the STR field...\n"), strLen);
else{
RfcGetString(importTab, cU("STR"), buffer, 257, &strLen, &errorInfo);
printfU(cU("\t\t\t-STR:\t%s\n"), buffer);
}
RfcGetStringLength(importTab, cU("XSTR"), &strLen, &errorInfo);
if (strLen > 128) printfU(cU("XSTRING length bigger than 128: %d. Omitting the XSTR field...\n"), strLen);
else{
RfcGetString(importTab, cU("XSTR"), buffer, 257, &strLen, &errorInfo);
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), &errorInfo);
printfU(cU("\nPlease enter the number of lines in EXPORT_TAB:\n> "));
getsU(buffer);
tabLen = atoiU(buffer);
RfcGetTable(funcHandle, cU("EXPORT_TAB"), &exportTab, &errorInfo);
for (i=0; i<tabLen; i++){
tabLine = RfcAppendNewRow(exportTab, &errorInfo);
printfU(cU("Line %d\n"), i);
printfU(cU("\tPlease enter a value for C [CHAR10]:> "));
getsU(buffer);
RfcSetChars(tabLine, cU("C"), buffer, strlenU(buffer), &errorInfo);
printfU(cU("\tPlease enter a value for I [INT4]:> "));
getsU(buffer);
RfcSetInt(tabLine, cU("I"), atoiU(buffer), &errorInfo);
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, &errorInfo);
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, &errorInfo);
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, &errorInfo);
if (repoHandle == NULL) errorHandling(errorInfo.code, cU("Error in RfcOpenConnection()"), &errorInfo, NULL);
printfU(cU(" ...done\n"));
printfU(cU("Fetching metadata..."));
stfcDeepTableDesc = RfcGetFunctionDesc(repoHandle, cU("STFC_DEEP_TABLE"), &errorInfo);
// Note: STFC_DEEP_TABLE exists only from SAP_BASIS release 6.20 on
if (stfcDeepTableDesc == NULL) errorHandling(errorInfo.code, cU("Error in Repository Lookup"), &errorInfo, repoHandle);
printfU(cU(" ...done\n"));
printfU(cU("Logging out..."));
RfcCloseConnection(repoHandle, &errorInfo);
printfU(cU(" ...done\n"));
rc = RfcInstallServerFunction(NULL, stfcDeepTableDesc, stfcDeepTableImplementation, &errorInfo);
if (rc != RFC_OK) errorHandling(rc, cU("Error Setting "), &errorInfo, repoHandle);
printfU(cU("Registering Server..."));
serverHandle = RfcRegisterServer(serverCon, 3, &errorInfo);
if (serverHandle == NULL) errorHandling(errorInfo.code, cU("Error Starting RFC Server"), &errorInfo, 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, &errorInfo);
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, &errorInfo);
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;
}