규모확장 Wave B: 전 11모듈 svc 75→133·batch 35→46 (BAIS 온라인 1:1)
- svc 825→1,463 (모듈당 133), batch 385→506 (모듈당 46) — 전부 새 고유 실업무 로직 + 카피북 헤더, 디스패처 133 advertise, 한글 기능설명(매니페스트 추출) - BAIS As-Is 대비: 온라인 1,463 vs 1,466(99.8%), 배치 506 vs 503(초과) - 화면 매니페스트 1,463 재생성 - 검증: build DONE modules=11 batches=506, 12서버 runok, xadmin psc 1,466 AVAIL, 매입체인 XA 커밋, 신규서비스 실데이터 스모크, 전 코퍼스 .pgc 클론 0 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
ea90bef264
commit
c62d91b7a7
1526 changed files with 59213 additions and 12 deletions
52
app/src/mg/batch/mg_chanfail_batch.pgc
Normal file
52
app/src/mg/batch/mg_chanfail_batch.pgc
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* mg_chanfail_batch.pgc - mg 이중화 채널 다운 탐지 배치 (커서 + XA).
|
||||
*
|
||||
* 등록된 전 채널의 상태를 커서로 훑어 UP/DOWN 개수를 세고, DOWN 채널이 하나라도
|
||||
* 있으면 경보 로그를 남긴다 (채널 상태 모니터/이중화 감시의 일배치판).
|
||||
* Usage: mg_chanfail_batch
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
#include <userlog.h>
|
||||
#include "mg_chanfail_batch.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
(void)argc; (void)argv;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_chan[16], h_status[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
mg_chanfail_rec_t rec;
|
||||
memset(&rec, 0, sizeof(rec));
|
||||
|
||||
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
|
||||
EXEC SQL DECLARE cfc CURSOR FOR
|
||||
SELECT channel, status FROM mg_channel ORDER BY channel;
|
||||
EXEC SQL OPEN cfc;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
|
||||
for (;;) {
|
||||
EXEC SQL FETCH cfc INTO :h_chan, :h_status;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE cfc; tpabort(0); return 1; }
|
||||
rec.channels++;
|
||||
if (strcmp(h_status, "UP") == 0) {
|
||||
rec.up_cnt++;
|
||||
} else {
|
||||
rec.down_cnt++;
|
||||
userlog("mg_chanfail_batch 채널 DOWN 감지: %s (%s)", h_chan, h_status);
|
||||
}
|
||||
}
|
||||
EXEC SQL CLOSE cfc;
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> mg_chanfail_batch COMMIT: 채널수=%ld UP=%ld DOWN=%ld\n",
|
||||
rec.channels, rec.up_cnt, rec.down_cnt);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
58
app/src/mg/batch/mg_dupmark_batch.pgc
Normal file
58
app/src/mg/batch/mg_dupmark_batch.pgc
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* mg_dupmark_batch.pgc - mg 중복 STAN 전문 마킹 배치 (커서 + XA).
|
||||
*
|
||||
* 당일 STAN 별 건수를 group by 커서로 훑어 2건 이상인 STAN 마다, 최소 msg_id(원본)만
|
||||
* 남기고 나머지를 rc=94/status=X 로 폐기 마킹한다 (중복검출의 대량 마킹 일배치판).
|
||||
* Usage: mg_dupmark_batch [YYYY-MM-DD]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
#include "mg_dupmark_batch.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_bizdate[16];
|
||||
long h_stan, h_cnt, h_keep;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
mg_dupmark_rec_t rec;
|
||||
memset(&rec, 0, sizeof(rec));
|
||||
|
||||
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
|
||||
|
||||
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
|
||||
EXEC SQL DECLARE dmc CURSOR FOR
|
||||
SELECT stan, count(*) FROM mg_msg_log WHERE biz_date = :h_bizdate
|
||||
GROUP BY stan HAVING count(*) > 1 ORDER BY stan;
|
||||
EXEC SQL OPEN dmc;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
|
||||
for (;;) {
|
||||
EXEC SQL FETCH dmc INTO :h_stan, :h_cnt;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE dmc; tpabort(0); return 1; }
|
||||
rec.dup_stans++;
|
||||
|
||||
EXEC SQL SELECT min(msg_id) INTO :h_keep
|
||||
FROM mg_msg_log WHERE biz_date = :h_bizdate AND stan = :h_stan;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE dmc; tpabort(0); return 1; }
|
||||
|
||||
EXEC SQL UPDATE mg_msg_log SET rc = '94', status = 'X'
|
||||
WHERE biz_date = :h_bizdate AND stan = :h_stan AND msg_id <> :h_keep;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE dmc; tpabort(0); return 1; }
|
||||
rec.marked += (long)sqlca.sqlerrd[2];
|
||||
}
|
||||
EXEC SQL CLOSE dmc;
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> mg_dupmark_batch COMMIT: bizdate=%s 중복STAN=%ld 폐기마킹=%ld건\n",
|
||||
bizdate, rec.dup_stans, rec.marked);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
51
app/src/mg/batch/mg_errescal_batch.pgc
Normal file
51
app/src/mg/batch/mg_errescal_batch.pgc
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* mg_errescal_batch.pgc - mg 재시도초과 오류전문 에스컬레이션 배치 (XA 단일 갱신).
|
||||
*
|
||||
* mg_seq(ESCALLIM) 재시도 임계를 읽어, 그 횟수를 넘긴 실패(F) 큐 건을 한 문장에
|
||||
* 에스컬레이션(E)으로 전이시킨다 (오류전문 재처리 워크플로의 일배치 대량판).
|
||||
* Usage: mg_errescal_batch [YYYY-MM-DD]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
#include "mg_errescal_batch.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_bizdate[16];
|
||||
long h_lim, h_scanned;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
mg_errescal_rec_t rec;
|
||||
memset(&rec, 0, sizeof(rec));
|
||||
|
||||
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
|
||||
|
||||
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
|
||||
h_lim = 5;
|
||||
EXEC SQL SELECT seq_val INTO :h_lim FROM mg_seq WHERE seq_name = 'ESCALLIM';
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "ESCALLIM 조회 FAIL [%d]\n", sqlca.sqlcode); tpabort(0); return 1; }
|
||||
if (h_lim <= 0) h_lim = 5;
|
||||
|
||||
EXEC SQL SELECT count(*) INTO :h_scanned
|
||||
FROM mg_queue WHERE status = 'F' AND biz_date = :h_bizdate;
|
||||
if (sqlca.sqlcode < 0) { tpabort(0); return 1; }
|
||||
rec.scanned = h_scanned;
|
||||
|
||||
EXEC SQL UPDATE mg_queue SET status = 'E', updated_at = now()
|
||||
WHERE status = 'F' AND biz_date = :h_bizdate AND retry_cnt > :h_lim;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "에스컬 전이 FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
|
||||
rec.escalated = (long)sqlca.sqlerrd[2];
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> mg_errescal_batch COMMIT: bizdate=%s 실패건=%ld 에스컬=%ld건 (임계=%ld)\n",
|
||||
bizdate, rec.scanned, rec.escalated, h_lim);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
52
app/src/mg/batch/mg_healthz_batch.pgc
Normal file
52
app/src/mg/batch/mg_healthz_batch.pgc
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* mg_healthz_batch.pgc - mg 게이트웨이 종합 헬스 스냅 배치 (다중 집계 + XA).
|
||||
*
|
||||
* UP 채널 수, 대기(Q) 큐 적체, 당일 오류(rc<>'00') 전문 수를 각각 집계해 한 스냅으로
|
||||
* 모아, UP 채널이 있고 적체가 임계 미만이면 healthy=1 로 판정한다 (헬스체크 세분).
|
||||
* Usage: mg_healthz_batch [YYYY-MM-DD]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
#include "mg_healthz_batch.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
|
||||
const long backlog_limit = 1000;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_bizdate[16];
|
||||
long h_up, h_backlog, h_err;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
mg_healthz_rec_t rec;
|
||||
memset(&rec, 0, sizeof(rec));
|
||||
|
||||
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
|
||||
|
||||
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
|
||||
EXEC SQL SELECT count(*) INTO :h_up FROM mg_channel WHERE status = 'UP';
|
||||
if (sqlca.sqlcode < 0) { tpabort(0); return 1; }
|
||||
EXEC SQL SELECT count(*) INTO :h_backlog
|
||||
FROM mg_queue WHERE status = 'Q' AND biz_date = :h_bizdate;
|
||||
if (sqlca.sqlcode < 0) { tpabort(0); return 1; }
|
||||
EXEC SQL SELECT count(*) INTO :h_err
|
||||
FROM mg_msg_log WHERE biz_date = :h_bizdate AND rc <> '00';
|
||||
if (sqlca.sqlcode < 0) { tpabort(0); return 1; }
|
||||
|
||||
rec.chan_up = h_up;
|
||||
rec.queue_backlog = h_backlog;
|
||||
rec.err_today = h_err;
|
||||
rec.healthy = (h_up > 0 && h_backlog < backlog_limit) ? 1 : 0;
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> mg_healthz_batch COMMIT: bizdate=%s UP채널=%ld 큐적체=%ld 오류전문=%ld 건강=%s\n",
|
||||
bizdate, rec.chan_up, rec.queue_backlog, rec.err_today,
|
||||
rec.healthy ? "YES" : "NO");
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
59
app/src/mg/batch/mg_loadrpt_batch.pgc
Normal file
59
app/src/mg/batch/mg_loadrpt_batch.pgc
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* mg_loadrpt_batch.pgc - mg 채널 부하 가중 리포트 배치 (커서 + XA).
|
||||
*
|
||||
* 채널별 당일 전문건수와 큐 재시도합을 결합한 부하지표(건수 + 재시도*2)를 커서로
|
||||
* 훑으며 총 부하와 최대 부하 채널을 집계한다 (트래픽 부하분산 근거용 일배치).
|
||||
* Usage: mg_loadrpt_batch [YYYY-MM-DD]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
#include "mg_loadrpt_batch.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
|
||||
long load;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_bizdate[16], h_chan[16];
|
||||
long h_msgcnt, h_retry;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
mg_loadrpt_rec_t rec;
|
||||
memset(&rec, 0, sizeof(rec));
|
||||
|
||||
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
|
||||
|
||||
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
|
||||
EXEC SQL DECLARE lrc CURSOR FOR
|
||||
SELECT channel, count(*) FROM mg_msg_log
|
||||
WHERE biz_date = :h_bizdate GROUP BY channel ORDER BY channel;
|
||||
EXEC SQL OPEN lrc;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
|
||||
for (;;) {
|
||||
EXEC SQL FETCH lrc INTO :h_chan, :h_msgcnt;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE lrc; tpabort(0); return 1; }
|
||||
rec.channels++;
|
||||
|
||||
h_retry = 0;
|
||||
EXEC SQL SELECT coalesce(sum(retry_cnt),0) INTO :h_retry
|
||||
FROM mg_queue WHERE biz_date = :h_bizdate AND channel = :h_chan;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE lrc; tpabort(0); return 1; }
|
||||
|
||||
load = h_msgcnt + h_retry * 2; /* 재시도에 가중 2배 */
|
||||
rec.load_sum += load;
|
||||
if (load > rec.busiest_load) rec.busiest_load = load;
|
||||
}
|
||||
EXEC SQL CLOSE lrc;
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> mg_loadrpt_batch COMMIT: bizdate=%s 채널수=%ld 총부하=%ld 최대부하=%ld\n",
|
||||
bizdate, rec.channels, rec.load_sum, rec.busiest_load);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
53
app/src/mg/batch/mg_mtiroll_batch.pgc
Normal file
53
app/src/mg/batch/mg_mtiroll_batch.pgc
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* mg_mtiroll_batch.pgc - mg 전문유형(MTI)별 금액/건수 롤업 배치 (커서 + XA).
|
||||
*
|
||||
* 당일 전문을 MTI 로 그룹핑해 유형별 건수/금액합을 커서로 훑으며 총계를 누적하고,
|
||||
* 금액합이 가장 큰 유형을 찾아낸다 (전문 통계 유형별 세분의 일배치판).
|
||||
* Usage: mg_mtiroll_batch [YYYY-MM-DD]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
#include "mg_mtiroll_batch.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_bizdate[16], h_mti[8];
|
||||
long h_cnt, h_amt;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
mg_mtiroll_rec_t rec;
|
||||
memset(&rec, 0, sizeof(rec));
|
||||
|
||||
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
|
||||
|
||||
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
|
||||
EXEC SQL DECLARE mrc CURSOR FOR
|
||||
SELECT mti, count(*), coalesce(sum(amount),0)
|
||||
FROM mg_msg_log WHERE biz_date = :h_bizdate
|
||||
GROUP BY mti ORDER BY mti;
|
||||
EXEC SQL OPEN mrc;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
|
||||
for (;;) {
|
||||
EXEC SQL FETCH mrc INTO :h_mti, :h_cnt, :h_amt;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE mrc; tpabort(0); return 1; }
|
||||
rec.groups++;
|
||||
rec.total_cnt += h_cnt;
|
||||
rec.total_amt += h_amt;
|
||||
if (h_amt > rec.top_amt) rec.top_amt = h_amt;
|
||||
}
|
||||
EXEC SQL CLOSE mrc;
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> mg_mtiroll_batch COMMIT: bizdate=%s 유형수=%ld 총건=%ld 총금액=%ld 최대유형금액=%ld\n",
|
||||
bizdate, rec.groups, rec.total_cnt, rec.total_amt, rec.top_amt);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
52
app/src/mg/batch/mg_peakhour_batch.pgc
Normal file
52
app/src/mg/batch/mg_peakhour_batch.pgc
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* mg_peakhour_batch.pgc - mg 시간대별 피크 트래픽 탐지 배치 (커서 + XA).
|
||||
*
|
||||
* 당일 전문을 생성시각의 시(0~23)로 그룹핑해 시간대별 건수를 커서로 훑으며
|
||||
* 최다 건수 시간대를 찾는다 (시간대별 통계에서 피크만 뽑는 일배치판).
|
||||
* Usage: mg_peakhour_batch [YYYY-MM-DD]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
#include "mg_peakhour_batch.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_bizdate[16];
|
||||
long h_hour, h_cnt;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
mg_peakhour_rec_t rec;
|
||||
memset(&rec, 0, sizeof(rec));
|
||||
rec.peak_hour = -1;
|
||||
|
||||
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
|
||||
|
||||
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
|
||||
EXEC SQL DECLARE phc CURSOR FOR
|
||||
SELECT extract(hour from created_at)::int AS hh, count(*)
|
||||
FROM mg_msg_log WHERE biz_date = :h_bizdate
|
||||
GROUP BY hh ORDER BY hh;
|
||||
EXEC SQL OPEN phc;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
|
||||
for (;;) {
|
||||
EXEC SQL FETCH phc INTO :h_hour, :h_cnt;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE phc; tpabort(0); return 1; }
|
||||
rec.buckets++;
|
||||
if (h_cnt > rec.peak_cnt) { rec.peak_cnt = h_cnt; rec.peak_hour = h_hour; }
|
||||
}
|
||||
EXEC SQL CLOSE phc;
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> mg_peakhour_batch COMMIT: bizdate=%s 활동시간대=%ld 피크시=%ld시 피크건수=%ld\n",
|
||||
bizdate, rec.buckets, rec.peak_hour, rec.peak_cnt);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
52
app/src/mg/batch/mg_rcfreq_batch.pgc
Normal file
52
app/src/mg/batch/mg_rcfreq_batch.pgc
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* mg_rcfreq_batch.pgc - mg 응답코드별 빈도/오류율 집계 배치 (커서 + XA).
|
||||
*
|
||||
* 당일 전문을 응답코드(rc)로 그룹핑해 코드 종류 수와 전체 건수를 커서로 누적하고,
|
||||
* 정상('00') 외 건수로 오류율(bps)을 산출한다 (응답코드별 통계의 일배치판).
|
||||
* Usage: mg_rcfreq_batch [YYYY-MM-DD]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
#include "mg_rcfreq_batch.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_bizdate[16], h_rc[4];
|
||||
long h_cnt;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
mg_rcfreq_rec_t rec;
|
||||
memset(&rec, 0, sizeof(rec));
|
||||
|
||||
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
|
||||
|
||||
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
|
||||
EXEC SQL DECLARE rfc CURSOR FOR
|
||||
SELECT rc, count(*) FROM mg_msg_log WHERE biz_date = :h_bizdate
|
||||
GROUP BY rc ORDER BY rc;
|
||||
EXEC SQL OPEN rfc;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
|
||||
for (;;) {
|
||||
EXEC SQL FETCH rfc INTO :h_rc, :h_cnt;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE rfc; tpabort(0); return 1; }
|
||||
rec.rc_kinds++;
|
||||
rec.total += h_cnt;
|
||||
if (strcmp(h_rc, "00") != 0) rec.err += h_cnt;
|
||||
}
|
||||
EXEC SQL CLOSE rfc;
|
||||
rec.err_bps = (rec.total > 0) ? (rec.err * 10000L) / rec.total : 0;
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> mg_rcfreq_batch COMMIT: bizdate=%s 코드종류=%ld 총건=%ld 오류건=%ld 오류율=%ldbps\n",
|
||||
bizdate, rec.rc_kinds, rec.total, rec.err, rec.err_bps);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
51
app/src/mg/batch/mg_routechk_batch.pgc
Normal file
51
app/src/mg/batch/mg_routechk_batch.pgc
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* mg_routechk_batch.pgc - mg 라우팅 룰 감사 배치 (커서 + XA).
|
||||
*
|
||||
* 전 라우팅 룰을 채널+MTI 순으로 커서 훑으며 비활성 룰 수를 세고, 직전 키와 같은
|
||||
* (채널,MTI) 활성 룰이 연달아 나오면 중복 라우팅으로 집계한다 (라우팅 룰 관리 감사).
|
||||
* Usage: mg_routechk_batch
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
#include "mg_routechk_batch.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
(void)argc; (void)argv;
|
||||
char prevkey[32] = "", curkey[32];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_chan[16], h_mti[8];
|
||||
int h_active;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
mg_routechk_rec_t rec;
|
||||
memset(&rec, 0, sizeof(rec));
|
||||
|
||||
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
|
||||
EXEC SQL DECLARE rkc CURSOR FOR
|
||||
SELECT channel, mti, active FROM mg_route ORDER BY channel, mti, route_id;
|
||||
EXEC SQL OPEN rkc;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
|
||||
for (;;) {
|
||||
EXEC SQL FETCH rkc INTO :h_chan, :h_mti, :h_active;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE rkc; tpabort(0); return 1; }
|
||||
rec.rules++;
|
||||
if (!h_active) { rec.inactive++; continue; }
|
||||
snprintf(curkey, sizeof(curkey), "%s|%s", h_chan, h_mti);
|
||||
if (strcmp(curkey, prevkey) == 0) rec.dup_keys++; /* 같은 키 활성 룰 중복 */
|
||||
strcpy(prevkey, curkey);
|
||||
}
|
||||
EXEC SQL CLOSE rkc;
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> mg_routechk_batch COMMIT: 룰수=%ld 비활성=%ld 중복키=%ld\n",
|
||||
rec.rules, rec.inactive, rec.dup_keys);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
69
app/src/mg/batch/mg_seqrepair_batch.pgc
Normal file
69
app/src/mg/batch/mg_seqrepair_batch.pgc
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* mg_seqrepair_batch.pgc - mg 채널별 순번 결번 보정 통계 배치 (중첩 커서 + XA).
|
||||
*
|
||||
* 채널을 바깥 커서로, 각 채널의 STAN 을 안쪽 커서로 오름차순 훑으며 채널마다
|
||||
* 결번(간격>1) 유무와 최대 결번폭을 잰다 (순번 갭 검출을 채널단위로 세분한 일배치).
|
||||
* Usage: mg_seqrepair_batch [YYYY-MM-DD]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
#include "mg_seqrepair_batch.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
|
||||
long prev, chan_gaps;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_bizdate[16], h_chan[16];
|
||||
long h_stan;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
mg_seqrepair_rec_t rec;
|
||||
memset(&rec, 0, sizeof(rec));
|
||||
|
||||
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
|
||||
|
||||
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
|
||||
EXEC SQL DECLARE srchan CURSOR FOR
|
||||
SELECT DISTINCT channel FROM mg_msg_log WHERE biz_date = :h_bizdate ORDER BY channel;
|
||||
EXEC SQL DECLARE srstan CURSOR FOR
|
||||
SELECT DISTINCT stan FROM mg_msg_log
|
||||
WHERE biz_date = :h_bizdate AND channel = :h_chan ORDER BY stan;
|
||||
|
||||
EXEC SQL OPEN srchan;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d]\n", sqlca.sqlcode); tpabort(0); return 1; }
|
||||
for (;;) {
|
||||
EXEC SQL FETCH srchan INTO :h_chan;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE srchan; tpabort(0); return 1; }
|
||||
rec.channels++;
|
||||
prev = -1; chan_gaps = 0;
|
||||
|
||||
EXEC SQL OPEN srstan;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE srchan; tpabort(0); return 1; }
|
||||
for (;;) {
|
||||
EXEC SQL FETCH srstan INTO :h_stan;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE srstan; EXEC SQL CLOSE srchan; tpabort(0); return 1; }
|
||||
if (prev >= 0 && h_stan - prev > 1) {
|
||||
chan_gaps++;
|
||||
if (h_stan - prev - 1 > rec.widest) rec.widest = h_stan - prev - 1;
|
||||
}
|
||||
prev = h_stan;
|
||||
}
|
||||
EXEC SQL CLOSE srstan;
|
||||
if (chan_gaps > 0) rec.gap_chans++;
|
||||
}
|
||||
EXEC SQL CLOSE srchan;
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> mg_seqrepair_batch COMMIT: bizdate=%s 채널수=%ld 결번채널=%ld 최대결번폭=%ld\n",
|
||||
bizdate, rec.channels, rec.gap_chans, rec.widest);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
61
app/src/mg/batch/mg_throttle_batch.pgc
Normal file
61
app/src/mg/batch/mg_throttle_batch.pgc
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* mg_throttle_batch.pgc - mg 채널 유입 임계 초과 탐지 배치 (커서 + XA).
|
||||
*
|
||||
* mg_seq(THROTLIM) 채널 유입한도를 읽어, 채널별 당일 수신(IN) 건수를 커서로 훑으며
|
||||
* 한도 초과 채널 수와 최다 유입 채널의 건수를 집계한다 (트래픽 제어의 일배치판).
|
||||
* Usage: mg_throttle_batch [YYYY-MM-DD]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
#include <userlog.h>
|
||||
#include "mg_throttle_batch.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_bizdate[16], h_chan[16];
|
||||
long h_cnt, h_lim;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
mg_throttle_rec_t rec;
|
||||
memset(&rec, 0, sizeof(rec));
|
||||
|
||||
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
|
||||
|
||||
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
|
||||
h_lim = 10000;
|
||||
EXEC SQL SELECT seq_val INTO :h_lim FROM mg_seq WHERE seq_name = 'THROTLIM';
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "THROTLIM 조회 FAIL [%d]\n", sqlca.sqlcode); tpabort(0); return 1; }
|
||||
if (h_lim <= 0) h_lim = 10000;
|
||||
|
||||
EXEC SQL DECLARE thc CURSOR FOR
|
||||
SELECT channel, count(*) FROM mg_msg_log
|
||||
WHERE biz_date = :h_bizdate AND direction = 'IN'
|
||||
GROUP BY channel ORDER BY channel;
|
||||
EXEC SQL OPEN thc;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
|
||||
for (;;) {
|
||||
EXEC SQL FETCH thc INTO :h_chan, :h_cnt;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE thc; tpabort(0); return 1; }
|
||||
rec.channels++;
|
||||
if (h_cnt > rec.busiest) rec.busiest = h_cnt;
|
||||
if (h_cnt >= h_lim) {
|
||||
rec.over_cnt++;
|
||||
userlog("mg_throttle_batch 유입초과 채널=%s %ld/%ld", h_chan, h_cnt, h_lim);
|
||||
}
|
||||
}
|
||||
EXEC SQL CLOSE thc;
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> mg_throttle_batch COMMIT: bizdate=%s 채널수=%ld 초과채널=%ld 최다유입=%ld (한도=%ld)\n",
|
||||
bizdate, rec.channels, rec.over_cnt, rec.busiest, h_lim);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
10
app/src/mg/dbio/mg_chanfail_batch.h
Normal file
10
app/src/mg/dbio/mg_chanfail_batch.h
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* mg_chanfail_batch.h - mg mg_chanfail_batch 배치 전용 카피북 (copybook). 이중화 채널 다운 탐지 배치
|
||||
* 배치 집계 결과 레코드. Included by mg_chanfail_batch.pgc.
|
||||
*/
|
||||
#ifndef MG_CHANFAIL_BATCH_H
|
||||
#define MG_CHANFAIL_BATCH_H
|
||||
|
||||
typedef struct { long channels; long down_cnt; long up_cnt; } mg_chanfail_rec_t;
|
||||
|
||||
#endif
|
||||
10
app/src/mg/dbio/mg_dupmark_batch.h
Normal file
10
app/src/mg/dbio/mg_dupmark_batch.h
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* mg_dupmark_batch.h - mg mg_dupmark_batch 배치 전용 카피북 (copybook). 중복 STAN 전문 마킹 배치
|
||||
* 배치 집계 결과 레코드. Included by mg_dupmark_batch.pgc.
|
||||
*/
|
||||
#ifndef MG_DUPMARK_BATCH_H
|
||||
#define MG_DUPMARK_BATCH_H
|
||||
|
||||
typedef struct { long dup_stans; long marked; } mg_dupmark_rec_t;
|
||||
|
||||
#endif
|
||||
10
app/src/mg/dbio/mg_errescal_batch.h
Normal file
10
app/src/mg/dbio/mg_errescal_batch.h
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* mg_errescal_batch.h - mg mg_errescal_batch 배치 전용 카피북 (copybook). 재시도초과 오류전문 에스컬레이션 배치
|
||||
* 배치 집계 결과 레코드. Included by mg_errescal_batch.pgc.
|
||||
*/
|
||||
#ifndef MG_ERRESCAL_BATCH_H
|
||||
#define MG_ERRESCAL_BATCH_H
|
||||
|
||||
typedef struct { long scanned; long escalated; } mg_errescal_rec_t;
|
||||
|
||||
#endif
|
||||
10
app/src/mg/dbio/mg_healthz_batch.h
Normal file
10
app/src/mg/dbio/mg_healthz_batch.h
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* mg_healthz_batch.h - mg mg_healthz_batch 배치 전용 카피북 (copybook). 게이트웨이 종합 헬스 스냅 배치
|
||||
* 배치 집계 결과 레코드. Included by mg_healthz_batch.pgc.
|
||||
*/
|
||||
#ifndef MG_HEALTHZ_BATCH_H
|
||||
#define MG_HEALTHZ_BATCH_H
|
||||
|
||||
typedef struct { long chan_up; long queue_backlog; long err_today; int healthy; } mg_healthz_rec_t;
|
||||
|
||||
#endif
|
||||
10
app/src/mg/dbio/mg_loadrpt_batch.h
Normal file
10
app/src/mg/dbio/mg_loadrpt_batch.h
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* mg_loadrpt_batch.h - mg mg_loadrpt_batch 배치 전용 카피북 (copybook). 채널 부하 가중 리포트 배치
|
||||
* 배치 집계 결과 레코드. Included by mg_loadrpt_batch.pgc.
|
||||
*/
|
||||
#ifndef MG_LOADRPT_BATCH_H
|
||||
#define MG_LOADRPT_BATCH_H
|
||||
|
||||
typedef struct { long channels; long load_sum; long busiest_load; } mg_loadrpt_rec_t;
|
||||
|
||||
#endif
|
||||
10
app/src/mg/dbio/mg_mtiroll_batch.h
Normal file
10
app/src/mg/dbio/mg_mtiroll_batch.h
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* mg_mtiroll_batch.h - mg mg_mtiroll_batch 배치 전용 카피북 (copybook). MTI별 금액/건수 롤업 요약 배치
|
||||
* 배치 집계 결과 레코드. Included by mg_mtiroll_batch.pgc.
|
||||
*/
|
||||
#ifndef MG_MTIROLL_BATCH_H
|
||||
#define MG_MTIROLL_BATCH_H
|
||||
|
||||
typedef struct { long groups; long total_cnt; long total_amt; long top_amt; } mg_mtiroll_rec_t;
|
||||
|
||||
#endif
|
||||
10
app/src/mg/dbio/mg_peakhour_batch.h
Normal file
10
app/src/mg/dbio/mg_peakhour_batch.h
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* mg_peakhour_batch.h - mg mg_peakhour_batch 배치 전용 카피북 (copybook). 시간대별 피크 트래픽 탐지 배치
|
||||
* 배치 집계 결과 레코드. Included by mg_peakhour_batch.pgc.
|
||||
*/
|
||||
#ifndef MG_PEAKHOUR_BATCH_H
|
||||
#define MG_PEAKHOUR_BATCH_H
|
||||
|
||||
typedef struct { long buckets; long peak_hour; long peak_cnt; } mg_peakhour_rec_t;
|
||||
|
||||
#endif
|
||||
10
app/src/mg/dbio/mg_rcfreq_batch.h
Normal file
10
app/src/mg/dbio/mg_rcfreq_batch.h
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* mg_rcfreq_batch.h - mg mg_rcfreq_batch 배치 전용 카피북 (copybook). 응답코드별 빈도/오류율 집계 배치
|
||||
* 배치 집계 결과 레코드. Included by mg_rcfreq_batch.pgc.
|
||||
*/
|
||||
#ifndef MG_RCFREQ_BATCH_H
|
||||
#define MG_RCFREQ_BATCH_H
|
||||
|
||||
typedef struct { long rc_kinds; long total; long err; long err_bps; } mg_rcfreq_rec_t;
|
||||
|
||||
#endif
|
||||
10
app/src/mg/dbio/mg_routechk_batch.h
Normal file
10
app/src/mg/dbio/mg_routechk_batch.h
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* mg_routechk_batch.h - mg mg_routechk_batch 배치 전용 카피북 (copybook). 라우팅 룰 감사(중복/비활성) 배치
|
||||
* 배치 집계 결과 레코드. Included by mg_routechk_batch.pgc.
|
||||
*/
|
||||
#ifndef MG_ROUTECHK_BATCH_H
|
||||
#define MG_ROUTECHK_BATCH_H
|
||||
|
||||
typedef struct { long rules; long inactive; long dup_keys; } mg_routechk_rec_t;
|
||||
|
||||
#endif
|
||||
10
app/src/mg/dbio/mg_seqrepair_batch.h
Normal file
10
app/src/mg/dbio/mg_seqrepair_batch.h
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* mg_seqrepair_batch.h - mg mg_seqrepair_batch 배치 전용 카피북 (copybook). 채널별 순번 결번 보정 통계 배치
|
||||
* 배치 집계 결과 레코드. Included by mg_seqrepair_batch.pgc.
|
||||
*/
|
||||
#ifndef MG_SEQREPAIR_BATCH_H
|
||||
#define MG_SEQREPAIR_BATCH_H
|
||||
|
||||
typedef struct { long channels; long gap_chans; long widest; } mg_seqrepair_rec_t;
|
||||
|
||||
#endif
|
||||
10
app/src/mg/dbio/mg_throttle_batch.h
Normal file
10
app/src/mg/dbio/mg_throttle_batch.h
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* mg_throttle_batch.h - mg mg_throttle_batch 배치 전용 카피북 (copybook). 채널 유입 임계 초과 탐지 배치
|
||||
* 배치 집계 결과 레코드. Included by mg_throttle_batch.pgc.
|
||||
*/
|
||||
#ifndef MG_THROTTLE_BATCH_H
|
||||
#define MG_THROTTLE_BATCH_H
|
||||
|
||||
typedef struct { long channels; long over_cnt; long busiest; } mg_throttle_rec_t;
|
||||
|
||||
#endif
|
||||
|
|
@ -2,13 +2,13 @@
|
|||
* mg_svr.pgc - mg (전문게이트웨이 / message gateway) MODULE SERVER (thin dispatcher).
|
||||
*
|
||||
* The legacy "one module server, many services" pattern: this binary owns NO
|
||||
* business logic. Each of mg's 75 online services now lives in its own file
|
||||
* business logic. Each of mg's 133 online services now lives in its own file
|
||||
* (app/src/mg/svc/<SVCNAME>.pgc) with its own copybook header
|
||||
* (app/src/mg/svc/<SVCNAME>.h); those objects are archived into libmgsvc.a
|
||||
* and linked into this server. Here we only:
|
||||
* - include every service copybook (for the extern prototypes),
|
||||
* - tpopen() the ECPG XA RM,
|
||||
* - tpadvertise() all 75 services from a {name, fn} table,
|
||||
* - tpadvertise() all 133 services from a {name, fn} table,
|
||||
* - tpclose() at shutdown.
|
||||
*
|
||||
* XA: the connection is opened once by tpopen() (ECPG XA switch libndrxxaecpg.so);
|
||||
|
|
@ -103,6 +103,76 @@
|
|||
#include "MG_SETTLEREQ.h"
|
||||
#include "MG_SETTLERSP.h"
|
||||
#include "MG_QDEPTH.h"
|
||||
/* ===== 스케일아웃 신규 서비스 (+58) ===== */
|
||||
/* --- 전문유형별 처리 세분 (0100/0110/0120/0200/0210/0220/0400/0420/0800/0810) --- */
|
||||
#include "MG_AUTHADV.h"
|
||||
#include "MG_AUTHADVRSP.h"
|
||||
#include "MG_FINREQ.h"
|
||||
#include "MG_FINRSP.h"
|
||||
#include "MG_FINADV.h"
|
||||
#include "MG_FINADVRSP.h"
|
||||
#include "MG_REVRSP.h"
|
||||
#include "MG_REVADVRSP.h"
|
||||
#include "MG_NMRSP.h"
|
||||
#include "MG_NMADVICE.h"
|
||||
#include "MG_BALINQ.h"
|
||||
#include "MG_INQRSP.h"
|
||||
#include "MG_CARDVER.h"
|
||||
#include "MG_PREAUTH.h"
|
||||
/* --- 채널별 어댑터 (VAN사별/직연동/중계) --- */
|
||||
#include "MG_VAN3ADPT.h"
|
||||
#include "MG_VAN4ADPT.h"
|
||||
#include "MG_RELAYADPT.h"
|
||||
#include "MG_ISOADPT.h"
|
||||
#include "MG_HOSTADPT.h"
|
||||
#include "MG_CHANMAP.h"
|
||||
#include "MG_FEP.h"
|
||||
/* --- 전문 조립/분해/변환 (내부<->ISO8583) --- */
|
||||
#include "MG_ENCODE.h"
|
||||
#include "MG_DECODE.h"
|
||||
#include "MG_FIELDGET.h"
|
||||
#include "MG_FIELDSET.h"
|
||||
#include "MG_BMPPARSE.h"
|
||||
#include "MG_BMPMERGE.h"
|
||||
/* --- MAC/키 관리 세분 --- */
|
||||
#include "MG_MACSESSION.h"
|
||||
#include "MG_KEYLOAD.h"
|
||||
#include "MG_KEYCHECK.h"
|
||||
#include "MG_PINBLOCK.h"
|
||||
#include "MG_KEYEXPIRE.h"
|
||||
/* --- 타임아웃/재전송/중복검출 세분 --- */
|
||||
#include "MG_RESNDONE.h"
|
||||
#include "MG_STALEMARK.h"
|
||||
#include "MG_DUPPURGE.h"
|
||||
#include "MG_INFLIGHT.h"
|
||||
/* --- 순번 갭 검출/보정 --- */
|
||||
#include "MG_SEQNEXT.h"
|
||||
#include "MG_SEQRESET.h"
|
||||
#include "MG_SEQFILL.h"
|
||||
/* --- 라우팅 룰 관리 --- */
|
||||
#include "MG_RTFIND.h"
|
||||
#include "MG_RTDISABLE.h"
|
||||
#include "MG_RTENABLE.h"
|
||||
#include "MG_RTCOUNT.h"
|
||||
/* --- 채널 상태 모니터/이중화 전환 --- */
|
||||
#include "MG_CHANPING.h"
|
||||
#include "MG_CHANFAILOVER.h"
|
||||
#include "MG_CHANLIST.h"
|
||||
#include "MG_CHANRESET.h"
|
||||
/* --- 전문 통계 (채널/금액/응답코드/시간대/종합) --- */
|
||||
#include "MG_STATCHAN.h"
|
||||
#include "MG_STATAMT.h"
|
||||
#include "MG_STATERR.h"
|
||||
#include "MG_STATPEAK.h"
|
||||
#include "MG_STATSUM.h"
|
||||
/* --- 오류전문 재처리 워크플로 --- */
|
||||
#include "MG_ERRREQUEUE.h"
|
||||
#include "MG_ERRCLASS.h"
|
||||
#include "MG_ERRESCAL.h"
|
||||
/* --- 트래픽 제어/부하분산 + 헬스체크 세분 --- */
|
||||
#include "MG_LOADBAL.h"
|
||||
#include "MG_RATELIMIT.h"
|
||||
#include "MG_READYZ.h"
|
||||
|
||||
/* ----- advertise table: {service name, function} (fn is extern from its file) */
|
||||
static struct { const char *name; void (*fn)(TPSVCINFO *); } SVCS[] = {
|
||||
|
|
@ -144,6 +214,36 @@ static struct { const char *name; void (*fn)(TPSVCINFO *); } SVCS[] = {
|
|||
{"MG_AMTCHECK", MG_AMTCHECK}, {"MG_ADVICE", MG_ADVICE},
|
||||
{"MG_SETTLEREQ", MG_SETTLEREQ}, {"MG_SETTLERSP", MG_SETTLERSP},
|
||||
{"MG_QDEPTH", MG_QDEPTH},
|
||||
/* ===== 스케일아웃 신규 서비스 (+58) ===== */
|
||||
{"MG_AUTHADV", MG_AUTHADV}, {"MG_AUTHADVRSP", MG_AUTHADVRSP},
|
||||
{"MG_FINREQ", MG_FINREQ}, {"MG_FINRSP", MG_FINRSP},
|
||||
{"MG_FINADV", MG_FINADV}, {"MG_FINADVRSP", MG_FINADVRSP},
|
||||
{"MG_REVRSP", MG_REVRSP}, {"MG_REVADVRSP", MG_REVADVRSP},
|
||||
{"MG_NMRSP", MG_NMRSP}, {"MG_NMADVICE", MG_NMADVICE},
|
||||
{"MG_BALINQ", MG_BALINQ}, {"MG_INQRSP", MG_INQRSP},
|
||||
{"MG_CARDVER", MG_CARDVER}, {"MG_PREAUTH", MG_PREAUTH},
|
||||
{"MG_VAN3ADPT", MG_VAN3ADPT}, {"MG_VAN4ADPT", MG_VAN4ADPT},
|
||||
{"MG_RELAYADPT", MG_RELAYADPT}, {"MG_ISOADPT", MG_ISOADPT},
|
||||
{"MG_HOSTADPT", MG_HOSTADPT}, {"MG_CHANMAP", MG_CHANMAP},
|
||||
{"MG_FEP", MG_FEP}, {"MG_ENCODE", MG_ENCODE},
|
||||
{"MG_DECODE", MG_DECODE}, {"MG_FIELDGET", MG_FIELDGET},
|
||||
{"MG_FIELDSET", MG_FIELDSET}, {"MG_BMPPARSE", MG_BMPPARSE},
|
||||
{"MG_BMPMERGE", MG_BMPMERGE}, {"MG_MACSESSION", MG_MACSESSION},
|
||||
{"MG_KEYLOAD", MG_KEYLOAD}, {"MG_KEYCHECK", MG_KEYCHECK},
|
||||
{"MG_PINBLOCK", MG_PINBLOCK}, {"MG_KEYEXPIRE", MG_KEYEXPIRE},
|
||||
{"MG_RESNDONE", MG_RESNDONE}, {"MG_STALEMARK", MG_STALEMARK},
|
||||
{"MG_DUPPURGE", MG_DUPPURGE}, {"MG_INFLIGHT", MG_INFLIGHT},
|
||||
{"MG_SEQNEXT", MG_SEQNEXT}, {"MG_SEQRESET", MG_SEQRESET},
|
||||
{"MG_SEQFILL", MG_SEQFILL}, {"MG_RTFIND", MG_RTFIND},
|
||||
{"MG_RTDISABLE", MG_RTDISABLE}, {"MG_RTENABLE", MG_RTENABLE},
|
||||
{"MG_RTCOUNT", MG_RTCOUNT}, {"MG_CHANPING", MG_CHANPING},
|
||||
{"MG_CHANFAILOVER", MG_CHANFAILOVER}, {"MG_CHANLIST", MG_CHANLIST},
|
||||
{"MG_CHANRESET", MG_CHANRESET}, {"MG_STATCHAN", MG_STATCHAN},
|
||||
{"MG_STATAMT", MG_STATAMT}, {"MG_STATERR", MG_STATERR},
|
||||
{"MG_STATPEAK", MG_STATPEAK}, {"MG_STATSUM", MG_STATSUM},
|
||||
{"MG_ERRREQUEUE", MG_ERRREQUEUE}, {"MG_ERRCLASS", MG_ERRCLASS},
|
||||
{"MG_ERRESCAL", MG_ERRESCAL}, {"MG_LOADBAL", MG_LOADBAL},
|
||||
{"MG_RATELIMIT", MG_RATELIMIT}, {"MG_READYZ", MG_READYZ},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
|
|
|
|||
12
app/src/mg/svc/MG_AUTHADV.h
Normal file
12
app/src/mg/svc/MG_AUTHADV.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_AUTHADV.h - mg (전문게이트웨이) 서비스 MG_AUTHADV 카피북 (copybook / record header).
|
||||
* 신규 스케일아웃 서비스; mg_svr 가 tpsvrinit 에서 광고한다.
|
||||
*/
|
||||
#ifndef MG_AUTHADV_H
|
||||
#define MG_AUTHADV_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_AUTHADV(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_AUTHADV_H */
|
||||
33
app/src/mg/svc/MG_AUTHADV.pgc
Normal file
33
app/src/mg/svc/MG_AUTHADV.pgc
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* MG_AUTHADV.pgc - mg 모듈 서비스 MG_AUTHADV (one service = one file).
|
||||
* 신규 스케일아웃 서비스; 캘러의 XA 브랜치에서 실행. mg_svr 가 광고.
|
||||
*/
|
||||
#include "MG_AUTHADV.h"
|
||||
|
||||
/* MG_AUTHADV - 0120 승인통지(advice) 수신: 승인응답 유실 후 단말이 재차 보낸
|
||||
* 통지 전문을 원장에 0120/IN 으로 채번·적재하고 통지수신(A) 상태로 표시한다. */
|
||||
void MG_AUTHADV(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char chan[16], raw[512], proc[8], bizdate[16];
|
||||
long stan, msg_id, amount, n;
|
||||
|
||||
gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "CH01");
|
||||
gets_(b, T_STR3, raw, sizeof(raw));
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
n = (long)strlen(raw);
|
||||
|
||||
memset(proc, 0, sizeof(proc));
|
||||
if (n >= 10) strncpy(proc, raw + 4, 6); else strcpy(proc, "000000");
|
||||
amount = (n >= 22) ? atol(raw + 10) : getl(b, T_AMOUNT);
|
||||
|
||||
stan = mgdb_next_stan(); if (stan < 0) FAIL(b);
|
||||
msg_id = mgdb_next_msg_id(); if (msg_id < 0) FAIL(b);
|
||||
if (mgdb_insert_msg(msg_id, stan, "0120", chan, "IN", proc, "", amount,
|
||||
"", "00", raw, "A", bizdate) < 0) FAIL(b);
|
||||
|
||||
setl(b, T_ID1, msg_id);
|
||||
setl(b, T_ARG1, stan);
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_AUTHADVRSP.h
Normal file
12
app/src/mg/svc/MG_AUTHADVRSP.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_AUTHADVRSP.h - mg (전문게이트웨이) 서비스 MG_AUTHADVRSP 카피북 (copybook / record header).
|
||||
* 신규 스케일아웃 서비스; mg_svr 가 tpsvrinit 에서 광고한다.
|
||||
*/
|
||||
#ifndef MG_AUTHADVRSP_H
|
||||
#define MG_AUTHADVRSP_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_AUTHADVRSP(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_AUTHADVRSP_H */
|
||||
33
app/src/mg/svc/MG_AUTHADVRSP.pgc
Normal file
33
app/src/mg/svc/MG_AUTHADVRSP.pgc
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* MG_AUTHADVRSP.pgc - mg 모듈 서비스 MG_AUTHADVRSP (one service = one file).
|
||||
* 신규 스케일아웃 서비스; 캘러의 XA 브랜치에서 실행. mg_svr 가 광고.
|
||||
*/
|
||||
#include "MG_AUTHADVRSP.h"
|
||||
|
||||
/* MG_AUTHADVRSP - 0130 승인통지응답 생성: 원 STAN 의 0120 통지를 원장에서 찾아
|
||||
* 0130 응답전문을 OUT 으로 채번·적재하고, 원 통지를 확인완료(C) 상태로 갱신. */
|
||||
void MG_AUTHADVRSP(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char chan[16], bizdate[16];
|
||||
long orig_stan, orig_id, stan, msg_id;
|
||||
|
||||
gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "CH01");
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
orig_stan = getl(b, T_ARG1);
|
||||
if (orig_stan <= 0) { setl(b, T_RC, 13); FAIL(b); }
|
||||
|
||||
orig_id = mgdb_find_msg_by_stan(orig_stan);
|
||||
if (orig_id < 0) { setl(b, T_RC, 25); FAIL(b); } /* 원 통지 없음 */
|
||||
|
||||
stan = mgdb_next_stan(); if (stan < 0) FAIL(b);
|
||||
msg_id = mgdb_next_msg_id(); if (msg_id < 0) FAIL(b);
|
||||
if (mgdb_insert_msg(msg_id, stan, "0130", chan, "OUT", "000000", "", 0,
|
||||
"", "00", "", "S", bizdate) < 0) FAIL(b);
|
||||
if (mgdb_update_msg_rc(orig_id, "00", "C") < 0) FAIL(b);
|
||||
|
||||
setl(b, T_ID1, msg_id);
|
||||
setl(b, T_ID2, orig_id);
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_BALINQ.h
Normal file
12
app/src/mg/svc/MG_BALINQ.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_BALINQ.h - mg (전문게이트웨이) 서비스 MG_BALINQ 카피북 (copybook / record header).
|
||||
* 신규 스케일아웃 서비스; mg_svr 가 tpsvrinit 에서 광고한다.
|
||||
*/
|
||||
#ifndef MG_BALINQ_H
|
||||
#define MG_BALINQ_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_BALINQ(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_BALINQ_H */
|
||||
38
app/src/mg/svc/MG_BALINQ.pgc
Normal file
38
app/src/mg/svc/MG_BALINQ.pgc
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* MG_BALINQ.pgc - mg 모듈 서비스 MG_BALINQ (one service = one file).
|
||||
* 신규 스케일아웃 서비스; 캘러의 XA 브랜치에서 실행. mg_svr 가 광고.
|
||||
*/
|
||||
#include "MG_BALINQ.h"
|
||||
|
||||
/* MG_BALINQ - 0100 잔액조회 요청 수신: 금액 0 · 처리코드 31xxxx(조회) 인 전문을
|
||||
* PAN Luhn 검증 후 원장에 0100/IN 으로 적재. 처리코드가 조회계열(31)이 아니면 rc=12. */
|
||||
void MG_BALINQ(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char chan[16], raw[512], bizdate[16], proc[8], pan[24], rc[4];
|
||||
long stan, msg_id, n;
|
||||
|
||||
gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "CH01");
|
||||
gets_(b, T_STR3, raw, sizeof(raw));
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
n = (long)strlen(raw);
|
||||
|
||||
memset(proc, 0, sizeof(proc)); memset(pan, 0, sizeof(pan));
|
||||
if (n >= 10) strncpy(proc, raw + 4, 6); else strcpy(proc, "310000");
|
||||
if (n >= 38) strncpy(pan, raw + 22, 16);
|
||||
|
||||
if (strncmp(proc, "31", 2) != 0) strcpy(rc, "12"); /* 12 = 처리불가 거래 */
|
||||
else if (pan[0] && !acq_luhn_ok(pan)) strcpy(rc, "14");
|
||||
else strcpy(rc, "00");
|
||||
|
||||
stan = mgdb_next_stan(); if (stan < 0) FAIL(b);
|
||||
msg_id = mgdb_next_msg_id(); if (msg_id < 0) FAIL(b);
|
||||
if (mgdb_insert_msg(msg_id, stan, "0100", chan, "IN", proc, "", 0,
|
||||
"", rc, raw, "R", bizdate) < 0) FAIL(b);
|
||||
|
||||
sets_(b, T_STR2, rc);
|
||||
sets_(b, T_STR4, proc);
|
||||
setl(b, T_ID1, msg_id);
|
||||
setl(b, T_ARG1, stan);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_BMPMERGE.h
Normal file
12
app/src/mg/svc/MG_BMPMERGE.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_BMPMERGE.h - mg (전문게이트웨이) 서비스 MG_BMPMERGE 카피북 (copybook / record header).
|
||||
* 신규 스케일아웃 서비스; mg_svr 가 tpsvrinit 에서 광고한다.
|
||||
*/
|
||||
#ifndef MG_BMPMERGE_H
|
||||
#define MG_BMPMERGE_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_BMPMERGE(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_BMPMERGE_H */
|
||||
29
app/src/mg/svc/MG_BMPMERGE.pgc
Normal file
29
app/src/mg/svc/MG_BMPMERGE.pgc
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* MG_BMPMERGE.pgc - mg 모듈 서비스 MG_BMPMERGE (one service = one file).
|
||||
* 신규 스케일아웃 서비스; 캘러의 XA 브랜치에서 실행. mg_svr 가 광고.
|
||||
*/
|
||||
#include "MG_BMPMERGE.h"
|
||||
|
||||
/* MG_BMPMERGE - 비트맵 병합(순수계산): 1차 비트맵(T_STR6)과 2차 비트맵(T_STR7)을
|
||||
* OR 로 합쳐 통합 마스크를 만들고, 2차 존재 시 필드1(확장비트) 을 세워 회신. */
|
||||
void MG_BMPMERGE(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char hex1[24], hex2[24], out[24];
|
||||
unsigned long m1 = 0, m2 = 0, merged;
|
||||
|
||||
gets_(b, T_STR6, hex1, sizeof(hex1));
|
||||
gets_(b, T_STR7, hex2, sizeof(hex2));
|
||||
|
||||
if (hex1[0] && sscanf(hex1, "%16lx", &m1) != 1) { setl(b, T_RC, 30); FAIL(b); }
|
||||
if (hex2[0] && sscanf(hex2, "%16lx", &m2) != 1) { setl(b, T_RC, 30); FAIL(b); }
|
||||
|
||||
merged = m1 | m2;
|
||||
if (m2 != 0) merged |= (1UL << (64 - 1)); /* 2차비트맵 존재표시 = 필드1 */
|
||||
|
||||
sprintf(out, "%016lX", merged);
|
||||
sets_(b, T_STR6, out);
|
||||
setl(b, T_ARG3, (long)(m2 != 0));
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_BMPPARSE.h
Normal file
12
app/src/mg/svc/MG_BMPPARSE.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_BMPPARSE.h - mg (전문게이트웨이) 서비스 MG_BMPPARSE 카피북 (copybook / record header).
|
||||
* 신규 스케일아웃 서비스; mg_svr 가 tpsvrinit 에서 광고한다.
|
||||
*/
|
||||
#ifndef MG_BMPPARSE_H
|
||||
#define MG_BMPPARSE_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_BMPPARSE(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_BMPPARSE_H */
|
||||
34
app/src/mg/svc/MG_BMPPARSE.pgc
Normal file
34
app/src/mg/svc/MG_BMPPARSE.pgc
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* MG_BMPPARSE.pgc - mg 모듈 서비스 MG_BMPPARSE (one service = one file).
|
||||
* 신규 스케일아웃 서비스; 캘러의 XA 브랜치에서 실행. mg_svr 가 광고.
|
||||
*/
|
||||
#include "MG_BMPPARSE.h"
|
||||
|
||||
/* MG_BMPPARSE - 비트맵 해석(순수계산): 16-hex 1차 비트맵을 64비트로 풀어 존재하는
|
||||
* 필드번호 목록(콤마구분)과 존재 필드 개수를 회신. hex 형식 오류면 rc=30. */
|
||||
void MG_BMPPARSE(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char hex[24], list[256], tmp[8];
|
||||
unsigned long mask = 0;
|
||||
long cnt = 0;
|
||||
int i;
|
||||
|
||||
gets_(b, T_STR6, hex, sizeof(hex));
|
||||
if (strlen(hex) < 16) { setl(b, T_RC, 30); FAIL(b); }
|
||||
if (sscanf(hex, "%16lx", &mask) != 1) { setl(b, T_RC, 30); FAIL(b); }
|
||||
|
||||
list[0] = 0;
|
||||
for (i = 1; i <= 64; i++) { /* 비트 i = 필드 i (MSB=필드1) */
|
||||
if (mask & (1UL << (64 - i))) {
|
||||
sprintf(tmp, "%s%d", (cnt ? "," : ""), i);
|
||||
if (strlen(list) + strlen(tmp) < sizeof(list) - 1) strcat(list, tmp);
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
|
||||
sets_(b, T_STR3, list);
|
||||
setl(b, T_COUNT, cnt);
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_CARDVER.h
Normal file
12
app/src/mg/svc/MG_CARDVER.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_CARDVER.h - mg (전문게이트웨이) 서비스 MG_CARDVER 카피북 (copybook / record header).
|
||||
* 신규 스케일아웃 서비스; mg_svr 가 tpsvrinit 에서 광고한다.
|
||||
*/
|
||||
#ifndef MG_CARDVER_H
|
||||
#define MG_CARDVER_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_CARDVER(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_CARDVER_H */
|
||||
45
app/src/mg/svc/MG_CARDVER.pgc
Normal file
45
app/src/mg/svc/MG_CARDVER.pgc
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* MG_CARDVER.pgc - mg 모듈 서비스 MG_CARDVER (one service = one file).
|
||||
* 신규 스케일아웃 서비스; 캘러의 XA 브랜치에서 실행. mg_svr 가 광고.
|
||||
*/
|
||||
#include "MG_CARDVER.h"
|
||||
|
||||
/* ----- service-local pure helper(s) ----- */
|
||||
/* PAN 앞6(BIN)만 남기고 뒤 전부 마스킹 (카드검증 로그용, 뒤4 미노출). */
|
||||
static void mg_cardver_mask(const char *pan, char *out /* >= 20 */)
|
||||
{
|
||||
int i, len = (int)strlen(pan);
|
||||
for (i = 0; i < len && i < 19; i++)
|
||||
out[i] = (i < 6) ? pan[i] : '*';
|
||||
out[i] = 0;
|
||||
}
|
||||
|
||||
/* MG_CARDVER - 0100 카드검증(금액 0 승인): PAN 자릿수(13~19)와 Luhn 을 함께 검사해
|
||||
* 유효(00)/무효(14)/포맷오류(30)를 판정하고 BIN6 마스킹 원장을 적재한다. */
|
||||
void MG_CARDVER(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char chan[16], pan[24], masked[24], rc[4], bizdate[16];
|
||||
long stan, msg_id, plen;
|
||||
|
||||
gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "CH01");
|
||||
gets_(b, T_STR5, pan, sizeof(pan));
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
plen = (long)strlen(pan);
|
||||
|
||||
if (plen < 13 || plen > 19) strcpy(rc, "30");
|
||||
else if (!acq_luhn_ok(pan)) strcpy(rc, "14");
|
||||
else strcpy(rc, "00");
|
||||
mg_cardver_mask(pan, masked);
|
||||
|
||||
stan = mgdb_next_stan(); if (stan < 0) FAIL(b);
|
||||
msg_id = mgdb_next_msg_id(); if (msg_id < 0) FAIL(b);
|
||||
if (mgdb_insert_msg(msg_id, stan, "0100", chan, "IN", "000000", "", 0,
|
||||
masked, rc, "", "R", bizdate) < 0) FAIL(b);
|
||||
|
||||
sets_(b, T_STR2, rc);
|
||||
sets_(b, T_STR6, masked);
|
||||
setl(b, T_COUNT, plen);
|
||||
setl(b, T_ID1, msg_id);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_CHANFAILOVER.h
Normal file
12
app/src/mg/svc/MG_CHANFAILOVER.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_CHANFAILOVER.h - mg (전문게이트웨이) 서비스 MG_CHANFAILOVER 카피북 (copybook / record header).
|
||||
* 신규 스케일아웃 서비스; mg_svr 가 tpsvrinit 에서 광고한다.
|
||||
*/
|
||||
#ifndef MG_CHANFAILOVER_H
|
||||
#define MG_CHANFAILOVER_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_CHANFAILOVER(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_CHANFAILOVER_H */
|
||||
42
app/src/mg/svc/MG_CHANFAILOVER.pgc
Normal file
42
app/src/mg/svc/MG_CHANFAILOVER.pgc
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* MG_CHANFAILOVER.pgc - mg 모듈 서비스 MG_CHANFAILOVER (one service = one file).
|
||||
* 신규 스케일아웃 서비스; 캘러의 XA 브랜치에서 실행. mg_svr 가 광고.
|
||||
*/
|
||||
#include "MG_CHANFAILOVER.h"
|
||||
|
||||
/* MG_CHANFAILOVER - 이중화 절체: 주채널(T_CHANNEL)이 DOWN 이면 예비채널(T_STR1)을
|
||||
* UP 으로 승격하고 주채널을 DOWN 확정. 주채널이 살아있으면 절체 없이 rc=1. */
|
||||
void MG_CHANFAILOVER(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char primary[16], backup[16], curp[16], curb[16];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_primary[16], h_backup[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_CHANNEL, primary, sizeof(primary)); if (primary[0] == 0) strcpy(primary, "CH01");
|
||||
gets_(b, T_STR1, backup, sizeof(backup)); if (backup[0] == 0) strcpy(backup, "CH02");
|
||||
|
||||
if (mgdb_get_channel_status(primary, curp) < 0) { setl(b, T_RC, 25); FAIL(b); }
|
||||
if (mgdb_get_channel_status(backup, curb) < 0) { setl(b, T_RC, 25); FAIL(b); }
|
||||
|
||||
if (strcmp(curp, "UP") == 0) { /* 주채널 정상 = 절체 불필요 */
|
||||
sets_(b, T_STATUS, "PRIMARY");
|
||||
setl(b, T_RC, 1);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
strncpy(h_primary, primary, sizeof(h_primary)-1); h_primary[sizeof(h_primary)-1] = 0;
|
||||
strncpy(h_backup, backup, sizeof(h_backup)-1); h_backup[sizeof(h_backup)-1] = 0;
|
||||
EXEC SQL UPDATE mg_channel SET status = 'DOWN', updated_at = now() WHERE channel = :h_primary;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
EXEC SQL UPDATE mg_channel SET status = 'UP', signon_at = now(), updated_at = now()
|
||||
WHERE channel = :h_backup;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
userlog("MG_CHANFAILOVER 절체 %s(DOWN) -> %s(UP)", primary, backup);
|
||||
sets_(b, T_STATUS, "FAILOVER");
|
||||
sets_(b, T_STR5, backup);
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_CHANLIST.h
Normal file
12
app/src/mg/svc/MG_CHANLIST.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_CHANLIST.h - mg (전문게이트웨이) 서비스 MG_CHANLIST 카피북 (copybook / record header).
|
||||
* 신규 스케일아웃 서비스; mg_svr 가 tpsvrinit 에서 광고한다.
|
||||
*/
|
||||
#ifndef MG_CHANLIST_H
|
||||
#define MG_CHANLIST_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_CHANLIST(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_CHANLIST_H */
|
||||
42
app/src/mg/svc/MG_CHANLIST.pgc
Normal file
42
app/src/mg/svc/MG_CHANLIST.pgc
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* MG_CHANLIST.pgc - mg 모듈 서비스 MG_CHANLIST (one service = one file).
|
||||
* 신규 스케일아웃 서비스; 캘러의 XA 브랜치에서 실행. mg_svr 가 광고.
|
||||
*/
|
||||
#include "MG_CHANLIST.h"
|
||||
|
||||
/* MG_CHANLIST - 채널 상태 요약: 전체 채널 중 UP/DOWN 개수를 집계하고, UP 채널ID 를
|
||||
* 콤마로 이어 목록으로 회신. UP 이 하나도 없으면 rc=1(전면 다운) 경고. */
|
||||
void MG_CHANLIST(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char list[256], tmp[24];
|
||||
long up = 0, down = 0;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_chan[16], h_status[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
list[0] = 0;
|
||||
EXEC SQL DECLARE clst CURSOR FOR
|
||||
SELECT channel, status FROM mg_channel ORDER BY channel;
|
||||
EXEC SQL OPEN clst;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
for (;;) {
|
||||
EXEC SQL FETCH clst INTO :h_chan, :h_status;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE clst; FAIL(b); }
|
||||
if (strcmp(h_status, "UP") == 0) {
|
||||
up++;
|
||||
sprintf(tmp, "%s%s", (up > 1 ? "," : ""), h_chan);
|
||||
if (strlen(list) + strlen(tmp) < sizeof(list) - 1) strcat(list, tmp);
|
||||
} else {
|
||||
down++;
|
||||
}
|
||||
}
|
||||
EXEC SQL CLOSE clst;
|
||||
|
||||
sets_(b, T_STR3, list);
|
||||
setl(b, T_ARG2, up);
|
||||
setl(b, T_ARG3, down);
|
||||
setl(b, T_RC, (up == 0) ? 1 : 0);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_CHANMAP.h
Normal file
12
app/src/mg/svc/MG_CHANMAP.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_CHANMAP.h - mg (전문게이트웨이) 서비스 MG_CHANMAP 카피북 (copybook / record header).
|
||||
* 신규 스케일아웃 서비스; mg_svr 가 tpsvrinit 에서 광고한다.
|
||||
*/
|
||||
#ifndef MG_CHANMAP_H
|
||||
#define MG_CHANMAP_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_CHANMAP(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_CHANMAP_H */
|
||||
26
app/src/mg/svc/MG_CHANMAP.pgc
Normal file
26
app/src/mg/svc/MG_CHANMAP.pgc
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* MG_CHANMAP.pgc - mg 모듈 서비스 MG_CHANMAP (one service = one file).
|
||||
* 신규 스케일아웃 서비스; 캘러의 XA 브랜치에서 실행. mg_svr 가 광고.
|
||||
*/
|
||||
#include "MG_CHANMAP.h"
|
||||
|
||||
/* MG_CHANMAP - 외부 채널코드 -> 내부 채널ID 매핑: VAN1/VAN2->CH01, EDC->CH02,
|
||||
* FEP/직연동->CH03 규칙으로 정규화하고, 미등록 외부코드는 rc=25 로 반려. */
|
||||
void MG_CHANMAP(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char ext[24], chan[16];
|
||||
|
||||
gets_(b, T_STR1, ext, sizeof(ext));
|
||||
if (ext[0] == 0) { setl(b, T_RC, 30); FAIL(b); }
|
||||
|
||||
if (strcmp(ext, "VAN1") == 0 || strcmp(ext, "VAN2") == 0) strcpy(chan, "CH01");
|
||||
else if (strcmp(ext, "EDC") == 0 || strcmp(ext, "POS") == 0) strcpy(chan, "CH02");
|
||||
else if (strcmp(ext, "FEP") == 0 || strcmp(ext, "ISO") == 0) strcpy(chan, "CH03");
|
||||
else { userlog("MG_CHANMAP 미등록 채널코드 %s", ext); setl(b, T_RC, 25); FAIL(b); }
|
||||
|
||||
sets_(b, T_CHANNEL, chan);
|
||||
sets_(b, T_STR5, ext);
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_CHANPING.h
Normal file
12
app/src/mg/svc/MG_CHANPING.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_CHANPING.h - mg (전문게이트웨이) 서비스 MG_CHANPING 카피북 (copybook / record header).
|
||||
* 신규 스케일아웃 서비스; mg_svr 가 tpsvrinit 에서 광고한다.
|
||||
*/
|
||||
#ifndef MG_CHANPING_H
|
||||
#define MG_CHANPING_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_CHANPING(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_CHANPING_H */
|
||||
33
app/src/mg/svc/MG_CHANPING.pgc
Normal file
33
app/src/mg/svc/MG_CHANPING.pgc
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* MG_CHANPING.pgc - mg 모듈 서비스 MG_CHANPING (one service = one file).
|
||||
* 신규 스케일아웃 서비스; 캘러의 XA 브랜치에서 실행. mg_svr 가 광고.
|
||||
*/
|
||||
#include "MG_CHANPING.h"
|
||||
|
||||
/* MG_CHANPING - 채널 하트비트: UP 채널의 updated_at 을 now() 로 눌러 살아있음을
|
||||
* 기록한다. DOWN 채널이면 rc=1 로 핑 실패를 알리고 갱신하지 않는다. */
|
||||
void MG_CHANPING(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char chan[16], cur[16];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_chan[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "CH01");
|
||||
if (mgdb_get_channel_status(chan, cur) < 0) { setl(b, T_RC, 25); FAIL(b); }
|
||||
|
||||
if (strcmp(cur, "UP") != 0) {
|
||||
sets_(b, T_STATUS, cur);
|
||||
setl(b, T_RC, 1); /* 살아있지 않은 채널 */
|
||||
OK(b);
|
||||
}
|
||||
|
||||
strncpy(h_chan, chan, sizeof(h_chan)-1); h_chan[sizeof(h_chan)-1] = 0;
|
||||
EXEC SQL UPDATE mg_channel SET updated_at = now() WHERE channel = :h_chan;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
sets_(b, T_STATUS, "UP");
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_CHANRESET.h
Normal file
12
app/src/mg/svc/MG_CHANRESET.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_CHANRESET.h - mg (전문게이트웨이) 서비스 MG_CHANRESET 카피북 (copybook / record header).
|
||||
* 신규 스케일아웃 서비스; mg_svr 가 tpsvrinit 에서 광고한다.
|
||||
*/
|
||||
#ifndef MG_CHANRESET_H
|
||||
#define MG_CHANRESET_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_CHANRESET(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_CHANRESET_H */
|
||||
32
app/src/mg/svc/MG_CHANRESET.pgc
Normal file
32
app/src/mg/svc/MG_CHANRESET.pgc
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* MG_CHANRESET.pgc - mg 모듈 서비스 MG_CHANRESET (one service = one file).
|
||||
* 신규 스케일아웃 서비스; 캘러의 XA 브랜치에서 실행. mg_svr 가 광고.
|
||||
*/
|
||||
#include "MG_CHANRESET.h"
|
||||
|
||||
/* MG_CHANRESET - 채널 세션 초기화: 채널을 DOWN 으로 내리고 세션키/사인온시각/last_stan
|
||||
* 을 일괄 비워 재개통(사인온) 이전 상태로 되돌린다. 초기화 전 상태를 회신. */
|
||||
void MG_CHANRESET(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char chan[16], cur[16];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_chan[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "CH01");
|
||||
if (mgdb_get_channel_status(chan, cur) < 0) { setl(b, T_RC, 25); FAIL(b); }
|
||||
|
||||
strncpy(h_chan, chan, sizeof(h_chan)-1); h_chan[sizeof(h_chan)-1] = 0;
|
||||
EXEC SQL UPDATE mg_channel
|
||||
SET status = 'DOWN', session_key = '', signon_at = NULL,
|
||||
last_stan = 0, updated_at = now()
|
||||
WHERE channel = :h_chan;
|
||||
if (sqlca.sqlcode < 0) { userlog("MG_CHANRESET FAIL [%d]", sqlca.sqlcode); FAIL(b); }
|
||||
|
||||
userlog("MG_CHANRESET 채널 초기화 %s (%s -> DOWN)", chan, cur);
|
||||
sets_(b, T_STR5, cur); /* 초기화 전 상태 */
|
||||
sets_(b, T_STATUS, "DOWN");
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_DECODE.h
Normal file
12
app/src/mg/svc/MG_DECODE.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_DECODE.h - mg (전문게이트웨이) 서비스 MG_DECODE 카피북 (copybook / record header).
|
||||
* 신규 스케일아웃 서비스; mg_svr 가 tpsvrinit 에서 광고한다.
|
||||
*/
|
||||
#ifndef MG_DECODE_H
|
||||
#define MG_DECODE_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_DECODE(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_DECODE_H */
|
||||
33
app/src/mg/svc/MG_DECODE.pgc
Normal file
33
app/src/mg/svc/MG_DECODE.pgc
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* MG_DECODE.pgc - mg 모듈 서비스 MG_DECODE (one service = one file).
|
||||
* 신규 스케일아웃 서비스; 캘러의 XA 브랜치에서 실행. mg_svr 가 광고.
|
||||
*/
|
||||
#include "MG_DECODE.h"
|
||||
|
||||
/* MG_DECODE - 확장 고정길이 해체(순수계산): MG_ENCODE 가 만든 32자 프레임을
|
||||
* MTI/처리코드/금액/STAN/채널 필드로 되돌린다. 길이 32 미만이면 rc=31. */
|
||||
void MG_DECODE(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char raw[64], mti[8], proc[8], chan[8];
|
||||
long amount, stan, n;
|
||||
|
||||
gets_(b, T_STR3, raw, sizeof(raw));
|
||||
n = (long)strlen(raw);
|
||||
if (n < 32) { setl(b, T_RC, 31); FAIL(b); }
|
||||
|
||||
memset(mti, 0, sizeof(mti)); memset(proc, 0, sizeof(proc)); memset(chan, 0, sizeof(chan));
|
||||
strncpy(mti, raw, 4);
|
||||
strncpy(proc, raw + 4, 6);
|
||||
amount = atol(raw + 10); /* [10..21] 금액 12 */
|
||||
stan = atol(raw + 22); /* [22..27] STAN 6 */
|
||||
strncpy(chan, raw + 28, 4); /* [28..31] 채널 4 */
|
||||
|
||||
sets_(b, T_STR1, mti);
|
||||
sets_(b, T_STR4, proc);
|
||||
setl(b, T_AMOUNT, amount);
|
||||
setl(b, T_ARG1, stan);
|
||||
sets_(b, T_CHANNEL, chan);
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_DUPPURGE.h
Normal file
12
app/src/mg/svc/MG_DUPPURGE.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_DUPPURGE.h - mg (전문게이트웨이) 서비스 MG_DUPPURGE 카피북 (copybook / record header).
|
||||
* 신규 스케일아웃 서비스; mg_svr 가 tpsvrinit 에서 광고한다.
|
||||
*/
|
||||
#ifndef MG_DUPPURGE_H
|
||||
#define MG_DUPPURGE_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_DUPPURGE(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_DUPPURGE_H */
|
||||
37
app/src/mg/svc/MG_DUPPURGE.pgc
Normal file
37
app/src/mg/svc/MG_DUPPURGE.pgc
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* MG_DUPPURGE.pgc - mg 모듈 서비스 MG_DUPPURGE (one service = one file).
|
||||
* 신규 스케일아웃 서비스; 캘러의 XA 브랜치에서 실행. mg_svr 가 광고.
|
||||
*/
|
||||
#include "MG_DUPPURGE.h"
|
||||
|
||||
/* MG_DUPPURGE - 중복전문 정리: 동일 STAN 이 2건 이상이면 최소 msg_id(원본)만 남기고
|
||||
* 나머지 중복본을 rc=94/status=X(폐기)로 마킹. 폐기 건수를 회신한다. */
|
||||
void MG_DUPPURGE(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long purged;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_stan, h_keep;
|
||||
char h_bizdate[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate));
|
||||
h_stan = getl(b, T_ARG1);
|
||||
if (h_stan <= 0) { setl(b, T_RC, 13); FAIL(b); }
|
||||
|
||||
EXEC SQL SELECT min(msg_id) INTO :h_keep
|
||||
FROM mg_msg_log WHERE stan = :h_stan AND biz_date = :h_bizdate;
|
||||
if (sqlca.sqlcode == 100) { setl(b, T_COUNT, 0); OK(b); }
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
EXEC SQL UPDATE mg_msg_log
|
||||
SET rc = '94', status = 'X'
|
||||
WHERE stan = :h_stan AND biz_date = :h_bizdate AND msg_id <> :h_keep;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
purged = (long)sqlca.sqlerrd[2];
|
||||
|
||||
setl(b, T_ID1, h_keep); /* 보존한 원본 msg_id */
|
||||
setl(b, T_COUNT, purged);
|
||||
setl(b, T_RC, (purged > 0) ? 94 : 0);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_ENCODE.h
Normal file
12
app/src/mg/svc/MG_ENCODE.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_ENCODE.h - mg (전문게이트웨이) 서비스 MG_ENCODE 카피북 (copybook / record header).
|
||||
* 신규 스케일아웃 서비스; mg_svr 가 tpsvrinit 에서 광고한다.
|
||||
*/
|
||||
#ifndef MG_ENCODE_H
|
||||
#define MG_ENCODE_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_ENCODE(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_ENCODE_H */
|
||||
26
app/src/mg/svc/MG_ENCODE.pgc
Normal file
26
app/src/mg/svc/MG_ENCODE.pgc
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* MG_ENCODE.pgc - mg 모듈 서비스 MG_ENCODE (one service = one file).
|
||||
* 신규 스케일아웃 서비스; 캘러의 XA 브랜치에서 실행. mg_svr 가 광고.
|
||||
*/
|
||||
#include "MG_ENCODE.h"
|
||||
|
||||
/* MG_ENCODE - 확장 고정길이 인코딩(순수계산): MTI(4)+처리코드(6)+금액(12)+
|
||||
* STAN(6)+채널(4) 을 이어붙여 32자 프레임으로 조립하고 길이를 회신. */
|
||||
void MG_ENCODE(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char mti[8], proc[8], chan[16], raw[64];
|
||||
long amount, stan;
|
||||
|
||||
gets_(b, T_STR1, mti, sizeof(mti)); if (mti[0] == 0) strcpy(mti, "0200");
|
||||
gets_(b, T_STR4, proc, sizeof(proc)); if (proc[0] == 0) strcpy(proc, "000000");
|
||||
gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "CH01");
|
||||
amount = getl(b, T_AMOUNT);
|
||||
stan = getl(b, T_ARG1); if (stan < 0) stan = 0;
|
||||
|
||||
sprintf(raw, "%.4s%.6s%012ld%06ld%.4s", mti, proc, amount, stan % 1000000, chan);
|
||||
sets_(b, T_STR3, raw);
|
||||
setl(b, T_COUNT, (long)strlen(raw));
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_ERRCLASS.h
Normal file
12
app/src/mg/svc/MG_ERRCLASS.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_ERRCLASS.h - mg (전문게이트웨이) 서비스 MG_ERRCLASS 카피북 (copybook / record header).
|
||||
* 신규 스케일아웃 서비스; mg_svr 가 tpsvrinit 에서 광고한다.
|
||||
*/
|
||||
#ifndef MG_ERRCLASS_H
|
||||
#define MG_ERRCLASS_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_ERRCLASS(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_ERRCLASS_H */
|
||||
30
app/src/mg/svc/MG_ERRCLASS.pgc
Normal file
30
app/src/mg/svc/MG_ERRCLASS.pgc
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* MG_ERRCLASS.pgc - mg 모듈 서비스 MG_ERRCLASS (one service = one file).
|
||||
* 신규 스케일아웃 서비스; 캘러의 XA 브랜치에서 실행. mg_svr 가 광고.
|
||||
*/
|
||||
#include "MG_ERRCLASS.h"
|
||||
|
||||
/* MG_ERRCLASS - 오류전문 분류: 응답코드(T_STR2)를 군으로 나눠 재처리 정책을 정한다.
|
||||
* 68/91=일시오류(재시도 RETRY), 14/54=카드오류(반려 REJECT), 그 외=수동(MANUAL). */
|
||||
void MG_ERRCLASS(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char rc[4], cls[16];
|
||||
long policy;
|
||||
|
||||
gets_(b, T_STR2, rc, sizeof(rc));
|
||||
if (rc[0] == 0) { setl(b, T_RC, 30); FAIL(b); }
|
||||
|
||||
if (strcmp(rc, "68") == 0 || strcmp(rc, "91") == 0 || strcmp(rc, "96") == 0) {
|
||||
strcpy(cls, "RETRY"); policy = 1; /* 일시오류 = 자동재시도 */
|
||||
} else if (strcmp(rc, "14") == 0 || strcmp(rc, "54") == 0 || strcmp(rc, "05") == 0) {
|
||||
strcpy(cls, "REJECT"); policy = 2; /* 카드/승인오류 = 반려 */
|
||||
} else {
|
||||
strcpy(cls, "MANUAL"); policy = 3; /* 기타 = 수동확인 */
|
||||
}
|
||||
|
||||
sets_(b, T_STR5, cls);
|
||||
setl(b, T_ARG3, policy);
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_ERRESCAL.h
Normal file
12
app/src/mg/svc/MG_ERRESCAL.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_ERRESCAL.h - mg (전문게이트웨이) 서비스 MG_ERRESCAL 카피북 (copybook / record header).
|
||||
* 신규 스케일아웃 서비스; mg_svr 가 tpsvrinit 에서 광고한다.
|
||||
*/
|
||||
#ifndef MG_ERRESCAL_H
|
||||
#define MG_ERRESCAL_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_ERRESCAL(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_ERRESCAL_H */
|
||||
31
app/src/mg/svc/MG_ERRESCAL.pgc
Normal file
31
app/src/mg/svc/MG_ERRESCAL.pgc
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* MG_ERRESCAL.pgc - mg 모듈 서비스 MG_ERRESCAL (one service = one file).
|
||||
* 신규 스케일아웃 서비스; 캘러의 XA 브랜치에서 실행. mg_svr 가 광고.
|
||||
*/
|
||||
#include "MG_ERRESCAL.h"
|
||||
|
||||
/* MG_ERRESCAL - 재시도초과 에스컬레이션: 재시도횟수가 임계(기본5)를 넘긴 실패(F) 큐
|
||||
* 건을 에스컬레이션(status='E')으로 올려 운영자 개입 대상으로 전이한다. */
|
||||
void MG_ERRESCAL(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long escalated;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_bizdate[16];
|
||||
long h_limit;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate));
|
||||
h_limit = getl(b, T_ARG4); if (h_limit <= 0) h_limit = 5;
|
||||
|
||||
EXEC SQL UPDATE mg_queue
|
||||
SET status = 'E', updated_at = now()
|
||||
WHERE status = 'F' AND biz_date = :h_bizdate AND retry_cnt > :h_limit;
|
||||
if (sqlca.sqlcode < 0) { userlog("MG_ERRESCAL FAIL [%d]", sqlca.sqlcode); FAIL(b); }
|
||||
escalated = (long)sqlca.sqlerrd[2];
|
||||
|
||||
setl(b, T_COUNT, escalated);
|
||||
setl(b, T_ARG4, h_limit);
|
||||
setl(b, T_RC, (escalated > 0) ? 1 : 0);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_ERRREQUEUE.h
Normal file
12
app/src/mg/svc/MG_ERRREQUEUE.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_ERRREQUEUE.h - mg (전문게이트웨이) 서비스 MG_ERRREQUEUE 카피북 (copybook / record header).
|
||||
* 신규 스케일아웃 서비스; mg_svr 가 tpsvrinit 에서 광고한다.
|
||||
*/
|
||||
#ifndef MG_ERRREQUEUE_H
|
||||
#define MG_ERRREQUEUE_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_ERRREQUEUE(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_ERRREQUEUE_H */
|
||||
38
app/src/mg/svc/MG_ERRREQUEUE.pgc
Normal file
38
app/src/mg/svc/MG_ERRREQUEUE.pgc
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* MG_ERRREQUEUE.pgc - mg 모듈 서비스 MG_ERRREQUEUE (one service = one file).
|
||||
* 신규 스케일아웃 서비스; 캘러의 XA 브랜치에서 실행. mg_svr 가 광고.
|
||||
*/
|
||||
#include "MG_ERRREQUEUE.h"
|
||||
|
||||
/* MG_ERRREQUEUE - 오류전문 큐 재투입: NACK(N) 상태 전문의 원 전문(raw_msg)을 다시
|
||||
* 송신큐(Q)에 적재하고, 원 전문을 재처리중(P)으로 전이. 원전문 없으면 rc=25. */
|
||||
void MG_ERRREQUEUE(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char bizdate[16];
|
||||
long qid;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_msgid, h_stan;
|
||||
char h_chan[16], h_mti[8], h_raw[512], h_status[4];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
h_msgid = getl(b, T_ID1);
|
||||
if (h_msgid <= 0) { setl(b, T_RC, 13); FAIL(b); }
|
||||
|
||||
EXEC SQL SELECT stan, channel, mti, raw_msg, status
|
||||
INTO :h_stan, :h_chan, :h_mti, :h_raw, :h_status
|
||||
FROM mg_msg_log WHERE msg_id = :h_msgid;
|
||||
if (sqlca.sqlcode == 100) { setl(b, T_RC, 25); FAIL(b); }
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
if (strcmp(h_status, "N") != 0) { setl(b, T_RC, 1); FAIL(b); } /* NACK 아님 */
|
||||
|
||||
qid = mgdb_next_queue_id(); if (qid < 0) FAIL(b);
|
||||
if (mgdb_enqueue(qid, h_stan, h_chan, h_mti, h_raw, bizdate) < 0) FAIL(b);
|
||||
if (mgdb_update_msg_rc(h_msgid, "00", "P") < 0) FAIL(b);
|
||||
|
||||
setl(b, T_ID2, qid);
|
||||
setl(b, T_ARG1, h_stan);
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_FEP.h
Normal file
12
app/src/mg/svc/MG_FEP.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_FEP.h - mg (전문게이트웨이) 서비스 MG_FEP 카피북 (copybook / record header).
|
||||
* 신규 스케일아웃 서비스; mg_svr 가 tpsvrinit 에서 광고한다.
|
||||
*/
|
||||
#ifndef MG_FEP_H
|
||||
#define MG_FEP_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_FEP(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_FEP_H */
|
||||
31
app/src/mg/svc/MG_FEP.pgc
Normal file
31
app/src/mg/svc/MG_FEP.pgc
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* MG_FEP.pgc - mg 모듈 서비스 MG_FEP (one service = one file).
|
||||
* 신규 스케일아웃 서비스; 캘러의 XA 브랜치에서 실행. mg_svr 가 광고.
|
||||
*/
|
||||
#include "MG_FEP.h"
|
||||
|
||||
/* MG_FEP - 프론트엔드 프로세서(FEP) 정규화 게이트: 전문 앞뒤 STX/ETX 제어문자와
|
||||
* 좌우 공백을 벗겨 순수 페이로드로 정돈하고, 제거 바이트 수를 회신한다. */
|
||||
void MG_FEP(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char raw[512], out[512];
|
||||
long n, i, s, e, trimmed;
|
||||
|
||||
gets_(b, T_STR3, raw, sizeof(raw));
|
||||
n = (long)strlen(raw);
|
||||
|
||||
s = 0; e = n - 1;
|
||||
while (s <= e && (raw[s] == 0x02 || raw[s] == ' ')) s++; /* 앞 STX/공백 */
|
||||
while (e >= s && (raw[e] == 0x03 || raw[e] == ' ')) e--; /* 뒤 ETX/공백 */
|
||||
|
||||
for (i = s; i <= e; i++) out[i - s] = raw[i];
|
||||
out[(e >= s) ? e - s + 1 : 0] = 0;
|
||||
trimmed = n - (long)strlen(out);
|
||||
|
||||
sets_(b, T_STR3, out);
|
||||
setl(b, T_COUNT, (long)strlen(out));
|
||||
setl(b, T_ARG2, trimmed);
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_FIELDGET.h
Normal file
12
app/src/mg/svc/MG_FIELDGET.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_FIELDGET.h - mg (전문게이트웨이) 서비스 MG_FIELDGET 카피북 (copybook / record header).
|
||||
* 신규 스케일아웃 서비스; mg_svr 가 tpsvrinit 에서 광고한다.
|
||||
*/
|
||||
#ifndef MG_FIELDGET_H
|
||||
#define MG_FIELDGET_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_FIELDGET(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_FIELDGET_H */
|
||||
31
app/src/mg/svc/MG_FIELDGET.pgc
Normal file
31
app/src/mg/svc/MG_FIELDGET.pgc
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* MG_FIELDGET.pgc - mg 모듈 서비스 MG_FIELDGET (one service = one file).
|
||||
* 신규 스케일아웃 서비스; 캘러의 XA 브랜치에서 실행. mg_svr 가 광고.
|
||||
*/
|
||||
#include "MG_FIELDGET.h"
|
||||
|
||||
/* MG_FIELDGET - 전문 임의필드 추출(순수계산): 오프셋(T_ARG1)/길이(T_ARG2)로 지정한
|
||||
* 구간을 원 전문에서 잘라 회신. 범위가 전문 길이를 벗어나면 rc=31. */
|
||||
void MG_FIELDGET(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char raw[512], field[256];
|
||||
long off, len, n;
|
||||
|
||||
gets_(b, T_STR3, raw, sizeof(raw));
|
||||
off = getl(b, T_ARG1);
|
||||
len = getl(b, T_ARG2);
|
||||
n = (long)strlen(raw);
|
||||
|
||||
if (off < 0 || len <= 0 || off + len > n || len >= (long)sizeof(field)) {
|
||||
setl(b, T_RC, 31);
|
||||
FAIL(b);
|
||||
}
|
||||
|
||||
memcpy(field, raw + off, len);
|
||||
field[len] = 0;
|
||||
sets_(b, T_STR5, field);
|
||||
setl(b, T_COUNT, len);
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_FIELDSET.h
Normal file
12
app/src/mg/svc/MG_FIELDSET.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_FIELDSET.h - mg (전문게이트웨이) 서비스 MG_FIELDSET 카피북 (copybook / record header).
|
||||
* 신규 스케일아웃 서비스; mg_svr 가 tpsvrinit 에서 광고한다.
|
||||
*/
|
||||
#ifndef MG_FIELDSET_H
|
||||
#define MG_FIELDSET_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_FIELDSET(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_FIELDSET_H */
|
||||
30
app/src/mg/svc/MG_FIELDSET.pgc
Normal file
30
app/src/mg/svc/MG_FIELDSET.pgc
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* MG_FIELDSET.pgc - mg 모듈 서비스 MG_FIELDSET (one service = one file).
|
||||
* 신규 스케일아웃 서비스; 캘러의 XA 브랜치에서 실행. mg_svr 가 광고.
|
||||
*/
|
||||
#include "MG_FIELDSET.h"
|
||||
|
||||
/* MG_FIELDSET - 전문 임의필드 치환(순수계산): 오프셋(T_ARG1)부터 대체값(T_STR5)을
|
||||
* 덮어써 전문을 갱신. 대체값이 남은 길이를 넘어가면 rc=31 로 반려한다. */
|
||||
void MG_FIELDSET(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char raw[512], val[256];
|
||||
long off, vlen, n, i;
|
||||
|
||||
gets_(b, T_STR3, raw, sizeof(raw));
|
||||
gets_(b, T_STR5, val, sizeof(val));
|
||||
off = getl(b, T_ARG1);
|
||||
n = (long)strlen(raw);
|
||||
vlen = (long)strlen(val);
|
||||
|
||||
if (off < 0 || off + vlen > n) { setl(b, T_RC, 31); FAIL(b); }
|
||||
|
||||
for (i = 0; i < vlen; i++) raw[off + i] = val[i]; /* 제자리 덮어쓰기 */
|
||||
|
||||
sets_(b, T_STR3, raw);
|
||||
setl(b, T_COUNT, vlen);
|
||||
setl(b, T_ARG2, off + vlen); /* 다음 필드 시작 오프셋 */
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_FINADV.h
Normal file
12
app/src/mg/svc/MG_FINADV.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_FINADV.h - mg (전문게이트웨이) 서비스 MG_FINADV 카피북 (copybook / record header).
|
||||
* 신규 스케일아웃 서비스; mg_svr 가 tpsvrinit 에서 광고한다.
|
||||
*/
|
||||
#ifndef MG_FINADV_H
|
||||
#define MG_FINADV_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_FINADV(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_FINADV_H */
|
||||
36
app/src/mg/svc/MG_FINADV.pgc
Normal file
36
app/src/mg/svc/MG_FINADV.pgc
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* MG_FINADV.pgc - mg 모듈 서비스 MG_FINADV (one service = one file).
|
||||
* 신규 스케일아웃 서비스; 캘러의 XA 브랜치에서 실행. mg_svr 가 광고.
|
||||
*/
|
||||
#include "MG_FINADV.h"
|
||||
|
||||
/* MG_FINADV - 0220 금융통지 수신: 온라인 승인 없이 오프라인 거래를 사후 통지하는
|
||||
* 전문을 원장에 0220/IN/통지수신(A)으로 적재. 처리코드 앞2자리를 거래구분으로 회신. */
|
||||
void MG_FINADV(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char chan[16], raw[512], proc[8], txntype[4], bizdate[16];
|
||||
long stan, msg_id, amount, n;
|
||||
|
||||
gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "CH01");
|
||||
gets_(b, T_STR3, raw, sizeof(raw));
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
n = (long)strlen(raw);
|
||||
|
||||
memset(proc, 0, sizeof(proc));
|
||||
if (n >= 10) strncpy(proc, raw + 4, 6); else strcpy(proc, "000000");
|
||||
amount = (n >= 22) ? atol(raw + 10) : getl(b, T_AMOUNT);
|
||||
memset(txntype, 0, sizeof(txntype));
|
||||
strncpy(txntype, proc, 2); /* 처리코드 상위 2자리 = 거래구분 */
|
||||
|
||||
stan = mgdb_next_stan(); if (stan < 0) FAIL(b);
|
||||
msg_id = mgdb_next_msg_id(); if (msg_id < 0) FAIL(b);
|
||||
if (mgdb_insert_msg(msg_id, stan, "0220", chan, "IN", proc, "", amount,
|
||||
"", "00", raw, "A", bizdate) < 0) FAIL(b);
|
||||
|
||||
sets_(b, T_STR4, txntype);
|
||||
setl(b, T_ID1, msg_id);
|
||||
setl(b, T_ARG1, stan);
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_FINADVRSP.h
Normal file
12
app/src/mg/svc/MG_FINADVRSP.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_FINADVRSP.h - mg (전문게이트웨이) 서비스 MG_FINADVRSP 카피북 (copybook / record header).
|
||||
* 신규 스케일아웃 서비스; mg_svr 가 tpsvrinit 에서 광고한다.
|
||||
*/
|
||||
#ifndef MG_FINADVRSP_H
|
||||
#define MG_FINADVRSP_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_FINADVRSP(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_FINADVRSP_H */
|
||||
36
app/src/mg/svc/MG_FINADVRSP.pgc
Normal file
36
app/src/mg/svc/MG_FINADVRSP.pgc
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* MG_FINADVRSP.pgc - mg 모듈 서비스 MG_FINADVRSP (one service = one file).
|
||||
* 신규 스케일아웃 서비스; 캘러의 XA 브랜치에서 실행. mg_svr 가 광고.
|
||||
*/
|
||||
#include "MG_FINADVRSP.h"
|
||||
|
||||
/* MG_FINADVRSP - 0230 금융통지응답 생성: 원 0220 통지를 STAN 으로 조회해 응답전문
|
||||
* 0230 을 OUT 으로 채번·적재하고 원 통지를 확인완료(C)로 마감. 원 통지 없으면 rc=25. */
|
||||
void MG_FINADVRSP(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char chan[16], bizdate[16], curstat[4];
|
||||
long orig_stan, orig_id, stan, msg_id;
|
||||
|
||||
gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "CH01");
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
orig_stan = getl(b, T_ARG1);
|
||||
if (orig_stan <= 0) { setl(b, T_RC, 13); FAIL(b); }
|
||||
|
||||
orig_id = mgdb_find_msg_by_stan(orig_stan);
|
||||
if (orig_id < 0) { setl(b, T_RC, 25); FAIL(b); }
|
||||
|
||||
curstat[0] = 0;
|
||||
if (mgdb_get_msg_status(orig_id, curstat) < 0) FAIL(b);
|
||||
|
||||
stan = mgdb_next_stan(); if (stan < 0) FAIL(b);
|
||||
msg_id = mgdb_next_msg_id(); if (msg_id < 0) FAIL(b);
|
||||
if (mgdb_insert_msg(msg_id, stan, "0230", chan, "OUT", "000000", "", 0,
|
||||
"", "00", "", "S", bizdate) < 0) FAIL(b);
|
||||
if (mgdb_update_msg_rc(orig_id, "00", "C") < 0) FAIL(b);
|
||||
|
||||
sets_(b, T_STR5, curstat); /* 마감 직전 상태 */
|
||||
setl(b, T_ID1, msg_id);
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_FINREQ.h
Normal file
12
app/src/mg/svc/MG_FINREQ.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_FINREQ.h - mg (전문게이트웨이) 서비스 MG_FINREQ 카피북 (copybook / record header).
|
||||
* 신규 스케일아웃 서비스; mg_svr 가 tpsvrinit 에서 광고한다.
|
||||
*/
|
||||
#ifndef MG_FINREQ_H
|
||||
#define MG_FINREQ_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_FINREQ(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_FINREQ_H */
|
||||
41
app/src/mg/svc/MG_FINREQ.pgc
Normal file
41
app/src/mg/svc/MG_FINREQ.pgc
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* MG_FINREQ.pgc - mg 모듈 서비스 MG_FINREQ (one service = one file).
|
||||
* 신규 스케일아웃 서비스; 캘러의 XA 브랜치에서 실행. mg_svr 가 광고.
|
||||
*/
|
||||
#include "MG_FINREQ.h"
|
||||
|
||||
/* MG_FINREQ - 0200 금융요청 수신: 고정길이(MTI/처리코드/금액/PAN/할부개월) 파싱,
|
||||
* PAN Luhn 검증 후 원장 적재. 할부개월이 있으면 회차금액(month_amount)도 산출. */
|
||||
void MG_FINREQ(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char chan[16], raw[512], bizdate[16], proc[8], pan[24], rc[4], months_s[4];
|
||||
long stan, msg_id, amount, months, month_amt, n;
|
||||
|
||||
gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "CH01");
|
||||
gets_(b, T_STR3, raw, sizeof(raw));
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
n = (long)strlen(raw);
|
||||
|
||||
memset(proc, 0, sizeof(proc)); memset(pan, 0, sizeof(pan)); memset(months_s, 0, sizeof(months_s));
|
||||
if (n >= 10) strncpy(proc, raw + 4, 6); else strcpy(proc, "000000");
|
||||
amount = (n >= 22) ? atol(raw + 10) : getl(b, T_AMOUNT);
|
||||
if (n >= 38) strncpy(pan, raw + 22, 16);
|
||||
if (n >= 40) strncpy(months_s, raw + 38, 2);
|
||||
months = atol(months_s);
|
||||
if (months < 1) months = 1;
|
||||
month_amt = amount / months;
|
||||
|
||||
strcpy(rc, (pan[0] && !acq_luhn_ok(pan)) ? "14" : "00");
|
||||
stan = mgdb_next_stan(); if (stan < 0) FAIL(b);
|
||||
msg_id = mgdb_next_msg_id(); if (msg_id < 0) FAIL(b);
|
||||
if (mgdb_insert_msg(msg_id, stan, "0200", chan, "IN", proc, "", amount,
|
||||
"", rc, raw, "R", bizdate) < 0) FAIL(b);
|
||||
|
||||
sets_(b, T_STR2, rc);
|
||||
setl(b, T_ID1, msg_id);
|
||||
setl(b, T_ARG1, stan);
|
||||
setl(b, T_INSTALL_N, months);
|
||||
setl(b, T_AMT1, month_amt);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_FINRSP.h
Normal file
12
app/src/mg/svc/MG_FINRSP.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_FINRSP.h - mg (전문게이트웨이) 서비스 MG_FINRSP 카피북 (copybook / record header).
|
||||
* 신규 스케일아웃 서비스; mg_svr 가 tpsvrinit 에서 광고한다.
|
||||
*/
|
||||
#ifndef MG_FINRSP_H
|
||||
#define MG_FINRSP_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_FINRSP(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_FINRSP_H */
|
||||
37
app/src/mg/svc/MG_FINRSP.pgc
Normal file
37
app/src/mg/svc/MG_FINRSP.pgc
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* MG_FINRSP.pgc - mg 모듈 서비스 MG_FINRSP (one service = one file).
|
||||
* 신규 스케일아웃 서비스; 캘러의 XA 브랜치에서 실행. mg_svr 가 광고.
|
||||
*/
|
||||
#include "MG_FINRSP.h"
|
||||
|
||||
/* MG_FINRSP - 0210 금융응답 생성: 승인여부(T_ARG2!=0=승인)를 응답코드로 매핑하여
|
||||
* 0210 응답전문을 OUT 으로 채번·적재하고, 원 0200 요청의 응답코드/상태를 갱신. */
|
||||
void MG_FINRSP(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char chan[16], bizdate[16], rc[4];
|
||||
long orig_stan, orig_id, stan, msg_id, amount, approved;
|
||||
|
||||
gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "CH01");
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
amount = getl(b, T_AMOUNT);
|
||||
approved = getl(b, T_ARG2);
|
||||
orig_stan = getl(b, T_ARG1);
|
||||
|
||||
strcpy(rc, approved ? "00" : "05"); /* 05 = 승인거절 */
|
||||
|
||||
stan = mgdb_next_stan(); if (stan < 0) FAIL(b);
|
||||
msg_id = mgdb_next_msg_id(); if (msg_id < 0) FAIL(b);
|
||||
if (mgdb_insert_msg(msg_id, stan, "0210", chan, "OUT", "000000", "", amount,
|
||||
"", rc, "", "S", bizdate) < 0) FAIL(b);
|
||||
|
||||
if (orig_stan > 0) {
|
||||
orig_id = mgdb_find_msg_by_stan(orig_stan);
|
||||
if (orig_id >= 0 && mgdb_update_msg_rc(orig_id, rc, "S") < 0) FAIL(b);
|
||||
}
|
||||
|
||||
sets_(b, T_STR2, rc);
|
||||
setl(b, T_ID1, msg_id);
|
||||
setl(b, T_RC, approved ? 0 : 5);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_HOSTADPT.h
Normal file
12
app/src/mg/svc/MG_HOSTADPT.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_HOSTADPT.h - mg (전문게이트웨이) 서비스 MG_HOSTADPT 카피북 (copybook / record header).
|
||||
* 신규 스케일아웃 서비스; mg_svr 가 tpsvrinit 에서 광고한다.
|
||||
*/
|
||||
#ifndef MG_HOSTADPT_H
|
||||
#define MG_HOSTADPT_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_HOSTADPT(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_HOSTADPT_H */
|
||||
29
app/src/mg/svc/MG_HOSTADPT.pgc
Normal file
29
app/src/mg/svc/MG_HOSTADPT.pgc
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* MG_HOSTADPT.pgc - mg 모듈 서비스 MG_HOSTADPT (one service = one file).
|
||||
* 신규 스케일아웃 서비스; 캘러의 XA 브랜치에서 실행. mg_svr 가 광고.
|
||||
*/
|
||||
#include "MG_HOSTADPT.h"
|
||||
|
||||
/* MG_HOSTADPT - 매입사 호스트 직연동 어댑터: 내부 고정길이 전문 뒤에 라우팅 조회로
|
||||
* 구한 목적지 노드ID 를 부착한 호스트 프레임 "<전문>@<dest>" 를 만든다. */
|
||||
void MG_HOSTADPT(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char chan[16], mti[8], raw[512], dest[64], frame[600];
|
||||
|
||||
gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "CH02");
|
||||
gets_(b, T_STR1, mti, sizeof(mti)); if (mti[0] == 0) strcpy(mti, "0200");
|
||||
gets_(b, T_STR3, raw, sizeof(raw));
|
||||
|
||||
if (mgdb_lookup_route(chan, mti, dest) < 0) {
|
||||
userlog("MG_HOSTADPT 목적지 미상 chan=%s mti=%s", chan, mti);
|
||||
strcpy(dest, "DEFAULT"); /* 라우팅 없으면 기본 호스트 */
|
||||
}
|
||||
|
||||
snprintf(frame, sizeof(frame), "%s@%s", raw, dest);
|
||||
sets_(b, T_STR3, frame);
|
||||
sets_(b, T_STR5, dest);
|
||||
setl(b, T_COUNT, (long)strlen(frame));
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_INFLIGHT.h
Normal file
12
app/src/mg/svc/MG_INFLIGHT.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_INFLIGHT.h - mg (전문게이트웨이) 서비스 MG_INFLIGHT 카피북 (copybook / record header).
|
||||
* 신규 스케일아웃 서비스; mg_svr 가 tpsvrinit 에서 광고한다.
|
||||
*/
|
||||
#ifndef MG_INFLIGHT_H
|
||||
#define MG_INFLIGHT_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_INFLIGHT(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_INFLIGHT_H */
|
||||
31
app/src/mg/svc/MG_INFLIGHT.pgc
Normal file
31
app/src/mg/svc/MG_INFLIGHT.pgc
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* MG_INFLIGHT.pgc - mg 모듈 서비스 MG_INFLIGHT (one service = one file).
|
||||
* 신규 스케일아웃 서비스; 캘러의 XA 브랜치에서 실행. mg_svr 가 광고.
|
||||
*/
|
||||
#include "MG_INFLIGHT.h"
|
||||
|
||||
/* MG_INFLIGHT - 미완료(in-flight) 전문 집계: 아직 응답이 확정되지 않은 수신(R)+
|
||||
* 송신중(S) 상태 전문 수를 채널별로 세어, 임계(기본500) 초과 시 rc=1 경보. */
|
||||
void MG_INFLIGHT(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long limit;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_chan[16], h_bizdate[16];
|
||||
long h_cnt;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_CHANNEL, h_chan, sizeof(h_chan)); if (h_chan[0] == 0) strcpy(h_chan, "CH01");
|
||||
gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate));
|
||||
limit = getl(b, T_ARG4); if (limit <= 0) limit = 500;
|
||||
|
||||
EXEC SQL SELECT count(*) INTO :h_cnt
|
||||
FROM mg_msg_log
|
||||
WHERE channel = :h_chan AND biz_date = :h_bizdate AND status IN ('R', 'S');
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
setl(b, T_ARG4, limit);
|
||||
setl(b, T_RC, (h_cnt > limit) ? 1 : 0);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_INQRSP.h
Normal file
12
app/src/mg/svc/MG_INQRSP.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_INQRSP.h - mg (전문게이트웨이) 서비스 MG_INQRSP 카피북 (copybook / record header).
|
||||
* 신규 스케일아웃 서비스; mg_svr 가 tpsvrinit 에서 광고한다.
|
||||
*/
|
||||
#ifndef MG_INQRSP_H
|
||||
#define MG_INQRSP_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_INQRSP(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_INQRSP_H */
|
||||
36
app/src/mg/svc/MG_INQRSP.pgc
Normal file
36
app/src/mg/svc/MG_INQRSP.pgc
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* MG_INQRSP.pgc - mg 모듈 서비스 MG_INQRSP (one service = one file).
|
||||
* 신규 스케일아웃 서비스; 캘러의 XA 브랜치에서 실행. mg_svr 가 광고.
|
||||
*/
|
||||
#include "MG_INQRSP.h"
|
||||
|
||||
/* MG_INQRSP - 0110 조회응답 생성: 조회 잔액(T_AMT1)을 12자리 우측정렬로 응답전문
|
||||
* 0110 필드52에 채워 OUT 으로 채번·적재하고, 원 0100 조회요청을 완료(C)로 전이. */
|
||||
void MG_INQRSP(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char chan[16], bizdate[16], iso[64];
|
||||
long orig_stan, orig_id, stan, msg_id, balance;
|
||||
|
||||
gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "CH01");
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
balance = getl(b, T_AMT1);
|
||||
orig_stan = getl(b, T_ARG1);
|
||||
|
||||
sprintf(iso, "0110%012ld", balance); /* 필드52: 조회잔액 12자리 */
|
||||
|
||||
stan = mgdb_next_stan(); if (stan < 0) FAIL(b);
|
||||
msg_id = mgdb_next_msg_id(); if (msg_id < 0) FAIL(b);
|
||||
if (mgdb_insert_msg(msg_id, stan, "0110", chan, "OUT", "310000", "", balance,
|
||||
"", "00", iso, "S", bizdate) < 0) FAIL(b);
|
||||
|
||||
if (orig_stan > 0) {
|
||||
orig_id = mgdb_find_msg_by_stan(orig_stan);
|
||||
if (orig_id >= 0 && mgdb_update_msg_rc(orig_id, "00", "C") < 0) FAIL(b);
|
||||
}
|
||||
|
||||
sets_(b, T_STR3, iso);
|
||||
setl(b, T_ID1, msg_id);
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_ISOADPT.h
Normal file
12
app/src/mg/svc/MG_ISOADPT.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_ISOADPT.h - mg (전문게이트웨이) 서비스 MG_ISOADPT 카피북 (copybook / record header).
|
||||
* 신규 스케일아웃 서비스; mg_svr 가 tpsvrinit 에서 광고한다.
|
||||
*/
|
||||
#ifndef MG_ISOADPT_H
|
||||
#define MG_ISOADPT_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_ISOADPT(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_ISOADPT_H */
|
||||
43
app/src/mg/svc/MG_ISOADPT.pgc
Normal file
43
app/src/mg/svc/MG_ISOADPT.pgc
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* MG_ISOADPT.pgc - mg 모듈 서비스 MG_ISOADPT (one service = one file).
|
||||
* 신규 스케일아웃 서비스; 캘러의 XA 브랜치에서 실행. mg_svr 가 광고.
|
||||
*/
|
||||
#include "MG_ISOADPT.h"
|
||||
|
||||
/* ----- service-local pure helper(s) ----- */
|
||||
/* ISO8583 MTI 유효성: 4자리 숫자이면서 첫자리(버전)가 0~2 인지 검사. */
|
||||
static int mg_iso_mti_ok(const char *mti)
|
||||
{
|
||||
int i;
|
||||
if (strlen(mti) < 4) return 0;
|
||||
for (i = 0; i < 4; i++) if (mti[i] < '0' || mti[i] > '9') return 0;
|
||||
return (mti[0] >= '0' && mti[0] <= '2');
|
||||
}
|
||||
|
||||
/* MG_ISOADPT - 표준 ISO8583 직연동 어댑터: 원 전문의 MTI(선두4)를 표준규격으로
|
||||
* 검증하고 클래스(승인02/금융02·통지 등)를 판별해 회신. 규격위반 시 rc=30. */
|
||||
void MG_ISOADPT(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char raw[512], mti[8], cls[16];
|
||||
|
||||
gets_(b, T_STR3, raw, sizeof(raw));
|
||||
memset(mti, 0, sizeof(mti));
|
||||
strncpy(mti, raw, 4);
|
||||
|
||||
if (!mg_iso_mti_ok(mti)) { setl(b, T_RC, 30); FAIL(b); }
|
||||
|
||||
switch (mti[1]) { /* 메시지 클래스(둘째자리) */
|
||||
case '1': strcpy(cls, "AUTH"); break; /* 1xxx 승인 */
|
||||
case '2': strcpy(cls, "FINANCE");break; /* 2xxx 금융 */
|
||||
case '4': strcpy(cls, "REVERSE");break; /* 4xxx 취소 */
|
||||
case '8': strcpy(cls, "NETMGMT");break; /* 8xxx 망관리 */
|
||||
default: strcpy(cls, "OTHER"); break;
|
||||
}
|
||||
|
||||
sets_(b, T_STR1, mti);
|
||||
sets_(b, T_STR5, cls);
|
||||
sets_(b, T_CHANNEL, "CH03");
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_KEYCHECK.h
Normal file
12
app/src/mg/svc/MG_KEYCHECK.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_KEYCHECK.h - mg (전문게이트웨이) 서비스 MG_KEYCHECK 카피북 (copybook / record header).
|
||||
* 신규 스케일아웃 서비스; mg_svr 가 tpsvrinit 에서 광고한다.
|
||||
*/
|
||||
#ifndef MG_KEYCHECK_H
|
||||
#define MG_KEYCHECK_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_KEYCHECK(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_KEYCHECK_H */
|
||||
49
app/src/mg/svc/MG_KEYCHECK.pgc
Normal file
49
app/src/mg/svc/MG_KEYCHECK.pgc
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* MG_KEYCHECK.pgc - mg 모듈 서비스 MG_KEYCHECK (one service = one file).
|
||||
* 신규 스케일아웃 서비스; 캘러의 XA 브랜치에서 실행. mg_svr 가 광고.
|
||||
*/
|
||||
#include "MG_KEYCHECK.h"
|
||||
|
||||
/* ----- service-local pure helper(s) ----- */
|
||||
/* 키 문자열의 체크값(KCV): 바이트 합을 세대(keyver)로 섞어 6-hex 로 산출. */
|
||||
static void mg_keycheck_kcv(const char *key, long keyver, char *out /* >= 7 */)
|
||||
{
|
||||
unsigned long acc = (unsigned long)(keyver * 2654435761UL);
|
||||
int i;
|
||||
for (i = 0; key[i]; i++) acc += (unsigned char)key[i] * (unsigned long)(i + 1);
|
||||
sprintf(out, "%06lX", acc & 0xFFFFFFUL);
|
||||
}
|
||||
|
||||
/* MG_KEYCHECK - 키 체크값(KCV) 계산·대조: 채널 세션키로 KCV 를 만들어 입력 기대값
|
||||
* (T_KEY2)과 비교. 기대값 미제공이면 계산만 회신, 불일치면 rc=1(키 불일치). */
|
||||
void MG_KEYCHECK(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char expect[16], kcv[12];
|
||||
long keyver, mismatch = 0;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_chan[16], h_sk[64];
|
||||
long h_kv;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_CHANNEL, h_chan, sizeof(h_chan)); if (h_chan[0] == 0) strcpy(h_chan, "CH01");
|
||||
gets_(b, T_KEY2, expect, sizeof(expect));
|
||||
|
||||
h_sk[0] = 0;
|
||||
EXEC SQL SELECT session_key INTO :h_sk FROM mg_channel WHERE channel = :h_chan;
|
||||
if (sqlca.sqlcode == 100) { setl(b, T_RC, 25); FAIL(b); }
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
if (h_sk[0] == 0) { setl(b, T_RC, 1); FAIL(b); }
|
||||
|
||||
h_kv = 0;
|
||||
EXEC SQL SELECT seq_val INTO :h_kv FROM mg_seq WHERE seq_name = 'KEYVER';
|
||||
keyver = (sqlca.sqlcode == 100) ? 0 : h_kv;
|
||||
|
||||
mg_keycheck_kcv(h_sk, keyver, kcv);
|
||||
if (expect[0] && strcmp(expect, kcv) != 0) mismatch = 1;
|
||||
|
||||
sets_(b, T_KEY1, kcv);
|
||||
setl(b, T_ARG3, keyver);
|
||||
setl(b, T_RC, mismatch ? 1 : 0);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_KEYEXPIRE.h
Normal file
12
app/src/mg/svc/MG_KEYEXPIRE.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_KEYEXPIRE.h - mg (전문게이트웨이) 서비스 MG_KEYEXPIRE 카피북 (copybook / record header).
|
||||
* 신규 스케일아웃 서비스; mg_svr 가 tpsvrinit 에서 광고한다.
|
||||
*/
|
||||
#ifndef MG_KEYEXPIRE_H
|
||||
#define MG_KEYEXPIRE_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_KEYEXPIRE(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_KEYEXPIRE_H */
|
||||
33
app/src/mg/svc/MG_KEYEXPIRE.pgc
Normal file
33
app/src/mg/svc/MG_KEYEXPIRE.pgc
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* MG_KEYEXPIRE.pgc - mg 모듈 서비스 MG_KEYEXPIRE (one service = one file).
|
||||
* 신규 스케일아웃 서비스; 캘러의 XA 브랜치에서 실행. mg_svr 가 광고.
|
||||
*/
|
||||
#include "MG_KEYEXPIRE.h"
|
||||
|
||||
/* MG_KEYEXPIRE - 키 만료 판정: 현재 KEYVER 세대와 전문에 실린 사용세대(T_ARG3)의
|
||||
* 차이가 허용범위(기본 1세대)를 넘으면 만료(rc=1)로 판정해 재키교환을 유도. */
|
||||
void MG_KEYEXPIRE(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long used_ver, allow, drift, expired;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cur;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
used_ver = getl(b, T_ARG3);
|
||||
allow = getl(b, T_ARG4); if (allow <= 0) allow = 1;
|
||||
|
||||
h_cur = 0;
|
||||
EXEC SQL SELECT seq_val INTO :h_cur FROM mg_seq WHERE seq_name = 'KEYVER';
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
drift = h_cur - used_ver;
|
||||
expired = (drift > allow) ? 1 : 0;
|
||||
if (expired)
|
||||
userlog("MG_KEYEXPIRE 키만료 현재세대=%ld 사용세대=%ld 허용=%ld", h_cur, used_ver, allow);
|
||||
|
||||
setl(b, T_ARG1, h_cur);
|
||||
setl(b, T_ARG6, drift);
|
||||
setl(b, T_RC, expired);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_KEYLOAD.h
Normal file
12
app/src/mg/svc/MG_KEYLOAD.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_KEYLOAD.h - mg (전문게이트웨이) 서비스 MG_KEYLOAD 카피북 (copybook / record header).
|
||||
* 신규 스케일아웃 서비스; mg_svr 가 tpsvrinit 에서 광고한다.
|
||||
*/
|
||||
#ifndef MG_KEYLOAD_H
|
||||
#define MG_KEYLOAD_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_KEYLOAD(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_KEYLOAD_H */
|
||||
41
app/src/mg/svc/MG_KEYLOAD.pgc
Normal file
41
app/src/mg/svc/MG_KEYLOAD.pgc
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* MG_KEYLOAD.pgc - mg 모듈 서비스 MG_KEYLOAD (one service = one file).
|
||||
* 신규 스케일아웃 서비스; 캘러의 XA 브랜치에서 실행. mg_svr 가 광고.
|
||||
*/
|
||||
#include "MG_KEYLOAD.h"
|
||||
|
||||
/* MG_KEYLOAD - 초기 키 적재(KEK 주입): KEYVER 카운터를 1로 초기 승번하고 대상 채널에
|
||||
* 최초 세션키 "K0001-초기STAN" 을 발급, 채널을 SIGNON 준비상태로 만든다. */
|
||||
void MG_KEYLOAD(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char chan[16], newkey[24];
|
||||
long stan;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_chan[16];
|
||||
long h_kv;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "CH01");
|
||||
strncpy(h_chan, chan, sizeof(h_chan)-1); h_chan[sizeof(h_chan)-1] = 0;
|
||||
|
||||
/* KEYVER 를 1 로 (재)초기화 (초기 키적재는 세대 리셋) */
|
||||
EXEC SQL UPDATE mg_seq SET seq_val = 1, updated_at = now() WHERE seq_name = 'KEYVER';
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
if (sqlca.sqlerrd[2] == 0) {
|
||||
EXEC SQL INSERT INTO mg_seq (seq_name, seq_val) VALUES ('KEYVER', 1);
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
}
|
||||
EXEC SQL SELECT seq_val INTO :h_kv FROM mg_seq WHERE seq_name = 'KEYVER';
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
stan = mgdb_next_stan(); if (stan < 0) FAIL(b);
|
||||
sprintf(newkey, "K%04ld-%04ld", h_kv, stan % 10000);
|
||||
if (mgdb_set_channel_session(chan, newkey, stan) < 0) FAIL(b);
|
||||
|
||||
userlog("MG_KEYLOAD 초기키 적재 채널=%s 키=%s", chan, newkey);
|
||||
sets_(b, T_KEY1, newkey);
|
||||
setl(b, T_ARG3, h_kv);
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_LOADBAL.h
Normal file
12
app/src/mg/svc/MG_LOADBAL.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_LOADBAL.h - mg (전문게이트웨이) 서비스 MG_LOADBAL 카피북 (copybook / record header).
|
||||
* 신규 스케일아웃 서비스; mg_svr 가 tpsvrinit 에서 광고한다.
|
||||
*/
|
||||
#ifndef MG_LOADBAL_H
|
||||
#define MG_LOADBAL_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_LOADBAL(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_LOADBAL_H */
|
||||
44
app/src/mg/svc/MG_LOADBAL.pgc
Normal file
44
app/src/mg/svc/MG_LOADBAL.pgc
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* MG_LOADBAL.pgc - mg 모듈 서비스 MG_LOADBAL (one service = one file).
|
||||
* 신규 스케일아웃 서비스; 캘러의 XA 브랜치에서 실행. mg_svr 가 광고.
|
||||
*/
|
||||
#include "MG_LOADBAL.h"
|
||||
|
||||
/* MG_LOADBAL - 채널 부하분산 선택: UP 상태 채널들 중 당일 처리건수가 가장 적은
|
||||
* 채널을 골라 다음 전문의 송신 채널로 회신한다. UP 채널이 없으면 rc=1. */
|
||||
void MG_LOADBAL(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char best[16];
|
||||
long best_load = -1, considered = 0;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_chan[16], h_bizdate[16];
|
||||
long h_cnt;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate));
|
||||
best[0] = 0;
|
||||
|
||||
EXEC SQL DECLARE lbc CURSOR FOR
|
||||
SELECT channel FROM mg_channel WHERE status = 'UP' ORDER BY channel;
|
||||
EXEC SQL OPEN lbc;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
for (;;) {
|
||||
EXEC SQL FETCH lbc INTO :h_chan;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE lbc; FAIL(b); }
|
||||
considered++;
|
||||
EXEC SQL SELECT count(*) INTO :h_cnt
|
||||
FROM mg_msg_log WHERE channel = :h_chan AND biz_date = :h_bizdate;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE lbc; FAIL(b); }
|
||||
if (best_load < 0 || h_cnt < best_load) { best_load = h_cnt; strcpy(best, h_chan); }
|
||||
}
|
||||
EXEC SQL CLOSE lbc;
|
||||
|
||||
if (best[0] == 0) { setl(b, T_RC, 1); FAIL(b); }
|
||||
sets_(b, T_CHANNEL, best);
|
||||
setl(b, T_COUNT, best_load);
|
||||
setl(b, T_ARG3, considered);
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_MACSESSION.h
Normal file
12
app/src/mg/svc/MG_MACSESSION.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_MACSESSION.h - mg (전문게이트웨이) 서비스 MG_MACSESSION 카피북 (copybook / record header).
|
||||
* 신규 스케일아웃 서비스; mg_svr 가 tpsvrinit 에서 광고한다.
|
||||
*/
|
||||
#ifndef MG_MACSESSION_H
|
||||
#define MG_MACSESSION_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_MACSESSION(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_MACSESSION_H */
|
||||
46
app/src/mg/svc/MG_MACSESSION.pgc
Normal file
46
app/src/mg/svc/MG_MACSESSION.pgc
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* MG_MACSESSION.pgc - mg 모듈 서비스 MG_MACSESSION (one service = one file).
|
||||
* 신규 스케일아웃 서비스; 캘러의 XA 브랜치에서 실행. mg_svr 가 광고.
|
||||
*/
|
||||
#include "MG_MACSESSION.h"
|
||||
|
||||
/* ----- service-local pure helper(s) ----- */
|
||||
/* 세션키 문자열과 전문을 합성 CBC-MAC 흉내로 섞어 8-hex MAC 산출. */
|
||||
static void mg_macsession_calc(const char *sk, const char *msg, char *out /* >= 9 */)
|
||||
{
|
||||
unsigned long acc = 0;
|
||||
int i;
|
||||
for (i = 0; sk[i]; i++) acc = acc * 131UL + (unsigned char)sk[i]; /* 키 프리믹스 */
|
||||
for (i = 0; msg[i]; i++) {
|
||||
acc ^= (unsigned char)msg[i];
|
||||
acc = (acc << 3) | (acc >> 29); /* 3비트 좌회전(체이닝) */
|
||||
}
|
||||
sprintf(out, "%08lX", acc & 0xFFFFFFFFUL);
|
||||
}
|
||||
|
||||
/* MG_MACSESSION - 세션키 기반 MAC 생성: 채널의 현재 세션키(mg_channel.session_key)를
|
||||
* 읽어 전문과 합성한 세션MAC 을 회신. 세션키 미설정(사인온 전) 채널이면 rc=1. */
|
||||
void MG_MACSESSION(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char raw[512], mac[12];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_chan[16], h_sk[64];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_CHANNEL, h_chan, sizeof(h_chan)); if (h_chan[0] == 0) strcpy(h_chan, "CH01");
|
||||
gets_(b, T_STR3, raw, sizeof(raw));
|
||||
if (raw[0] == 0) { setl(b, T_RC, 30); FAIL(b); }
|
||||
|
||||
h_sk[0] = 0;
|
||||
EXEC SQL SELECT session_key INTO :h_sk FROM mg_channel WHERE channel = :h_chan;
|
||||
if (sqlca.sqlcode == 100) { setl(b, T_RC, 25); FAIL(b); }
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
if (h_sk[0] == 0) { setl(b, T_RC, 1); FAIL(b); } /* 세션키 없음 */
|
||||
|
||||
mg_macsession_calc(h_sk, raw, mac);
|
||||
sets_(b, T_KEY1, mac);
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_NMADVICE.h
Normal file
12
app/src/mg/svc/MG_NMADVICE.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_NMADVICE.h - mg (전문게이트웨이) 서비스 MG_NMADVICE 카피북 (copybook / record header).
|
||||
* 신규 스케일아웃 서비스; mg_svr 가 tpsvrinit 에서 광고한다.
|
||||
*/
|
||||
#ifndef MG_NMADVICE_H
|
||||
#define MG_NMADVICE_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_NMADVICE(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_NMADVICE_H */
|
||||
40
app/src/mg/svc/MG_NMADVICE.pgc
Normal file
40
app/src/mg/svc/MG_NMADVICE.pgc
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* MG_NMADVICE.pgc - mg 모듈 서비스 MG_NMADVICE (one service = one file).
|
||||
* 신규 스케일아웃 서비스; 캘러의 XA 브랜치에서 실행. mg_svr 가 광고.
|
||||
*/
|
||||
#include "MG_NMADVICE.h"
|
||||
|
||||
/* MG_NMADVICE - 0820 망관리통지 처리: 키교환(NMIC 101)/컷오버(201) 등 무응답 통지를
|
||||
* 원장에 0820/IN 으로 적재. NMIC 101 이면 세션키 재발급을 함께 트리거한다. */
|
||||
void MG_NMADVICE(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char chan[16], raw[512], nmic[8], bizdate[16], newkey[24];
|
||||
long stan, msg_id, n, kv = 0;
|
||||
|
||||
gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "CH01");
|
||||
gets_(b, T_STR3, raw, sizeof(raw));
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
n = (long)strlen(raw);
|
||||
|
||||
memset(nmic, 0, sizeof(nmic));
|
||||
if (n >= 7) strncpy(nmic, raw + 4, 3); else strcpy(nmic, "201");
|
||||
|
||||
stan = mgdb_next_stan(); if (stan < 0) FAIL(b);
|
||||
msg_id = mgdb_next_msg_id(); if (msg_id < 0) FAIL(b);
|
||||
if (mgdb_insert_msg(msg_id, stan, "0820", chan, "IN", nmic, "", 0,
|
||||
"", "00", raw, "A", bizdate) < 0) FAIL(b);
|
||||
|
||||
if (strcmp(nmic, "101") == 0) { /* 키교환 통지 -> 세션키 재발급 */
|
||||
kv = mgdb_seq_bump("KEYVER"); if (kv < 0) FAIL(b);
|
||||
sprintf(newkey, "K%04ld-%04ld", kv, stan % 10000);
|
||||
if (mgdb_set_channel_session(chan, newkey, stan) < 0) FAIL(b);
|
||||
sets_(b, T_KEY1, newkey);
|
||||
}
|
||||
|
||||
sets_(b, T_STR4, nmic);
|
||||
setl(b, T_ID1, msg_id);
|
||||
setl(b, T_ARG3, kv);
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_NMRSP.h
Normal file
12
app/src/mg/svc/MG_NMRSP.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_NMRSP.h - mg (전문게이트웨이) 서비스 MG_NMRSP 카피북 (copybook / record header).
|
||||
* 신규 스케일아웃 서비스; mg_svr 가 tpsvrinit 에서 광고한다.
|
||||
*/
|
||||
#ifndef MG_NMRSP_H
|
||||
#define MG_NMRSP_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_NMRSP(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_NMRSP_H */
|
||||
32
app/src/mg/svc/MG_NMRSP.pgc
Normal file
32
app/src/mg/svc/MG_NMRSP.pgc
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* MG_NMRSP.pgc - mg 모듈 서비스 MG_NMRSP (one service = one file).
|
||||
* 신규 스케일아웃 서비스; 캘러의 XA 브랜치에서 실행. mg_svr 가 광고.
|
||||
*/
|
||||
#include "MG_NMRSP.h"
|
||||
|
||||
/* MG_NMRSP - 0810 망관리응답 생성: 수신한 0800 망관리요청의 네트워크정보코드(NMIC,
|
||||
* 처리코드 상위3자리)를 그대로 되받아 0810 응답전문을 OUT 으로 채번·적재. */
|
||||
void MG_NMRSP(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char chan[16], raw[512], nmic[8], bizdate[16];
|
||||
long stan, msg_id, n;
|
||||
|
||||
gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "CH01");
|
||||
gets_(b, T_STR3, raw, sizeof(raw));
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
n = (long)strlen(raw);
|
||||
|
||||
memset(nmic, 0, sizeof(nmic));
|
||||
if (n >= 7) strncpy(nmic, raw + 4, 3); else strcpy(nmic, "001"); /* 001=로그온 */
|
||||
|
||||
stan = mgdb_next_stan(); if (stan < 0) FAIL(b);
|
||||
msg_id = mgdb_next_msg_id(); if (msg_id < 0) FAIL(b);
|
||||
if (mgdb_insert_msg(msg_id, stan, "0810", chan, "OUT", nmic, "", 0,
|
||||
"", "00", raw, "S", bizdate) < 0) FAIL(b);
|
||||
|
||||
sets_(b, T_STR4, nmic);
|
||||
setl(b, T_ID1, msg_id);
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_PINBLOCK.h
Normal file
12
app/src/mg/svc/MG_PINBLOCK.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_PINBLOCK.h - mg (전문게이트웨이) 서비스 MG_PINBLOCK 카피북 (copybook / record header).
|
||||
* 신규 스케일아웃 서비스; mg_svr 가 tpsvrinit 에서 광고한다.
|
||||
*/
|
||||
#ifndef MG_PINBLOCK_H
|
||||
#define MG_PINBLOCK_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_PINBLOCK(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_PINBLOCK_H */
|
||||
47
app/src/mg/svc/MG_PINBLOCK.pgc
Normal file
47
app/src/mg/svc/MG_PINBLOCK.pgc
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* MG_PINBLOCK.pgc - mg 모듈 서비스 MG_PINBLOCK (one service = one file).
|
||||
* 신규 스케일아웃 서비스; 캘러의 XA 브랜치에서 실행. mg_svr 가 광고.
|
||||
*/
|
||||
#include "MG_PINBLOCK.h"
|
||||
|
||||
/* ----- service-local pure helper(s) ----- */
|
||||
/* ISO-0 PIN 블록: PIN(0x0N + PIN + F패딩) XOR PAN(0000 + PAN뒤12중앙) -> 16-hex. */
|
||||
static void mg_pinblock_iso0(const char *pin, const char *pan, char *out /* >= 17 */)
|
||||
{
|
||||
unsigned char pinb[8], panb[8], i;
|
||||
char t[17];
|
||||
int plen = (int)strlen(pin), panlen = (int)strlen(pan);
|
||||
|
||||
/* PIN 필드 */
|
||||
sprintf(t, "0%X%-14.14s", plen, pin);
|
||||
for (i = 0; i < 14; i++) if (t[2 + i] == ' ') t[2 + i] = 'F';
|
||||
for (i = 0; i < 8; i++) { char h[3] = { t[i*2], t[i*2+1], 0 }; pinb[i] = (unsigned char)strtol(h, NULL, 16); }
|
||||
|
||||
/* PAN 필드: 0000 + PAN(체크자리 제외 우측 12) */
|
||||
memset(panb, 0, sizeof(panb));
|
||||
if (panlen >= 13) {
|
||||
char pp[13]; memcpy(pp, pan + (panlen - 13), 12); pp[12] = 0;
|
||||
for (i = 0; i < 6; i++) { char h[3] = { pp[i*2], pp[i*2+1], 0 }; panb[2 + i] = (unsigned char)strtol(h, NULL, 16); }
|
||||
}
|
||||
for (i = 0; i < 8; i++) sprintf(out + i*2, "%02X", pinb[i] ^ panb[i]);
|
||||
}
|
||||
|
||||
/* MG_PINBLOCK - ISO-0 PIN 블록 조립(순수계산): PIN(T_KEY1)과 PAN(T_STR5)으로
|
||||
* 포맷0 PIN 블록 16-hex 를 만들어 회신. PIN 길이 4~12 아니면 rc=30. */
|
||||
void MG_PINBLOCK(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char pin[16], pan[24], block[20];
|
||||
long plen;
|
||||
|
||||
gets_(b, T_KEY1, pin, sizeof(pin));
|
||||
gets_(b, T_STR5, pan, sizeof(pan));
|
||||
plen = (long)strlen(pin);
|
||||
if (plen < 4 || plen > 12) { setl(b, T_RC, 30); FAIL(b); }
|
||||
|
||||
mg_pinblock_iso0(pin, pan, block);
|
||||
sets_(b, T_KEY2, block);
|
||||
setl(b, T_COUNT, plen);
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_PREAUTH.h
Normal file
12
app/src/mg/svc/MG_PREAUTH.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_PREAUTH.h - mg (전문게이트웨이) 서비스 MG_PREAUTH 카피북 (copybook / record header).
|
||||
* 신규 스케일아웃 서비스; mg_svr 가 tpsvrinit 에서 광고한다.
|
||||
*/
|
||||
#ifndef MG_PREAUTH_H
|
||||
#define MG_PREAUTH_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_PREAUTH(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_PREAUTH_H */
|
||||
37
app/src/mg/svc/MG_PREAUTH.pgc
Normal file
37
app/src/mg/svc/MG_PREAUTH.pgc
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* MG_PREAUTH.pgc - mg 모듈 서비스 MG_PREAUTH (one service = one file).
|
||||
* 신규 스케일아웃 서비스; 캘러의 XA 브랜치에서 실행. mg_svr 가 광고.
|
||||
*/
|
||||
#include "MG_PREAUTH.h"
|
||||
|
||||
/* MG_PREAUTH - 0100 예비승인(hold): 요청금액에 홀드율(기본110%)을 적용한 승인예정액을
|
||||
* 산출해 원장에 0100/IN/status='H'(보류) 로 적재. 홀드율은 T_ARG4(bps)로 조정 가능. */
|
||||
void MG_PREAUTH(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char chan[16], raw[512], bizdate[16], proc[8];
|
||||
long stan, msg_id, amount, hold_bps, hold_amt, n;
|
||||
|
||||
gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "CH01");
|
||||
gets_(b, T_STR3, raw, sizeof(raw));
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
n = (long)strlen(raw);
|
||||
|
||||
memset(proc, 0, sizeof(proc));
|
||||
if (n >= 10) strncpy(proc, raw + 4, 6); else strcpy(proc, "000000");
|
||||
amount = (n >= 22) ? atol(raw + 10) : getl(b, T_AMOUNT);
|
||||
|
||||
hold_bps = getl(b, T_ARG4); if (hold_bps <= 0) hold_bps = 11000; /* 110% */
|
||||
hold_amt = amount * hold_bps / 10000;
|
||||
|
||||
stan = mgdb_next_stan(); if (stan < 0) FAIL(b);
|
||||
msg_id = mgdb_next_msg_id(); if (msg_id < 0) FAIL(b);
|
||||
if (mgdb_insert_msg(msg_id, stan, "0100", chan, "IN", proc, "", hold_amt,
|
||||
"", "00", raw, "H", bizdate) < 0) FAIL(b);
|
||||
|
||||
setl(b, T_AMT1, hold_amt);
|
||||
setl(b, T_ARG4, hold_bps);
|
||||
setl(b, T_ID1, msg_id);
|
||||
setl(b, T_ARG1, stan);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_RATELIMIT.h
Normal file
12
app/src/mg/svc/MG_RATELIMIT.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_RATELIMIT.h - mg (전문게이트웨이) 서비스 MG_RATELIMIT 카피북 (copybook / record header).
|
||||
* 신규 스케일아웃 서비스; mg_svr 가 tpsvrinit 에서 광고한다.
|
||||
*/
|
||||
#ifndef MG_RATELIMIT_H
|
||||
#define MG_RATELIMIT_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_RATELIMIT(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_RATELIMIT_H */
|
||||
37
app/src/mg/svc/MG_RATELIMIT.pgc
Normal file
37
app/src/mg/svc/MG_RATELIMIT.pgc
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* MG_RATELIMIT.pgc - mg 모듈 서비스 MG_RATELIMIT (one service = one file).
|
||||
* 신규 스케일아웃 서비스; 캘러의 XA 브랜치에서 실행. mg_svr 가 광고.
|
||||
*/
|
||||
#include "MG_RATELIMIT.h"
|
||||
|
||||
/* MG_RATELIMIT - 초당 유입 레이트리밋: 채널의 최근 1초간 수신 전문 수를 세어
|
||||
* 초당한도(TPS, 기본50) 초과면 차단(rc=91), 80% 이상이면 경보(rc=1)로 판정. */
|
||||
void MG_RATELIMIT(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long tps, pct;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_chan[16];
|
||||
long h_cnt, h_tps;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_CHANNEL, h_chan, sizeof(h_chan)); if (h_chan[0] == 0) strcpy(h_chan, "CH01");
|
||||
tps = getl(b, T_ARG4); if (tps <= 0) tps = 50;
|
||||
h_tps = tps;
|
||||
|
||||
EXEC SQL SELECT count(*) INTO :h_cnt
|
||||
FROM mg_msg_log
|
||||
WHERE channel = :h_chan AND direction = 'IN'
|
||||
AND created_at >= now() - interval '1 second';
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
pct = (h_cnt * 100L) / h_tps;
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
setl(b, T_ARG4, h_tps);
|
||||
setl(b, T_ARG8, pct);
|
||||
|
||||
if (h_cnt > h_tps) setl(b, T_RC, 91);
|
||||
else if (pct >= 80) setl(b, T_RC, 1);
|
||||
else setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_READYZ.h
Normal file
12
app/src/mg/svc/MG_READYZ.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_READYZ.h - mg (전문게이트웨이) 서비스 MG_READYZ 카피북 (copybook / record header).
|
||||
* 신규 스케일아웃 서비스; mg_svr 가 tpsvrinit 에서 광고한다.
|
||||
*/
|
||||
#ifndef MG_READYZ_H
|
||||
#define MG_READYZ_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_READYZ(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_READYZ_H */
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue