@mcp-abap-adt/sap-rfc-lite 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1108 @@
1
+ // SPDX-FileCopyrightText: 2014 SAP SE Srdjan Boskovic <srdjan.boskovic@sap.com>
2
+ // SPDX-FileCopyrightText: 2026 sap-rfc-lite contributors
3
+ //
4
+ // SPDX-License-Identifier: Apache-2.0
5
+
6
+ #include "nwrfcsdk.h"
7
+
8
+ namespace node_rfc {
9
+
10
+ ////////////////////////////////////////////////////////////////////////////////
11
+ // Set Parameters (to SDK)
12
+ ////////////////////////////////////////////////////////////////////////////////
13
+
14
+ SAP_UC* setString(const Napi::String napistr) {
15
+ RFC_RC rc;
16
+ RFC_ERROR_INFO errorInfo;
17
+ uint_t sapucSize, resultLen = 0;
18
+
19
+ std::string sstr = std::string(napistr);
20
+ // std::string str = napistr.Utf8Value();
21
+ sapucSize = sstr.length() + 1;
22
+
23
+ SAP_UC* sapuc = new SAP_UC[sapucSize];
24
+ memsetU(sapuc, 0, sapucSize);
25
+ rc = RfcUTF8ToSAPUC((RFC_BYTE*)&sstr[0],
26
+ sapucSize - 1,
27
+ sapuc,
28
+ &sapucSize,
29
+ &resultLen,
30
+ &errorInfo);
31
+
32
+ if (rc != RFC_OK) {
33
+ delete[] sapuc;
34
+ Napi::Error::Fatal("setString",
35
+ "NodeJS string could not be parsed to ABAP string");
36
+ }
37
+ return sapuc;
38
+ }
39
+
40
+ SAP_UC* setString(std::string sstr) {
41
+ RFC_RC rc;
42
+ RFC_ERROR_INFO errorInfo;
43
+ uint_t sapucSize, resultLen = 0;
44
+ sapucSize = sstr.length() + 1;
45
+
46
+ SAP_UC* sapuc = new SAP_UC[sapucSize];
47
+ memsetU(sapuc, 0, sapucSize);
48
+ rc = RfcUTF8ToSAPUC((RFC_BYTE*)&sstr[0],
49
+ sapucSize - 1,
50
+ sapuc,
51
+ &sapucSize,
52
+ &resultLen,
53
+ &errorInfo);
54
+
55
+ if (rc != RFC_OK) {
56
+ delete[] sapuc;
57
+ Napi::Error::Fatal("setString",
58
+ "NodeJS string could not be parsed to ABAP string");
59
+ }
60
+ return sapuc;
61
+ }
62
+
63
+ Napi::Value setRfmParameter(RFC_FUNCTION_DESC_HANDLE functionDescHandle,
64
+ RFC_FUNCTION_HANDLE functionHandle,
65
+ Napi::String name,
66
+ Napi::Value value,
67
+ RfmErrorPath* errorPath,
68
+ ClientOptionsStruct* client_options) {
69
+ Napi::EscapableHandleScope scope(value.Env());
70
+
71
+ RFC_RC rc;
72
+ RFC_ERROR_INFO errorInfo;
73
+ RFC_PARAMETER_DESC paramDesc;
74
+ SAP_UC* cName = setString(name);
75
+ errorPath->setParameterName(cName);
76
+ rc = RfcGetParameterDescByName(
77
+ functionDescHandle, cName, &paramDesc, &errorInfo);
78
+ delete[] cName;
79
+ if (rc != RFC_OK) {
80
+ return scope.Escape(rfcSdkError(&errorInfo, errorPath));
81
+ }
82
+ return scope.Escape(setVariable(paramDesc.type,
83
+ functionHandle,
84
+ paramDesc.name,
85
+ value,
86
+ paramDesc.typeDescHandle,
87
+ errorPath,
88
+ client_options));
89
+ }
90
+
91
+ Napi::Value setStructure(RFC_STRUCTURE_HANDLE structHandle,
92
+ RFC_TYPE_DESC_HANDLE functionDescHandle,
93
+ Napi::Value value,
94
+ RfmErrorPath* errorPath,
95
+ ClientOptionsStruct* client_options) {
96
+ RFC_RC rc;
97
+ RFC_ERROR_INFO errorInfo;
98
+
99
+ Napi::EscapableHandleScope scope(value.Env());
100
+
101
+ Napi::Object structObj = value.ToObject();
102
+ Napi::Array structNames = structObj.GetPropertyNames();
103
+ uint_t structSize = structNames.Length();
104
+
105
+ RFC_FIELD_DESC fieldDesc;
106
+
107
+ Napi::Value retVal = value.Env().Undefined();
108
+
109
+ for (uint_t i = 0; i < structSize; i++) {
110
+ Napi::String name = structNames.Get(i).ToString();
111
+ Napi::Value _value = structObj.Get(name);
112
+
113
+ SAP_UC* cValue = setString(name);
114
+ rc = RfcGetFieldDescByName(
115
+ functionDescHandle, cValue, &fieldDesc, &errorInfo);
116
+ delete[] cValue;
117
+ if (rc != RFC_OK) {
118
+ errorPath->setFieldName(fieldDesc.name);
119
+ retVal = rfcSdkError(&errorInfo, errorPath);
120
+ break;
121
+ }
122
+ retVal = setVariable(fieldDesc.type,
123
+ structHandle,
124
+ fieldDesc.name,
125
+ _value,
126
+ fieldDesc.typeDescHandle,
127
+ errorPath,
128
+ client_options);
129
+ if (!retVal.IsUndefined()) {
130
+ break;
131
+ }
132
+ }
133
+ return retVal;
134
+ }
135
+
136
+ Napi::Value setVariable(RFCTYPE typ,
137
+ RFC_FUNCTION_HANDLE functionHandle,
138
+ SAP_UC* cName,
139
+ Napi::Value value,
140
+ RFC_TYPE_DESC_HANDLE functionDescHandle,
141
+ RfmErrorPath* errorPath,
142
+ ClientOptionsStruct* client_options) {
143
+ Napi::EscapableHandleScope scope(value.Env());
144
+ RFC_RC rc = RFC_OK;
145
+ RFC_ERROR_INFO errorInfo;
146
+ SAP_UC* cValue;
147
+
148
+ errorPath->setName(typ, cName);
149
+
150
+ switch (typ) {
151
+ case RFCTYPE_STRUCTURE: {
152
+ RFC_STRUCTURE_HANDLE structHandle;
153
+ rc = RfcGetStructure(functionHandle, cName, &structHandle, &errorInfo);
154
+ if (rc != RFC_OK) {
155
+ return scope.Escape(rfcSdkError(&errorInfo, errorPath));
156
+ }
157
+ Napi::Value rv = setStructure(
158
+ structHandle, functionDescHandle, value, errorPath, client_options);
159
+ if (!rv.IsUndefined()) {
160
+ return scope.Escape(rv);
161
+ }
162
+ break;
163
+ }
164
+ case RFCTYPE_TABLE: {
165
+ RFC_TABLE_HANDLE tableHandle;
166
+ rc = RfcGetTable(functionHandle, cName, &tableHandle, &errorInfo);
167
+
168
+ if (rc != RFC_OK) {
169
+ break;
170
+ }
171
+ if (!value.IsArray()) {
172
+ return nodeRfcError(
173
+ "Array expected from NodeJS, for ABAP RFM table of type " +
174
+ std::to_string(typ),
175
+ errorPath);
176
+ }
177
+ Napi::Array array = value.As<Napi::Array>();
178
+ uint_t rowCount = array.Length();
179
+
180
+ for (uint_t i = 0; i < rowCount; i++) {
181
+ errorPath->table_line = i;
182
+ RFC_STRUCTURE_HANDLE structHandle =
183
+ RfcAppendNewRow(tableHandle, &errorInfo);
184
+ Napi::Value line = array.Get(i);
185
+ if (line.IsBuffer() || line.IsString() || line.IsNumber()) {
186
+ Napi::Object lineObj = Napi::Object::New(value.Env());
187
+ lineObj.Set(Napi::String::New(value.Env(), ""), line);
188
+ line = lineObj;
189
+ }
190
+ Napi::Value rv = setStructure(
191
+ structHandle, functionDescHandle, line, errorPath, client_options);
192
+ if (!rv.IsUndefined()) {
193
+ return scope.Escape(rv);
194
+ }
195
+ }
196
+ break;
197
+ }
198
+ case RFCTYPE_BYTE: {
199
+ if (!value.IsBuffer()) {
200
+ return nodeRfcError(
201
+ "Buffer expected from NodeJS for ABAP field of type " +
202
+ std::to_string(typ),
203
+ errorPath);
204
+ }
205
+
206
+ Napi::Buffer<SAP_RAW> js_buf = value.As<Napi::Buffer<SAP_RAW>>();
207
+ uint_t js_buf_bytelen = js_buf.ByteLength();
208
+ SAP_RAW* byteValue = new SAP_RAW[js_buf_bytelen];
209
+ memcpy(byteValue, js_buf.Data(), js_buf_bytelen);
210
+
211
+ // excessive padding bytes sent from NodeJS, are silently trimmed by SDK
212
+ // to ABAP field length
213
+ rc = RfcSetBytes(
214
+ functionHandle, cName, byteValue, js_buf_bytelen, &errorInfo);
215
+ delete[] byteValue;
216
+ break;
217
+ }
218
+ case RFCTYPE_XSTRING: {
219
+ if (!value.IsBuffer()) {
220
+ return nodeRfcError(
221
+ "Buffer expected from NodeJS for ABAP field of type " +
222
+ std::to_string(typ),
223
+ errorPath);
224
+ }
225
+
226
+ Napi::Buffer<SAP_RAW> js_buf = value.As<Napi::Buffer<SAP_RAW>>();
227
+ uint_t js_buf_bytelen = js_buf.ByteLength();
228
+ SAP_RAW* byteValue = new SAP_RAW[js_buf_bytelen];
229
+ memcpy(byteValue, js_buf.Data(), js_buf_bytelen);
230
+
231
+ rc = RfcSetXString(
232
+ functionHandle, cName, byteValue, js_buf_bytelen, &errorInfo);
233
+ delete[] byteValue;
234
+ break;
235
+ }
236
+ case RFCTYPE_CHAR:
237
+ case RFCTYPE_STRING: {
238
+ if (!value.IsString()) {
239
+ return nodeRfcError(
240
+ "String expected from NodeJS for ABAP field of type " +
241
+ std::to_string(typ),
242
+ errorPath);
243
+ }
244
+ cValue = setString(value.ToString());
245
+ rc = RfcSetString(
246
+ functionHandle, cName, cValue, strlenU(cValue), &errorInfo);
247
+ delete[] cValue;
248
+ break;
249
+ }
250
+ case RFCTYPE_NUM: {
251
+ if (!value.IsString()) {
252
+ return nodeRfcError(
253
+ "Char expected from NodeJS for ABAP field of type " +
254
+ std::to_string(typ),
255
+ errorPath);
256
+ }
257
+ cValue = setString(value.ToString());
258
+ rc =
259
+ RfcSetNum(functionHandle, cName, cValue, strlenU(cValue), &errorInfo);
260
+ delete[] cValue;
261
+ break;
262
+ }
263
+ case RFCTYPE_BCD: // fallthrough
264
+ case RFCTYPE_DECF16:
265
+ case RFCTYPE_DECF34:
266
+ case RFCTYPE_FLOAT: {
267
+ if (!value.IsNumber() && !value.IsObject() && !value.IsString()) {
268
+ return nodeRfcError("Number, number object or string expected from "
269
+ "NodeJS for ABAP field of type " +
270
+ std::to_string(typ),
271
+ errorPath);
272
+ }
273
+ cValue = setString(value.ToString());
274
+ rc = RfcSetString(
275
+ functionHandle, cName, cValue, strlenU(cValue), &errorInfo);
276
+ delete[] cValue;
277
+ break;
278
+ }
279
+ case RFCTYPE_INT: // fallthrough
280
+ case RFCTYPE_INT1:
281
+ case RFCTYPE_INT2:
282
+ case RFCTYPE_INT8: {
283
+ if (!value.IsNumber()) {
284
+ return nodeRfcError(
285
+ "Integer number expected from NodeJS for ABAP field of type " +
286
+ std::to_string(typ),
287
+ errorPath);
288
+ }
289
+
290
+ // https://github.com/mhdawson/node-sqlite3/pull/3
291
+ double numDouble = value.ToNumber().DoubleValue();
292
+ if ((int64_t)numDouble !=
293
+ numDouble) // or std::trunc(numDouble) == numDouble;
294
+ {
295
+ return nodeRfcError(
296
+ "Integer number expected from NodeJS for ABAP field of type " +
297
+ std::to_string(typ) + ", got " + value.ToString().Utf8Value(),
298
+ errorPath);
299
+ }
300
+ RFC_INT rfcInt = (RFC_INT)value.As<Napi::Number>().Int64Value();
301
+ // int64_t rfcInt = value.As<Napi::Number>().Int64Value();
302
+ // printf("typ: %d value: %d %u", typ, rfcInt, UINT8_MAX);
303
+ if (typ == RFCTYPE_INT8) {
304
+ rc = RfcSetInt8(functionHandle, cName, rfcInt, &errorInfo);
305
+ } else {
306
+ if ((typ == RFCTYPE_INT1 && rfcInt > UINT8_MAX) ||
307
+ (typ == RFCTYPE_INT2 &&
308
+ ((rfcInt > INT16_MAX) || (rfcInt < INT16_MIN)))) {
309
+ return nodeRfcError(
310
+ "Overflow or other error when putting NodeJS value " +
311
+ std::to_string(rfcInt) + " into ABAP integer field of type " +
312
+ std::to_string(typ),
313
+ errorPath);
314
+ }
315
+
316
+ rc = RfcSetInt(functionHandle, cName, rfcInt, &errorInfo);
317
+ }
318
+ break;
319
+ }
320
+ case RFCTYPE_UTCLONG: {
321
+ if (!value.IsString()) {
322
+ return nodeRfcError(
323
+ "UTCLONG string expected from NodeJS for ABAP field of type " +
324
+ std::to_string(typ),
325
+ errorPath);
326
+ }
327
+ cValue = setString(value.ToString());
328
+ rc = RfcSetString(
329
+ functionHandle, cName, cValue, strlenU(cValue), &errorInfo);
330
+ delete[] cValue;
331
+ break;
332
+ }
333
+ case RFCTYPE_DATE: {
334
+ if (!client_options->dateToABAP.IsEmpty()) {
335
+ // YYYYMMDD format expected
336
+ value = client_options->dateToABAP.Call({value});
337
+ }
338
+ if (!value.IsString()) {
339
+ return nodeRfcError("Date format YYYYMMDD expected from NodeJS "
340
+ "for ABAP field of type " +
341
+ std::to_string(typ),
342
+ errorPath);
343
+ }
344
+ cValue = setString(value.ToString());
345
+ rc = RfcSetDate(functionHandle, cName, cValue, &errorInfo);
346
+ delete[] cValue;
347
+ break;
348
+ }
349
+ case RFCTYPE_TIME: {
350
+ if (!client_options->timeToABAP.IsEmpty()) {
351
+ // HHMMSS format expected
352
+ value = client_options->timeToABAP.Call({value});
353
+ }
354
+ if (!value.IsString()) {
355
+ return nodeRfcError("Time format HHMMSS expected from NodeJS for "
356
+ "ABAP field of type " +
357
+ std::to_string(typ),
358
+ errorPath);
359
+ }
360
+ cValue = setString(value.ToString());
361
+ rc = RfcSetTime(functionHandle, cName, cValue, &errorInfo);
362
+ delete[] cValue;
363
+ break;
364
+ }
365
+ default: {
366
+ return nodeRfcError("Unknown RFC type from NodeJS " + std::to_string(typ),
367
+ errorPath);
368
+ }
369
+ }
370
+ if (rc != RFC_OK) {
371
+ return scope.Escape(rfcSdkError(&errorInfo, errorPath));
372
+ }
373
+ return scope.Env().Undefined();
374
+ }
375
+
376
+ ////////////////////////////////////////////////////////////////////////////////
377
+ // Get Parameters (from SDK)
378
+ ////////////////////////////////////////////////////////////////////////////////
379
+
380
+ Napi::Value wrapString(const SAP_UC* uc, int length) {
381
+ RFC_ERROR_INFO errorInfo;
382
+
383
+ Napi::EscapableHandleScope scope(node_rfc::__env);
384
+
385
+ if (length == -1) {
386
+ length = strlenU(uc);
387
+ }
388
+ if (length == 0) {
389
+ return scope.Escape(Napi::String::New(node_rfc::__env, ""));
390
+ }
391
+ // try with 3 bytes per unicode character
392
+ uint_t utf8Size = length * 3;
393
+ RFC_BYTE* utf8 = new RFC_BYTE[utf8Size + 1];
394
+ utf8[0] = '\0';
395
+ uint_t resultLen = 0;
396
+ RfcSAPUCToUTF8(uc, length, utf8, &utf8Size, &resultLen, &errorInfo);
397
+ if (errorInfo.code != RFC_OK) {
398
+ // not enough, try with 5
399
+ delete[] utf8;
400
+ utf8Size = length * 5;
401
+ utf8 = new RFC_BYTE[utf8Size + 1];
402
+ utf8[0] = '\0';
403
+ resultLen = 0;
404
+ RfcSAPUCToUTF8(uc, length, utf8, &utf8Size, &resultLen, &errorInfo);
405
+ if (errorInfo.code != RFC_OK) {
406
+ delete[] utf8;
407
+ return node_rfc::__env.Undefined();
408
+ }
409
+ }
410
+
411
+ // trim trailing whitespaces
412
+ int i = resultLen - 1;
413
+ while (i >= 0 && isspace(utf8[i])) {
414
+ i--;
415
+ }
416
+ utf8[i + 1] = '\0';
417
+ Napi::Value resultValue = Napi::String::New(
418
+ node_rfc::__env, std::string(reinterpret_cast<char*>(utf8), i + 1));
419
+ delete[] utf8;
420
+ return scope.Escape(resultValue);
421
+ }
422
+
423
+ ValuePair getRfmParameters(RFC_FUNCTION_DESC_HANDLE functionDescHandle,
424
+ RFC_FUNCTION_HANDLE functionHandle,
425
+ RfmErrorPath* errorPath,
426
+ ClientOptionsStruct* client_options) {
427
+ Napi::EscapableHandleScope scope(node_rfc::__env);
428
+
429
+ RFC_PARAMETER_DESC paramDesc;
430
+
431
+ uint_t paramCount = 0;
432
+
433
+ RfcGetParameterCount(functionDescHandle, &paramCount, nullptr);
434
+ Napi::Object resultObj = Napi::Object::New(node_rfc::__env);
435
+
436
+ for (uint_t i = 0; i < paramCount; i++) {
437
+ RfcGetParameterDescByIndex(functionDescHandle, i, &paramDesc, nullptr);
438
+ if ((paramDesc.direction & client_options->filter_param_type) == 0) {
439
+ Napi::String name = wrapString(paramDesc.name).As<Napi::String>();
440
+ errorPath->setParameterName(paramDesc.name);
441
+ ValuePair result = getVariable(paramDesc.type,
442
+ functionHandle,
443
+ paramDesc.name,
444
+ paramDesc.nucLength,
445
+ paramDesc.typeDescHandle,
446
+ errorPath,
447
+ client_options);
448
+ if (!result.first.IsUndefined()) {
449
+ return result;
450
+ }
451
+ (resultObj).Set(name, result.second);
452
+ }
453
+ }
454
+ return ValuePair(ENV_UNDEFINED, scope.Escape(resultObj));
455
+ }
456
+
457
+ ValuePair getStructure(RFC_TYPE_DESC_HANDLE typeDesc,
458
+ RFC_STRUCTURE_HANDLE structHandle,
459
+ RfmErrorPath* errorPath,
460
+ ClientOptionsStruct* client_options) {
461
+ Napi::EscapableHandleScope scope(node_rfc::__env);
462
+
463
+ Napi::Object resultObj = Napi::Object::New(node_rfc::__env);
464
+
465
+ RFC_RC rc;
466
+ RFC_ERROR_INFO errorInfo;
467
+ RFC_FIELD_DESC fieldDesc;
468
+ uint_t fieldCount;
469
+ rc = RfcGetFieldCount(typeDesc, &fieldCount, &errorInfo);
470
+ if (rc != RFC_OK) {
471
+ return ValuePair(rfcSdkError(&errorInfo, errorPath), ENV_UNDEFINED);
472
+ }
473
+
474
+ for (uint_t i = 0; i < fieldCount; i++) {
475
+ rc = RfcGetFieldDescByIndex(typeDesc, i, &fieldDesc, &errorInfo);
476
+ if (rc != RFC_OK) {
477
+ errorPath->setFieldName(fieldDesc.name);
478
+ return ValuePair(rfcSdkError(&errorInfo, errorPath), ENV_UNDEFINED);
479
+ }
480
+ ValuePair result = getVariable(fieldDesc.type,
481
+ structHandle,
482
+ fieldDesc.name,
483
+ fieldDesc.nucLength,
484
+ fieldDesc.typeDescHandle,
485
+ errorPath,
486
+ client_options);
487
+ if (!result.first.IsUndefined()) {
488
+ return result;
489
+ }
490
+ (resultObj).Set(wrapString(fieldDesc.name), result.second);
491
+ }
492
+
493
+ if (fieldCount == 1) {
494
+ Napi::String fieldName =
495
+ resultObj.GetPropertyNames().Get((uint_t)0).As<Napi::String>();
496
+ if (fieldName.Utf8Value().size() == 0) {
497
+ return ValuePair(ENV_UNDEFINED, scope.Escape(resultObj.Get(fieldName)));
498
+ }
499
+ }
500
+
501
+ return ValuePair(ENV_UNDEFINED, scope.Escape(resultObj));
502
+ }
503
+
504
+ ValuePair getVariable(RFCTYPE typ,
505
+ RFC_FUNCTION_HANDLE functionHandle,
506
+ SAP_UC* cName,
507
+ uint_t cLen,
508
+ RFC_TYPE_DESC_HANDLE typeDesc,
509
+ RfmErrorPath* errorPath,
510
+ ClientOptionsStruct* client_options) {
511
+ Napi::EscapableHandleScope scope(node_rfc::__env);
512
+ Napi::Value resultValue = ENV_UNDEFINED;
513
+
514
+ RFC_RC rc = RFC_OK;
515
+ RFC_ERROR_INFO errorInfo;
516
+ RFC_STRUCTURE_HANDLE structHandle;
517
+
518
+ errorPath->setName(typ, cName);
519
+
520
+ switch (typ) {
521
+ case RFCTYPE_STRUCTURE: {
522
+ rc = RfcGetStructure(functionHandle, cName, &structHandle, &errorInfo);
523
+ if (rc != RFC_OK) {
524
+ break;
525
+ }
526
+
527
+ ValuePair result =
528
+ getStructure(typeDesc, structHandle, errorPath, client_options);
529
+ if (!result.first.IsUndefined()) {
530
+ return result;
531
+ }
532
+ resultValue = result.second;
533
+ break;
534
+ }
535
+ case RFCTYPE_TABLE: {
536
+ RFC_TABLE_HANDLE tableHandle;
537
+ rc = RfcGetTable(functionHandle, cName, &tableHandle, &errorInfo);
538
+ if (rc != RFC_OK) {
539
+ break;
540
+ }
541
+ uint_t rowCount;
542
+ rc = RfcGetRowCount(tableHandle, &rowCount, &errorInfo);
543
+
544
+ Napi::Array table = Napi::Array::New(node_rfc::__env);
545
+
546
+ while (rowCount-- > 0) {
547
+ errorPath->table_line = rowCount;
548
+ RfcMoveTo(tableHandle, rowCount, nullptr);
549
+ ValuePair result =
550
+ getStructure(typeDesc, tableHandle, errorPath, client_options);
551
+ if (!result.first.IsUndefined()) {
552
+ return result;
553
+ }
554
+ RfcDeleteCurrentRow(tableHandle, &errorInfo);
555
+ (table).Set(rowCount, result.second);
556
+ }
557
+ resultValue = table;
558
+ break;
559
+ }
560
+ case RFCTYPE_CHAR: {
561
+ RFC_CHAR* charValue = new RFC_CHAR[cLen];
562
+ rc = RfcGetChars(functionHandle, cName, charValue, cLen, &errorInfo);
563
+ if (rc != RFC_OK) {
564
+ break;
565
+ }
566
+ resultValue = wrapString(charValue, cLen);
567
+ delete[] charValue;
568
+ break;
569
+ }
570
+ case RFCTYPE_STRING: {
571
+ uint_t resultLen = 0, strLen = 0;
572
+ RfcGetStringLength(functionHandle, cName, &strLen, &errorInfo);
573
+ SAP_UC* stringValue = new RFC_CHAR[strLen + 1];
574
+ rc = RfcGetString(functionHandle,
575
+ cName,
576
+ stringValue,
577
+ strLen + 1,
578
+ &resultLen,
579
+ &errorInfo);
580
+ if (rc != RFC_OK) {
581
+ break;
582
+ }
583
+ resultValue = wrapString(stringValue, strLen);
584
+ delete[] stringValue;
585
+ break;
586
+ }
587
+ case RFCTYPE_NUM: {
588
+ RFC_NUM* numValue = new RFC_CHAR[cLen];
589
+ rc = RfcGetNum(functionHandle, cName, numValue, cLen, &errorInfo);
590
+ if (rc != RFC_OK) {
591
+ delete[] numValue;
592
+ break;
593
+ }
594
+ resultValue = wrapString(numValue, cLen);
595
+ delete[] numValue;
596
+ break;
597
+ }
598
+ case RFCTYPE_BYTE: {
599
+ SAP_RAW* byteValue = new SAP_RAW[cLen];
600
+
601
+ rc = RfcGetBytes(functionHandle, cName, byteValue, cLen, &errorInfo);
602
+ if (rc != RFC_OK) {
603
+ delete[] byteValue;
604
+ break;
605
+ }
606
+ resultValue = Napi::Buffer<SAP_RAW>::New(
607
+ node_rfc::__env, byteValue, cLen, [](void*, SAP_RAW* byteValue) {
608
+ delete[] byteValue;
609
+ });
610
+ break;
611
+ }
612
+
613
+ case RFCTYPE_XSTRING: {
614
+ uint_t strLen, resultLen;
615
+ RfcGetStringLength(functionHandle, cName, &strLen, &errorInfo);
616
+
617
+ SAP_RAW* byteValue = new SAP_RAW[strLen + 1];
618
+ byteValue[strLen] = '\0';
619
+
620
+ rc = RfcGetXString(
621
+ functionHandle, cName, byteValue, strLen, &resultLen, &errorInfo);
622
+
623
+ if (rc != RFC_OK) {
624
+ delete[] byteValue;
625
+ break;
626
+ }
627
+ resultValue = Napi::Buffer<SAP_RAW>::New(
628
+ node_rfc::__env, byteValue, resultLen, [](void*, SAP_RAW* byteValue) {
629
+ delete[] byteValue;
630
+ });
631
+ break;
632
+ }
633
+ case RFCTYPE_BCD: {
634
+ // An upper bound for the length of the _string representation_
635
+ // of the BCD is given by (2*cLen)-1 (each digit is encoded in 4bit,
636
+ // the first 4 bit are reserved for the sign)
637
+ // Furthermore, a sign char, a decimal separator char may be present
638
+ // => (2*cLen)+1
639
+ uint_t resultLen;
640
+ uint_t strLen = 2 * cLen + 1;
641
+ SAP_UC* sapuc = new SAP_UC[strLen + 1];
642
+ rc = RfcGetString(
643
+ functionHandle, cName, sapuc, strLen + 1, &resultLen, &errorInfo);
644
+ if (rc == 23) // Buffer too small, use returned requried result length
645
+ {
646
+ RFC_LOG("Buffer for BCD/DECF type too small");
647
+ delete[] sapuc;
648
+ strLen = resultLen;
649
+ sapuc = new SAP_UC[strLen + 1];
650
+ rc = RfcGetString(
651
+ functionHandle, cName, sapuc, strLen + 1, &resultLen, &errorInfo);
652
+ }
653
+ if (rc != RFC_OK) {
654
+ delete[] sapuc;
655
+ break;
656
+ }
657
+ resultValue = wrapString(sapuc, resultLen).ToString();
658
+ delete[] sapuc;
659
+
660
+ if (client_options->bcd == CLIENT_OPTION_BCD_FUNCTION) {
661
+ resultValue = client_options->bcdFunction.Call({resultValue});
662
+ } else if (client_options->bcd == CLIENT_OPTION_BCD_NUMBER) {
663
+ resultValue = resultValue.ToNumber();
664
+ }
665
+ break;
666
+ }
667
+ case RFCTYPE_FLOAT: {
668
+ RFC_FLOAT floatValue;
669
+ rc = RfcGetFloat(functionHandle, cName, &floatValue, &errorInfo);
670
+ resultValue = Napi::Number::New(node_rfc::__env, floatValue);
671
+ break;
672
+ }
673
+ case RFCTYPE_DECF16:
674
+ case RFCTYPE_DECF34: {
675
+ // An upper bound for the length of the _string representation_
676
+ // of the BCD is given by (2*cLen)-1 (each digit is encoded in 4bit,
677
+ // the first 4 bit are reserved for the sign)
678
+ // Furthermore, a sign char, a decimal separator char may be present
679
+ // => (2*cLen)+1
680
+ // and exponent char, sign and exponent
681
+ // => +9
682
+ uint_t resultLen;
683
+ uint_t strLen = 2 * cLen + 10;
684
+ SAP_UC* sapuc = new SAP_UC[strLen + 1];
685
+ rc = RfcGetString(
686
+ functionHandle, cName, sapuc, strLen + 1, &resultLen, &errorInfo);
687
+ if (rc == 23) // Buffer too small, use returned requried result length
688
+ {
689
+ RFC_LOG("Buffer for BCD/DECF type too small");
690
+ delete[] sapuc;
691
+ strLen = resultLen;
692
+ sapuc = new SAP_UC[strLen + 1];
693
+ rc = RfcGetString(
694
+ functionHandle, cName, sapuc, strLen + 1, &resultLen, &errorInfo);
695
+ }
696
+ if (rc != RFC_OK) {
697
+ delete[] sapuc;
698
+ break;
699
+ }
700
+ resultValue = wrapString(sapuc, resultLen).ToString();
701
+ delete[] sapuc;
702
+
703
+ if (client_options->bcd == CLIENT_OPTION_BCD_FUNCTION) {
704
+ resultValue = client_options->bcdFunction.Call({resultValue});
705
+ } else if (client_options->bcd == CLIENT_OPTION_BCD_NUMBER) {
706
+ resultValue = resultValue.ToNumber();
707
+ }
708
+ break;
709
+ }
710
+ case RFCTYPE_INT: {
711
+ RFC_INT intValue;
712
+ rc = RfcGetInt(functionHandle, cName, &intValue, &errorInfo);
713
+ if (rc != RFC_OK) {
714
+ break;
715
+ }
716
+ resultValue = Napi::Number::New(node_rfc::__env, intValue);
717
+ break;
718
+ }
719
+ case RFCTYPE_INT1: {
720
+ RFC_INT1 intValue;
721
+ rc = RfcGetInt1(functionHandle, cName, &intValue, &errorInfo);
722
+ if (rc != RFC_OK) {
723
+ break;
724
+ }
725
+ resultValue = Napi::Number::New(node_rfc::__env, intValue);
726
+ break;
727
+ }
728
+ case RFCTYPE_INT2: {
729
+ RFC_INT2 intValue;
730
+ rc = RfcGetInt2(functionHandle, cName, &intValue, &errorInfo);
731
+ if (rc != RFC_OK) {
732
+ break;
733
+ }
734
+ resultValue = Napi::Number::New(node_rfc::__env, intValue);
735
+ break;
736
+ }
737
+ case RFCTYPE_INT8: {
738
+ RFC_INT8 intValue;
739
+ rc = RfcGetInt8(functionHandle, cName, &intValue, &errorInfo);
740
+ if (rc != RFC_OK) {
741
+ break;
742
+ }
743
+ resultValue = Napi::Number::New(node_rfc::__env, intValue);
744
+ break;
745
+ }
746
+ case RFCTYPE_UTCLONG: {
747
+ uint_t resultLen = 0, strLen = 27;
748
+ SAP_UC* stringValue = new SAP_UC[strLen + 1];
749
+ rc = RfcGetString(functionHandle,
750
+ cName,
751
+ stringValue,
752
+ strLen + 1,
753
+ &resultLen,
754
+ &errorInfo);
755
+ if (rc != RFC_OK) {
756
+ break;
757
+ }
758
+ stringValue[19] = '.';
759
+ resultValue = wrapString(stringValue, strLen);
760
+ delete[] stringValue;
761
+ break;
762
+ }
763
+ case RFCTYPE_DATE: {
764
+ RFC_DATE dateValue;
765
+ rc = RfcGetDate(functionHandle, cName, dateValue, &errorInfo);
766
+ if (rc != RFC_OK) {
767
+ break;
768
+ }
769
+ resultValue = wrapString(dateValue, 8);
770
+ if (!client_options->dateFromABAP.IsEmpty()) {
771
+ resultValue = client_options->dateFromABAP.Call({resultValue});
772
+ }
773
+ break;
774
+ }
775
+ case RFCTYPE_TIME: {
776
+ RFC_TIME timeValue;
777
+ rc = RfcGetTime(functionHandle, cName, timeValue, &errorInfo);
778
+ if (rc != RFC_OK) {
779
+ break;
780
+ }
781
+ resultValue = wrapString(timeValue, 6);
782
+ if (!client_options->timeFromABAP.IsEmpty()) {
783
+ resultValue = client_options->timeFromABAP.Call({resultValue});
784
+ }
785
+ break;
786
+ }
787
+ default:
788
+ return ValuePair(
789
+ ENV_UNDEFINED,
790
+ nodeRfcError("RFC type from ABAP not supported" + std::to_string(typ),
791
+ errorPath));
792
+ break;
793
+ }
794
+
795
+ if (rc != RFC_OK) {
796
+ return ValuePair(scope.Escape(rfcSdkError(&errorInfo, errorPath)),
797
+ ENV_UNDEFINED);
798
+ }
799
+
800
+ if (resultValue.IsUndefined()) {
801
+ return ValuePair(
802
+ scope.Escape(nodeRfcError("Non-unicode ABAP string", errorPath)),
803
+ ENV_UNDEFINED);
804
+ }
805
+
806
+ return ValuePair(ENV_UNDEFINED, scope.Escape(resultValue));
807
+ }
808
+
809
+ ////////////////////////////////////////////////////////////////////////////////
810
+ // NODE-RFC ERRORS
811
+ ////////////////////////////////////////////////////////////////////////////////
812
+
813
+ Napi::Value nodeRfcError(std::string message, RfmErrorPath* errorPath) {
814
+ Napi::EscapableHandleScope scope(node_rfc::__env);
815
+ Napi::Object errorObj = Napi::Object::New(node_rfc::__env);
816
+ errorObj.Set("name", "nodeRfcError");
817
+ errorObj.Set("message", message);
818
+ if (errorPath != nullptr) {
819
+ errorObj.Set("rfmPath", errorPath->getpath());
820
+ }
821
+ return scope.Escape(errorObj);
822
+ }
823
+
824
+ ////////////////////////////////////////////////////////////////////////////////
825
+ // NWRFC SDK ERRORS
826
+ ////////////////////////////////////////////////////////////////////////////////
827
+
828
+ Napi::Object RfcLibError(RFC_ERROR_INFO* errorInfo) {
829
+ Napi::Object errorObj = Napi::Object::New(node_rfc::__env);
830
+ (errorObj).Set("name", "RfcLibError");
831
+ (errorObj).Set("group", Napi::Number::New(node_rfc::__env, errorInfo->group));
832
+ (errorObj).Set("code", Napi::Number::New(node_rfc::__env, errorInfo->code));
833
+ (errorObj).Set("codeString", wrapString(RfcGetRcAsString(errorInfo->code)));
834
+ (errorObj).Set("key", wrapString(errorInfo->key));
835
+ (errorObj).Set("message", wrapString(errorInfo->message));
836
+ return errorObj;
837
+ }
838
+
839
+ Napi::Object AbapError(RFC_ERROR_INFO* errorInfo) {
840
+ Napi::Object errorObj = Napi::Object::New(node_rfc::__env);
841
+ (errorObj).Set("name", "ABAPError");
842
+ (errorObj).Set("group", Napi::Number::New(node_rfc::__env, errorInfo->group));
843
+ (errorObj).Set("code", Napi::Number::New(node_rfc::__env, errorInfo->code));
844
+ (errorObj).Set("codeString", wrapString(RfcGetRcAsString(errorInfo->code)));
845
+ (errorObj).Set("key", wrapString(errorInfo->key));
846
+ (errorObj).Set("message", wrapString(errorInfo->message));
847
+ (errorObj).Set("abapMsgClass", wrapString(errorInfo->abapMsgClass));
848
+ (errorObj).Set("abapMsgType", wrapString(errorInfo->abapMsgType));
849
+ (errorObj).Set("abapMsgNumber", wrapString(errorInfo->abapMsgNumber));
850
+ (errorObj).Set("abapMsgV1", wrapString(errorInfo->abapMsgV1));
851
+ (errorObj).Set("abapMsgV2", wrapString(errorInfo->abapMsgV2));
852
+ (errorObj).Set("abapMsgV3", wrapString(errorInfo->abapMsgV3));
853
+ (errorObj).Set("abapMsgV4", wrapString(errorInfo->abapMsgV4));
854
+
855
+ return errorObj;
856
+ }
857
+
858
+ Napi::Value rfcSdkError(RFC_ERROR_INFO* errorInfo, RfmErrorPath* errorPath) {
859
+ Napi::EscapableHandleScope scope(node_rfc::__env);
860
+ Napi::Object errorObj;
861
+
862
+ switch (errorInfo->group) {
863
+ case OK: // 0: should never happen
864
+ errorObj = nodeRfcError("rfcSdkError invoked with the RFC error group OK")
865
+ .As<Napi::Object>();
866
+ break;
867
+
868
+ case LOGON_FAILURE: // 3: Error message raised when logon fails
869
+ case COMMUNICATION_FAILURE: // 4: Problems with the network connection (or
870
+ // backend broke down and killed the
871
+ // connection)
872
+ case EXTERNAL_RUNTIME_FAILURE: // 5: Problems in the RFC runtime of the
873
+ // external program (i.e "this" library)
874
+ errorObj = RfcLibError(errorInfo);
875
+ break;
876
+
877
+ case ABAP_APPLICATION_FAILURE: // 1: ABAP Exception raised in ABAP function
878
+ // modules
879
+ case ABAP_RUNTIME_FAILURE: // 2: ABAP Message raised in ABAP function
880
+ // modules or in ABAP runtime of the backend
881
+ // (e.g Kernel)
882
+ case EXTERNAL_APPLICATION_FAILURE: // 6: Problems in the external program
883
+ // (e.g in the external server
884
+ // implementation)
885
+ case EXTERNAL_AUTHORIZATION_FAILURE: // 7: Problems raised in the
886
+ // authorization check handler
887
+ // provided by the external server
888
+ // implementation
889
+ errorObj = AbapError(errorInfo);
890
+ break;
891
+ default:
892
+
893
+ errorObj = nodeRfcError("wrapError invoked with an unknown err group:" +
894
+ std::to_string(errorInfo->group))
895
+ .As<Napi::Object>();
896
+ }
897
+
898
+ if (errorPath != nullptr) {
899
+ errorObj.Set("rfmPath", errorPath->getpath());
900
+ }
901
+ return scope.Escape(errorObj);
902
+ }
903
+
904
+ ////////////////////////////////////////////////////////////////////////////////
905
+ // Connection parameters and client options parsers
906
+ ////////////////////////////////////////////////////////////////////////////////
907
+
908
+ void getConnectionParams(Napi::Object clientParamsObject,
909
+ ConnectionParamsStruct* clientParams) {
910
+ Napi::Array paramNames = clientParamsObject.GetPropertyNames();
911
+ clientParams->paramSize = paramNames.Length();
912
+ if (clientParams->paramSize == 0) {
913
+ Napi::TypeError::New(node_rfc::__env,
914
+ "Client connection parameters missing")
915
+ .ThrowAsJavaScriptException();
916
+ }
917
+ clientParams->connectionParams =
918
+ new RFC_CONNECTION_PARAMETER[clientParams->paramSize *
919
+ sizeof(RFC_CONNECTION_PARAMETER)];
920
+ for (uint_t ii = 0; ii < clientParams->paramSize; ii++) {
921
+ Napi::String name = paramNames.Get(ii).ToString();
922
+ Napi::String value = clientParamsObject.Get(name).ToString();
923
+ clientParams->connectionParams[ii].name = setString(name);
924
+ clientParams->connectionParams[ii].value = setString(value);
925
+ }
926
+ }
927
+
928
+ void checkClientOptions(Napi::Object clientOptionsObject,
929
+ ClientOptionsStruct* client_options) {
930
+ if (clientOptionsObject.Has("clientOptions")) {
931
+ // server constructor call
932
+ clientOptionsObject =
933
+ clientOptionsObject.Get("clientOptions").As<Napi::Object>();
934
+ }
935
+
936
+ char errmsg[ERRMSG_LENGTH];
937
+ Napi::Array props = clientOptionsObject.GetPropertyNames();
938
+ for (uint_t ii = 0; ii < props.Length(); ii++) {
939
+ std::string key = props.Get(ii).ToString().Utf8Value();
940
+ Napi::Value opt = clientOptionsObject.Get(key).As<Napi::Value>();
941
+
942
+ // Client option: "bcd"
943
+ if (key == CLIENT_OPTION_BCD) {
944
+ if (opt.IsFunction()) {
945
+ client_options->bcd = CLIENT_OPTION_BCD_FUNCTION;
946
+ client_options->bcdFunction =
947
+ Napi::Persistent(opt.As<Napi::Function>());
948
+ } else if (opt.IsString()) {
949
+ std::string bcdString = opt.ToString().Utf8Value();
950
+ if (bcdString == "number") {
951
+ client_options->bcd = CLIENT_OPTION_BCD_NUMBER;
952
+ } else {
953
+ snprintf(errmsg,
954
+ ERRMSG_LENGTH - 1,
955
+ "Client option \"%s\" value not allowed: \"%s\"",
956
+ CLIENT_OPTION_BCD,
957
+ &bcdString[0]);
958
+ Napi::TypeError::New(node_rfc::__env, errmsg)
959
+ .ThrowAsJavaScriptException();
960
+ }
961
+ }
962
+ }
963
+
964
+ // Client option: "date"
965
+ else if (key == CLIENT_OPTION_DATE) {
966
+ if (!opt.IsObject()) {
967
+ opt = node_rfc::__env.Null();
968
+ } else {
969
+ Napi::Value toABAP = opt.As<Napi::Object>().Get("toABAP");
970
+ Napi::Value fromABAP = opt.As<Napi::Object>().Get("fromABAP");
971
+ if (!toABAP.IsFunction() || !fromABAP.IsFunction()) {
972
+ snprintf(errmsg,
973
+ ERRMSG_LENGTH - 1,
974
+ "Client option \"%s\" is not an object with toABAP() and "
975
+ "fromABAP() functions",
976
+ CLIENT_OPTION_DATE);
977
+ Napi::TypeError::New(node_rfc::__env, errmsg)
978
+ .ThrowAsJavaScriptException();
979
+ } else {
980
+ client_options->dateToABAP =
981
+ Napi::Persistent(toABAP.As<Napi::Function>());
982
+ client_options->dateFromABAP =
983
+ Napi::Persistent(fromABAP.As<Napi::Function>());
984
+ }
985
+ }
986
+ }
987
+
988
+ // Client option: "time"
989
+ else if (key == CLIENT_OPTION_TIME) {
990
+ if (!opt.IsObject()) {
991
+ opt = node_rfc::__env.Null();
992
+ } else {
993
+ Napi::Value toABAP = opt.As<Napi::Object>().Get("toABAP");
994
+ Napi::Value fromABAP = opt.As<Napi::Object>().Get("fromABAP");
995
+ if (!toABAP.IsFunction() || !fromABAP.IsFunction()) {
996
+ snprintf(errmsg,
997
+ ERRMSG_LENGTH - 1,
998
+ "Client option \"%s\" is not an object with toABAP() and "
999
+ "fromABAP() functions",
1000
+ CLIENT_OPTION_TIME);
1001
+ Napi::TypeError::New(node_rfc::__env, errmsg)
1002
+ .ThrowAsJavaScriptException();
1003
+ ;
1004
+ } else {
1005
+ client_options->timeToABAP =
1006
+ Napi::Persistent(toABAP.As<Napi::Function>());
1007
+ client_options->timeFromABAP =
1008
+ Napi::Persistent(fromABAP.As<Napi::Function>());
1009
+ }
1010
+ }
1011
+ }
1012
+
1013
+ // Client option: "filter"
1014
+ else if (key == CLIENT_OPTION_FILTER) {
1015
+ client_options->filter_param_type =
1016
+ (RFC_DIRECTION)clientOptionsObject.Get(key)
1017
+ .As<Napi::Number>()
1018
+ .Uint32Value();
1019
+ if (((int)client_options->filter_param_type < 1) ||
1020
+ ((int)client_options->filter_param_type) > 4) {
1021
+ snprintf(errmsg,
1022
+ ERRMSG_LENGTH - 1,
1023
+ "Client option \"%s\" value allowed: \"%u\"",
1024
+ CLIENT_OPTION_FILTER,
1025
+ (uint_t)client_options->filter_param_type);
1026
+ Napi::TypeError::New(node_rfc::__env, errmsg)
1027
+ .ThrowAsJavaScriptException();
1028
+ }
1029
+ }
1030
+
1031
+ // Client option: "stateless"
1032
+ else if (key == CLIENT_OPTION_STATELESS) {
1033
+ if (!opt.IsBoolean()) {
1034
+ snprintf(errmsg,
1035
+ ERRMSG_LENGTH - 1,
1036
+ "Client option \"%s\" requires a boolean value",
1037
+ CLIENT_OPTION_STATELESS);
1038
+ Napi::TypeError::New(node_rfc::__env, errmsg)
1039
+ .ThrowAsJavaScriptException();
1040
+ }
1041
+ client_options->stateless = opt.As<Napi::Boolean>();
1042
+ }
1043
+
1044
+ // Client option: "timeout"
1045
+ else if (key == CLIENT_OPTION_TIMEOUT) {
1046
+ if (!opt.IsNumber()) {
1047
+ snprintf(errmsg,
1048
+ ERRMSG_LENGTH - 1,
1049
+ "Client option \"%s\" requires a number of seconds",
1050
+ CLIENT_OPTION_TIMEOUT);
1051
+ Napi::TypeError::New(node_rfc::__env, errmsg)
1052
+ .ThrowAsJavaScriptException();
1053
+ }
1054
+ client_options->timeout = opt.As<Napi::Number>();
1055
+ }
1056
+
1057
+ // Client option: unknown
1058
+ else {
1059
+ snprintf(errmsg,
1060
+ ERRMSG_LENGTH - 1,
1061
+ "Client option not allowed: \"%s\"",
1062
+ key.c_str());
1063
+ Napi::TypeError::New(node_rfc::__env, errmsg)
1064
+ .ThrowAsJavaScriptException();
1065
+ }
1066
+ }
1067
+ }
1068
+
1069
+ Napi::Value getConnectionAttributes(Napi::Env env,
1070
+ RFC_CONNECTION_HANDLE connectionHandle) {
1071
+ Napi::Object infoObj = Napi::Object::New(env);
1072
+ RFC_ERROR_INFO errorInfo;
1073
+ RFC_ATTRIBUTES connInfo;
1074
+ RFC_RC rc =
1075
+ RfcGetConnectionAttributes(connectionHandle, &connInfo, &errorInfo);
1076
+
1077
+ if (rc != RFC_OK || errorInfo.code != RFC_OK) {
1078
+ return rfcSdkError(&errorInfo);
1079
+ }
1080
+ CONNECTION_INFO_SET(dest);
1081
+ CONNECTION_INFO_SET(host);
1082
+ CONNECTION_INFO_SET(partnerHost)
1083
+ CONNECTION_INFO_SET(sysNumber);
1084
+ CONNECTION_INFO_SET(sysId);
1085
+ CONNECTION_INFO_SET(client);
1086
+ CONNECTION_INFO_SET(user);
1087
+ CONNECTION_INFO_SET(language);
1088
+ CONNECTION_INFO_SET(trace);
1089
+ CONNECTION_INFO_SET(isoLanguage);
1090
+ CONNECTION_INFO_SET(codepage);
1091
+ CONNECTION_INFO_SET(partnerCodepage);
1092
+ CONNECTION_INFO_SET(rfcRole);
1093
+ CONNECTION_INFO_SET(type);
1094
+ CONNECTION_INFO_SET(partnerType);
1095
+ CONNECTION_INFO_SET(rel);
1096
+ CONNECTION_INFO_SET(partnerRel);
1097
+ CONNECTION_INFO_SET(kernelRel);
1098
+ CONNECTION_INFO_SET(cpicConvId);
1099
+ CONNECTION_INFO_SET(progName);
1100
+ CONNECTION_INFO_SET(partnerBytesPerChar);
1101
+ CONNECTION_INFO_SET(partnerSystemCodepage);
1102
+ CONNECTION_INFO_SET(partnerIP);
1103
+ CONNECTION_INFO_SET(partnerIPv6);
1104
+
1105
+ return infoObj;
1106
+ }
1107
+
1108
+ } // namespace node_rfc