Changeset 4728 for pjproject/trunk/pjlib-util/src/pjlib-util/cli_telnet.c
- Timestamp:
- Feb 4, 2014 10:13:56 AM (10 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjlib-util/src/pjlib-util/cli_telnet.c
r4537 r4728 37 37 (defined(PJ_WIN32_WINCE) && PJ_WIN32_WINCE!=0) 38 38 39 #define EADDRINUSE WSAEADDRINUSE 39 #define EADDRINUSE WSAEADDRINUSE 40 40 41 41 #endif … … 67 67 * This specify the state for the telnet option negotiation. 68 68 */ 69 enum cli_telnet_option_states 70 { 69 enum cli_telnet_option_states 70 { 71 71 OPT_DISABLE, /* Option disable */ 72 72 OPT_ENABLE, /* Option enable */ 73 73 OPT_EXPECT_DISABLE, /* Already send disable req, expecting resp */ 74 74 OPT_EXPECT_ENABLE, /* Already send enable req, expecting resp */ 75 OPT_EXPECT_DISABLE_REV, /* Already send disable req, expecting resp, 75 OPT_EXPECT_DISABLE_REV, /* Already send disable req, expecting resp, 76 76 * need to send enable req */ 77 77 OPT_EXPECT_ENABLE_REV /* Already send enable req, expecting resp, … … 199 199 }; 200 200 201 enum terminal_cmd 201 enum terminal_cmd 202 202 { 203 203 TC_ESC = 27, … … 207 207 TC_LEFT = 68, 208 208 TC_END = 70, 209 TC_HOME = 72, 209 TC_HOME = 72, 210 210 TC_CTRL_C = 3, 211 211 TC_CR = 13, … … 229 229 230 230 /** 231 * This structure contains the command line shown to the user. 232 * The telnet also needs to maintain and manage command cursor position. 231 * This structure contains the command line shown to the user. 232 * The telnet also needs to maintain and manage command cursor position. 233 233 * Due to that reason, the insert/delete character process from buffer will 234 234 * consider its current cursor position. … … 252 252 253 253 /** 254 * This structure contains the command history executed by user. 254 * This structure contains the command history executed by user. 255 255 * Besides storing the command history, it is necessary to be able 256 256 * to browse it. … … 291 291 pj_thread_t *worker_thread; 292 292 pj_bool_t is_quitting; 293 pj_mutex_t *mutex; 293 pj_mutex_t *mutex; 294 294 } cli_telnet_fe; 295 295 … … 305 305 306 306 /** 307 * Return the number of characters between the current cursor position 307 * Return the number of characters between the current cursor position 308 308 * to the end of line. 309 309 */ … … 314 314 315 315 /** 316 * Insert character to the receive buffer. 317 */ 318 static pj_bool_t recv_buf_insert(telnet_recv_buf *recv_buf, 319 unsigned char *data) 320 { 316 * Insert character to the receive buffer. 317 */ 318 static pj_bool_t recv_buf_insert(telnet_recv_buf *recv_buf, 319 unsigned char *data) 320 { 321 321 if (recv_buf->len+1 >= PJ_CLI_MAX_CMDBUF) { 322 322 return PJ_FALSE; 323 } else { 323 } else { 324 324 if (*data == '\t' || *data == '?' || *data == '\r') { 325 325 /* Always insert to the end of line */ … … 328 328 /* Insert based on the current cursor pos */ 329 329 unsigned cur_pos = recv_buf->cur_pos; 330 unsigned rlen = recv_buf_right_len(recv_buf); 331 if (rlen > 0) { 330 unsigned rlen = recv_buf_right_len(recv_buf); 331 if (rlen > 0) { 332 332 /* Shift right characters */ 333 pj_memmove(&recv_buf->rbuf[cur_pos+1], 334 &recv_buf->rbuf[cur_pos], 333 pj_memmove(&recv_buf->rbuf[cur_pos+1], 334 &recv_buf->rbuf[cur_pos], 335 335 rlen+1); 336 } 336 } 337 337 recv_buf->rbuf[cur_pos] = *data; 338 338 } … … 356 356 unsigned cur_pos = recv_buf->cur_pos; 357 357 /* Shift left characters */ 358 pj_memmove(&recv_buf->rbuf[cur_pos-1], &recv_buf->rbuf[cur_pos], 358 pj_memmove(&recv_buf->rbuf[cur_pos-1], &recv_buf->rbuf[cur_pos], 359 359 rlen); 360 360 } … … 362 362 --recv_buf->len; 363 363 recv_buf->rbuf[recv_buf->len] = 0; 364 } 364 } 365 365 return PJ_TRUE; 366 366 } … … 373 373 374 374 /** 375 * Insert the command to history. If the entered command is not on the list, 376 * a new entry will be created. All entered command will be moved to 377 * the first entry of the history. 378 */ 379 static pj_status_t insert_history(cli_telnet_sess *sess, 375 * Insert the command to history. If the entered command is not on the list, 376 * a new entry will be created. All entered command will be moved to 377 * the first entry of the history. 378 */ 379 static pj_status_t insert_history(cli_telnet_sess *sess, 380 380 char *cmd_val) 381 381 { … … 393 393 in_history = pj_list_search(sess->history, (void*)&cmd, compare_str); 394 394 if (!in_history) { 395 if (pj_list_size(sess->history) < PJ_CLI_MAX_CMD_HISTORY) { 395 if (pj_list_size(sess->history) < PJ_CLI_MAX_CMD_HISTORY) { 396 396 char *data_history; 397 397 in_history = PJ_POOL_ZALLOC_T(sess->pool, cmd_history); 398 398 pj_list_init(in_history); 399 data_history = (char *)pj_pool_calloc(sess->pool, 399 data_history = (char *)pj_pool_calloc(sess->pool, 400 400 sizeof(char), PJ_CLI_MAX_CMDBUF); 401 401 in_history->command.ptr = data_history; … … 404 404 /* Get the oldest history */ 405 405 in_history = sess->history->prev; 406 } 406 } 407 407 } else { 408 408 pj_list_insert_nodes_after(in_history->prev, in_history->next); … … 416 416 417 417 /** 418 * Get the next or previous history of the shown/active history. 418 * Get the next or previous history of the shown/active history. 419 419 */ 420 420 static pj_str_t* get_prev_history(cli_telnet_sess *sess, pj_bool_t is_forward) … … 434 434 return NULL; 435 435 } else { 436 if (is_forward) { 437 node = (node->next==root)?node->next->next:node->next; 436 if (is_forward) { 437 node = (node->next==root)?node->next->next:node->next; 438 438 } else { 439 node = (node->prev==root)?node->prev->prev:node->prev; 439 node = (node->prev==root)?node->prev->prev:node->prev; 440 440 } 441 441 retval = &node->command; … … 451 451 * referenced - (RFC-854). 452 452 */ 453 static pj_bool_t send_telnet_cmd(cli_telnet_sess *sess, 454 cli_telnet_command cmd, 453 static pj_bool_t send_telnet_cmd(cli_telnet_sess *sess, 454 cli_telnet_command cmd, 455 455 unsigned char option) 456 { 456 { 457 457 unsigned char buf[3]; 458 458 PJ_ASSERT_RETURN(sess, PJ_FALSE); … … 470 470 * For local option: send WILL. 471 471 * For remote option: send DO. 472 * This method also handle the state transition of the ENABLE 472 * This method also handle the state transition of the ENABLE 473 473 * negotiation process. 474 474 */ 475 static pj_bool_t send_enable_option(cli_telnet_sess *sess, 476 pj_bool_t is_local, 475 static pj_bool_t send_enable_option(cli_telnet_sess *sess, 476 pj_bool_t is_local, 477 477 unsigned char option) 478 478 { … … 500 500 *state = OPT_EXPECT_ENABLE; 501 501 break; 502 case OPT_EXPECT_DISABLE_REV: 502 case OPT_EXPECT_DISABLE_REV: 503 503 *state = OPT_DISABLE; 504 504 break; … … 509 509 } 510 510 511 static pj_bool_t send_cmd_do(cli_telnet_sess *sess, 511 static pj_bool_t send_cmd_do(cli_telnet_sess *sess, 512 512 unsigned char option) 513 513 { … … 515 515 } 516 516 517 static pj_bool_t send_cmd_will(cli_telnet_sess *sess, 517 static pj_bool_t send_cmd_will(cli_telnet_sess *sess, 518 518 unsigned char option) 519 519 { … … 523 523 /** 524 524 * This method will handle receiving telnet's ENABLE option negotiation. 525 * This method also handle the state transition of the ENABLE 526 * negotiation process. 527 */ 528 static pj_bool_t receive_enable_option(cli_telnet_sess *sess, 529 pj_bool_t is_local, 525 * This method also handle the state transition of the ENABLE 526 * negotiation process. 527 */ 528 static pj_bool_t receive_enable_option(cli_telnet_sess *sess, 529 pj_bool_t is_local, 530 530 unsigned char option) 531 531 { … … 550 550 } 551 551 break; 552 case OPT_EXPECT_ENABLE: 552 case OPT_EXPECT_ENABLE: 553 553 *state = OPT_ENABLE; 554 554 break; 555 case OPT_EXPECT_DISABLE: 555 case OPT_EXPECT_DISABLE: 556 556 *state = OPT_DISABLE; 557 557 break; 558 558 case OPT_EXPECT_ENABLE_REV: 559 559 *state = OPT_EXPECT_DISABLE; 560 send_telnet_cmd(sess, is_local?WONT:DONT, option); 560 send_telnet_cmd(sess, is_local?WONT:DONT, option); 561 561 break; 562 562 case OPT_EXPECT_DISABLE_REV: … … 566 566 return PJ_FALSE; 567 567 } 568 return PJ_TRUE; 568 return PJ_TRUE; 569 569 } 570 570 571 571 /** 572 572 * This method will handle receiving telnet's DISABLE option negotiation. 573 * This method also handle the state transition of the DISABLE 574 * negotiation process. 575 */ 576 static pj_bool_t receive_disable_option(cli_telnet_sess *sess, 577 pj_bool_t is_local, 573 * This method also handle the state transition of the DISABLE 574 * negotiation process. 575 */ 576 static pj_bool_t receive_disable_option(cli_telnet_sess *sess, 577 pj_bool_t is_local, 578 578 unsigned char option) 579 579 { … … 585 585 sess_opt = &sess->telnet_option[option]; 586 586 state = is_local?(&sess_opt->local_state):(&sess_opt->peer_state); 587 587 588 588 switch (*state) { 589 589 case OPT_ENABLE: … … 595 595 /* Ignore if already enabled */ 596 596 break; 597 case OPT_EXPECT_ENABLE: 597 case OPT_EXPECT_ENABLE: 598 598 case OPT_EXPECT_DISABLE: 599 599 *state = OPT_DISABLE; … … 601 601 case OPT_EXPECT_ENABLE_REV: 602 602 *state = OPT_DISABLE; 603 send_telnet_cmd(sess, is_local?WONT:DONT, option); 603 send_telnet_cmd(sess, is_local?WONT:DONT, option); 604 604 break; 605 605 case OPT_EXPECT_DISABLE_REV: … … 610 610 return PJ_FALSE; 611 611 } 612 return PJ_TRUE; 612 return PJ_TRUE; 613 613 } 614 614 … … 633 633 } 634 634 635 static void set_local_option(cli_telnet_sess *sess, 636 unsigned char option, 637 pj_bool_t enable) 635 static void set_local_option(cli_telnet_sess *sess, 636 unsigned char option, 637 pj_bool_t enable) 638 638 { 639 639 sess->telnet_option[option].local_is_enable = enable; 640 640 } 641 641 642 static void set_peer_option(cli_telnet_sess *sess, 643 unsigned char option, 644 pj_bool_t enable) 642 static void set_peer_option(cli_telnet_sess *sess, 643 unsigned char option, 644 pj_bool_t enable) 645 645 { 646 646 sess->telnet_option[option].peer_is_enable = enable; 647 647 } 648 648 649 static pj_bool_t is_local_option_state_ena(cli_telnet_sess *sess, 649 static pj_bool_t is_local_option_state_ena(cli_telnet_sess *sess, 650 650 unsigned char option) 651 { 651 { 652 652 return (sess->telnet_option[option].local_state == OPT_ENABLE); 653 653 } 654 654 655 static void send_return_key(cli_telnet_sess *sess) 656 { 655 static void send_return_key(cli_telnet_sess *sess) 656 { 657 657 telnet_sess_send2(sess, (unsigned char*)"\r\n", 2); 658 658 } … … 671 671 send_data.ptr = data_str; 672 672 send_data.slen = 0; 673 673 674 674 pj_strcat(&send_data, &fe->cfg.prompt_str); 675 675 … … 681 681 * the error position of the source command. 682 682 */ 683 static void send_err_arg(cli_telnet_sess *sess, 684 const pj_cli_exec_info *info, 683 static void send_err_arg(cli_telnet_sess *sess, 684 const pj_cli_exec_info *info, 685 685 const pj_str_t *msg, 686 686 pj_bool_t with_return, … … 715 715 } 716 716 717 static void send_inv_arg(cli_telnet_sess *sess, 717 static void send_inv_arg(cli_telnet_sess *sess, 718 718 const pj_cli_exec_info *info, 719 719 pj_bool_t with_return, … … 724 724 } 725 725 726 static void send_too_many_arg(cli_telnet_sess *sess, 726 static void send_too_many_arg(cli_telnet_sess *sess, 727 727 const pj_cli_exec_info *info, 728 728 pj_bool_t with_return, … … 733 733 } 734 734 735 static void send_hint_arg(cli_telnet_sess *sess, 736 pj_str_t *send_data, 735 static void send_hint_arg(cli_telnet_sess *sess, 736 pj_str_t *send_data, 737 737 const pj_str_t *desc, 738 738 pj_ssize_t cmd_len, … … 756 756 * is ambiguous. It will show the matching command as the hint information. 757 757 */ 758 static void send_ambi_arg(cli_telnet_sess *sess, 758 static void send_ambi_arg(cli_telnet_sess *sess, 759 759 const pj_cli_exec_info *info, 760 760 pj_bool_t with_return, … … 770 770 pj_ssize_t max_length = 0; 771 771 pj_ssize_t cmd_length = 0; 772 const pj_str_t *cmd_desc = 0;773 772 static const pj_str_t sc_type = {"sc", 2}; 774 773 static const pj_str_t choice_type = {"choice", 6}; 775 774 send_data.ptr = data; 776 775 send_data.slen = 0; 777 776 778 777 if (with_return) 779 778 pj_strcat2(&send_data, "\r\n"); … … 787 786 /* Get the max length of the command name */ 788 787 for (i=0;i<info->hint_cnt;++i) { 789 if ((&hint[i].type) && (hint[i].type.slen > 0)) { 790 if (pj_stricmp(&hint[i].type, &sc_type) == 0) { 788 if ((&hint[i].type) && (hint[i].type.slen > 0)) { 789 if (pj_stricmp(&hint[i].type, &sc_type) == 0) { 791 790 if ((i > 0) && (!pj_stricmp(&hint[i-1].desc, &hint[i].desc))) { 792 791 cmd_length += (hint[i].name.slen + 3); 793 792 } else { 794 793 cmd_length = hint[i].name.slen; 795 } 794 } 796 795 } else { 797 796 cmd_length = hint[i].name.slen; 798 797 } 799 } else { 798 } else { 800 799 cmd_length = hint[i].name.slen; 801 800 } … … 805 804 } 806 805 } 807 806 808 807 cmd_length = 0; 809 808 /* Build hint information */ 810 for (i=0;i<info->hint_cnt;++i) { 811 if ((&hint[i].type) && (hint[i].type.slen > 0)) { 809 for (i=0;i<info->hint_cnt;++i) { 810 if ((&hint[i].type) && (hint[i].type.slen > 0)) { 812 811 if (pj_stricmp(&hint[i].type, &sc_type) == 0) { 813 812 parse_state = OP_SHORTCUT; … … 817 816 parse_state = OP_TYPE; 818 817 } 819 } else { 818 } else { 820 819 parse_state = OP_NORMAL; 821 820 } 822 821 823 822 if (parse_state != OP_SHORTCUT) { 824 823 pj_strcat2(&send_data, "\r\n "); 825 824 cmd_length = hint[i].name.slen; 826 } 827 825 } 826 828 827 switch (parse_state) { 829 828 case OP_CHOICE: 830 /* Format : "[Choice Value] description" */ 829 /* Format : "[Choice Value] description" */ 831 830 pj_strcat2(&send_data, "["); 832 831 pj_strcat(&send_data, &hint[i].name); 833 pj_strcat2(&send_data, "]"); 832 pj_strcat2(&send_data, "]"); 834 833 break; 835 834 case OP_TYPE: … … 837 836 pj_strcat2(&send_data, "<"); 838 837 pj_strcat(&send_data, &hint[i].name); 839 pj_strcat2(&send_data, ">"); 838 pj_strcat2(&send_data, ">"); 840 839 break; 841 840 case OP_SHORTCUT: 842 841 /* Format : "Command | sc | description" */ 843 { 842 { 844 843 cmd_length += hint[i].name.slen; 845 844 if ((i > 0) && (!pj_stricmp(&hint[i-1].desc, &hint[i].desc))) { 846 845 pj_strcat2(&send_data, " | "); 847 cmd_length += 3; 846 cmd_length += 3; 848 847 } else { 849 848 pj_strcat2(&send_data, "\r\n "); 850 849 } 851 pj_strcat(&send_data, &hint[i].name); 850 pj_strcat(&send_data, &hint[i].name); 852 851 } 853 852 break; … … 855 854 /* Command */ 856 855 pj_strcat(&send_data, &hint[i].name); 857 cmd_desc = &hint[i].desc; 858 break; 859 } 860 861 if ((parse_state == OP_TYPE) || (parse_state == OP_CHOICE) || 856 break; 857 } 858 859 if ((parse_state == OP_TYPE) || (parse_state == OP_CHOICE) || 862 860 ((i+1) >= info->hint_cnt) || 863 (pj_strncmp(&hint[i].desc, &hint[i+1].desc, hint[i].desc.slen))) 861 (pj_strncmp(&hint[i].desc, &hint[i+1].desc, hint[i].desc.slen))) 864 862 { 865 863 /* Add description info */ 866 send_hint_arg(sess, &send_data, 867 &hint[i].desc, cmd_length, 864 send_hint_arg(sess, &send_data, 865 &hint[i].desc, cmd_length, 868 866 max_length); 869 867 870 868 cmd_length = 0; 871 } 872 } 873 pj_strcat2(&send_data, "\r\n"); 869 } 870 } 871 pj_strcat2(&send_data, "\r\n"); 874 872 pj_strcat(&send_data, &fe->cfg.prompt_str); 875 873 if (with_last_cmd) 876 874 pj_strcat2(&send_data, (char *)sess->rcmd->rbuf); 877 875 878 telnet_sess_send(sess, &send_data); 876 telnet_sess_send(sess, &send_data); 879 877 } 880 878 … … 882 880 * This method is to send command completion of the entered command. 883 881 */ 884 static void send_comp_arg(cli_telnet_sess *sess, 882 static void send_comp_arg(cli_telnet_sess *sess, 885 883 pj_cli_exec_info *info) 886 884 { … … 893 891 send_data.slen = 0; 894 892 895 pj_strcat(&send_data, &info->hint[0].name); 893 pj_strcat(&send_data, &info->hint[0].name); 896 894 897 895 telnet_sess_send(sess, &send_data); … … 902 900 */ 903 901 static pj_bool_t handle_alfa_num(cli_telnet_sess *sess, unsigned char *data) 904 { 902 { 905 903 if (is_local_option_state_ena(sess, TERM_ECHO)) { 906 904 if (recv_buf_right_len(sess->rcmd) > 0) { 907 /* Cursor is not at EOL, insert character */ 905 /* Cursor is not at EOL, insert character */ 908 906 unsigned char echo[5] = {0x1b, 0x5b, 0x31, 0x40, 0x00}; 909 907 echo[4] = *data; … … 914 912 } 915 913 return PJ_TRUE; 916 } 914 } 917 915 return PJ_FALSE; 918 916 } … … 926 924 if (recv_buf_backspace(sess->rcmd)) { 927 925 if (rlen) { 928 /* 929 * Cursor is not at the end of line, move the characters 926 /* 927 * Cursor is not at the end of line, move the characters 930 928 * after the cursor to left 931 929 */ … … 934 932 telnet_sess_send2(sess, echo, 5); 935 933 } else { 936 const static unsigned char echo[3] = {0x08, 0x20, 0x08}; 934 const static unsigned char echo[3] = {0x08, 0x20, 0x08}; 937 935 telnet_sess_send2(sess, echo, 3); 938 936 } … … 942 940 } 943 941 944 /* 945 * Syntax error handler for parser. 942 /* 943 * Syntax error handler for parser. 946 944 */ 947 945 static void on_syntax_error(pj_scanner *scanner) … … 958 956 pj_scanner scanner; 959 957 PJ_USE_EXCEPTION; 960 pj_scan_init(&scanner, cmd->ptr, cmd->slen, PJ_SCAN_AUTOSKIP_WS, 958 pj_scan_init(&scanner, cmd->ptr, cmd->slen, PJ_SCAN_AUTOSKIP_WS, 961 959 &on_syntax_error); 962 960 PJ_TRY { … … 966 964 } 967 965 PJ_CATCH_ANY { 968 pj_scan_fini(&scanner); 966 pj_scan_fini(&scanner); 969 967 return PJ_GET_EXCEPTION(); 970 968 } … … 981 979 pj_bool_t retval = PJ_TRUE; 982 980 unsigned len; 983 981 984 982 pj_pool_t *pool; 985 983 pj_cli_cmd_val *cmd_val; … … 990 988 991 989 cmd_val = PJ_POOL_ZALLOC_T(pool, pj_cli_cmd_val); 992 993 status = pj_cli_sess_parse(&sess->base, (char *)&sess->rcmd->rbuf, cmd_val, 994 pool, &info); 990 991 status = pj_cli_sess_parse(&sess->base, (char *)&sess->rcmd->rbuf, cmd_val, 992 pool, &info); 995 993 996 994 len = (unsigned)pj_ansi_strlen((char *)sess->rcmd->rbuf); … … 998 996 switch (status) { 999 997 case PJ_CLI_EINVARG: 1000 send_inv_arg(sess, &info, PJ_TRUE, PJ_TRUE); 998 send_inv_arg(sess, &info, PJ_TRUE, PJ_TRUE); 1001 999 break; 1002 1000 case PJ_CLI_ETOOMANYARGS: … … 1015 1013 telnet_sess_send2(sess, data_sent, rlen); 1016 1014 } 1017 if (info.hint_cnt > 0) { 1015 if (info.hint_cnt > 0) { 1018 1016 /* Complete command */ 1019 1017 pj_str_t cmd = pj_str((char *)sess->rcmd->rbuf); … … 1026 1024 if (hint_info->slen >= last_token.slen) { 1027 1025 hint_info->slen -= last_token.slen; 1028 pj_memmove(hint_info->ptr, 1029 &hint_info->ptr[last_token.slen], 1030 hint_info->slen); 1031 } 1026 pj_memmove(hint_info->ptr, 1027 &hint_info->ptr[last_token.slen], 1028 hint_info->slen); 1029 } 1032 1030 send_comp_arg(sess, &info); 1033 1031 1034 pj_memcpy(&sess->rcmd->rbuf[len], info.hint[0].name.ptr, 1032 pj_memcpy(&sess->rcmd->rbuf[len], info.hint[0].name.ptr, 1035 1033 info.hint[0].name.slen); 1036 1034 1037 1035 len += (unsigned)info.hint[0].name.slen; 1038 sess->rcmd->rbuf[len] = 0; 1036 sess->rcmd->rbuf[len] = 0; 1039 1037 } 1040 1038 } else { … … 1046 1044 sess->rcmd->cur_pos = sess->rcmd->len; 1047 1045 1048 pj_pool_release(pool); 1049 return retval; 1046 pj_pool_release(pool); 1047 return retval; 1050 1048 } 1051 1049 … … 1057 1055 pj_status_t status; 1058 1056 pj_bool_t retval = PJ_TRUE; 1059 1060 pj_pool_t *pool; 1061 pj_cli_exec_info info; 1062 1057 1058 pj_pool_t *pool; 1059 pj_cli_exec_info info; 1060 1063 1061 send_return_key(sess); 1064 1062 insert_history(sess, (char *)&sess->rcmd->rbuf); … … 1066 1064 pool = pj_pool_create(sess->pool->factory, "handle_return", 1067 1065 PJ_CLI_TELNET_POOL_SIZE, PJ_CLI_TELNET_POOL_INC, 1068 NULL); 1069 1070 status = pj_cli_sess_exec(&sess->base, (char *)&sess->rcmd->rbuf, 1066 NULL); 1067 1068 status = pj_cli_sess_exec(&sess->base, (char *)&sess->rcmd->rbuf, 1071 1069 pool, &info); 1072 1070 1073 1071 switch (status) { 1074 1072 case PJ_CLI_EINVARG: 1075 send_inv_arg(sess, &info, PJ_FALSE, PJ_FALSE); 1073 send_inv_arg(sess, &info, PJ_FALSE, PJ_FALSE); 1076 1074 break; 1077 1075 case PJ_CLI_ETOOMANYARGS: … … 1088 1086 send_prompt_str(sess); 1089 1087 break; 1090 } 1088 } 1091 1089 if (retval) { 1092 1090 sess->rcmd->rbuf[0] = 0; … … 1095 1093 } 1096 1094 1097 pj_pool_release(pool); 1098 return retval; 1095 pj_pool_release(pool); 1096 return retval; 1099 1097 } 1100 1098 … … 1106 1104 if (recv_buf_right_len(sess->rcmd)) { 1107 1105 unsigned char *data = &sess->rcmd->rbuf[sess->rcmd->cur_pos++]; 1108 telnet_sess_send2(sess, data, 1); 1106 telnet_sess_send2(sess, data, 1); 1109 1107 return PJ_TRUE; 1110 1108 } … … 1116 1114 */ 1117 1115 static pj_bool_t handle_left_key(cli_telnet_sess *sess) 1118 { 1116 { 1119 1117 static const unsigned char move_cursor_left = 0x08; 1120 1118 if (sess->rcmd->cur_pos) { … … 1151 1149 send_data.slen = sess->rcmd->cur_pos; 1152 1150 } 1153 1151 1154 1152 if (sess->rcmd->len > (unsigned)history->slen) { 1155 1153 /* Clear the command currently shown*/ … … 1159 1157 1160 1158 /* Move cursor position to the beginning of line */ 1161 pj_memset(&send_data.ptr[send_data.slen], MOVE_CURSOR_LEFT, 1159 pj_memset(&send_data.ptr[send_data.slen], MOVE_CURSOR_LEFT, 1162 1160 buf_len); 1163 1161 send_data.slen += buf_len; 1164 } 1162 } 1165 1163 /* Send data */ 1166 1164 pj_strcat(&send_data, history); … … 1175 1173 } 1176 1174 1177 static pj_status_t process_vt100_cmd(cli_telnet_sess *sess, 1175 static pj_status_t process_vt100_cmd(cli_telnet_sess *sess, 1178 1176 unsigned char *cmd) 1179 { 1177 { 1180 1178 pj_status_t status = PJ_TRUE; 1181 1179 switch (*cmd) { … … 1225 1223 } 1226 1224 1227 /* 1228 * Send a message to a telnet session 1225 /* 1226 * Send a message to a telnet session 1229 1227 */ 1230 1228 static pj_status_t telnet_sess_send(cli_telnet_sess *sess, … … 1241 1239 1242 1240 if (sess->buf_len == 0) 1243 status = pj_activesock_send(sess->asock, &sess->op_key, 1241 status = pj_activesock_send(sess->asock, &sess->op_key, 1244 1242 str->ptr, &sz, 0); 1245 /* If we cannot send now, append it at the end of the buffer 1243 /* If we cannot send now, append it at the end of the buffer 1246 1244 * to be sent later. 1247 1245 */ 1248 if (sess->buf_len > 0 || 1246 if (sess->buf_len > 0 || 1249 1247 (status != PJ_SUCCESS && status != PJ_EPENDING)) 1250 1248 { … … 1273 1271 } 1274 1272 1275 /* 1276 * Send a message to a telnet session with formatted text 1273 /* 1274 * Send a message to a telnet session with formatted text 1277 1275 * (add single linefeed character with carriage return) 1278 1276 */ … … 1288 1286 PJ_USE_EXCEPTION; 1289 1287 1290 pj_scan_init(&scanner, str->ptr, str->slen, 1288 pj_scan_init(&scanner, str->ptr, str->slen, 1291 1289 PJ_SCAN_AUTOSKIP_WS, &on_syntax_error); 1292 1290 1293 1291 str_begin = scanner.begin; 1294 1292 1295 1293 PJ_TRY { 1296 while (!pj_scan_is_eof(&scanner)) { 1297 pj_scan_get_until_ch(&scanner, '\n', &out_str); 1294 while (!pj_scan_is_eof(&scanner)) { 1295 pj_scan_get_until_ch(&scanner, '\n', &out_str); 1298 1296 str_len = (int)(scanner.curptr - str_begin); 1299 if (*scanner.curptr == '\n') { 1300 if ((str_len > 1) && (out_str.ptr[str_len-2] == '\r')) 1301 { 1297 if (*scanner.curptr == '\n') { 1298 if ((str_len > 1) && (out_str.ptr[str_len-2] == '\r')) 1299 { 1302 1300 continue; 1303 } else { 1301 } else { 1304 1302 int str_pos = (int)(str_begin - scanner.begin); 1305 1303 … … 1314 1312 pj_scan_advance_n(&scanner, 1, PJ_TRUE); 1315 1313 str_begin = scanner.curptr; 1316 } 1314 } 1317 1315 } 1318 1316 } else { … … 1355 1353 pj_mutex_unlock(tsess->smutex); 1356 1354 pj_activesock_close(tsess->asock); 1357 pj_mutex_destroy(tsess->smutex); 1355 pj_mutex_destroy(tsess->smutex); 1358 1356 pj_pool_release(tsess->pool); 1359 1357 } … … 1363 1361 { 1364 1362 cli_telnet_fe *tfe = (cli_telnet_fe *)fe; 1365 pj_cli_sess *sess; 1363 pj_cli_sess *sess; 1366 1364 1367 1365 pj_mutex_lock(tfe->mutex); … … 1371 1369 cli_telnet_sess *tsess = (cli_telnet_sess *)sess; 1372 1370 1373 sess = sess->next; 1371 sess = sess->next; 1374 1372 if (tsess->base.log_level > level) { 1375 1373 pj_str_t s; … … 1379 1377 } 1380 1378 } 1381 1379 1382 1380 pj_mutex_unlock(tfe->mutex); 1383 1381 } … … 1436 1434 pj_activesock_get_user_data(asock); 1437 1435 1438 PJ_UNUSED_ARG(op_key); 1436 PJ_UNUSED_ARG(op_key); 1439 1437 1440 1438 if (sent <= 0) { … … 1471 1469 pj_activesock_get_user_data(asock); 1472 1470 cli_telnet_fe *tfe = (cli_telnet_fe *)sess->base.fe; 1473 unsigned char *cdata = (unsigned char*)data; 1471 unsigned char *cdata = (unsigned char*)data; 1474 1472 pj_status_t is_valid = PJ_TRUE; 1475 1473 … … 1483 1481 TRACE_((THIS_FILE, "Error on data read %d", status)); 1484 1482 return PJ_FALSE; 1485 } 1483 } 1486 1484 1487 1485 pj_mutex_lock(sess->smutex); … … 1490 1488 case ST_CR: 1491 1489 sess->parse_state = ST_NORMAL; 1492 if (*cdata == 0 || *cdata == '\n') 1490 if (*cdata == 0 || *cdata == '\n') 1493 1491 pj_mutex_unlock(sess->smutex); 1494 1492 is_valid = handle_return(sess); 1495 if (!is_valid) 1493 if (!is_valid) 1496 1494 return PJ_FALSE; 1497 pj_mutex_lock(sess->smutex); 1495 pj_mutex_lock(sess->smutex); 1498 1496 break; 1499 1497 case ST_NORMAL: … … 1502 1500 } else if (*cdata == 127) { 1503 1501 is_valid = handle_backspace(sess, cdata); 1504 } else if (*cdata == 27) { 1502 } else if (*cdata == 27) { 1505 1503 sess->parse_state = ST_ESC; 1506 } else { 1504 } else { 1507 1505 if (recv_buf_insert(sess->rcmd, cdata)) { 1508 1506 if (*cdata == '\r') { … … 1519 1517 break; 1520 1518 case ST_ESC: 1521 if (*cdata == 91) { 1519 if (*cdata == 91) { 1522 1520 sess->parse_state = ST_VT100; 1523 1521 } else { … … 1598 1596 if (status != PJ_SUCCESS && status != PJ_EPENDING) { 1599 1597 TRACE_((THIS_FILE, "Error on data accept %d", status)); 1600 if (status == PJ_ESOCKETSTOP) 1601 telnet_restart(fe); 1602 1598 if (status == PJ_ESOCKETSTOP) 1599 telnet_restart(fe); 1600 1603 1601 return PJ_FALSE; 1604 } 1602 } 1605 1603 1606 1604 /* An incoming connection is accepted, create a new session */ … … 1609 1607 NULL); 1610 1608 if (!pool) { 1611 TRACE_((THIS_FILE, 1609 TRACE_((THIS_FILE, 1612 1610 "Not enough memory to create a new telnet session")); 1613 1611 return PJ_TRUE; … … 1632 1630 if (sstatus != PJ_SUCCESS) 1633 1631 goto on_exit; 1634 1632 1635 1633 sstatus = pj_activesock_create(pool, newsock, pj_SOCK_STREAM(), 1636 1634 NULL, fe->cfg.ioqueue, … … 1657 1655 send_cmd_do(sess, SUPPRESS_GA); 1658 1656 send_cmd_will(sess, TERM_ECHO); 1659 send_cmd_will(sess, STATUS); 1657 send_cmd_will(sess, STATUS); 1660 1658 send_cmd_will(sess, SUPPRESS_GA); 1661 1659 … … 1682 1680 else 1683 1681 pj_sock_close(newsock); 1684 1682 1685 1683 if (sess->smutex) 1686 1684 pj_mutex_destroy(sess->smutex); … … 1697 1695 cli_telnet_fe *fe; 1698 1696 pj_pool_t *pool; 1699 pj_status_t status; 1697 pj_status_t status; 1700 1698 1701 1699 PJ_ASSERT_RETURN(cli, PJ_EINVAL); … … 1707 1705 if (!fe) 1708 1706 return PJ_ENOMEM; 1709 1707 1710 1708 fe->base.op = PJ_POOL_ZALLOC_T(pool, struct pj_cli_front_end_op); 1711 1709 … … 1714 1712 else 1715 1713 pj_memcpy(&fe->cfg, param, sizeof(*param)); 1716 1714 1717 1715 pj_list_init(&fe->sess_head); 1718 1716 fe->base.cli = cli; … … 1722 1720 fe->pool = pool; 1723 1721 1724 if (!fe->cfg.ioqueue) { 1722 if (!fe->cfg.ioqueue) { 1725 1723 /* Create own ioqueue if application doesn't supply one */ 1726 1724 status = pj_ioqueue_create(pool, 8, &fe->cfg.ioqueue); … … 1762 1760 pj_activesock_cb asock_cb; 1763 1761 pj_sockaddr_in addr; 1764 pj_status_t status; 1762 pj_status_t status; 1765 1763 int val; 1766 1764 int restart_retry; … … 1794 1792 PJ_LOG(4,(THIS_FILE, "Address is still in use, retrying..")); 1795 1793 pj_thread_sleep(msec); 1796 } 1797 1798 if (status == PJ_SUCCESS) { 1799 int addr_len = sizeof(addr); 1794 } 1795 1796 if (status == PJ_SUCCESS) { 1797 int addr_len = sizeof(addr); 1800 1798 1801 1799 status = pj_sock_getsockname(sock, &addr, &addr_len); 1802 1800 if (status != PJ_SUCCESS) 1803 1801 goto on_exit; 1804 1805 fe->cfg.port = pj_sockaddr_in_get_port(&addr); 1802 1803 fe->cfg.port = pj_sockaddr_in_get_port(&addr); 1806 1804 1807 1805 if (fe->cfg.prompt_str.slen == 0) { 1808 1806 pj_str_t prompt_sign = {"> ", 2}; 1809 char *prompt_data = pj_pool_alloc(fe->pool, 1807 char *prompt_data = pj_pool_alloc(fe->pool, 1810 1808 pj_gethostname()->slen+2); 1811 1809 fe->cfg.prompt_str.ptr = prompt_data; … … 1813 1811 pj_strcpy(&fe->cfg.prompt_str, pj_gethostname()); 1814 1812 pj_strcat(&fe->cfg.prompt_str, &prompt_sign); 1815 } 1813 } 1816 1814 } else { 1817 1815 PJ_LOG(3, (THIS_FILE, "Failed binding the socket")); … … 1869 1867 { 1870 1868 pj_status_t status; 1871 pj_cli_sess *sess; 1869 pj_cli_sess *sess; 1872 1870 1873 1871 fe->is_quitting = PJ_TRUE; 1874 if (fe->worker_thread) { 1872 if (fe->worker_thread) { 1875 1873 pj_thread_join(fe->worker_thread); 1876 1874 } … … 1911 1909 } 1912 1910 1913 PJ_DEF(pj_status_t) pj_cli_telnet_get_info(pj_cli_front_end *fe, 1911 PJ_DEF(pj_status_t) pj_cli_telnet_get_info(pj_cli_front_end *fe, 1914 1912 pj_cli_telnet_info *info) 1915 1913 { 1916 1914 pj_sockaddr hostip; 1917 1915 pj_status_t status; 1918 cli_telnet_fe *tfe = (cli_telnet_fe*) fe; 1919 1920 PJ_ASSERT_RETURN(fe && (fe->type == PJ_CLI_TELNET_FRONT_END) && info, 1916 cli_telnet_fe *tfe = (cli_telnet_fe*) fe; 1917 1918 PJ_ASSERT_RETURN(fe && (fe->type == PJ_CLI_TELNET_FRONT_END) && info, 1921 1919 PJ_EINVAL); 1922 1920
Note: See TracChangeset
for help on using the changeset viewer.