Skip to content

Latest commit

 

History

4 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

How to use https://github.com/ZigRFC/ZigRFC - client example.

Requirements

Download .lib and .dll files from https://support.sap.com/en/product/connectors/nwrfcsdk.html into folder src/dll/[here]

Create remote function module on your system:

FUNCTION ZIG_RFC_DECOMPRESS
  IMPORTING
    VALUE(COMPRESSED) TYPE XSTRING
  EXPORTING
    VALUE(DECOMPRESSED) TYPE STRING.
ENDFUNCTION.

Create connection in SM59 (type T, program ID same as used in parameters).

Allow server to register itself at SAP gateway:

  • Transaction SMGW -> Goto -> Expert Functions -> External Security -> Maintenance of ACL files -> RegInfo File
    • Parameters: P/D=P and TP=ZIG_RFC_SERVER, rest can be * for testing but should be filled for security with correct data

Example

The following wil allow the function ZIG_RFC_DECOMPRESS to be called form ABAP at destination specified in SM59.

const std = @import("std");
const rfc = @import("rfc");

const W = std.unicode.utf8ToUtf16LeStringLiteral;

fn createFuncDesc() !*rfc.desc.FunctionDesc {
    var error_info: rfc.ErrorInfo = undefined;
    const descr = rfc.desc.RfcCreateFunctionDesc(W("ZIG_RFC_DECOMPRESS"), null);

    var parameters: [2]rfc.desc.ParameterDesc = .{
        .{ .type = .xstring, .direction = .import },
        .{ .type = .string, .direction = .@"export" },
    };

    @memcpy(parameters[0].name[0..10], W("COMPRESSED"));
    @memcpy(parameters[1].name[0..12], W("DECOMPRESSED"));

    for (&parameters) |*p| {
        if (descr.AddParameter(p, &error_info) != .ok) {
            try rfc.PrintErrorToLog(&error_info);
            return error.CouldNotAddParameter;
        }
    }
    return descr;
}

fn ZIG_RFC_DECOMPRESS(rfc_handle: *rfc.connection.Connection, func_handle: *rfc.data_container.Function, error_info: *rfc.ErrorInfo) callconv(.c) rfc.ReturnCode {
    _ = rfc_handle;
    std.log.info("ZIG_RFC_DECOMPRESS called...", .{});

    var dummy_buffer: [0]u8 = undefined;
    var xstring_len: c_uint = undefined;
    switch (func_handle.GetXString(W("COMPRESSED"), &dummy_buffer, @intCast(dummy_buffer.len), &xstring_len, error_info)) {
        .buffer_too_small => {
            std.log.info("COMPRESSED required len={d}...", .{xstring_len});

            var gpa = std.heap.GeneralPurposeAllocator(.{}){};
            const allocator = gpa.allocator();

            //xstring_len has required length
            var xstring_buffer = allocator.alloc(u8, xstring_len) catch unreachable;
            defer allocator.free(xstring_buffer);

            if (func_handle.GetXString(W("COMPRESSED"), xstring_buffer.ptr, @intCast(xstring_buffer.len), &xstring_len, error_info) != .ok) {
                rfc.PrintErrorToLog(error_info) catch unreachable;
                return .invalid_parameter;
            }

            var reader = std.Io.Reader.fixed(xstring_buffer);

            var flate_buffer: [std.compress.flate.max_window_len]u8 = undefined;
            var flate = std.compress.flate.Decompress.init(&reader, std.compress.flate.Container.zlib, &flate_buffer);
            var string_buffer = flate.reader.allocRemaining(allocator, .unlimited) catch unreachable;
            defer allocator.free(string_buffer);

            std.log.info("DECOMPRESSED len={d}, result={s}", .{ string_buffer.len, string_buffer });

            //Now we need to convert to UTF16LE and fill exporting parameter
            var string_utf16le = std.unicode.utf8ToUtf16LeAlloc(allocator, string_buffer) catch unreachable;
            defer allocator.free(string_utf16le);

            if (func_handle.SetString(W("DECOMPRESSED"), string_utf16le.ptr, @intCast(string_utf16le.len), error_info) != .ok) {
                rfc.PrintErrorToLog(error_info) catch unreachable;
                return .invalid_parameter;
            }

            return .ok;
        },
        else => {
            //Empty compressed, so return empty uncompressed
            return .ok;
        },
    }
}

pub fn main() !void {
    var conn_params: [3]rfc.connection.Parameter = undefined;
    var error_info: rfc.ErrorInfo = undefined;

    // Must be registered in some connection in SM59 as Type=T, and registered as a program server with the same Program ID=ZIG_RFC_SERVER
    //
    // You also need to allow the server to register itslef via:
    // Transaction SMGW -> Goto -> Expert Functions -> External Security -> Maintenance of ACL files -> RegInfo File
    // Parameters: P/D=P and TP=ZIG_RFC_SERVER, rest can be * for testing but should be filled for security with correct data
    conn_params[0].name = W("PROGRAM_ID");
    conn_params[0].value = W("ZIG_RFC_SERVER");
    conn_params[1].name = W("gwhost");
    conn_params[1].value = W("*");
    conn_params[2].name = W("gwserv");
    conn_params[2].value = W("*");

    if (rfc.server.RfcInstallServerFunction(null, try createFuncDesc(), ZIG_RFC_DECOMPRESS, &error_info) != .ok) {
        try rfc.PrintErrorToLog(&error_info);
        return;
    }

    var conn = rfc.connection.RfcRegisterServer(&conn_params, 3, &error_info) orelse {
        try rfc.PrintErrorToLog(&error_info);
        return;
    };

    std.log.info("Listening...", .{});
    while (true) {
        const result = conn.ListenAndDispatch(30, &error_info);
        switch (result) {
            .ok => {
                std.log.info("Processed function call, listening again...", .{});
            },
            .retry => {
                std.log.info("No function call, listening again...", .{});
            },
            .abap_exception => {
                std.log.info("Function call ended with error, listening again...", .{});
            },
            else => {
                std.log.err("Unexpected ErrorCode={s}", .{std.enums.tagName(rfc.ReturnCode, result).?});
                try rfc.PrintErrorToLog(&error_info);
                return;
            },
        }
    }
}

About

Server example

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages