/* * Developed by Hillstone Software. http://www.hillstone-software.com * HS X25 with RFC1613 XOT - Demo / Test Application */ #include "HsX25_Demo.h" #include "Bl_win.h" #include #include #include #include "resource.h" TCHAR szWindowClass[] = " "; HINSTANCE hInst; TCHAR szTitle[] = "HsX.25 1.2 (With RFC1613 XOT) C Source Library Demo (www.hillstone-software.com)"; HWND hwnd_main; HWND dlg_main; HBRUSH hbrush1 = NULL; unsigned char *pktsz[] = { {"128"}, {"256"}, {"512"}, {"1024"}, 0, }; unsigned char *wszs[] = { {"1"}, {"2"}, {"3"}, {"4"}, {"5"}, {"6"}, {"7"}, 0, }; static int num_vcs_up = 0; static int num_events = 0; static int pkttrace_len = 0; static int low_lcn = 2048; static int high_lcn = 4095; static long app_timer = 0; static long stats_k = 0; static long rq_k = 0; static unsigned char static_str_buf[200] = {0}; static timer_cell_t timers[APP_MAX_TIMERS] = {0}; x25app_vc_t vclist[4096] = {0}; /* request queue */ request_q_t rq = {0}; hs_x25_conn_t conn = {0}; int rq_put(int type, void *pData, int data_size) { void *p; if (rq.size >= MAX_REQS) return FALSE; p = malloc(data_size); if (!p) return FALSE; memcpy(p, pData, data_size); rq.cells[rq.in].req_type = type; rq.cells[rq.in++].req_data = (long)p; if (rq.in == MAX_REQS) rq.in = 0; rq.size++; return TRUE; } void service_rq(void) { void *p; int type; hs_x25_conn_t *pConn; data_cell_t *dc; int rc; if (rq.size == 0) return; type = rq.cells[rq.out].req_type; p = (void *)rq.cells[rq.out].req_data; switch (type) { case REQ_CALL: pConn = (hs_x25_conn_t *)p; rc = submit_call(pConn); break; case REQ_DATA: dc = (data_cell_t *)p; rc = submit_data(dc->lci, dc->bufp, dc->len, dc->qbit); break; } if ((type == REQ_DATA) && (rc == HS_X25_RC_TXQ_FULL)) return; rq.out++; if (rq.out == MAX_REQS) rq.out = 0; rq.size--; if (dc->release_buf) free(dc->bufp); free(p); } /* allocate new timer call */ static timer_cell_t *timer_alloc(void) { timer_cell_t *t; long i; for (i=0; iallocated) { memset(t, 0, sizeof (timer_cell_t)); t->allocated = TRUE; return t; } } return NULL; } /* release timer cell */ static void timer_free(timer_cell_t *t) { t->allocated = FALSE; } /* find timer cell by timer handle */ static timer_cell_t *timer_find(long timer_handle) { timer_cell_t *t; long i; for (i=0; iallocated) && (t->timer_handle == timer_handle)) return t; } return NULL; } /* windows timer callback */ TIMERPROC TimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) { timer_cell_t *t; KillTimer(hwnd, idEvent); t = timer_find(idEvent); if (!t) return 0; t->callback(t->user_handle); timer_free(t); return 0; } static void clear_stats(void) { SetDlgItemText(dlg_main, IDC_STATIC_SLCI, ""); SetDlgItemText(dlg_main, IDC_STATIC_SRES_TX, ""); SetDlgItemText(dlg_main, IDC_STATIC_SRES_RX, ""); SetDlgItemText(dlg_main, IDC_STATIC_SDTX, ""); SetDlgItemText(dlg_main, IDC_STATIC_SDRX, ""); SetDlgItemText(dlg_main, IDC_STATIC_SWIN, ""); } /* windows timer callback */ TIMERPROC AppTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) { int lci; hs_x25_stats_t stat; x25app_vc_t *vc; unsigned char s[80]; rq_k++; if (rq_k == APP_TMR_RQ_K) { rq_k = 0; service_rq(); } HsX25Tick(); stats_k++; // time to pull stats for a selected call if any if (stats_k == APP_TMR_STATS_K) { stats_k = 0; if (ListViewVCGetSelectedLCI(&lci)) { vc = &vclist[lci]; HsX25GetStats(vc->vchan, &stat); SetDlgItemInt(dlg_main, IDC_STATIC_SLCI, lci, FALSE); memset(s, 0, sizeof s); sprintf(s, "%u", stat.tx.reset); SetDlgItemText(dlg_main, IDC_STATIC_SRES_TX, s); memset(s, 0, sizeof s); sprintf(s, "%u", stat.rx.reset); SetDlgItemText(dlg_main, IDC_STATIC_SRES_RX, s); memset(s, 0, sizeof s); sprintf(s, "%u", stat.tx.data); SetDlgItemText(dlg_main, IDC_STATIC_SDTX, s); memset(s, 0, sizeof s); sprintf(s, "%u", stat.rx.data); SetDlgItemText(dlg_main, IDC_STATIC_SDRX, s); SetDlgItemInt(dlg_main, IDC_STATIC_SWIN, stat.w, FALSE); } else { clear_stats(); } } return 0; } /* * called from X25 to start a timer * handle - HsX25 handle * secs - timeout in seconds * callback - timer expired callback address (function in HsX25 code) * tid - timer id * return - timer handle */ long hs_x25_start_timer(long handle, unsigned long secs, hs_x25_timer_callback_t *callback, int tid) { timer_cell_t *t; if (!callback) { write_event("hs_x25_start_timer: cannot start timer: NULL callback"); return 0; } t = timer_alloc(); if (!t) { write_event("hs_x25_start_timer: cannot start timer: no free timer cells"); return 0; } t->timer_handle = (long)SetTimer(NULL, 0, (UINT)(secs * 1000), (TIMERPROC)TimerProc); if (t->timer_handle == 0) { write_event("hs_x25_start_timer: cannot start windows timer"); timer_free(t); return 0; } t->user_handle = handle; t->callback = callback; return t->timer_handle; } /* called from X25 to stop a timer */ void hs_x25_stop_timer(long timer_handle, int tid) { timer_cell_t *t = timer_find(timer_handle); if (!t) return; KillTimer(0, (UINT_PTR )timer_handle); timer_free(t); } BOOL InitListView (HWND hwndListView) { int index; LV_COLUMN lvColumn; TCHAR szString[4][20] = {TEXT("LCI"), TEXT("In/Out"), TEXT("Called NUA"), TEXT("Calling NUA"), }; int clen[4] = {40,45, 100,100}; int i = 0; // Initialize the columns in the list view. lvColumn.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; lvColumn.fmt = LVCFMT_LEFT; // Insert the five columns in the list view. for (index = 0; index < 4; index++) { lvColumn.pszText = szString[index]; lvColumn.cx = clen[index]; ListView_InsertColumn (hwndListView, index, &lvColumn); } ListView_SetExtendedListViewStyle(hwndListView, LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT); return TRUE; } void ListViewVCAddCall(int lci, int is_out) { LVITEM item = {0}; unsigned char s[60]; int index; x25app_vc_t *vc = &vclist[lci]; HWND lvhan = GetDlgItem(dlg_main, IDC_LIST_VC); memset(&item, 0, sizeof (LVITEM)); item.mask = LVIF_TEXT | LVIF_PARAM; memset(s, 0, sizeof s); sprintf(s, "%d",lci); item.pszText = s; item.lParam = (LPARAM)lci; item.iItem = 0xffff; index = ListView_InsertItem(lvhan, (LPLVITEM)&item); memset(s, 0, sizeof s); sprintf(s, "%s", is_out ? "Out" : "In"); ListView_SetItemText(lvhan, index, 1, s); ListView_SetItemText(lvhan, index, 2, vc->conn.called); ListView_SetItemText(lvhan, index, 3, vc->conn.calling); ListView_EnsureVisible(lvhan, index, 0); num_vcs_up++; SetDlgItemInt(dlg_main, IDC_STATIC_NVC, num_vcs_up, FALSE); } void ListViewVCDeleteCall(int lci) { LVFINDINFO findinfo = {0}; int i; findinfo.flags = LVFI_PARAM; findinfo.lParam = (LPARAM)lci; i = ListView_FindItem(GetDlgItem(dlg_main, IDC_LIST_VC), -1, &findinfo); if (i == -1) return; ListView_DeleteItem(GetDlgItem(dlg_main, IDC_LIST_VC), i); num_vcs_up--; SetDlgItemInt(dlg_main, IDC_STATIC_NVC, num_vcs_up, FALSE); } int ListViewVCGetSelectedLCI(int *lci) { LRESULT iSelect; LVITEM item = {0}; iSelect=SendMessage(GetDlgItem(dlg_main, IDC_LIST_VC), LVM_GETNEXTITEM, -1, LVNI_FOCUSED); if (iSelect == -1) { return FALSE; } item.mask = LVIF_PARAM; item.iItem = (int)iSelect; ListView_GetItem(GetDlgItem(dlg_main, IDC_LIST_VC), &item); *lci = (int)item.lParam; return TRUE; } static void write_event(unsigned char *str) { LVITEM item = {0}; unsigned char s[80]; int index; int *p; HWND lvhan = GetDlgItem(dlg_main, IDC_LIST_EV); memset(&item, 0, sizeof (LVITEM)); item.mask = LVIF_TEXT | LVIF_PARAM; memset(s, 0, sizeof s); sprintf(s, "%s",str); item.pszText = s; item.lParam = (LPARAM)1; item.iItem = 0xffff; index = ListView_InsertItem(lvhan, (LPLVITEM)&item); ListView_EnsureVisible(lvhan, index, 0); p = &num_events; if (*p < MAX_EVENTS) { (*p)++; } else { ListView_DeleteItem(lvhan, 0); } } BOOL InitListViewTrace (HWND hwndListView) { int index; LV_COLUMN lvColumn; TCHAR szString[7][20] = {TEXT("LCI"), TEXT("In/Out"), TEXT("Q"), TEXT("D"), TEXT("M"), TEXT("Decode"), TEXT("Raw Data"), }; int clen[7] = {30,45, 20, 20,25,200,300}; int i = 0; // Initialize the columns in the list view. lvColumn.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; lvColumn.fmt = LVCFMT_LEFT; // Insert the five columns in the list view. for (index = 0; index < 7; index++) { lvColumn.pszText = szString[index]; lvColumn.cx = clen[index]; ListView_InsertColumn (hwndListView, index, &lvColumn); } ListView_SetExtendedListViewStyle(hwndListView, LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT); return TRUE; } BOOL InitListAppView (HWND hwndListView) { int index; LV_COLUMN lvColumn; TCHAR szString[1][20] = {TEXT(" "),}; int clen[1] = {360}; int i = 0; // Initialize the columns in the list view. lvColumn.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; lvColumn.fmt = LVCFMT_LEFT; lvColumn.cx = 120; // Insert the five columns in the list view. for (index = 0; index < 1; index++) { lvColumn.pszText = szString[index]; lvColumn.cx = clen[index]; ListView_InsertColumn (hwndListView, index, &lvColumn); } ListView_SetExtendedListViewStyle(hwndListView, /*LVS_EX_GRIDLINES |*/ LVS_EX_FULLROWSELECT); return TRUE; } void WritePktTrace(int is_rx, unsigned char *buf, int len, long arg) { LVITEM item = {0}; unsigned char s[MAX_TRC_ENTRY_LEN]; int index; int i, n; int rlen; int rc; int ev; hs_x25_pkt_info_t info = {0}; int lci; HWND lvhan = GetDlgItem(dlg_main, IDC_LIST_TRACE); rc = HsX25DecodePkt(buf, len, &ev, &info, 1); if (rc != HS_X25_RC_DECODE_OK) { lci = 0; } else { lci = (int)info.lci; } memset(&item, 0, sizeof (LVITEM)); item.mask = LVIF_TEXT | LVIF_PARAM; memset(s, 0, sizeof s); sprintf(s, "%d", lci); item.pszText = s; item.lParam = (LPARAM)1; item.iItem = 0xffff; index = ListView_InsertItem(lvhan, (LPLVITEM)&item); ListView_SetItemText(lvhan, index, 1, is_rx ? "In":"Out"); memset(s, 0, sizeof s); rlen = (len > 20) ? 20 : len; n = 0; for (i=0; ibufp; len = pDat->len; // only display max 10 bytes sprintf(s, "DATA RX (LCI %d) (len %d) ", lci, len); write_event(s); break; case HS_X25_EV_CALL_CLEAR_COMPLETE: ListViewVCDeleteCall((int)arg1); sprintf(s, "X.25 VC disconnect complete (%d)", (int)arg1); write_event(s); vclist[arg1].vchan = 0; if (!vclist[arg1].is_out) submit_new_listen(); break; case HS_X25_EV_CALL_CLEARED: ListViewVCDeleteCall((int)arg1); sprintf(s, "X.25 VC disconnected by network (%d)", (int)arg1); write_event(s); vclist[arg1].vchan = 0; if (!vclist[arg1].is_out) submit_new_listen(); break; case HS_X25_EV_PKTLR_RESTARTED: ListViewVCDeleteCall((int)arg1); sprintf(s, "X.25 VC cleared (%d) packet layer restart", (int)arg1); write_event(s); break; case HS_X25_EV_EXP_DATA_TX_FAIL: sprintf(s, "X.25 failed to send exp. data. Previous exp data not confirmed"); write_event(s); break; case HS_X25_EV_EXP_DATA_DELIVERED: sprintf(s, "X.25 expedited data delivered to remote"); write_event(s); break; case HS_X25_EV_DATA_EXP: buf = (unsigned char *)arg1; len = (int)arg2; n = sprintf(s, "X.25 RX EXP DATA: "); for (i=0 ; il2_addr = 0xffff; conn->arg = 1261; rc = HsX25Connect(conn, &vchan, &lci); if (rc != HS_X25_RC_OK) { sprintf(s, "X25 connect failed rc [%d]", rc); write_event(s); return FALSE; } memcpy(&vclist[lci].conn, conn, sizeof (hs_x25_conn_t)); vclist[lci].vchan = vchan; vclist[lci].is_out = FALSE; sprintf(s, "Making outgoing call (lci %d)", lci); write_event(s); return TRUE; } int submit_data(int lci, unsigned char *p, int len, int qbit) { int rc; long han; unsigned char s[80] = {0}; han = vclist[lci].vchan; rc = HsX25Data(han, p, len, qbit); if (rc != HS_X25_RC_OK) { if (rc == HS_X25_RC_BUF_TOO_BIG) sprintf(s, "X25 send data failed (Buffer Too Big)"); else if (rc == HS_X25_RC_TXQ_FULL) sprintf(s, "X25 send data (TXQ Full, Will Try Later)"); else sprintf(s, "X25 send data failed (rc %d)", rc); write_event(s); return rc; } sprintf(s, "Sending data (lci %d)", lci); write_event(s); return rc; } void submit_data_req(int lci, unsigned char *p, int len, int qbit, int release_buf) { data_cell_t dc; memset(&dc, 0, sizeof (data_cell_t)); dc.bufp = p; dc.lci = lci; dc.len = len; dc.qbit = qbit; dc.release_buf = release_buf; if (!rq_put(REQ_DATA, &dc, sizeof (data_cell_t))) write_event("Failed to submit data request"); } static unsigned char hex2byte(unsigned char *buf) { unsigned char hex[] = "0123456789ABCDEF"; unsigned char b = 0; unsigned char b1, b2; int i; b1 = toupper(buf[0]); b2 = toupper(buf[1]); for (i = 0; i<16; i++) { if (b1 == hex[i]) { b = (unsigned char)((i << 4) & 0xf0); break; } } for (i = 0; i<16; i++) { if (b2 == hex[i]) { b |= (unsigned char)(i & 0x0f); break; } } return b; } /* * Convert source buffer from ASCII hex format to byte buffer. * Source buffer length must be exactly twice as large as destination buffer length */ static void hexbuf2Bin(unsigned char *src, unsigned char *dst, int len) { int i, n, ln; if ((len % 2) != 0) return; ln = (len / 2); n = 0; for (i=0; i