diff --git a/TELNETasp_CNL113320.tpd b/TELNETasp_CNL113320.tpd new file mode 100644 index 0000000000000000000000000000000000000000..5a7feb67fefb87bd8002913096a5cd400b3f38e1 --- /dev/null +++ b/TELNETasp_CNL113320.tpd @@ -0,0 +1,65 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright (c) 2014 Ericsson + + All rights reserved. This program and the accompanying materials + are made available under the terms of the Eclipse Public License v1.0 + which accompanies this distribution, and is available at + http://www.eclipse.org/legal/epl-v10.html + + + File: TELNETasp_CNL113320.tpd + Description: tpd project file + Rev: R8E + Prodnr: CNL 113 320 + Updated: 2014-09-05 + Contact: http://ttcn.ericsson.se + + --> +<TITAN_Project_File_Information version="1.0"> + <ProjectName>TELNETasp_CNL113320</ProjectName> + <ReferencedProjects> + <ReferencedProject name="Abstract_Socket_CNL113384" projectLocationURI="../Common_Components/Abstract_Socket_CNL113384/Abstract_Socket_CNL113384.tpd"/> + </ReferencedProjects> + <Folders> + <FolderResource projectRelativePath="doc" relativeURI="doc"/> + <FolderResource projectRelativePath="src" relativeURI="src"/> + </Folders> + <Files> + <FileResource projectRelativePath="doc/TELNETasp_CNL113320_FS.pdf" relativeURI="doc/TELNETasp_CNL113320_FS.pdf"/> + <FileResource projectRelativePath="doc/TELNETasp_CNL113320_PRI.pdf" relativeURI="doc/TELNETasp_CNL113320_PRI.pdf"/> + <FileResource projectRelativePath="doc/TELNETasp_CNL113320_UG.pdf" relativeURI="doc/TELNETasp_CNL113320_UG.pdf"/> + <FileResource projectRelativePath="src/TELNETasp_PT.cc" relativeURI="src/TELNETasp_PT.cc"/> + <FileResource projectRelativePath="src/TELNETasp_PT.hh" relativeURI="src/TELNETasp_PT.hh"/> + <FileResource projectRelativePath="src/TELNETasp_PortType.ttcn" relativeURI="src/TELNETasp_PortType.ttcn"/> + </Files> + <ActiveConfiguration>Default</ActiveConfiguration> + <Configurations> + <Configuration name="Default"> + <ProjectProperties> + <MakefileSettings> + <generateInternalMakefile>true</generateInternalMakefile> + <GNUMake>true</GNUMake> + <incrementalDependencyRefresh>true</incrementalDependencyRefresh> + <targetExecutable>bin/TELNETasp_CNL113320</targetExecutable> + </MakefileSettings> + <LocalBuildSettings> + <workingDirectory>bin</workingDirectory> + </LocalBuildSettings> + <NamingCoventions> + <enableProjectSpecificSettings>true</enableProjectSpecificSettings> + <externalFunction>.*</externalFunction> + <formalParameter>.*</formalParameter> + </NamingCoventions> + </ProjectProperties> + <FolderProperties> + <FolderResource> + <FolderPath>doc</FolderPath> + <FolderProperties> + <ExcludeFromBuild>true</ExcludeFromBuild> + </FolderProperties> + </FolderResource> + </FolderProperties> + </Configuration> + </Configurations> +</TITAN_Project_File_Information> diff --git a/demo/TELNETasp_CNL113320_demo.tpd b/demo/TELNETasp_CNL113320_demo.tpd new file mode 100644 index 0000000000000000000000000000000000000000..7d827b4c1fe0e894ec11df5d1f6a46c594f2f88e --- /dev/null +++ b/demo/TELNETasp_CNL113320_demo.tpd @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright (c) 2014 Ericsson + + All rights reserved. This program and the accompanying materials + are made available under the terms of the Eclipse Public License v1.0 + which accompanies this distribution, and is available at + http://www.eclipse.org/legal/epl-v10.html + --> +<TITAN_Project_File_Information version="1.0"> + <ProjectName>TELNETasp_CNL113320_demo</ProjectName> + <ReferencedProjects> + <ReferencedProject name="TELNETasp_CNL113320" projectLocationURI="../TELNETasp_CNL113320.tpd"/> + </ReferencedProjects> + <Folders> + <FolderResource projectRelativePath="demo" relativeURI=""/> + </Folders> + <Files> + <FileResource projectRelativePath="demo/TELNETasp_echo.cfg" relativeURI="TELNETasp_echo.cfg"/> + <FileResource projectRelativePath="demo/TELNETasp_echo.ttcn" relativeURI="TELNETasp_echo.ttcn"/> + </Files> + <ActiveConfiguration>Default</ActiveConfiguration> + <Configurations> + <Configuration name="Default"> + <ProjectProperties> + <MakefileSettings> + <generateInternalMakefile>true</generateInternalMakefile> + <GNUMake>true</GNUMake> + <incrementalDependencyRefresh>true</incrementalDependencyRefresh> + <targetExecutable>bin/TELNETasp_CNL113320_demo</targetExecutable> + </MakefileSettings> + <LocalBuildSettings> + <workingDirectory>bin</workingDirectory> + </LocalBuildSettings> + <NamingCoventions> + <enableProjectSpecificSettings>true</enableProjectSpecificSettings> + <globalPort>.*</globalPort> + <localVariable>.*</localVariable> + <localTimer>.*</localTimer> + <formalParameter>.*</formalParameter> + </NamingCoventions> + </ProjectProperties> + </Configuration> + </Configurations> +</TITAN_Project_File_Information> diff --git a/demo/TELNETasp_echo.cfg b/demo/TELNETasp_echo.cfg new file mode 100755 index 0000000000000000000000000000000000000000..3d30b91fc0234ec85edd8f636931d9e0c9352942 --- /dev/null +++ b/demo/TELNETasp_echo.cfg @@ -0,0 +1,58 @@ +/****************************************************************************** +* Copyright (c) 2004, 2014 Ericsson AB +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v10.html +* +* Contributors: +* Tibor Csondes - initial implementation and initial documentation +* Akos Cserveni +* Elemer Lelik +* Gabor Szalai +* Gabor Tatarka +* Gergely Futo +* Istvan Sandor +* Peter Dimitrov +* Peter Kremer +* Tibor Bende +* Zoltan Medve +******************************************************************************/ +[LOGGING] +#LogFile := "logs/%l/%e.%h-%t%r.%s" +FileMask := LOG_ALL | DEBUG +ConsoleMask := ERROR | WARNING | TESTCASE | STATISTICS | PORTEVENT | DEBUG +LogSourceInfo := Yes + +[MODULE_PARAMETERS] +//MML.par_MMLEncDec_debug:=false; + +[TESTPORT_PARAMETERS] +*.*.DEBUG := "yes" +system.T_Server_PCO.CTRL_PORTNUM := "1488" +system.T_Server_PCO.CTRL_LOGIN_SKIPPED := "no" +system.T_Server_PCO.CTRL_USERNAME_CLIENT := "ezolmed" +system.T_Server_PCO.CTRL_PASSWORD_CLIENT := "ezolmed" +system.T_Server_PCO.CTRL_SERVER_PROMPT := "ezolm >" +system.T_Server_PCO.CTRL_MODE := "server" + +system.T_Client_PCO.CTRL_HOSTNAME := "localhost" +system.T_Client_PCO.CTRL_PORTNUM := "1488" +system.T_Client_PCO.CTRL_USERNAME := "ezolmed" +system.T_Client_PCO.CTRL_PASSWORD := "ezolmed" +system.T_Client_PCO.CTRL_READMODE := "buffered" +system.T_Client_PCO.CTRL_LOGIN_SKIPPED := "no" +system.T_Client_PCO.CTRL_DETECT_SERVER_DISCONNECTED := "yes" +system.T_Client_PCO.CTRL_MODE := "client" +system.T_Client_PCO.RAW_REGEX_PROMPT1 := "^(.*)(ezolm >)(.*)$" +*.*.empty_echo := "yes" + + +[MAIN_CONTROLLER] +TCPPort := 9034 +//NumHCs := 1 + + +[EXECUTE] +TELNETasp_echo.control + diff --git a/demo/TELNETasp_echo.ttcn b/demo/TELNETasp_echo.ttcn new file mode 100644 index 0000000000000000000000000000000000000000..3db9e2e036d60d807543c17775a7db835de200b6 --- /dev/null +++ b/demo/TELNETasp_echo.ttcn @@ -0,0 +1,153 @@ +/****************************************************************************** +* Copyright (c) 2004, 2014 Ericsson AB +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v10.html +* +* Contributors: +* Tibor Csondes - initial implementation and initial documentation +* Akos Cserveni +* Elemer Lelik +* Gabor Szalai +* Gabor Tatarka +* Gergely Futo +* Istvan Sandor +* Peter Dimitrov +* Peter Kremer +* Tibor Bende +* Zoltan Medve +******************************************************************************/ + +module TELNETasp_echo { +import from TELNETasp_PortType all; + + +template charstring t_pattern(charstring vl_pattern) := pattern vl_pattern; + + +type component TELNETasp_CT { + port TELNETasp_PT T_Client_PCO; + port TELNETasp_PT T_Server_PCO; +} + +altstep as_Timeout(timer p_t) runs on TELNETasp_CT { + [] p_t.timeout { + log("Your time is up! I am not waitig for you anymore!"); + } +}//altstep + + +function f_server() runs on TELNETasp_CT { + map(self:T_Server_PCO, system:T_Server_PCO); + var charstring msg; + timer t := 3.0; + + t.start; + + alt { + + [] T_Server_PCO.receive("ls") { + t.stop; + T_Server_PCO.send("ls\n/\n/bin\n/tmp"); + t.start; + repeat; + } + + [] T_Server_PCO.receive(charstring:?) -> value msg { + t.stop; + T_Server_PCO.send(msg); + t.start; + repeat; + } + + [] T_Server_PCO.receive {repeat;} + + [] T_Client_PCO.receive { + t.stop; + log("Client port received data on server machine"); + setverdict (fail); + } + + [] as_Timeout(t); + + }//alt + + unmap(self:T_Server_PCO, system:T_Server_PCO); +}//server end + + +function f_client() runs on TELNETasp_CT { + map(self:T_Client_PCO, system:T_Client_PCO); + timer t := 0.1; + + t.start; + T_Client_PCO.send("cd"); + as_client_receive(t, "", pass); + + t.start; + T_Client_PCO.send("ls"); + as_client_receive(t, "/\n/bin\n/tmp", pass); + + unmap(self:T_Client_PCO, system:T_Client_PCO); +}//client end + + +altstep as_client_receive(timer vl_t, charstring vl_pattern, verdicttype vl_verdict) runs on TELNETasp_CT { +var charstring msg; + + + [] T_Client_PCO.receive(t_pattern(vl_pattern)) -> value msg { + vl_t.stop; + setverdict(vl_verdict); + log("Message: " & msg); + vl_t.start; + repeat; + } + + [] T_Client_PCO.receive { + vl_t.stop; + log("Other message type received"); + vl_t.start; + repeat; + } + + [] T_Server_PCO.receive { + vl_t.stop; + log("Server port received data on client machine"); + setverdict(fail); + } + + [] as_Timeout(vl_t); + +}//as receive + + + +testcase tc_01() runs on TELNETasp_CT { + log("tc_01 test started"); + + var TELNETasp_CT server, client; + + server := TELNETasp_CT.create("my server"); + client := TELNETasp_CT.create("my client"); + + server.start(f_server()); + client.start(f_client()); + + all component.done + + setverdict(pass); + + + log("tc_01 test finished"); +} + + +control{ + execute(tc_01()); +} + + +} + diff --git a/doc/15517-CNL113320_EN_J_PDFV1R5.pdf b/doc/15517-CNL113320_EN_J_PDFV1R5.pdf new file mode 100644 index 0000000000000000000000000000000000000000..49c14d178c294df8e192d2313da1f0d9424f28d4 Binary files /dev/null and b/doc/15517-CNL113320_EN_J_PDFV1R5.pdf differ diff --git a/doc/19817-CNL113320_EN_L_PDFV1R5.pdf b/doc/19817-CNL113320_EN_L_PDFV1R5.pdf new file mode 100644 index 0000000000000000000000000000000000000000..31bd252289cd77cd6db96582f5acc60d4368a02d Binary files /dev/null and b/doc/19817-CNL113320_EN_L_PDFV1R5.pdf differ diff --git a/src/TELNETasp_PT.cc b/src/TELNETasp_PT.cc new file mode 100644 index 0000000000000000000000000000000000000000..7a5bf0f140ad928f8efaf9a9b5ccd47a8853006b --- /dev/null +++ b/src/TELNETasp_PT.cc @@ -0,0 +1,2148 @@ +/****************************************************************************** +* Copyright (c) 2004, 2014 Ericsson AB +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v10.html +* +* Contributors: +* Tibor Csondes - initial implementation and initial documentation +* Akos Cserveni +* Elemer Lelik +* Gabor Szalai +* Gabor Tatarka +* Gergely Futo +* Istvan Sandor +* Peter Dimitrov +* Peter Kremer +* Tibor Bende +* Zoltan Medve +******************************************************************************/ +// +// File: TELNETasp_PT.cc +// Description: TELNET testport source file +// Rev: R8E +// Prodnr: CNL 113 320 +// + +#include "TELNETasp_PT.hh" + +#define TELCMDS 1 +#define TELOPTS 1 +#include <arpa/telnet.h> +#include <string.h> +#include <errno.h> + +#include <poll.h> + +#if ( defined TTCN3_VERSION_MONOTONE ) && ! ( TTCN3_VERSION_MONOTONE <= 1100099) +#include "pattern.hh" +char* TTCN_pattern_to_regexp_telnet(const char* patt){ + return TTCN_pattern_to_regexp(patt); +} +#else +#ifndef TTCN_pattern_to_regexp +extern char* TTCN_pattern_to_regexp(const char*,int); +char* TTCN_pattern_to_regexp_telnet(const char* patt){ + return TTCN_pattern_to_regexp(patt,1); +} +#endif +#endif + + +namespace TELNETasp__PortType { +TELNETasp__PT::TELNETasp__PT(const char *par_port_name) + : TELNETasp__PT_BASE(par_port_name), window_size(par_port_name) +{ +dont_close_fd=-1; + ctrl_hostname = NULL; + ctrl_portnum = 0; + ctrl_username = NULL; + ctrl_password = NULL; + ctrl_domain = NULL; + ctrl_readmode = READMODE_BUFFERED; + ctrl_login_skipped = false; + ctrl_detect_server_disconnected = false; + ctrl_detect_connection_establishment_result = false; + ctrl_client_cleanup_linefeed = true; + ctrl_terminal_type = NULL; + ctrl_echo = false; + ctrl_CRLF = false; + echobuf = ""; + config_finished = false; + asp_params = NULL; + map_poll_timeout=10000; // 10 sec = 10000 millisec + ctrl_username_client = NULL; + ctrl_password_client = NULL; + ctrl_server_prompt = NULL; + server_mode_def = false; + ctrl_server_attach_prompt = true; + ctrl_detect_client_disconnected = false; + ctrl_server_failsafe_sending = false; + port_mapped = false; + fd_server = -1; + isClientLoggedIn = false; + isRawRegexpPrompt = false; + pass_prompt_send = false; + emptyEcho = false; + suppressed = false; + login_incorrect = false; + ctrl_password_prompt = NULL; + ctrl_loginname_prompt = NULL; + + debugAllowed = false; +} + +TELNETasp__PT::~TELNETasp__PT() +{ + reset_configuration(); +} + +void TELNETasp__PT::set_parameter(const char *parameter_name, + const char *parameter_value) +{ + if (config_finished) { + reset_configuration(); + config_finished = false; + } + + if(strcmp( "MAP_RECV_TIMEOUT", parameter_name) == 0) { + map_poll_timeout = atoi ( parameter_value ); + log_debug( + "%s: Reading testport parameter: MAP_RECV_TIMEOUT = %d", + port_name, map_poll_timeout ); + } + + + else if(strcmp( "CTRL_HOSTNAME", parameter_name) == 0) + InitStrPar(ctrl_hostname, parameter_name, parameter_value); + else if(strcmp( "CTRL_PORTNUM", parameter_name) == 0) { + ctrl_portnum = atoi ( parameter_value ); + log_debug( + "%s: Reading testport parameter: CTRL_PORTNUM = %d", + port_name, ctrl_portnum ); + } + + else if(strcmp("CTRL_USERNAME", parameter_name) == 0) + InitStrPar(ctrl_username, parameter_name, parameter_value); + + else if(strcmp("CTRL_PASSWORD", parameter_name) == 0) { + //InitStrPar(ctrl_password, parameter_name, parameter_value); + InitStrPar(ctrl_password, NULL, parameter_value); + log_debug( + "%s: Reading testport parameter: CTRL_PASSWORD", port_name); + } + + else if(strcmp("CTRL_DOMAIN", parameter_name) == 0) + InitStrPar(ctrl_domain, parameter_name, parameter_value); + + else if(strcmp("CTRL_READMODE", parameter_name) == 0) { + log_debug( "%s: Reading testport parameter: %s = %s", + port_name, parameter_name, parameter_value ); + if(strcmp(parameter_value, "buffered") == 0) + ctrl_readmode = READMODE_BUFFERED; + else if(strcmp(parameter_value, "unbuffered") == 0) + ctrl_readmode = READMODE_UNBUFFERED; + else TTCN_error("Invalid value for: CTRL_READMODE"); + } + + else if(strncmp("PROMPT", parameter_name, 6) == 0) { + if(strlen(parameter_name) < 7) TTCN_error("%s: PROMPT " + "parameters should be given as PROMPT<number> := " + "\"value\".", port_name); + errno = 0; + size_t prompt_id = atoi(parameter_name + 6); + if(errno) TTCN_error("%s: error converting string \"%s\" in parameter " + "name \"%s\" to number.", port_name, parameter_name + 6, + parameter_name); + if(strlen(parameter_value)!=0) { + log_debug( "%s: Reading testport parameter: " + "%s = %s", port_name, parameter_name, parameter_value ); + prompt_list.set_prompt(prompt_id, parameter_value, false); + } else + TTCN_error("PROMPT parameter must contain at least one character"); + } + + else if(strncmp("REGEX_PROMPT", parameter_name, 12) == 0) { + if(strlen(parameter_name) < 13) TTCN_error("%s: REGEX_PROMPT " + "parameters should be given as REGEX_PROMPT<number> := " + "\"value\".", port_name); + errno = 0; + size_t prompt_id = atoi(parameter_name + 12); + if(errno) TTCN_error("%s: error converting string \"%s\" in parameter " + "name \"%s\" to number.", port_name, parameter_name + 12, + parameter_name); + if(strlen(parameter_value)!=0) { + log_debug( "%s: Reading testport parameter: " + "%s = %s", port_name, parameter_name, parameter_value ); + prompt_list.set_prompt(prompt_id, parameter_value, true); + } else + TTCN_error("REGEX_PROMPT parameter must contain at least one character"); + } + + else if(strncmp("RAW_REGEX_PROMPT", parameter_name, 16) == 0) { + if(strlen(parameter_name) < 16) TTCN_error("%s: REGEX_PROMPT " + "parameters should be given as RAW_REGEX_PROMPT<number> := " + "\"value\".", port_name); + errno = 0; + size_t prompt_id = atoi(parameter_name + 16); + if(errno) TTCN_error("%s: error converting string \"%s\" in parameter " + "name \"%s\" to number.", port_name, parameter_name + 12, + parameter_name); + if(strlen(parameter_value)!=0) { + log_debug( "%s: Reading testport parameter: " + "%s = %s", port_name, parameter_name, parameter_value ); + prompt_list.set_prompt(prompt_id, parameter_value, true,true); + } else + TTCN_error("REGEX_PROMPT parameter must contain at least one character"); + } + + else if(strcmp("API_REGEXP_PROMPT_MODE", parameter_name) == 0) { + log_debug( "%s: Reading testport parameter: %s = %s", + port_name, parameter_name, parameter_value ); + if(strcasecmp(parameter_value, "raw") == 0) + isRawRegexpPrompt = true; + else if(strcasecmp(parameter_value, "normal") == 0) + isRawRegexpPrompt = false; + else TTCN_error( "Invalid value for: API_REGEXP_PROMPT_MODE" ); + } + + else if(strcmp("CTRL_LOGIN_SKIPPED", parameter_name) == 0) { + log_debug( "%s: Reading testport parameter: %s = %s", + port_name, parameter_name, parameter_value ); + if(strcasecmp(parameter_value, "yes") == 0) + ctrl_login_skipped = true; + else if(strcasecmp(parameter_value, "no") == 0) + ctrl_login_skipped = false; + else TTCN_error( "Invalid value for: CTRL_LOGIN_SKIPPED" ); + } + + else if(strcmp("CTRL_DETECT_SERVER_DISCONNECTED", parameter_name) == 0) { + log_debug( "%s: Reading testport parameter: %s = %s", + port_name, parameter_name, parameter_value ); + if(strcasecmp(parameter_value, "yes") == 0) + ctrl_detect_server_disconnected = true; + else if(strcasecmp(parameter_value, "no") == 0) + ctrl_detect_server_disconnected = false; + else TTCN_error("Invalid value for: CTRL_DETECT_SERVER_DISCONNECTED"); + } + + else if(strcmp("CTRL_DETECT_CONNECTION_ESTABLISHMENT_RESULT", parameter_name) == 0) { + log_debug( "%s: Reading testport parameter: %s = %s", + port_name, parameter_name, parameter_value ); + if(strcasecmp(parameter_value, "yes") == 0) + ctrl_detect_connection_establishment_result = true; + else if(strcasecmp(parameter_value, "no") == 0) + ctrl_detect_connection_establishment_result = false; + else TTCN_error("Invalid value for: CTRL_DETECT_CONNECTION_ESTABLISHMENT_RESULT"); + } + + + else if(strcmp("CTRL_TERMINAL_TYPE", parameter_name) == 0) + InitStrPar( ctrl_terminal_type, parameter_name, parameter_value ); + + else if(strcmp("CTRL_ECHO", parameter_name) == 0) { + log_debug( "%s: Reading testport parameter: %s = %s", + port_name, parameter_name, parameter_value ); + if(strcasecmp(parameter_value, "yes") == 0) + ctrl_echo = true; + else if(strcasecmp(parameter_value, "no") == 0) + ctrl_echo = false; + else TTCN_error( "Invalid value for: CTRL_ECHO" ); + } + + else if(strcmp("CTRL_CRLF", parameter_name) == 0) { + log_debug( "%s: Reading testport parameter: %s = %s", + port_name, parameter_name, parameter_value ); + if(strcasecmp(parameter_value, "yes") == 0) + ctrl_CRLF = true; + else if(strcasecmp(parameter_value, "no") == 0) + ctrl_CRLF = false; + else TTCN_error( "Invalid value for: CTRL_CRLF" ); + } + + else if(strcmp("CTRL_WINDOW_WIDTH", parameter_name) == 0) { + window_size.set_width(atoi(parameter_value)); + log_debug( + "%s: Reading testport parameter: CTRL_WINDOW_WIDTH = %d", + port_name, window_size.get_width() ); + } + + else if(strcmp("CTRL_WINDOW_HEIGHT", parameter_name) == 0) { + window_size.set_height(atoi(parameter_value)); + log_debug( + "%s: Reading testport parameter: CTRL_WINDOW_HEIGHT = %d", + port_name, window_size.get_height() ); + } + else if (strcmp("CTRL_USERNAME_CLIENT", parameter_name) == 0) + InitStrPar(ctrl_username_client, parameter_name, parameter_value); + else if (strcmp("CTRL_PASSWORD_CLIENT", parameter_name) == 0) + InitStrPar(ctrl_password_client, parameter_name, parameter_value); + else if ( strcmp(parameter_name, "CTRL_MODE") == 0){ + log_debug("%s: Reading testport parameter: %s = %s", + port_name, parameter_name, parameter_value ); + server_mode_def = true; + if (strcmp(parameter_value, "server") == 0) + server_mode = true; + else if (strcmp(parameter_value, "client") == 0) + server_mode = false; + else TTCN_error("Invalid value for: CTRL_MODE"); + } + else if (strcmp(parameter_name, "CTRL_SERVER_PROMPT") == 0) + InitStrPar(ctrl_server_prompt, parameter_name, parameter_value); + else if (strcmp(parameter_name, "CTRL_PASSWORD_PROMPT") == 0) + InitStrPar(ctrl_password_prompt, parameter_name, parameter_value); + else if (strcmp(parameter_name, "CTRL_LOGINNAME_PROMPT") == 0) + InitStrPar(ctrl_loginname_prompt, parameter_name, parameter_value); + + + else if (strcmp(parameter_name, "CTRL_CLIENT_CLEANUP_LINEFEED") == 0){ + log_debug( "%s: Reading testport parameter: %s = %s", + port_name, parameter_name, parameter_value ); + if(strcasecmp(parameter_value, "yes") == 0) + ctrl_client_cleanup_linefeed = true; + else if(strcasecmp(parameter_value, "no") == 0) + ctrl_client_cleanup_linefeed = false; + else TTCN_error( "Invalid value for: CTRL_CLIENT_CLEANUP_LINEFEED" ); + } + + else if(strcmp(parameter_name, "CTRL_SERVER_ATTACH_PROMPT") == 0){ + log_debug( "%s: Reading testport parameter: %s = %s", + port_name, parameter_name, parameter_value ); + if(strcasecmp(parameter_value, "yes") == 0) + ctrl_server_attach_prompt = true; + else if(strcasecmp(parameter_value, "no") == 0) + ctrl_server_attach_prompt = false; + else TTCN_error( "Invalid value for: CTRL_SERVER_ATTACH_PROMPT" ); + } + + else if(strcmp(parameter_name, "CTRL_DETECT_CLIENT_DISCONNECTED") == 0){ + log_debug( "%s: Reading testport parameter: %s = %s", + port_name, parameter_name, parameter_value ); + if(strcasecmp(parameter_value, "yes") == 0) + ctrl_detect_client_disconnected = true; + else if(strcasecmp(parameter_value, "no") == 0) + ctrl_detect_client_disconnected = false; + else TTCN_error( "Invalid value for: CTRL_DETECT_CLIENT_DISCONNECTED" ); + } + + else if(strcmp(parameter_name, "CTRL_SERVER_FAILSAFE_SENDING") == 0){ + log_debug( "%s: Reading testport parameter: %s = %s", + port_name, parameter_name, parameter_value ); + if(strcasecmp(parameter_value, "yes") == 0) + ctrl_server_failsafe_sending = true; + else if(strcasecmp(parameter_value, "no") == 0) + ctrl_server_failsafe_sending = false; + else TTCN_error( "Invalid value for: CTRL_SERVER_FAILSAFE_SENDING" ); + } + + + else if (!strcmp(parameter_name, "DEBUG")) { + log_debug( "%s: Reading testport parameter: %s = %s", + port_name, parameter_name, parameter_value ); + if(strcasecmp(parameter_value, "yes") == 0) { + debugAllowed = true; + window_size.set_debug(true); + prompt_list.set_debug(true); + } + else if(strcasecmp(parameter_value, "no") == 0) { + debugAllowed = false; + window_size.set_debug(false); + prompt_list.set_debug(false); + } + else TTCN_error( "Invalid value for: DEBUG" ); + } + + else if (strcmp(parameter_name, "empty_echo") == 0 ) { + log_debug("%s: Reading testport parameter: %s = %s", port_name, parameter_name, parameter_value); + if (strcmp(parameter_value, "yes") == 0) { + emptyEcho = true; + } else { + log_debug("%s wasn't yes -> empty echo disabled.", parameter_value); + } + } + + else TTCN_warning("%s: unknown parameter: %s", port_name, parameter_name); +} + +/*void TELNETasp__PT::Event_Handler(const fd_set *read_fds, + const fd_set *write_fds, const fd_set *error_fds, + double time_since_last_call) +*/ +void TELNETasp__PT::Handle_Fd_Event_Readable(int fd) +{ +log_debug("Handle_Fd_Event_Readable(int fd=%d)",fd); +if (server_mode){ + if( fd==fd_server){ //incoming connection arrived + char addr[INET_ADDRSTRLEN]; + struct sockaddr_in client; +#if defined SOLARIS8 || LINUX || FREEBSD + socklen_t +#else /* SOLARIS or WIN32 */ + int +#endif + addr_len = sizeof(client); + + if ( (nvtsock = accept(fd_server, (struct sockaddr*)&client, &addr_len)) < 0 ) + TTCN_error("Error accepting connection"); + + inet_ntop(AF_INET, &(client.sin_addr), addr, sizeof(addr)); + log_debug("Accepting connection from: %s on socket %d", addr , nvtsock); + Handler_Remove_Fd_Read(fd_server); + Handler_Add_Fd_Read(nvtsock); +// FD_CLR(fd_server, &readfds); +// FD_SET(nvtsock, &readfds); +// Install_Handler(&readfds, NULL, NULL, 0.0); + + if (ctrl_login_skipped){ + if(ctrl_server_attach_prompt){ + if ( ::send(nvtsock, "\r\n", 2 , 0) < 0) + TTCN_error("TCP send failed"); + if ( ::send(nvtsock, ctrl_server_prompt, strlen(ctrl_server_prompt), 0) < 0) + TTCN_error("TCP send failed"); + } + incoming_message(INTEGER(1)); + isClientLoggedIn = true; + if (fcntl(nvtsock, F_SETFL, O_NONBLOCK) == -1) { + TTCN_error("fcntl(nvtsock, F_SETFL, O_NONBLOCK) failed: %d,%s",errno, strerror(errno)); + } + return; + } + //starting login procedure + if ( ::send(nvtsock,"\r\n", 2,0 ) < 0) + TTCN_error("TCP send failed"); + + if ( ::send(nvtsock,ctrl_loginname_prompt, strlen(ctrl_loginname_prompt),0 ) < 0) + TTCN_error("TCP send failed"); + } else if (fd==nvtsock){ + recv_msg_from_client(nvtsock); + } else {TTCN_error("Invalid file descriptor to read %d",fd);} +} else { + +/* int res=RecvClrMsg(); // workaround for a strange issue + if(res == -2){ + log_debug("It's kind of fun to do impossible. Enjoy it now."); + return; + }*/ + if (RecvClrMsg() < 0) { + if(ctrl_detect_server_disconnected) return; + else TTCN_error ("*** Socket error or the server closed the connection " + "(in Event_Handler)."); + } + + while(true) { + size_t echo_pos; + if(ctrl_echo==false && + buf_strcmp((const char*)echobuf, ttcn_buf.get_data(), + ttcn_buf.get_len(), echo_pos) && echo_pos == 0) { + /*log_buffer("Before echo proc.:", ttcn_buf.get_data(), + ttcn_buf.get_len());*/ + + ttcn_buf.set_pos(strlen((const char*)echobuf)); + ttcn_buf.cut(); + echobuf = ""; + + suppressed = true; + + /*log_buffer("After echo proc.:", ttcn_buf.get_data(), + ttcn_buf.get_len());*/ + + if(!ttcn_buf.get_len()) return; + } + + const unsigned char * bufptr = ttcn_buf.get_data(); + int prompt_len; + bool nl_found = false, prompt_found = false; + size_t prompt_start_pos_prompt, prompt_start_pos_nl; + + if (ctrl_readmode == READMODE_UNBUFFERED) { + nl_found = buf_strcmp("\n", bufptr, ttcn_buf.get_len(), + prompt_start_pos_nl); + if ((prompt_len = isPrompt(prompt_start_pos_prompt))>=0) + prompt_found = true; + + /*If there is neither new line nor prompt in the buffer then simply + return and wait for more data*/ + if(!nl_found && !prompt_found) + return; + + else if((nl_found && !prompt_found) || + (nl_found && prompt_found && prompt_start_pos_nl < + prompt_start_pos_prompt)) { + if(prompt_start_pos_nl){ + suppressed = false; + incoming_message(CHARSTRING(prompt_start_pos_nl, + (const char*)bufptr)); + } + ttcn_buf.set_pos(prompt_start_pos_nl+1); + ttcn_buf.cut(); + } else { + //First send the data previous to the prompt ... + if(prompt_start_pos_prompt) { + suppressed = false; + incoming_message(CHARSTRING(prompt_start_pos_prompt, + (const char*)bufptr)); + ttcn_buf.set_pos(prompt_start_pos_prompt); + ttcn_buf.cut(); + } + //... and then send the prompt itself + bufptr = ttcn_buf.get_data(); + suppressed = false; + incoming_message(CHARSTRING(prompt_len, + (const char*)bufptr)); + ttcn_buf.set_pos(prompt_len); + ttcn_buf.cut(); + } + nl_found = false; + prompt_found = false; + + if(!ttcn_buf.get_len()) return; + } else { // READMODE_BUFFERED + /* only send if the last line is prompt */ + if ((prompt_len = isPrompt(prompt_start_pos_prompt))>=0) { + // promptlen==0 is not checked here since it must contain + // at least 1 character, that is checked in set_parameter() + //First send the data previous to the prompt ... + log_debug("Prompt start pos: %d", prompt_start_pos_prompt); + if(prompt_start_pos_prompt) { + int msg_end_pos = prompt_start_pos_prompt; + if(ctrl_client_cleanup_linefeed){ + while(msg_end_pos>0) { + if(bufptr[msg_end_pos-1]!='\n') break; + else msg_end_pos--; + } + } + if(msg_end_pos){ + suppressed = false; + incoming_message(CHARSTRING(msg_end_pos, + (const char*)bufptr)); + } + ttcn_buf.set_pos(prompt_start_pos_prompt); + ttcn_buf.cut(); + } + + if (emptyEcho && suppressed){ + suppressed = false; + incoming_message(""); + } + + //... and then send the prompt itself + bufptr = ttcn_buf.get_data(); + suppressed = false; + incoming_message(CHARSTRING(prompt_len, (const char*)bufptr)); + ttcn_buf.set_pos(prompt_len); + ttcn_buf.cut(); + if(!ttcn_buf.get_len()) return; + } + return; + } + } // while + } // server-mode else (client mode) +} // TELNETasp__PT::Handle_Fd_Event_Readable + +void TELNETasp__PT::user_map(const char *system_port) +{ + +set_asp_params(); +config_finished = true; + suppressed = false; + +if(ctrl_portnum == 0) + TTCN_error("Missing mandatory parameter: CTRL_PORTNUM"); +if (!server_mode_def){ + TTCN_warning("Mode is not defined. Test Port will operate in client mode operation."); + server_mode = false; +} + +struct sockaddr_in address; +int enabled = 1; + +if (server_mode){ + nvtsock=-1; + if (port_mapped){ + TTCN_warning("%s: user_map() was called to a mapped port", port_name); + return; + } + + if(ctrl_server_prompt == NULL) + TTCN_error("Missing mandatory parameter: CTRL_SERVER_PROMPT"); + + if (ctrl_username_client == NULL && !ctrl_login_skipped) + TTCN_error("Missing mandatory parameter: CTRL_USERNAME_CLIENT"); + if (ctrl_password_client == NULL && !ctrl_login_skipped) + TTCN_error("Missing mandatory parameter: CTRL_PASSWORD_CLIENT"); + + if (ctrl_loginname_prompt == NULL){ + if ((ctrl_loginname_prompt = (char*)malloc(8*sizeof(char))) == NULL ) + TTCN_error("Not enough memory"); + strcpy(ctrl_loginname_prompt, "login: "); + } + + if (ctrl_password_prompt == NULL){ + if ((ctrl_password_prompt = (char*)malloc(11*sizeof(char))) == NULL ) + TTCN_error("Not enough memory"); + strcpy(ctrl_password_prompt, "password: "); + } + + if ((fd_server = socket(AF_INET, SOCK_STREAM, 0)) < 0) + TTCN_error("Socket creation failed"); + + log_debug( "%s: Server socket created: %d", port_name, fd_server); + if ( setsockopt(fd_server, SOL_SOCKET, SO_REUSEADDR, &enabled, sizeof(int)) < 0) + TTCN_error("setsockopt(SO_REUSEADDR) failed"); + + address.sin_family = AF_INET; + address.sin_port = htons(ctrl_portnum); + address.sin_addr.s_addr = htons(INADDR_ANY); + memset(&(address.sin_zero), '\0', 8); + + if ( bind(fd_server, (struct sockaddr*)&address, sizeof(address)) < 0 ) + TTCN_error("Error bindig socket to port %d", ctrl_portnum); + if (listen(fd_server,1) < 0 ) + TTCN_error("Error listening on port %d", ctrl_portnum); + +// FD_ZERO(&readfds); +// FD_SET(fd_server, &readfds); +// Install_Handler(&readfds, NULL, NULL, 0.0); + Handler_Add_Fd_Read(fd_server); + + log_debug( "%s: Listening on port %d for incoming connection", port_name, ctrl_portnum); + port_mapped = true; +}else{ + //char* nvtmsg; + size_t prompt_start_pos = 0; + + if(ctrl_hostname == NULL) + TTCN_error("Missing mandatory parameter: CTRL_HOSTNAME"); + if(ctrl_username == NULL && !ctrl_login_skipped) + TTCN_error("Missing mandatory parameter: CTRL_USERNAME"); + if(ctrl_password == NULL && !ctrl_login_skipped) + TTCN_error("Missing mandatory parameter: CTRL_PASSWORD"); + if(prompt_list.nof_prompts() == 0) + TTCN_error("Missing mandatory parameter: at least one PROMPT or " + "REGEX_PROMPT parameter must be provided"); + prompt_list.check(port_name); + + nvtsock = socket( AF_INET, SOCK_STREAM, 0 ); + if (nvtsock < 0) TTCN_error("Socket creation failed"); + log_debug( "%s: Client socket created: %d", port_name, nvtsock); + + if((he = gethostbyname(ctrl_hostname))==NULL) + TTCN_error("Unable to resolve hostname: %s", ctrl_hostname); + + if(setsockopt(nvtsock, SOL_SOCKET, SO_REUSEADDR, (const char *)&enabled, + sizeof(int)) == -1) + TTCN_error("setsockopt(SO_REUSEADDR) failed"); + + memcpy(&address.sin_addr, he->h_addr_list[0], he->h_length); + address.sin_family = AF_INET; + address.sin_port = htons(ctrl_portnum); + + // workaround for WinSock bug (For Cygwin) + int retries = 0; + while (connect(nvtsock, (struct sockaddr*)&address, sizeof(address))<0){ + + if (errno != EADDRINUSE) { + if(ctrl_detect_connection_establishment_result) { + break; + } else { + TTCN_error( "Error connecting %s", ctrl_hostname ); + break; + } + } + if (++retries > 18) { + if(ctrl_detect_connection_establishment_result) { + break; + } else { + TTCN_error( "Error connecting %s. Address already in use.", ctrl_hostname ); + break; + } + } + log_debug( "%s: WinSock EADDRINUSE bug" + " workaround: %i. retry", port_name, retries); + sleep(10); + } + + + log_debug( + "%s: Successfully connected to %s on TELNET port", port_name, + ctrl_hostname ); + + isLoginSent = false; + isPasswordSent = false; + isDomainSent = false; + isConnected = (ctrl_portnum==7)?true:false; + log_debug( "%s: ----- TELNET Login Started -----", + port_name); + + if(window_size.is_set()) { + const unsigned char IAC_WILL_NAWS[] = {IAC, WILL, TELOPT_NAWS}; + ::send(nvtsock, IAC_WILL_NAWS, sizeof(IAC_WILL_NAWS), 0); + window_size.set_state(WSS_WILL_SENT); + log_debug("%s: IAC WILL TELOPT_NAWS sent.", + port_name); + } + +#ifdef TELNET_ECHO_OPTION + if(ctrl_echo) { + const unsigned char IAC_DO_ECHO[] = {IAC, DO, TELOPT_ECHO}; + ::send(nvtsock, IAC_DO_ECHO, sizeof(IAC_DO_ECHO), 0); + log_debug("%s: IAC DO ECHO sent.", port_name); + } else { + const unsigned char IAC_DONT_ECHO[] = {IAC, DONT, TELOPT_ECHO}; + ::send(nvtsock, IAC_DONT_ECHO, sizeof(IAC_DONT_ECHO), 0); + log_debug("%s: IAC DONT ECHO sent.", port_name); + } +#endif +struct pollfd poll_fds; + poll_fds.fd=nvtsock; + poll_fds.events= POLLIN | POLLPRI; + while(!isConnected) { + int poll_res=poll(&poll_fds,1,map_poll_timeout); + if(poll_res==1){ + int res=RecvClrMsg(); +/* if(res==-2){ // Workaround for a strange issue + continue; + } else {*/ + if(res < 0) { + if(ctrl_detect_server_disconnected) return; + else TTCN_error("*** Socket error or the server closed" + " the connection."); + } +/* }*/ + } else { + if(ctrl_detect_server_disconnected) { + log_debug( "%s: Connection timeout during map." + " Unmap the port and map it again.", port_name); + if(ttcn_buf.get_len()!=0) { + ttcn_buf.clear(); + } + Uninstall_Handler(); + close( nvtsock ); + nvtsock = -1; + isConnected = false; + incoming_message(INTEGER(0)); + return; + } else { + TTCN_error("*** Socket timeot during map operation"); + } + } + + if(!ctrl_login_skipped) { //perform login procedure + const unsigned char * ttcn_buf_data = ttcn_buf.get_data(); + size_t buflen = ttcn_buf.get_len(), pos = 0; + + if((!isLoginSent) && + (buf_strcmp("sername", ttcn_buf_data, buflen, pos) || + buf_strcmp("ogin", ttcn_buf_data, buflen, pos))) + { + //usleep(100000UL); // 100 ms + ::send(nvtsock, ctrl_username, strlen(ctrl_username), 0); + if(ctrl_CRLF) ::send( nvtsock, "\r\n", 2, 0 ); + else ::send( nvtsock, "\n", 1, 0 ); + isLoginSent = true; + ttcn_buf.clear(); + log_debug("%s: user name sent.",port_name); + } + else if((!isPasswordSent) && + buf_strcmp("assword", ttcn_buf_data, buflen, pos)) + { + //usleep(100000UL); // 100 ms + ::send( nvtsock, ctrl_password, strlen(ctrl_password), 0); + if(ctrl_CRLF) ::send( nvtsock, "\r\n", 2, 0 ); + else ::send( nvtsock, "\n", 1, 0 ); + isLoginSent = true; + isPasswordSent = true; + ttcn_buf.clear(); + log_debug("%s: password sent.",port_name); + } + else if((!isDomainSent) && + buf_strcmp("omain", ttcn_buf_data, buflen, pos)) + { + //usleep(100000UL); // 100 ms + if(ctrl_domain == NULL) TTCN_error("%s: missing parameter " + "CTRL_DOMAIN.", port_name); + if(strlen(ctrl_domain))::send( nvtsock, ctrl_domain, strlen(ctrl_domain), 0); + if(ctrl_CRLF) ::send( nvtsock, "\r\n", 2, 0 ); + else ::send( nvtsock, "\n", 1, 0 ); + isDomainSent = true; + ttcn_buf.clear(); + log_debug("%s: domain sent.",port_name); + } + else if(isPasswordSent && (isPrompt(prompt_start_pos) >= 0)) + { + isConnected = true; + } + + else if((buf_strcmp("ogin incorrect", ttcn_buf_data, buflen, + pos) || buf_strcmp("ogin failed", ttcn_buf_data, buflen, + pos)) && (isPasswordSent)) + { + TTCN_error("Unable to connect to '%s' as '%s'", + ctrl_hostname, ctrl_username); + } + } + else { //login procedure is skipped + if(isPrompt(prompt_start_pos)>=0) isConnected = true; + } + } + + ttcn_buf.clear(); + + if(ctrl_detect_connection_establishment_result) { + incoming_message(INTEGER(2)); // connection establishment succeeded + } + if (fcntl(nvtsock, F_SETFL, O_NONBLOCK) == -1) { + TTCN_error("fcntl(nvtsock, F_SETFL, O_NONBLOCK) failed: %d,%s",errno, strerror(errno)); + } + + log_debug( "%s: ----- TELNET %sLogin Finished -----\n", + port_name, ctrl_portnum==7?"ECHO":"" ); +// FD_ZERO( &readfds ); +// FD_SET( nvtsock, &readfds ); +// Install_Handler( &readfds, NULL, NULL, 0.0 ); + Handler_Add_Fd_Read(nvtsock); + +} +} + +void TELNETasp__PT::user_unmap(const char *system_port) +{ + +if(ttcn_buf.get_len()!=0) { + TTCN_warning("%s: Dropping partial message", port_name); + log_buffer("The content of the buffer:", ttcn_buf.get_data(), ttcn_buf.get_len()); + ttcn_buf.clear(); +} + +if (server_mode){ + port_mapped = false; + + if (nvtsock != -1){ + close_connection(nvtsock); + } + + if (fd_server != -1) close(fd_server); + fd_server = -1; +// FD_ZERO(&readfds); +}else{ + if (nvtsock != -1) { + close(nvtsock); + nvtsock = -1; + } +} +Uninstall_Handler(); +} + +void TELNETasp__PT::user_start() +{ + +} + +void TELNETasp__PT::user_stop() +{ + +} + +void TELNETasp__PT::outgoing_send(const ASP__TelnetClose& send_par){ + + close_connection(nvtsock); +// FD_SET(fd_server, &readfds); +// Install_Handler(&readfds, NULL, NULL, 0.0); + Handler_Add_Fd_Read(fd_server); + +} + +void TELNETasp__PT::outgoing_send(const CHARSTRING& send_par) +{ + log_debug( "%s: TELNETasp__PT::outgoing_send", port_name); + if (server_mode) { + + if (!port_mapped){ + TTCN_Logger::log(TTCN_WARNING, "%s: Send operation failed: the port" + " is disconnected.", port_name); + return; + } + if (!isClientLoggedIn){ + TTCN_warning("%s: Send operation failed: the client has not logged in", port_name); + return; + } + if(ctrl_server_attach_prompt){ + if (send_nonblock(nvtsock, (const char*) (send_par + "\r\n" + ctrl_server_prompt), send_par.lengthof() + 2 + strlen(ctrl_server_prompt), 0 ) < 0){ + if(ctrl_server_failsafe_sending){ + TTCN_warning("TCP send failed"); + } + else{ + TTCN_error("TCP send failed"); + } + } + } else { + if (send_nonblock(nvtsock, (const char*) (send_par), send_par.lengthof(), 0 ) < 0) { + if(ctrl_server_failsafe_sending){ + TTCN_warning("TCP send failed"); + } + else{ + TTCN_error("TCP send failed"); + } + } + } + + if(debugAllowed) { + TTCN_Logger::begin_event(TTCN_DEBUG); + TTCN_Logger::log_event("%s: Message sent: ", port_name); + send_par.log(); + TTCN_Logger::end_event(); + } + } else { + + if(!isConnected) { + log_debug( "%s: Send operation failed: the port" + " is disconnected.", port_name); + return; + } + if(ctrl_CRLF) send_nonblock( nvtsock, ( const char* ) (send_par+"\r\n"), + send_par.lengthof()+2, 0 ); + else send_nonblock( nvtsock, ( const char* ) (send_par+"\n"), + send_par.lengthof()+1, 0 ); + if(ctrl_echo==false) echobuf = send_par+"\n"; + if(debugAllowed){ + TTCN_Logger::begin_event(TTCN_DEBUG); + TTCN_Logger::log_event("%s: Message sent: ", port_name); + send_par.log(); + TTCN_Logger::end_event(); + } + } + log_debug( "%s: TELNETasp__PT::outgoing_send end", port_name); +} + +int TELNETasp__PT::send_nonblock(int sockfd, const char *buf, size_t len, int flags){ + int ret_val=len; + bool w=false; + while(len){ + log_debug( "%s: TELNETasp__PT::send_nonblock", port_name); + int ret=::send(sockfd, buf, len, flags ); + + if(ret>0){ + len-=ret; + buf+=ret; + } else { + if(errno==EAGAIN){ + if(!w){ + TTCN_warning( "%s: TELNETasp__PT::send_nonblock, the send operation would block, waiting...", port_name); + w=true; + } + dont_close_fd=sockfd; // Signal the event handler, that ther is a pending write operation on the fd + // So the event handler won't close the conection. + TTCN_Snapshot::block_for_sending((int)sockfd); + if(dont_close_fd==-1){ // delayed close of the socket, the other side closed the socket meanwhile + // The event handler detected the close of the fd, but didn't called the close() + // Just set the dont_close_fd -1 + if (server_mode){ + close_connection(sockfd); + } else { + close(sockfd); + } + return -1; + } + dont_close_fd=-1; + TTCN_warning( "%s: TELNETasp__PT::send_nonblock, next try...", port_name); + } else { + TTCN_warning( "%s: TELNETasp__PT::send_nonblock, fail... %d,%s ", port_name, errno, strerror(errno)); + return -1; + } + } + } + if(w){ + TTCN_warning( "%s: TELNETasp__PT::send_nonblock, the message finally sent", port_name); + } + log_debug( "%s: TELNETasp__PT::send_nonblock, data sent", port_name); + return ret_val; +} + +void TELNETasp__PT::outgoing_send(const ASP__TelnetPortParameters& send_par) +{ + if(asp_params) delete asp_params; + asp_params = new ASP__TelnetPortParameters(send_par); +} + +void TELNETasp__PT::outgoing_send(const ASP__TelnetDynamicConfig& send_par) +{ + switch(send_par.get_selection()) { + case ASP__TelnetDynamicConfig::ALT_readmode: + if(send_par.readmode() == TelnetReadMode::UNBUFFERED) + ctrl_readmode = READMODE_UNBUFFERED; + else + ctrl_readmode = READMODE_BUFFERED; + break; + case ASP__TelnetDynamicConfig::ALT_window__size: { + const unsigned char IAC_WILL_NAWS[] = { + IAC, + WILL, + TELOPT_NAWS + }; + window_size.set_width(send_par.window__size().width()); + window_size.set_height(send_par.window__size().height()); + if(nvtsock != -1) { + switch(window_size.get_state()) { + case WSS_INIT: + ::send(nvtsock, IAC_WILL_NAWS, sizeof(IAC_WILL_NAWS), 0); + window_size.set_state(WSS_WILL_SENT); + break; // wait for server to send IAC DO TELOPT_NAWS + case WSS_WILL_SENT: + break; // wait for server to send IAC DO TELOPT_NAWS + case WSS_AGREED: + ::send(nvtsock, window_size.encode(), WINDOW_SIZE_LENGTH, 0); + break; + //case WSS_NOT_SET: - we did set window size so this never happens + case WSS_REFUSED: + default: + TTCN_warning("%s: server refused window size negotiation.", + port_name); + break; + } + } else { + TTCN_error("%s: error sending window size: not connected.", + port_name); + } + break; } + case ASP__TelnetDynamicConfig::ALT_echo: { +#ifdef TELNET_ECHO_OPTION + unsigned char cmd[3]={ IAC, 0, TELOPT_ECHO }; + if(send_par.echo()==TRUE) { + ctrl_echo = true; + cmd[1] = DO; + log_debug("%s: IAC DO ECHO sent.", port_name); + } else { + ctrl_echo = false; + cmd[1] = DONT; + log_debug("%s: IAC DONT ECHO sent.", port_name); + } + ::send(nvtsock, cmd, sizeof(cmd), 0); +#else + if(send_par.echo()==TRUE) { + ctrl_echo = true; + } else { + ctrl_echo = false; + } +#endif + break; } + case ASP__TelnetDynamicConfig::ALT_prompt: + prompt_list.set_prompt(send_par.prompt().id(), + send_par.prompt().prompt(), + send_par.prompt().has__wildcards()==TRUE, isRawRegexpPrompt); + break; + default: + TTCN_error("%s: ASP_TelnetDynamicConfig has invalid selection.", + port_name); + break; + } +} + +void TELNETasp__PT::outgoing_send(const ASP__TelnetConnection& send_par) +{ + user_unmap(NULL); + user_map(NULL); +} + +void TELNETasp__PT::InitStrPar(char *&par, const char* name, const char* val ) +{ + if(name)log_debug( "%s: Reading testport parameter: " + "%s = %s", port_name, name, val); + + if(par) free(par); + par = (char*) malloc(strlen(val)+1); + if(par == NULL) TTCN_error("Not enough memory."); + strcpy(par, val); +} + + +int TELNETasp__PT::ProcessCmd(unsigned char * buf, int buflen) +{ + TTCN_Buffer CMD; + unsigned char *ptr = buf; + int remaining_bytes = buflen; + + // option negotiation part + while(remaining_bytes>2) { // min. length of a command is 3 +#ifdef DEBUG_ProcessCmd + unsigned char *cmd_start=ptr; +#endif + if(*ptr++ == IAC) { + remaining_bytes -= 2; + switch(*ptr++) { + case WONT: + case DONT: + switch(*ptr) { + case TELOPT_NAWS: + window_size.set_state(WSS_REFUSED); + break; +/* case TELOPT_ECHO: + CMD.put_c(IAC); + CMD.put_c(WILL); + CMD.put_c(TELOPT_ECHO); + break; +*/ default: + break; + } + ptr++; + remaining_bytes--; + break; + case DO: + + switch(*ptr) { + case TELOPT_TTYPE: + CMD.put_c(IAC); + ptr++; + remaining_bytes--; + if(ctrl_terminal_type!=NULL)CMD.put_c(WILL); + else CMD.put_c(WONT); + CMD.put_c(TELOPT_TTYPE); + break; + case TELOPT_NAWS: + ptr++; + remaining_bytes--; + + switch(window_size.get_state()) { + case WSS_INIT: + CMD.put_c(IAC); + CMD.put_c(WILL); + CMD.put_c(TELOPT_NAWS); + // no break! + case WSS_WILL_SENT: + window_size.set_state(WSS_AGREED); + // no break! + case WSS_AGREED: + CMD.put_s(WINDOW_SIZE_LENGTH, window_size.encode()); + break; + default: + CMD.put_c(IAC); + CMD.put_c(WONT); + CMD.put_c(TELOPT_NAWS); + break; + } + + break; + case TELOPT_ECHO: +/* if(!ctrl_echo) { + CMD.put_c(IAC); + CMD.put_c(WILL); + CMD.put_c(TELOPT_ECHO); + ptr++; + remaining_bytes--; + break; + }*/ + default: + CMD.put_c(IAC); + CMD.put_c(WONT); + CMD.put_c(*ptr++); + remaining_bytes--; + break; + } + + break; + case WILL: + + switch(*ptr) { + case TELOPT_NAWS: + CMD.put_c(IAC); + + switch(window_size.get_state()) { + case WSS_INIT: + case WSS_WILL_SENT: + case WSS_AGREED: + CMD.put_c(DO); + break; + default: + CMD.put_c(DONT); + break; + } + + CMD.put_c(TELOPT_NAWS); + break; +#ifdef TELNET_ECHO_OPTION + case TELOPT_ECHO: + if(ctrl_echo) { + CMD.put_c(IAC); + CMD.put_c(DO); + CMD.put_c(TELOPT_ECHO); + } else { + CMD.put_c(IAC); + CMD.put_c(DONT); + CMD.put_c(TELOPT_ECHO); + } + break; +#endif + default: + CMD.put_c(IAC); + CMD.put_c(DONT); + CMD.put_c(*ptr); + break; + } + + ptr++; + remaining_bytes--; + break; + case SB: // Subnegotiation Begin + remaining_bytes--; + + switch(*ptr++) { + case TELOPT_TTYPE: + if(remaining_bytes<1) { + TTCN_warning("%s: Unable to decode Terminal Type " + "sub-negotiation.", port_name); + break; + } + if(*ptr==TELQUAL_IS) { + ptr++; + remaining_bytes--; + while(*ptr!=IAC) { // skip terminal type string + if(remaining_bytes>0) { + remaining_bytes--; + ptr++; + } else break; + } + } else if(*ptr==TELQUAL_SEND) { + ptr++; + remaining_bytes--; + CMD.put_c(IAC); + CMD.put_c(SB); + CMD.put_c(TELOPT_TTYPE); + CMD.put_c(TELQUAL_IS); + CMD.put_s(strlen(ctrl_terminal_type), + (const unsigned char *)ctrl_terminal_type); + CMD.put_c(IAC); + CMD.put_c(SE); + } else { + ptr++; + remaining_bytes--; + log_debug( "%s: octet after IAC SB " + "TERMINAL-TYPE is 0x%02x in option negotiation.", + port_name, *ptr); + } + break; + case TELOPT_NAWS: // Window Size - in case server sends this + ptr += 4; + remaining_bytes -= 4; + break; + default: + log_debug("%s: Telnet option not " + "handled: 0x%02x.", port_name, *ptr); + ptr++; + remaining_bytes--; + while(*ptr!=IAC) { // skip until IAC + if(remaining_bytes>0) { + remaining_bytes--; + ptr++; + } else break; + } + break; + } + + ptr += 2; // skip IAC SE + remaining_bytes -= 2; + break; + default: + log_debug(" %s: Telnet Command not handled: " + "0x%02x", port_name, *ptr); + break; + } + } else { ptr--; break;} +#ifdef DEBUG_ProcessCmd + if(debugAllowed) { + TTCN_Logger::begin_event(TTCN_DEBUG); + TTCN_Logger::log_event("%s: processed command: ", port_name); + bool ttype=false; + while(cmd_start<ptr) { + if(*cmd_start==IAC)ttype=false; + else if(*cmd_start==TELOPT_TTYPE)ttype=true; + if(*cmd_start >= TELCMD_FIRST) + TTCN_Logger::log_event("%s ",TELCMD(*cmd_start)); + else if(*cmd_start <= TELOPT_LAST) { + if(ttype && (*cmd_start)<2) + TTCN_Logger::log_event_str((*cmd_start)?"SEND ":"IS "); + else + TTCN_Logger::log_event("%s ", TELOPT(*cmd_start)); + } + else TTCN_Logger::log_event("%d ", *cmd_start); + cmd_start++; + } + TTCN_Logger::end_event(); + } +#endif + } + + if(CMD.get_len() > 0) { + CMD.rewind(); + ::send( nvtsock, CMD.get_read_data(), CMD.get_read_len(), 0 ); + if(debugAllowed) { + +#ifdef DEBUG_ProcessCmd + if(TTCN_Logger::log_this_event(TTCN_DEBUG)) { + TTCN_Logger::begin_event(TTCN_DEBUG); + TTCN_Logger::log_event("%s: command sent:", port_name); + bool ttype=false, subcmd=false, naws=false; + const unsigned char *cmd_ptr = CMD.get_read_data(); + unsigned int cmd_len=CMD.get_read_len(); + for(unsigned int i=0;i<cmd_len;i++) { + if(*cmd_ptr==SB)subcmd=true; + else if(*cmd_ptr==SE)subcmd=false; + if(*cmd_ptr==IAC) { + if(!subcmd)TTCN_Logger::log_event("\n "); + ttype=false; + naws=false; + } + if(*cmd_ptr >= TELCMD_FIRST) + TTCN_Logger::log_event("%s ",TELCMD(*cmd_ptr)); + else if(ttype) { + switch(*cmd_ptr) { + case 0: TTCN_Logger::log_event_str("IS "); break; + case 1: TTCN_Logger::log_event_str("SEND "); break; + default: + if(*cmd_ptr>' ' && *cmd_ptr<128) + TTCN_Logger::log_event("\"%c\" ",*cmd_ptr); + else TTCN_Logger::log_event("%d ",*cmd_ptr); + } + } else if(naws) TTCN_Logger::log_event("%d ", *cmd_ptr); + else if(*cmd_ptr <= TELOPT_LAST) + TTCN_Logger::log_event("%s ", TELOPT(*cmd_ptr)); + else TTCN_Logger::log_event("%d ", *cmd_ptr); + if(*cmd_ptr==TELOPT_NAWS)naws=true; + else if(*cmd_ptr==TELOPT_TTYPE)ttype=true; + cmd_ptr++; + } + TTCN_Logger::end_event(); + } +#else + log_buffer("ProcessCmd: command sent:", CMD.get_read_data(), + CMD.get_read_len()); +#endif + } + } + + if(remaining_bytes != buflen) { + ttcn_buf.set_pos(buflen-remaining_bytes); + ttcn_buf.cut(); + memmove(buf, ptr, remaining_bytes); + buflen = remaining_bytes; + } + + return buflen; +} + +int TELNETasp__PT::isPrompt(size_t &pos) +{ + return prompt_list.findPrompt(pos, ttcn_buf.get_data(), ttcn_buf.get_len()); +} + +int TELNETasp__PT::RecvClrMsg() +{ + unsigned char inbuf[BUFFER_SIZE]; + errno=0; + int end_len = BUFFER_SIZE, len = recv(nvtsock, inbuf , end_len, 0); + +/* if(len<0 && errno == EAGAIN){ // Workaround for a strange issue. + return -2; + } +*/ + if(len>0){ + log_debug( "%s: ********************** NEW MESSAGE" + " RECEIVED **********************", port_name); + log_buffer("RecvClrMsg received message:", inbuf, len); + } else if (len==0){ + log_debug("%s: ******** Connection is closed " + "by peer.",port_name); + } else { + log_debug("%s: ******** Error occured during reading " + "socket. errno value: %d",port_name,errno); + } + + if (len < 1) { + if(ctrl_detect_server_disconnected) { + log_debug( "%s: Connection is broken." + " Unmap the port and map it again.", port_name); + if(ttcn_buf.get_len()!=0) { + ttcn_buf.clear(); + } + Uninstall_Handler(); + nvtsock = -1; + isConnected = false; + incoming_message(INTEGER(0)); + if(dont_close_fd==nvtsock) { + dont_close_fd=-1; + } else { + close( nvtsock ); + } + } + return -1; + } + + len = ProcessCmd(inbuf, len); + + for(int i=0;i<len;i++) { + if(inbuf[i]!='\r' && inbuf[i]!='\0') ttcn_buf.put_c(inbuf[i]); + } + + log_buffer("RecvClrMsg ttcn_buf message:", ttcn_buf.get_data(), + ttcn_buf.get_len()); + CHARSTRING tmpchr(ttcn_buf.get_len(), (const char*)ttcn_buf.get_data()); + if(debugAllowed) { + TTCN_Logger::begin_event(TTCN_DEBUG); + tmpchr.log(); + TTCN_Logger::end_event(); + } + + return ttcn_buf.get_len(); +} + +/* buf_strcmp compares the NULL-terminated string s1 to s2 of length s2_len +(s2 is not necessarily NULL-terminated). If s2 containes the substring s1, +then the function returns true and pos is set to the starting position of s1 +within s2, otherwise the return value is false and pos remains unchanged.*/ + +bool TELNETasp__PT::buf_strcmp(const char * s1, const unsigned char * s2, + size_t s2_len, size_t& pos) +{ + size_t s1_len = strlen(s1); + if(s1_len == 0) return false; + if(s1_len>s2_len) { return false; } + for(int i=0;i<(int)(s2_len-s1_len+1); ) { + size_t j = 0; + while((unsigned char)s1[j] == s2[i+j]) { j++; } + if(j==s1_len) { pos = i; return true; } + i+=j>0?j:1; + } + return false; +} + +void TELNETasp__PT::log_debug(const char *fmt, ...) +{ + if(debugAllowed) { + TTCN_Logger::begin_event(TTCN_DEBUG); + TTCN_Logger::log_event("TELNET test port (%s): ", get_name()); + va_list ap; + va_start(ap, fmt); + TTCN_Logger::log_event_va_list(fmt, ap); + va_end(ap); + TTCN_Logger::end_event(); + } +} + +void TELNETasp__PT::log_buffer(const char * logmsg, const unsigned char * buf, + size_t buflen) +{ + if(debugAllowed) { + log_debug( "%s: %s: ", port_name, logmsg); + for(size_t j=0;j<buflen;) { + TTCN_Logger::begin_event(TTCN_DEBUG); + for(size_t i=0;j<buflen && i<16;i++) { + if(i == 8) TTCN_Logger::log_event(" "); + TTCN_Logger::log_event("%02x ", buf[j++]); + } + TTCN_Logger::end_event(); + } + } +} + +void TELNETasp__PT::set_asp_params() +{ + if(asp_params == NULL) return; + TTCN_Logger::begin_event(TTCN_PORTEVENT); + TTCN_Logger::log_event("%s: setting parameters from ASP: ", port_name); + asp_params->log(); + TTCN_Logger::end_event(); + + if(asp_params->ctrl__hostname().ispresent()==TRUE) + InitStrPar(ctrl_hostname, NULL, + (CHARSTRING)asp_params->ctrl__hostname()); + + if(asp_params->ctrl__portnum().ispresent()==TRUE) + ctrl_portnum = (INTEGER)asp_params->ctrl__portnum(); + + if(asp_params->ctrl__username().ispresent()==TRUE) + InitStrPar(ctrl_username, NULL, + (CHARSTRING)asp_params->ctrl__username()); + + if(asp_params->ctrl__password().ispresent()==TRUE) + InitStrPar(ctrl_password, NULL, + (CHARSTRING)asp_params->ctrl__password()); + + if(asp_params->ctrl__domain().ispresent()==TRUE) + InitStrPar(ctrl_domain, NULL, + (CHARSTRING)asp_params->ctrl__domain()); + + if(asp_params->ctrl__readmode().ispresent()==TRUE) { + if(((TelnetReadMode)asp_params->ctrl__readmode())== + TelnetReadMode::UNBUFFERED) { + ctrl_readmode = READMODE_UNBUFFERED; + } else { + ctrl_readmode = READMODE_BUFFERED; + } + } + + if(asp_params->ctrl__login__skipped().ispresent()==TRUE) { + if((BOOLEAN)asp_params->ctrl__login__skipped() == TRUE) + ctrl_login_skipped = true; + else ctrl_login_skipped = false; + } + + if(asp_params->ctrl__detect__server__disconnected().ispresent()==TRUE) { + if((BOOLEAN)asp_params->ctrl__detect__server__disconnected() == TRUE) + ctrl_detect_server_disconnected = true; + else ctrl_detect_server_disconnected = false; + } + + if(asp_params->prompts().ispresent()==TRUE && + ((TelnetPrompts)asp_params->prompts()).size_of() > 0) { + prompt_list.clear(); + const TelnetPrompts& asp_prompts = + (TelnetPrompts)asp_params->prompts(); + unsigned int nof_prompts = asp_prompts.size_of(); + for(unsigned int i=0;i<nof_prompts;i++) { + unsigned int id = asp_prompts[i].id(); + const char *p = asp_prompts[i].prompt(); + bool is_regex = asp_prompts[i].has__wildcards(); + if(strlen(p)==0) TTCN_error("%s: prompt parameter must contain at " + "least one character", port_name); +/* if(p[0]=='*') + TTCN_error("%s: prompt parameter with wildcards shouldn't " + "start with \"*\": \"%s\".", port_name, p); + if(p[strlen(p)-1]=='*') + TTCN_error("%s: prompt parameter with wildcards shouldn't " + "end with \"*\": \"%s\".", port_name, p);*/ + prompt_list.set_prompt(id, p, is_regex, isRawRegexpPrompt); + } + } + + if(asp_params->ctrl__terminal__type().ispresent()==TRUE) + InitStrPar(ctrl_terminal_type, NULL, + (CHARSTRING)asp_params->ctrl__terminal__type()); + + if(asp_params->ctrl__echo().ispresent()==TRUE) { + if((BOOLEAN)asp_params->ctrl__echo() == TRUE) ctrl_echo = true; + else ctrl_echo = false; + } + + if(asp_params->ctrl__CRLF().ispresent()==TRUE) { + if((BOOLEAN)asp_params->ctrl__CRLF() == TRUE) ctrl_CRLF = true; + else ctrl_CRLF = false; + } + + if(asp_params->ctrl__window__size().ispresent()==TRUE) { + window_size.set_width(((TelnetWindowSize) + asp_params->ctrl__window__size()).width()); + window_size.set_height(((TelnetWindowSize) + asp_params->ctrl__window__size()).height()); + } + + delete asp_params; + asp_params = NULL; +} + +void TELNETasp__PT::reset_configuration() +{ + free(ctrl_hostname); + ctrl_hostname = NULL; + ctrl_portnum = 0; + free(ctrl_username); + ctrl_username = NULL; + free(ctrl_password); + ctrl_password = NULL; + free(ctrl_domain); + ctrl_domain = NULL; + ctrl_readmode = READMODE_BUFFERED; + prompt_list.clear(); + ctrl_login_skipped = false; + ctrl_detect_server_disconnected = false; + free(ctrl_terminal_type); + ctrl_terminal_type = NULL; + ctrl_echo = false; + ctrl_CRLF = false; + window_size.reset(); + delete asp_params; + asp_params = NULL; + + free(ctrl_username_client); + ctrl_username_client = NULL; + free(ctrl_password_client); + ctrl_password_client = NULL; + free(ctrl_server_prompt); + ctrl_server_prompt = NULL; + server_mode_def = false; + isClientLoggedIn = false; + pass_prompt_send = false; + login_incorrect = false; + free(ctrl_password_prompt); + ctrl_password_prompt = NULL; + free(ctrl_loginname_prompt); + ctrl_loginname_prompt = NULL; + + debugAllowed = false; +} + +void TELNETasp__PT::recv_msg_from_client(int &fd){ + unsigned char inbuf[BUFFER_SIZE]; + unsigned int length; + + log_debug("%s: Receive message from client", port_name); + length = recv(fd, inbuf, BUFFER_SIZE, O_NONBLOCK); + + switch (length){ + case -1:{ + log_debug("%s: Error reading from file descriptor %d. Errno = %d", port_name, fd, errno); + errno = 0; +// close_connection(fd); +// nvtsock=-1; +// FD_SET(fd_server, &readfds); +// Install_Handler(&readfds, NULL, NULL, 0.0); + Handler_Add_Fd_Read(fd_server); + + if(ctrl_detect_client_disconnected){ //notify the server that the client disonnected. + incoming_message(INTEGER(3)); + } + if(dont_close_fd==fd) { + dont_close_fd=-1; + return; + } + close_connection(fd); + break; + } + case 0:{ + log_debug("Client closed connection (filedescriptor: %d)", fd); +// close_connection(fd); +// FD_SET(fd_server, &readfds); +// Install_Handler(&readfds, NULL, NULL, 0.0); +// nvtsock=-1; + Handler_Add_Fd_Read(fd_server); + + if(ctrl_detect_client_disconnected){ //notify the server that the client disonnected. + incoming_message(INTEGER(3)); + } + if(dont_close_fd==fd) { + dont_close_fd=-1; + return; + } + close_connection(fd); + break; + } + default:{ + int new_length; + bool delimiter_came = false; + if ( (new_length = ProcessNoCmd(inbuf, length)) == 0) return; + + if(debugAllowed) { + TTCN_logger.log(TTCN_DEBUG,"%s: ------------------------ Logging incoming messages -----------------------------", port_name); + TTCN_logger.log(TTCN_DEBUG," (characters after the first \\n or \\r character will be discarded)"); + log_buffer("Message received from client: (hexstring fromat)", inbuf, length); + CHARSTRING cc = CHARSTRING((int)length, (const char*)inbuf); + TTCN_Logger::begin_event(TTCN_DEBUG); + TTCN_Logger::log_event("%s: Message received from client: (charstring format)\n", port_name); + cc.log(); + TTCN_Logger::end_event(); + TTCN_logger.log(TTCN_DEBUG,"%s ------------------------ End logging -----------------------------\n", port_name); + } + + if (!isClientLoggedIn){ + + int pos; + for (int i = 0; i < new_length; i++){ + if ( (inbuf[i] == '\n') || (inbuf[i] == '\r')){ delimiter_came = true; pos = i; break; } + } + + if (delimiter_came) ttcn_buf.put_s(pos+1, inbuf); + else ttcn_buf.put_s(new_length, inbuf); + + if(debugAllowed) { + TTCN_logger.log(TTCN_DEBUG,"%s: ------------------------ Logging the incoming buffer -----------------------------", port_name); + log_buffer("The content of the incoming buffer: (hexstring fromat)", inbuf, length); + CHARSTRING cc = CHARSTRING((int)ttcn_buf.get_len(), (const char*)ttcn_buf.get_data()); + TTCN_Logger::begin_event(TTCN_DEBUG); + TTCN_Logger::log_event("%s: The content of the incoming buffert: (charstring format)\n", port_name); + cc.log(); + TTCN_Logger::end_event(); + TTCN_logger.log(TTCN_DEBUG,"%s ------------------------ End logging -----------------------------\n", port_name); + } + + if (delimiter_came && !pass_prompt_send){ + if (!check((const char *)ctrl_username_client, ttcn_buf.get_data(), ttcn_buf.get_len() ) ){ + login_incorrect = true; + } + ttcn_buf.set_pos(ttcn_buf.get_len()); + + if (::send(fd, "\r\n", 2, 0) < 0 ) + TTCN_error("TCP send failed"); + + if (::send(fd, ctrl_password_prompt, strlen(ctrl_password_prompt), 0) < 0 ) + TTCN_error("TCP send failed"); + + pass_prompt_send = true; + } else if (delimiter_came && pass_prompt_send){ + int pos = ttcn_buf.get_pos(); + if (login_incorrect || !check((const char *)ctrl_password_client, ttcn_buf.get_data()+pos, ttcn_buf.get_len()-pos) ) { + int len = ttcn_buf.get_len(); + const char *data = (const char*)ttcn_buf.get_data(); + CHARSTRING cc1( pos - 1, data); + CHARSTRING cc2(len - pos - 1, data + pos); + TTCN_Logger::begin_event(TTCN_ERROR); + TTCN_Logger::log_event("%s: ---------------------------Login incorrect------------------------\n", port_name); + TTCN_Logger::log_event("Username: "); + cc1.log(); + TTCN_Logger::log_event("\nPassword: "); + cc2.log(); + if (::send(nvtsock, "Login incorrect\r\n", 17, 0) < 0) + TTCN_error("TCP send failed"); + TTCN_Logger::end_event(); + TTCN_error("Login incorrect!"); + } + isClientLoggedIn = true; + if (fcntl(nvtsock, F_SETFL, O_NONBLOCK) == -1) { + TTCN_error("fcntl(nvtsock, F_SETFL, O_NONBLOCK) failed: %d,%s",errno, strerror(errno)); + } + + incoming_message(INTEGER(1)); + ttcn_buf.clear(); + + const char *welcome = "Welcome\r\n"; + if (::send(fd, welcome, strlen(welcome), 0) < 0) + TTCN_error("TCP send failed"); + if (::send(fd, ctrl_server_prompt, strlen(ctrl_server_prompt),0) < 0) + TTCN_error("TCP send failed"); + } + + break; + } + + + ttcn_buf.put_s(new_length,inbuf); + + if(debugAllowed) { + TTCN_logger.log(TTCN_DEBUG,"%s: ------------------------ Logging the incoming buffer -----------------------------", port_name); + log_buffer("The content of the incoming buffer: (hexstring fromat)", inbuf, length); + CHARSTRING cc = CHARSTRING((int)ttcn_buf.get_len(), (const char*)ttcn_buf.get_data()); + TTCN_Logger::begin_event(TTCN_DEBUG); + TTCN_Logger::log_event("%s: The content of the incoming buffert: (charstring format)\n", port_name); + cc.log(); + TTCN_Logger::end_event(); + TTCN_logger.log(TTCN_DEBUG,"%s ------------------------ End logging -----------------------------\n", port_name); + } + + int i,len; + const unsigned char *data; + for(;;){ + data = ttcn_buf.get_data(); + len = ttcn_buf.get_len(); + for (i = 0; i < len ; i++){ + if ( (data[i] == '\n' ) || (data[i] == '\r') ){ + incoming_message(CHARSTRING(i, (const char*)data )); + break; + } + } + if (i == len) break; + if (i < len - 1 && data[i] == '\r' && ( data[i+1] == '\0' || data[i+1] == '\n') ) i++; + ttcn_buf.set_pos(i+1); + ttcn_buf.cut(); + if (i == len) break; + }; + } + } + +} + +int TELNETasp__PT::ProcessNoCmd(unsigned char * buf, int buflen) +{ + unsigned char CMD[1024]; + int cmd_len = 0, i; + + log_debug("Processing commands"); + // option negotiation part + for ( i = 0; i+2 < buflen; i += 3 ) { + if(buf[i] == IAC ) { + switch(buf[i+1] ) { + case WONT: + case DONT: + break; + case DO: + CMD[cmd_len++] = IAC; + CMD[cmd_len++] = WONT; + CMD[cmd_len++] = buf[i+2]; + break; + case WILL: + CMD[cmd_len++] = IAC; + CMD[cmd_len++] = DONT; + CMD[cmd_len++] = buf[i+2]; + break; + default: + log_debug("%s: Telnet Command not handled: 0x%02x", port_name, buf[i+1]); + } + } + else break; + } + if(i!=0) { + log_debug("Sending commands"); + ::send( nvtsock, (const char*)CMD, cmd_len, 0 ); + ttcn_buf.set_pos(i); + ttcn_buf.cut(); + log_buffer("ProcessCmd: command sent:", CMD, cmd_len); + memmove(buf, &buf[i], buflen-i); + buflen -= i; + } + return buflen; +} + +bool TELNETasp__PT::check(const char * s1, const unsigned char * s2, int s2_len){ + int s1_len = strlen(s1); + if (s1_len > s2_len){return false;} + for (int i = 0; i< s1_len; i++){ + if (s1[i] != s2[i] ) return false; + } + return s2[s1_len] == '\n' || s2[s1_len] == '\r' || s2[s1_len] == '\0'; +} + +INTEGER FindString(const CHARSTRING& msg_ch, const CHARSTRING& pattern_ch) +{ + const char* p; + int n = 0, x = 0; + const char* msg = ( const char* ) msg_ch; + const char* pattern = ( const char* ) pattern_ch; + int plen = strlen( pattern ); + int mlen = strlen( msg ); + while( x < mlen + plen - 1 ) + { + if( ( p = strstr( &msg[x], pattern ) ) == NULL ) break; + else + { + x = ( int ) ( p - msg ) + plen; + n++; + } + } + return n; +} + +Window_Size::Window_Size(const char *p_port_name) + : my_state(WSS_NOT_SET), width(-1), height(-1), ws_debugAllowed(false) +{ + if(p_port_name==NULL) p_port_name = "<telnet>"; + port_name = new char[strlen(p_port_name) + 1]; + strcpy(port_name, p_port_name); +} + +Window_Size::~Window_Size() +{ + delete []port_name; +} + +void Window_Size::log_debug(const char *fmt, ...) +{ + if(ws_debugAllowed) { + TTCN_Logger::begin_event(TTCN_DEBUG); + va_list ap; + va_start(ap, fmt); + TTCN_Logger::log_event_va_list(fmt, ap); + va_end(ap); + TTCN_Logger::end_event(); + } +} + +void Window_Size::set_debug(bool debug_enabled) +{ + ws_debugAllowed = debug_enabled; +} + + +void Window_Size::set_state(WindowSize_state_t new_state) +{ + if(!is_set()) my_state = WSS_NOT_SET; + else switch(new_state) { + case WSS_INIT: + log_debug("Window_Size::set_state(): can't set " + "state to WSS_INIT."); + break; + case WSS_WILL_SENT: + if(my_state == WSS_INIT) my_state = WSS_WILL_SENT; + else log_debug("Window_Size::set_state(): can't set " + "state to WSS_WILL_SENT."); + break; + case WSS_AGREED: + + switch(my_state) { + case WSS_INIT: + case WSS_WILL_SENT: + case WSS_AGREED: + my_state = WSS_AGREED; + break; + default: + log_debug("Window_Size::set_state(): can't set " + "state to WSS_AGREED."); + break; + } + + break; + case WSS_REFUSED: + if(my_state != WSS_REFUSED && is_set()) TTCN_warning("%s: server " + "refused window size negotiation.", port_name); + my_state = WSS_REFUSED; + break; + case WSS_NOT_SET: + TTCN_error("Window_Size::set_state(): state shouldn't be set to " + "WSS_NOT_SET explicitly."); + break; + default: + TTCN_error("Window_Size::set_state(): unknown state."); + break; + } +} + +void Window_Size::set_width(int w) +{ + if(w<=0||w>65535) TTCN_error("%s: width of window size should be greater " + "than 0 and less than 65536.", port_name); + width = w; + if(height > 0 && my_state == WSS_NOT_SET) my_state = WSS_INIT; +} + +void Window_Size::set_height(int h) +{ + if(h<=0||h>65535) TTCN_error("%s: height of window size should be greater " + "than 0 and less than 65536.", port_name); + height = h; + if(width > 0 && my_state == WSS_NOT_SET) my_state = WSS_INIT; +} + +const unsigned char *Window_Size::encode() const +{ + static unsigned char pdu[] = { + IAC, + SB, + TELOPT_NAWS, + 0, 80, + 0, 24, + IAC, + SE + }; + if(!is_set()) TTCN_error("%s: sending window size option without window " + "size being set.", port_name); + pdu[3] = width >> 8; + pdu[4] = width; + pdu[5] = height >> 8; + pdu[6] = height; + return pdu; +} + + +Regex_Prompt::Regex_Prompt(const char *p_pattern, bool debug_enabled, bool raw_prompt) +{ + rp_debugAllowed = debug_enabled; + char *posix_str=NULL; + if(raw_prompt){ + posix_str = mcopystr(p_pattern); + } + else { + CHARSTRING cstr("(*)("); // string before prompt + cstr = cstr + p_pattern; // prompt + cstr = cstr + ")(*)"; // string after prompt + posix_str = TTCN_pattern_to_regexp_telnet(cstr); + } + if(posix_str == NULL) TTCN_error("Cannot convert pattern \"%s\" to " + "POSIX-equivalent.", p_pattern); +// posix_str[strlen(posix_str)-1] = '\0'; // remove trailing "$" + int ret_val=regcomp(&posix_regexp, posix_str, REG_EXTENDED); // +1 -> no ^ + log_debug("Translated pattern (%zd subexpressions): %s",posix_regexp.re_nsub, posix_str); + Free(posix_str); + if(ret_val!=0) { + char err[512]; + regerror(ret_val, &posix_regexp, err, sizeof(err)); + regfree(&posix_regexp); + TTCN_error("Function regcomp() failed while setting regexp pattern " + "\"%s\" as prompt: %s", p_pattern, err); + } +} + +Regex_Prompt::~Regex_Prompt() +{ + regfree(&posix_regexp); +} + +void Regex_Prompt::log_debug(const char *fmt, ...) +{ + if(rp_debugAllowed) + { + TTCN_Logger::begin_event(TTCN_DEBUG); + va_list ap; + va_start(ap, fmt); + TTCN_Logger::log_event_va_list(fmt, ap); + va_end(ap); + TTCN_Logger::end_event(); + } +} + +Regex_Prompt_MatchResult Regex_Prompt::match(const char *msg) +{ + Regex_Prompt_MatchResult ret_val; + regmatch_t pmatch[4]; + int result = regexec(&posix_regexp, msg, 4, pmatch, 0); +/* for (int i=0;i<4;i++) log_debug( + "result: %d, start: %u, end: %u", result, pmatch[i].rm_so, + pmatch[i].rm_eo);*/ + if(result == 0) { + ret_val.match = true; + ret_val.start = pmatch[2].rm_so; + ret_val.end = pmatch[2].rm_eo; + } else if(result == REG_NOMATCH) { + ret_val.match = false; + ret_val.start = 0; + ret_val.end = 0; + } else { + char err[512]; + regerror(result, &posix_regexp, err, sizeof(err)); + TTCN_error("Error matching regexp prompt: %s", err); + } + return ret_val; +} + + +Prompt_List::~Prompt_List() +{ + clear(); +} +void Prompt_List::log_debug(const char *fmt, ...) +{ + if(pl_debugAllowed) + { + TTCN_Logger::begin_event(TTCN_DEBUG); + va_list ap; + va_start(ap, fmt); + TTCN_Logger::log_event_va_list(fmt, ap); + va_end(ap); + TTCN_Logger::end_event(); + } +} + +void Prompt_List::set_debug(bool debug_enabled) +{ + pl_debugAllowed = debug_enabled; +} + +void Prompt_List::set_prompt(unsigned int p_id, const char *p_prompt, + bool p_is_regex, bool raw_prompt) +{ + size_t index; + if( !id_to_index(p_id, index) ) { + index = n_elems++; + if(n_elems==1) elems = (prompt_elem**)malloc(sizeof(prompt_elem*)); + else elems = (prompt_elem**)realloc(elems, n_elems + *sizeof(prompt_elem*)); + if(!elems) TTCN_error("Not enough memory."); + } else { + if(elems[index]->is_regex) delete elems[index]->regex_prompt; + else delete [](elems[index]->prompt); + delete elems[index]; + } + elems[index] = new prompt_elem; + elems[index]->id = p_id; + elems[index]->is_regex = p_is_regex; + if(p_is_regex) { + elems[index]->regex_prompt = new Regex_Prompt(p_prompt,pl_debugAllowed,raw_prompt); + } else { + elems[index]->prompt = new char[strlen(p_prompt)+1]; + strcpy(elems[index]->prompt, p_prompt); + } +} + +void Prompt_List::check(const char *warning_prefix) +{ + if(n_elems) { + for(unsigned int i=0;i<n_elems-1;i++) { + if(elems[i]->is_regex) continue; + const char *pi = elems[i]->prompt; + for(unsigned int j=i+1;j<n_elems;j++) { + if(elems[j]->is_regex) continue; + const char *pj = elems[j]->prompt; + if(!strcmp(pi, pj)) { + TTCN_warning("Duplicated prompt string '%s'", pi); + break; + } else if(strstr(pi, pj)) { + TTCN_warning("Using prompt '%s' that is a substring of" + " prompt '%s' might cause problems", pj, pi); + break; + } else if(strstr(pj, pi)) { + TTCN_warning("Using prompt '%s' that is a substring of" + " prompt '%s' might cause problems", pi, pj); + break; + } + } + } + } +} + +void Prompt_List::clear() +{ + if(elems) { + for(size_t i=0;i<n_elems;i++) { + if(elems[i]->is_regex) delete elems[i]->regex_prompt; + else delete [](elems[i]->prompt); + delete elems[i]; + } + free(elems); + elems = NULL; + } + n_elems = 0; +} + +int Prompt_List::findPrompt(size_t &pos, const unsigned char *bufptr, + size_t buflen) const +{ + char *buf_asciiz = NULL; + for(size_t i=0;i<n_elems;i++) { + if(elems[i]->is_regex == false) { + size_t prompt_len = strlen(elems[i]->prompt); + if(prompt_len<=buflen) { + if(strncmp(elems[i]->prompt, + (const char *) (bufptr+buflen-prompt_len), prompt_len)==0) { + pos = buflen-prompt_len; + if(buf_asciiz) delete []buf_asciiz; + return prompt_len; + } + } + } else { + if(!buf_asciiz) { + buf_asciiz = new char[buflen+1]; + memcpy(buf_asciiz, bufptr, buflen); + buf_asciiz[buflen] = '\0'; + } + Regex_Prompt_MatchResult result = + elems[i]->regex_prompt->match(buf_asciiz); + if(result.match) { + pos = result.start; + delete []buf_asciiz; + return result.end - result.start; + } + } + } + if(buf_asciiz) delete []buf_asciiz; + return -1; +} + +bool Prompt_List::id_to_index(unsigned int p_id, size_t &index) const +{ + for(index=0; index<n_elems; index++) + if(elems[index]->id == p_id) return true; + return false; +} + +void TELNETasp__PT::close_connection(int& fd){ + + if (fd < 0){ + log_debug("close_connection(): file descriptor is negative (%d)", fd); + return; + } +// FD_CLR(fd, &readfds); + +// Install_Handler(&readfds, NULL, NULL, 0.0); + Handler_Remove_Fd_Read(fd); + + close(fd); + isClientLoggedIn = false; + pass_prompt_send = false; + login_incorrect = false; + fd = -1; +} +} diff --git a/src/TELNETasp_PT.hh b/src/TELNETasp_PT.hh new file mode 100644 index 0000000000000000000000000000000000000000..80ac559e3a4769dc6b4ddfc15295f724121730b3 --- /dev/null +++ b/src/TELNETasp_PT.hh @@ -0,0 +1,239 @@ +/****************************************************************************** +* Copyright (c) 2004, 2014 Ericsson AB +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v10.html +* +* Contributors: +* Tibor Csondes - initial implementation and initial documentation +* Akos Cserveni +* Elemer Lelik +* Gabor Szalai +* Gabor Tatarka +* Gergely Futo +* Istvan Sandor +* Peter Dimitrov +* Peter Kremer +* Tibor Bende +* Zoltan Medve +******************************************************************************/ +// +// File: TELNETasp_PT.hh +// Description: TELNET testport header file +// Rev: R8E +// Prodnr: CNL 113 320 +// + +#ifndef TELNETasp__PT_HH +#define TELNETasp__PT_HH + +#include <sys/types.h> +#include <sys/socket.h> +#include <arpa/inet.h> +#include <stdio.h> +#include <errno.h> +#include <unistd.h> +#include <netdb.h> +#include <string.h> +#include <netinet/in.h> +#include <stdlib.h> +#include <string.h> +#include <regex.h> +#include <fcntl.h> + +#include <memory.h> + +#include "TELNETasp_PortType.hh" + +#define BUFFER_SIZE (100*1024) +#define READMODE_UNBUFFERED 0 +#define READMODE_BUFFERED 1 + +#define WINDOW_SIZE_LENGTH 9 // IAC SB NAWS x x y y IAC SE +namespace TELNETasp__PortType { +//#define DEBUG_ProcessCmd 1 + +//extern INTEGER FindString(const CHARSTRING& msg_ch, const CHARSTRING& pattern_ch); + + +typedef enum { + WSS_INIT, + WSS_WILL_SENT, + WSS_AGREED, + WSS_REFUSED, + WSS_NOT_SET +} WindowSize_state_t; + +class Window_Size { + WindowSize_state_t my_state; + int width, height; + char *port_name; + bool ws_debugAllowed; + +public: + Window_Size(const char *p_port_name); + ~Window_Size(); + inline void reset() { my_state = WSS_NOT_SET; width = -1; height = -1; ws_debugAllowed = false; } + void set_state(WindowSize_state_t new_state); + inline WindowSize_state_t get_state() const { return my_state; } + void set_width(int w); + inline int get_width() const { return width; } + void set_height(int h); + inline int get_height() const { return height; } + const unsigned char *encode() const; + inline bool is_set() const { return width > 0 && height > 0; } + void log_debug(const char *fmt, ...); + void set_debug(bool debug_enabled); +}; + +typedef struct { + bool match; + unsigned int start; + unsigned int end; +} Regex_Prompt_MatchResult; + +class Regex_Prompt { + regex_t posix_regexp; + bool rp_debugAllowed; + +public: + Regex_Prompt(const char *p_pattern, bool debug_enabled, bool raw_prompt); + ~Regex_Prompt(); + Regex_Prompt_MatchResult match(const char *msg); + void log_debug(const char *fmt, ...); +}; + +class Prompt_List { + typedef struct { + unsigned int id; + bool is_regex; + union { + char *prompt; + Regex_Prompt *regex_prompt; + }; + } prompt_elem; + prompt_elem **elems; + size_t n_elems; + bool id_to_index(unsigned int p_id, size_t &index) const; + bool pl_debugAllowed; +public: + Prompt_List() : elems(NULL), n_elems(0), pl_debugAllowed(false) { } + ~Prompt_List(); + void set_prompt(unsigned int p_id, const char *p_prompt, bool p_is_regex, bool raw_prompt = false); + void check(const char *warning_prefix); + void clear(); + size_t nof_prompts() const { return n_elems; } + int findPrompt(size_t &pos, const unsigned char *bufptr, size_t buflen) const; + void log_debug(const char *fmt, ...); + void set_debug(bool debug_enabled); +}; + + +class TELNETasp__PT : public TELNETasp__PT_BASE { +public: + TELNETasp__PT(const char *par_port_name = NULL); + ~TELNETasp__PT(); + + void set_parameter(const char *parameter_name, + const char *parameter_value); + + void Handle_Fd_Event_Readable(int fd); +/* void Event_Handler(const fd_set *read_fds, + const fd_set *write_fds, const fd_set *error_fds, + double time_since_last_call); +*/ + + +protected: + void user_map(const char *system_port); + void user_unmap(const char *system_port); + + void user_start(); + void user_stop(); + + void outgoing_send(const CHARSTRING& send_par); + void outgoing_send(const ASP__TelnetPortParameters& send_par); + void outgoing_send(const ASP__TelnetDynamicConfig& send_par); + void outgoing_send(const ASP__TelnetConnection& send_par); + void outgoing_send(const ASP__TelnetClose& send_par); + + void InitStrPar(char *&par, const char *name, const char *val); + int ProcessCmd(unsigned char * buf, int buflen); + int ProcessNoCmd(unsigned char * buf, int buflen); + void LoginCtrl( const char* buf, const char* nam, const char* pw ); + int isPrompt(size_t& pos); // returns the length of the found prompt + int RecvClrMsg(); + void log_buffer(const char * logmsg, + const unsigned char * buf, size_t buflen); + void log_debug(const char *fmt, ...); + bool buf_strcmp(const char * s1, const unsigned char * s2, + size_t s2_len, size_t& pos); + + int send_nonblock(int sockfd, const char *buf, size_t len, int flags); + + // Class variables and constants + int nvtsock; + bool isConnected; + bool isLoginSent; + bool isPasswordSent; + bool isDomainSent; + bool isRawRegexpPrompt; + CHARSTRING echobuf; + TTCN_Buffer ttcn_buf; + struct hostent *he; + bool config_finished; + + int map_poll_timeout; + + // parameters + char* ctrl_hostname; + int ctrl_portnum; + char* ctrl_username; + char* ctrl_password; + char* ctrl_domain; + int ctrl_readmode; + bool ctrl_login_skipped; + bool ctrl_detect_server_disconnected; + bool ctrl_detect_connection_establishment_result; + bool ctrl_client_cleanup_linefeed; + char* ctrl_terminal_type; + bool ctrl_echo; + bool ctrl_CRLF; + Prompt_List prompt_list; + Window_Size window_size; +int dont_close_fd; + char* ctrl_username_client; + char* ctrl_password_client; + char* ctrl_server_prompt; + char* ctrl_password_prompt; + char* ctrl_loginname_prompt; + bool server_mode_def; + bool ctrl_server_attach_prompt; + bool ctrl_detect_client_disconnected; + bool ctrl_server_failsafe_sending; + bool server_mode; + + bool port_mapped; + int fd_server; + bool isClientLoggedIn; + bool pass_prompt_send; + bool login_incorrect; + + bool debugAllowed; + + bool emptyEcho; + bool suppressed; + + void recv_msg_from_client(int& fd); + void close_connection(int& fd); + bool check(const char * s1, const unsigned char * s2, int s2_len); + +// fd_set readfds; + + ASP__TelnetPortParameters *asp_params; + void set_asp_params(); + void reset_configuration(); +}; +} +#endif diff --git a/src/TELNETasp_PortType.ttcn b/src/TELNETasp_PortType.ttcn new file mode 100644 index 0000000000000000000000000000000000000000..7b8a820a4faae232c7e8bd2c8ec430f0c3119c13 --- /dev/null +++ b/src/TELNETasp_PortType.ttcn @@ -0,0 +1,99 @@ +/****************************************************************************** +* Copyright (c) 2004, 2014 Ericsson AB +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v10.html +* +* Contributors: +* Tibor Csondes - initial implementation and initial documentation +* Akos Cserveni +* Elemer Lelik +* Gabor Szalai +* Gabor Tatarka +* Gergely Futo +* Istvan Sandor +* Peter Dimitrov +* Peter Kremer +* Tibor Bende +* Zoltan Medve +******************************************************************************/ +// +// File: TELNETasp_PortType.ttcn +// Description: TELNET testport port definition file +// Rev: R8E +// Prodnr: CNL 113 320 +// + +module TELNETasp_PortType +{ + + external function FindString(in charstring msg_ch, in charstring pattern_ch) return integer; + + type enumerated TelnetReadMode + { + UNBUFFERED (0), + BUFFERED (1) + } + + type record TelnetWindowSize + { + integer width (0..65535), + integer height (0..65535) + } + + type record TelnetPrompt + { + integer id, + charstring prompt, + boolean has_wildcards + } + + type record of TelnetPrompt TelnetPrompts; + + type boolean TelnetEcho; + + type record ASP_TelnetPortParameters + { + charstring ctrl_hostname optional, + integer ctrl_portnum optional, + charstring ctrl_username optional, + charstring ctrl_password optional, + charstring ctrl_domain optional, + TelnetReadMode ctrl_readmode optional, + boolean ctrl_login_skipped optional, + boolean ctrl_detect_server_disconnected optional, + TelnetPrompts prompts optional, + charstring ctrl_terminal_type optional, + TelnetEcho ctrl_echo optional, + boolean ctrl_CRLF optional, + TelnetWindowSize ctrl_window_size optional + } + + + type union ASP_TelnetDynamicConfig + { + TelnetReadMode readmode, + TelnetWindowSize window_size, + TelnetEcho echo, + TelnetPrompt prompt + } + + type enumerated ASP_TelnetConnection + { + CONNECT(0) + } + + type record ASP_TelnetClose {} + + type port TELNETasp_PT message + { + inout charstring; + in integer; + out ASP_TelnetPortParameters, + ASP_TelnetDynamicConfig, + ASP_TelnetConnection, + ASP_TelnetClose; + } + +}