/* @tier medium @module mg @transform msg-gateway-online */ /* * mg_ol_0019.pgc - 전문게이트웨이 공통헤더 파싱 서비스 (MG_OL_0019) [tier=medium] * * 표준 고정 공통헤더를 원시전문(RAWMSG)에서 오프셋 단위로 파싱한다. * 공통헤더 레이아웃(총 25바이트): * [전문길이 5][전문종별 4][채널 2][일자 8][시각 6] * 각 필드의 형식(숫자/종별화이트리스트)을 검증하고, 선언된 전문길이와 * 실제 본문길이의 일치 여부를 교차검증하여 헤더 필드들을 응답한다. */ #include #include #include #include "txcore.h" #include "txcore_dbio.h" #include "acq_util.h" #include "mg_core.h" EXEC SQL INCLUDE sqlca; #define HDR_LEN 25 #define OFF_LEN 0 #define OFF_TYPE 5 #define OFF_CHAN 9 #define OFF_DATE 11 #define OFF_TIME 19 /* 지정 구간이 전부 숫자인지 검사 */ static int all_digit(const char *p, int n) { int i; for (i = 0; i < n; i++) if (p[i] < '0' || p[i] > '9') return 0; return 1; } TX_SERVICE(MG_OL_0019, ctx) { char raw[256]; char declen[6]; char mtype[5]; char chan[3]; char cdate[9]; char ctime[7]; int rawlen; long decl_body; long real_body; tx_log(TX_LOG_INFO, "[MG_OL_0019] 공통헤더 파싱 서비스 진입"); rawlen = tx_buf_get(ctx->in, "RAWMSG", raw, sizeof(raw)); if (rawlen <= 0) { tx_log(TX_LOG_ERROR, "[MG_OL_0019] RAWMSG 누락"); tx_return(ctx, TX_EINVAL, ctx->out); return; } rawlen = (int)strlen(raw); if (rawlen < HDR_LEN) { tx_log(TX_LOG_WARN, "[MG_OL_0019] 헤더 길이부족 len=%d", rawlen); tx_buf_reset(ctx->out); tx_buf_sets(ctx->out, "RESPCODE", RESP_INVALID); tx_return(ctx, TX_FAIL, ctx->out); return; } /* 오프셋 파싱 */ memset(declen, 0, sizeof(declen)); memset(mtype, 0, sizeof(mtype)); memset(chan, 0, sizeof(chan)); memset(cdate, 0, sizeof(cdate)); memset(ctime, 0, sizeof(ctime)); memcpy(declen, raw + OFF_LEN, 5); memcpy(mtype, raw + OFF_TYPE, 4); memcpy(chan, raw + OFF_CHAN, 2); memcpy(cdate, raw + OFF_DATE, 8); memcpy(ctime, raw + OFF_TIME, 6); /* 형식 검증: 길이/일자/시각은 숫자, 종별은 화이트리스트 */ if (!all_digit(declen, 5) || !all_digit(cdate, 8) || !all_digit(ctime, 6)) { tx_log(TX_LOG_WARN, "[MG_OL_0019] 숫자필드 형식 오류"); tx_buf_reset(ctx->out); tx_buf_sets(ctx->out, "RESPCODE", RESP_INVALID); tx_return(ctx, TX_FAIL, ctx->out); return; } if (strcmp(mtype, MSG_TYPE_RECV) != 0 && strcmp(mtype, MSG_TYPE_RESP) != 0 && strcmp(mtype, MSG_TYPE_RECON) != 0) { tx_log(TX_LOG_WARN, "[MG_OL_0019] 전문종별 미허용 type=%s", mtype); tx_buf_reset(ctx->out); tx_buf_sets(ctx->out, "RESPCODE", RESP_INVALID); tx_return(ctx, TX_FAIL, ctx->out); return; } if (!date_is_valid(cdate)) { tx_log(TX_LOG_WARN, "[MG_OL_0019] 일자 유효성 오류 date=%s", cdate); tx_buf_reset(ctx->out); tx_buf_sets(ctx->out, "RESPCODE", RESP_INVALID); tx_return(ctx, TX_FAIL, ctx->out); return; } /* 선언 전문길이와 실제 본문길이 교차검증 */ decl_body = (long)atoi(declen); real_body = (long)(rawlen - HDR_LEN); if (decl_body != real_body) tx_log(TX_LOG_WARN, "[MG_OL_0019] 길이불일치 decl=%ld real=%ld", decl_body, real_body); tx_buf_reset(ctx->out); tx_buf_sets(ctx->out, "RESPCODE", RESP_OK); tx_buf_sets(ctx->out, "MSGTYPE", mtype); tx_buf_sets(ctx->out, "CHAN", chan); tx_buf_sets(ctx->out, "TXNDATE", cdate); tx_buf_sets(ctx->out, "TXNTIME", ctime); tx_buf_setlong(ctx->out, "DECLLEN", decl_body); tx_buf_setlong(ctx->out, "REALLEN", real_body); tx_buf_sets(ctx->out, "LENMATCH", (decl_body == real_body) ? "Y" : "N"); /* 공통헤더 파싱 이력(mg_hdr_log)을 임베디드 SQL 로 적재 */ { EXEC SQL BEGIN DECLARE SECTION; char h_hl_type[8]; char h_hl_chan[4]; long h_hl_decl; long h_hl_real; EXEC SQL END DECLARE SECTION; strncpy(h_hl_type, mtype, sizeof(h_hl_type) - 1); h_hl_type[sizeof(h_hl_type) - 1] = '\0'; strncpy(h_hl_chan, chan, sizeof(h_hl_chan) - 1); h_hl_chan[sizeof(h_hl_chan) - 1] = '\0'; h_hl_decl = decl_body; h_hl_real = real_body; if (tx_begin() == TX_OK) { EXEC SQL INSERT INTO mg_hdr_log (msg_type, chan, decl_len, real_len) VALUES (:h_hl_type, :h_hl_chan, :h_hl_decl, :h_hl_real); if (sqlca.sqlcode != TX_SQL_OK) { TX_DBIO_LOG_ERR("INSERT mg_hdr_log"); tx_abort(); } else { tx_commit(); } } } tx_log(TX_LOG_INFO, "[MG_OL_0019] 헤더파싱 완료 type=%s chan=%s date=%s time=%s", mtype, chan, cdate, ctime); tx_return(ctx, TX_OK, ctx->out); }