=UTF-8
5 |
--------------------------------------------------------------------------------
/socket_echo/.settings/org.eclipse.jdt.core.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
3 | org.eclipse.jdt.core.compiler.compliance=1.7
4 | org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
5 | org.eclipse.jdt.core.compiler.source=1.7
6 |
--------------------------------------------------------------------------------
/socket_echo/.settings/org.eclipse.m2e.core.prefs:
--------------------------------------------------------------------------------
1 | activeProfiles=
2 | eclipse.preferences.version=1
3 | resolveWorkspaceProjects=true
4 | version=1
5 |
--------------------------------------------------------------------------------
/socket_echo/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | com.xmeter
8 | xmeter-parent
9 | 0.0.3-SNAPSHOT
10 |
11 | net.xmeter
12 | socket_echo
13 | 0.0.1-SNAPSHOT
14 | socket_echo
15 | http://maven.apache.org
16 |
17 | UTF-8
18 |
19 |
20 |
21 | junit
22 | junit
23 | 3.8.1
24 | test
25 |
26 |
27 |
28 |
29 |
30 | org.apache.maven.plugins
31 | maven-compiler-plugin
32 | 3.2
33 |
34 | 1.7
35 | 1.7
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/socket_echo/src/main/java/net/xmeter/echo/BinaryClient.java:
--------------------------------------------------------------------------------
1 | package net.xmeter.echo;
2 |
3 | import java.io.InputStream;
4 | import java.io.OutputStream;
5 | import java.net.InetAddress;
6 | import java.net.Socket;
7 | import java.util.concurrent.TimeUnit;
8 |
9 | public class BinaryClient implements Constants{
10 | private static byte[] produceData() {
11 | byte[] data = new byte[]{START_DELIMITER, 0x3, TYPE_TEMPERATURE, 1, TYPE_BRIGHTNESS, 20, TYPE_HUMIDITY, 30};
12 | long checksum = BinaryServer.calculateChecksum(data);
13 | byte[] ret = new byte[data.length + 1];
14 | System.arraycopy(data, 0, ret, 0, data.length);
15 | ret[ret.length - 1] = (byte) checksum;
16 | System.out.println(bytesToHex(ret));
17 | return ret;
18 | }
19 |
20 | final protected static char[] hexArray = "0123456789ABCDEF".toCharArray();
21 | public static String bytesToHex(byte[] bytes) {
22 | char[] hexChars = new char[bytes.length * 2];
23 | for ( int j = 0; j < bytes.length; j++ ) {
24 | int v = bytes[j] & 0xFF;
25 | hexChars[j * 2] = hexArray[v >>> 4];
26 | hexChars[j * 2 + 1] = hexArray[v & 0x0F];
27 | }
28 | return new String(hexChars);
29 | }
30 |
31 |
32 | public static void main(String[] args) throws Exception {
33 | Socket server;
34 | server = new Socket(InetAddress.getLocalHost(), 4700);
35 | InputStream stream = server.getInputStream();
36 | OutputStream os = server.getOutputStream();
37 | int count = 0;
38 | while (true) {
39 | if(count == 3) {
40 | break;
41 | }
42 | os.write(produceData());
43 | os.flush();
44 | byte[] data = new byte[2014];
45 | int length = stream.read(data);
46 | if(length != -1) {
47 | byte[] tmp = new byte[length - 2];
48 | System.arraycopy(data, 0, tmp, 0, length - 2);
49 | System.out.println(bytesToHex(tmp));
50 | }
51 | TimeUnit.SECONDS.sleep(1);
52 | count++;
53 | }
54 | server.close();
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/socket_echo/src/main/java/net/xmeter/echo/BinaryServer.java:
--------------------------------------------------------------------------------
1 | package net.xmeter.echo;
2 |
3 | import java.io.DataInputStream;
4 | import java.io.IOException;
5 | import java.io.OutputStream;
6 | import java.net.ServerSocket;
7 | import java.net.Socket;
8 | import java.text.MessageFormat;
9 | import java.util.concurrent.ExecutorService;
10 | import java.util.concurrent.Executors;
11 | import java.util.concurrent.TimeUnit;
12 | import java.util.concurrent.atomic.AtomicInteger;
13 |
14 | class SensorData {
15 | int type;
16 | int value;
17 | }
18 |
19 | public class BinaryServer implements Constants {
20 | public static AtomicInteger sessions = new AtomicInteger(0);
21 |
22 | public void handleRequest(final Socket socket) {
23 | ExecutorService executor = Executors.newSingleThreadExecutor();
24 |
25 | executor.submit(new Runnable() {
26 | @Override
27 | public void run() {
28 | try {
29 | DataInputStream ds = new DataInputStream(socket.getInputStream());
30 | OutputStream os = socket.getOutputStream();
31 | int readEmptyContentCount = 0;
32 | while (true) {
33 | byte[] data = new byte[1024];
34 | int actualLen = ds.read(data);
35 | if (actualLen == -1) {
36 | TimeUnit.MICROSECONDS.sleep(100);
37 | readEmptyContentCount++;
38 | if(readEmptyContentCount == 50) {
39 | System.out.println("Probably the client side closed the connection, now close me as well.");
40 | socket.close();
41 | break;
42 | }
43 | continue;
44 | }
45 | byte[] tmp = new byte[actualLen];
46 | System.arraycopy(data, 0, tmp, 0, actualLen);
47 | int startDelimterIndex = -1;
48 | for (int i = 0; i < tmp.length; i++) {
49 | if (tmp[i] == START_DELIMITER) {
50 | startDelimterIndex = i;
51 | break;
52 | }
53 | }
54 | if (startDelimterIndex != -1) {
55 | System.out.println("Find the start delimiter at " + startDelimterIndex + ".");
56 | byte[] ret = parseData(startDelimterIndex, tmp);
57 | os.write(ret);
58 | os.flush();
59 | }
60 | }
61 | } catch (Exception ex) {
62 | ex.printStackTrace();
63 | } finally {
64 | try {
65 | socket.close();
66 | int num = sessions.decrementAndGet();
67 | System.out.println("Now has " + num + " of conn.");
68 | } catch (IOException e) {
69 | e.printStackTrace();
70 | }
71 | }
72 | }
73 |
74 | });
75 | }
76 |
77 | public static long calculateChecksum(byte[] buf) {
78 | int length = buf.length;
79 | int i = 0;
80 |
81 | long sum = 0;
82 | long data;
83 |
84 | // Handle all pairs
85 | while (length > 1) {
86 | data = (((buf[i] << 8) & 0xFF00) | ((buf[i + 1]) & 0xFF));
87 | sum += data;
88 | if ((sum & 0xFFFF0000) > 0) {
89 | sum = sum & 0xFFFF;
90 | sum += 1;
91 | }
92 |
93 | i += 2;
94 | length -= 2;
95 | }
96 |
97 | if (length > 0) {
98 | sum += (buf[i] << 8 & 0xFF00);
99 | if ((sum & 0xFFFF0000) > 0) {
100 | sum = sum & 0xFFFF;
101 | sum += 1;
102 | }
103 | }
104 |
105 | sum = ~sum;
106 | sum = sum & 0xFFFF;
107 | return sum;
108 | }
109 |
110 | /**
111 | * The protocol: start_delimit|length[|data_type|data_val]|checksum
112 | */
113 | private byte[] parseData(int startDelimiter, byte[] data) {
114 | if (!validateChecksum(startDelimiter, data)) {
115 | long checksum = calculateChecksum(new byte[] {START_DELIMITER, RESPONSE_ERR});
116 | System.out.println("Wrong data, invalid checksum. Return with err response code.");
117 | return new byte[] {START_DELIMITER, RESPONSE_ERR, (byte)checksum, '\n'};
118 | }
119 |
120 | int length = data[startDelimiter + 1];
121 | if(length == 0) {
122 | long checksum = calculateChecksum(new byte[] {START_DELIMITER, RESPONSE_ERR});
123 | System.out.println("Wrong data, invalid data length. Return with err response code.");
124 | return new byte[] {START_DELIMITER, RESPONSE_ERR, (byte)checksum, '\n'};
125 | }
126 |
127 | int dataCount = 0;
128 | for (int i = 2; i < data.length;) {
129 | int type = data[i++];
130 | int value = data[i++];
131 | dumpData(type, value);
132 | dataCount++;
133 | if(length == dataCount) {
134 | break;
135 | }
136 | }
137 | long checksum = calculateChecksum(new byte[] {START_DELIMITER, RESPONSE_OK});
138 | System.out.println("Correct data. Return with correct response code.");
139 | return new byte[] {START_DELIMITER, RESPONSE_OK, (byte)checksum, '\n'};
140 | }
141 |
142 | private void dumpData(int type, int data) {
143 | String desc = "Unknow type";
144 | if (type == TYPE_BRIGHTNESS) {
145 | desc = "brightness";
146 | } else if (type == TYPE_HUMIDITY) {
147 | desc = "humidity";
148 | } else if (type == TYPE_TEMPERATURE) {
149 | desc = "temperature";
150 | }
151 | System.out.println(MessageFormat.format("Received data {0} for sensor {1}.", data, desc));
152 | }
153 |
154 | private boolean validateChecksum(int startDelimiter, byte[] data) {
155 | byte[] tmp = new byte[data.length - 1];
156 | System.arraycopy(data, 0, tmp, 0, data.length - 1);
157 | byte checksum = (byte) calculateChecksum(tmp);
158 | return checksum == data[data.length - 1];
159 | }
160 |
161 | public static void main(String[] args) {
162 | try {
163 | ServerSocket server = new ServerSocket(4700);
164 | while (true) {
165 | Socket socket = server.accept();
166 | BinaryServer srv = new BinaryServer();
167 | srv.handleRequest(socket);
168 | int num = sessions.incrementAndGet();
169 | System.out.println("Received new conn, now totally has " + num + " of conn.");
170 | }
171 | } catch (Exception e) {
172 | e.printStackTrace();
173 | }
174 | }
175 | }
176 |
--------------------------------------------------------------------------------
/socket_echo/src/main/java/net/xmeter/echo/Constants.java:
--------------------------------------------------------------------------------
1 | package net.xmeter.echo;
2 |
3 | public interface Constants {
4 | public static final int START_DELIMITER = 0x7e;
5 | public static final int TYPE_TEMPERATURE = 0x1;
6 | public static final int TYPE_BRIGHTNESS = 0x2;
7 | public static final int TYPE_HUMIDITY = 0x3;
8 |
9 | public static final int RESPONSE_OK = 0x00;
10 | public static final int RESPONSE_ERR = 0x01;
11 | }
12 |
--------------------------------------------------------------------------------
/socket_echo/src/main/java/net/xmeter/echo/TextServer.java:
--------------------------------------------------------------------------------
1 | package net.xmeter.echo;
2 |
3 | import java.io.BufferedReader;
4 | import java.io.IOException;
5 | import java.io.InputStreamReader;
6 | import java.io.PrintWriter;
7 | import java.net.ServerSocket;
8 | import java.net.Socket;
9 | import java.util.concurrent.ExecutorService;
10 | import java.util.concurrent.Executors;
11 | import java.util.concurrent.atomic.AtomicInteger;
12 |
13 | public class TextServer {
14 | public static AtomicInteger sessions = new AtomicInteger(0);
15 |
16 | public void handleRequest(final Socket socket) {
17 | ExecutorService executor = Executors.newSingleThreadExecutor();
18 |
19 | executor.submit(new Runnable() {
20 | @Override
21 | public void run() {
22 | try {
23 | BufferedReader is = new BufferedReader(new InputStreamReader(socket.getInputStream()));
24 | PrintWriter os = new PrintWriter(socket.getOutputStream());
25 | while(true) {
26 | String line = is.readLine();
27 | if(line == null) {
28 | System.out.println("Probably the client side closed the connection, now close me as well.");
29 | socket.close();
30 | break;
31 | }
32 | System.out.println("Received message: " + line);
33 | os.println("Echo: " + line);
34 | os.flush();
35 | if("bye".equals(line)) {
36 | break;
37 | }
38 | }
39 | } catch(Exception ex) {
40 | ex.printStackTrace();
41 | } finally {
42 | try {
43 | socket.close();
44 | int num = sessions.decrementAndGet();
45 | System.out.println("Now totally has " + num + " of conn.");
46 | } catch (IOException e) {
47 | e.printStackTrace();
48 | }
49 | }
50 | }
51 |
52 | });
53 |
54 | }
55 |
56 | public static void main(String[] args) {
57 | try {
58 | ServerSocket server = new ServerSocket(4700);
59 | while(true) {
60 | Socket socket = server.accept();
61 | TextServer srv = new TextServer();
62 | srv.handleRequest(socket);
63 | int num = sessions.incrementAndGet();
64 | System.out.println("Received new conn, now totally has " + num + " of conn.");
65 | }
66 | } catch (Exception e) {
67 | e.printStackTrace();
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/socket_echo/src/test/java/net/xmeter/socket_echo/AppTest.java:
--------------------------------------------------------------------------------
1 | package net.xmeter.socket_echo;
2 |
3 | import junit.framework.Test;
4 | import junit.framework.TestCase;
5 | import junit.framework.TestSuite;
6 |
7 | /**
8 | * Unit test for simple App.
9 | */
10 | public class AppTest
11 | extends TestCase
12 | {
13 | /**
14 | * Create the test case
15 | *
16 | * @param testName name of the test case
17 | */
18 | public AppTest( String testName )
19 | {
20 | super( testName );
21 | }
22 |
23 | /**
24 | * @return the suite of tests being tested
25 | */
26 | public static Test suite()
27 | {
28 | return new TestSuite( AppTest.class );
29 | }
30 |
31 | /**
32 | * Rigourous Test :-)
33 | */
34 | public void testApp()
35 | {
36 | assertTrue( true );
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/tcp/src/protocol/tcp/org/apache/jmeter/protocol/tcp/config/gui/TCPConfigGui.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 |
19 | package org.apache.jmeter.protocol.tcp.config.gui;
20 |
21 | import java.awt.BorderLayout;
22 | import java.awt.Dimension;
23 | import java.awt.FlowLayout;
24 | import java.awt.event.ItemEvent;
25 |
26 | import javax.swing.BorderFactory;
27 | import javax.swing.JCheckBox;
28 | import javax.swing.JLabel;
29 | import javax.swing.JPanel;
30 | import javax.swing.JTextField;
31 |
32 | import org.apache.jmeter.config.ConfigTestElement;
33 | import org.apache.jmeter.config.gui.AbstractConfigGui;
34 | import org.apache.jmeter.gui.ServerPanel;
35 | import org.apache.jmeter.gui.util.HorizontalPanel;
36 | import org.apache.jmeter.gui.util.JSyntaxTextArea;
37 | import org.apache.jmeter.gui.util.JTextScrollPane;
38 | import org.apache.jmeter.gui.util.TristateCheckBox;
39 | import org.apache.jmeter.gui.util.VerticalPanel;
40 | import org.apache.jmeter.protocol.tcp.sampler.TCPSampler;
41 | import org.apache.jmeter.testelement.TestElement;
42 | import org.apache.jmeter.util.JMeterUtils;
43 | import org.apache.jorphan.gui.JLabeledTextField;
44 |
45 | public class TCPConfigGui extends AbstractConfigGui {
46 |
47 | private static final long serialVersionUID = 240L;
48 |
49 | private ServerPanel serverPanel;
50 |
51 | private JLabeledTextField classname;
52 |
53 | private JCheckBox reUseConnection;
54 |
55 | private TristateCheckBox setNoDelay;
56 |
57 | private TristateCheckBox closeConnection;
58 |
59 | private JTextField soLinger;
60 |
61 | private JTextField eolByte;
62 |
63 | private JTextField responseLenth;
64 |
65 | private JSyntaxTextArea requestData;
66 |
67 | private boolean displayName = true;
68 |
69 | public TCPConfigGui() {
70 | this(true);
71 | }
72 |
73 | public TCPConfigGui(boolean displayName) {
74 | this.displayName = displayName;
75 | init();
76 | }
77 |
78 | @Override
79 | public String getLabelResource() {
80 | return "tcp_config_title"; // $NON-NLS-1$
81 | }
82 |
83 | @Override
84 | public void configure(TestElement element) {
85 | super.configure(element);
86 | // N.B. this will be a config element, so we cannot use the getXXX() methods
87 | classname.setText(element.getPropertyAsString(TCPSampler.CLASSNAME));
88 | serverPanel.setServer(element.getPropertyAsString(TCPSampler.SERVER));
89 | // Default to original behaviour, i.e. re-use connection
90 | reUseConnection.setSelected(element.getPropertyAsBoolean(TCPSampler.RE_USE_CONNECTION, TCPSampler.RE_USE_CONNECTION_DEFAULT));
91 | serverPanel.setPort(element.getPropertyAsString(TCPSampler.PORT));
92 | serverPanel.setResponseTimeout(element.getPropertyAsString(TCPSampler.TIMEOUT));
93 | serverPanel.setConnectTimeout(element.getPropertyAsString(TCPSampler.TIMEOUT_CONNECT));
94 | setNoDelay.setTristateFromProperty(element, TCPSampler.NODELAY);
95 | requestData.setInitialText(element.getPropertyAsString(TCPSampler.REQUEST));
96 | requestData.setCaretPosition(0);
97 | closeConnection.setTristateFromProperty(element, TCPSampler.CLOSE_CONNECTION);
98 | soLinger.setText(element.getPropertyAsString(TCPSampler.SO_LINGER));
99 | eolByte.setText(element.getPropertyAsString(TCPSampler.EOL_BYTE));
100 | responseLenth.setText(element.getPropertyAsString(TCPSampler.LENGTH, ""));
101 | }
102 |
103 | @Override
104 | public TestElement createTestElement() {
105 | ConfigTestElement element = new ConfigTestElement();
106 | modifyTestElement(element);
107 | return element;
108 | }
109 |
110 | /**
111 | * Modifies a given TestElement to mirror the data in the gui components.
112 | *
113 | * @see org.apache.jmeter.gui.JMeterGUIComponent#modifyTestElement(TestElement)
114 | */
115 | @Override
116 | public void modifyTestElement(TestElement element) {
117 | configureTestElement(element);
118 | // N.B. this will be a config element, so we cannot use the setXXX() methods
119 | element.setProperty(TCPSampler.CLASSNAME, classname.getText(), "");
120 | element.setProperty(TCPSampler.SERVER, serverPanel.getServer());
121 | element.setProperty(TCPSampler.RE_USE_CONNECTION, reUseConnection.isSelected());
122 | element.setProperty(TCPSampler.PORT, serverPanel.getPort());
123 | setNoDelay.setPropertyFromTristate(element, TCPSampler.NODELAY);
124 | element.setProperty(TCPSampler.TIMEOUT, serverPanel.getResponseTimeout());
125 | element.setProperty(TCPSampler.TIMEOUT_CONNECT, serverPanel.getConnectTimeout(),"");
126 | element.setProperty(TCPSampler.REQUEST, requestData.getText());
127 | closeConnection.setPropertyFromTristate(element, TCPSampler.CLOSE_CONNECTION); // Don't use default for saving tristates
128 | element.setProperty(TCPSampler.SO_LINGER, soLinger.getText(), "");
129 | element.setProperty(TCPSampler.EOL_BYTE, eolByte.getText(), "");
130 | element.setProperty(TCPSampler.LENGTH, responseLenth.getText(), "");
131 | }
132 |
133 | /**
134 | * Implements JMeterGUIComponent.clearGui
135 | */
136 | @Override
137 | public void clearGui() {
138 | super.clearGui();
139 |
140 | serverPanel.clear();
141 | classname.setText(""); //$NON-NLS-1$
142 | requestData.setInitialText(""); //$NON-NLS-1$
143 | reUseConnection.setSelected(true);
144 | setNoDelay.setSelected(false); // TODO should this be indeterminate?
145 | closeConnection.setSelected(TCPSampler.CLOSE_CONNECTION_DEFAULT); // TODO should this be indeterminate?
146 | soLinger.setText(""); //$NON-NLS-1$
147 | eolByte.setText(""); //$NON-NLS-1$
148 | responseLenth.setText("");
149 | }
150 |
151 |
152 | private JPanel createNoDelayPanel() {
153 | JLabel label = new JLabel(JMeterUtils.getResString("tcp_nodelay")); // $NON-NLS-1$
154 |
155 | setNoDelay = new TristateCheckBox();
156 | label.setLabelFor(setNoDelay);
157 |
158 | JPanel nodelayPanel = new JPanel(new FlowLayout());
159 | nodelayPanel.add(label);
160 | nodelayPanel.add(setNoDelay);
161 | return nodelayPanel;
162 | }
163 |
164 | private JPanel createClosePortPanel() {
165 | JLabel label = new JLabel(JMeterUtils.getResString("reuseconnection")); //$NON-NLS-1$
166 |
167 | reUseConnection = new JCheckBox("", true);
168 | reUseConnection.addItemListener(e -> {
169 | if (e.getStateChange() == ItemEvent.SELECTED) {
170 | closeConnection.setEnabled(true);
171 | } else {
172 | closeConnection.setEnabled(false);
173 | }
174 | });
175 | label.setLabelFor(reUseConnection);
176 |
177 | JPanel closePortPanel = new JPanel(new FlowLayout());
178 | closePortPanel.add(label);
179 | closePortPanel.add(reUseConnection);
180 | return closePortPanel;
181 | }
182 |
183 | private JPanel createCloseConnectionPanel() {
184 | JLabel label = new JLabel(JMeterUtils.getResString("closeconnection")); // $NON-NLS-1$
185 |
186 | closeConnection = new TristateCheckBox("", TCPSampler.CLOSE_CONNECTION_DEFAULT);
187 | label.setLabelFor(closeConnection);
188 |
189 | JPanel closeConnectionPanel = new JPanel(new FlowLayout());
190 | closeConnectionPanel.add(label);
191 | closeConnectionPanel.add(closeConnection);
192 | return closeConnectionPanel;
193 | }
194 |
195 | private JPanel createSoLingerOption() {
196 | JLabel label = new JLabel(JMeterUtils.getResString("solinger")); //$NON-NLS-1$
197 |
198 | soLinger = new JTextField(5); // 5 columns size
199 | soLinger.setMaximumSize(new Dimension(soLinger.getPreferredSize()));
200 | label.setLabelFor(soLinger);
201 |
202 | JPanel soLingerPanel = new JPanel(new FlowLayout());
203 | soLingerPanel.add(label);
204 | soLingerPanel.add(soLinger);
205 | return soLingerPanel;
206 | }
207 |
208 | private JPanel createEolBytePanel() {
209 | JLabel label = new JLabel(JMeterUtils.getResString("eolbyte")); //$NON-NLS-1$
210 |
211 | eolByte = new JTextField(3); // 3 columns size
212 | eolByte.setMaximumSize(new Dimension(eolByte.getPreferredSize()));
213 | label.setLabelFor(eolByte);
214 |
215 | JPanel eolBytePanel = new JPanel(new FlowLayout());
216 | eolBytePanel.add(label);
217 | eolBytePanel.add(eolByte);
218 | return eolBytePanel;
219 | }
220 |
221 | private JPanel createLengthPanel() {
222 | JLabel label = new JLabel(JMeterUtils.getResString("response_length")); //$NON-NLS-1$
223 |
224 | responseLenth = new JTextField(3); // 3 columns size
225 | responseLenth.setMaximumSize(new Dimension(responseLenth.getPreferredSize()));
226 | label.setLabelFor(responseLenth);
227 |
228 | JPanel eolBytePanel = new JPanel(new FlowLayout());
229 | eolBytePanel.add(label);
230 | eolBytePanel.add(responseLenth);
231 | return eolBytePanel;
232 | }
233 |
234 | private JPanel createRequestPanel() {
235 | JLabel reqLabel = new JLabel(JMeterUtils.getResString("tcp_request_data")); // $NON-NLS-1$
236 | requestData = JSyntaxTextArea.getInstance(15, 80);
237 | requestData.setLanguage("text"); //$NON-NLS-1$
238 | reqLabel.setLabelFor(requestData);
239 |
240 | JPanel reqDataPanel = new JPanel(new BorderLayout(5, 0));
241 | reqDataPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder()));
242 |
243 | reqDataPanel.add(reqLabel, BorderLayout.WEST);
244 | reqDataPanel.add(JTextScrollPane.getInstance(requestData), BorderLayout.CENTER);
245 | return reqDataPanel;
246 | }
247 |
248 | private void init() { // WARNING: called from ctor so must not be overridden (i.e. must be private or final)
249 | setLayout(new BorderLayout(0, 5));
250 |
251 | serverPanel = new ServerPanel();
252 |
253 | if (displayName) {
254 | setBorder(makeBorder());
255 | add(makeTitlePanel(), BorderLayout.NORTH);
256 | }
257 |
258 | VerticalPanel mainPanel = new VerticalPanel();
259 | classname = new JLabeledTextField(JMeterUtils.getResString("tcp_classname")); // $NON-NLS-1$
260 | mainPanel.add(classname);
261 | mainPanel.add(serverPanel);
262 |
263 | HorizontalPanel optionsPanel = new HorizontalPanel();
264 | optionsPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder()));
265 | optionsPanel.add(createClosePortPanel());
266 | optionsPanel.add(createCloseConnectionPanel());
267 | optionsPanel.add(createNoDelayPanel());
268 | optionsPanel.add(createSoLingerOption());
269 | optionsPanel.add(createEolBytePanel());
270 | optionsPanel.add(createLengthPanel());
271 | mainPanel.add(optionsPanel);
272 | mainPanel.add(createRequestPanel());
273 |
274 | add(mainPanel, BorderLayout.CENTER);
275 | }
276 | }
277 |
--------------------------------------------------------------------------------
/tcp/src/protocol/tcp/org/apache/jmeter/protocol/tcp/control/gui/TCPSamplerGui.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 |
19 | package org.apache.jmeter.protocol.tcp.control.gui;
20 |
21 | import java.awt.BorderLayout;
22 |
23 | import javax.swing.BorderFactory;
24 |
25 | import org.apache.jmeter.config.gui.LoginConfigGui;
26 | import org.apache.jmeter.gui.util.VerticalPanel;
27 | import org.apache.jmeter.protocol.tcp.config.gui.TCPConfigGui;
28 | import org.apache.jmeter.protocol.tcp.sampler.TCPSampler;
29 | import org.apache.jmeter.samplers.gui.AbstractSamplerGui;
30 | import org.apache.jmeter.testelement.TestElement;
31 | import org.apache.jmeter.util.JMeterUtils;
32 |
33 | public class TCPSamplerGui extends AbstractSamplerGui {
34 |
35 | private static final long serialVersionUID = 240L;
36 |
37 | private LoginConfigGui loginPanel;
38 | private TCPConfigGui tcpDefaultPanel;
39 |
40 | public TCPSamplerGui() {
41 | init();
42 | }
43 |
44 | @Override
45 | public void configure(TestElement element) {
46 | super.configure(element);
47 | loginPanel.configure(element);
48 | tcpDefaultPanel.configure(element);
49 | }
50 |
51 | @Override
52 | public TestElement createTestElement() {
53 | TCPSampler sampler = new TCPSampler();
54 | modifyTestElement(sampler);
55 | return sampler;
56 | }
57 |
58 | /**
59 | * Modifies a given TestElement to mirror the data in the gui components.
60 | *
61 | * @see org.apache.jmeter.gui.JMeterGUIComponent#modifyTestElement(TestElement)
62 | */
63 | @Override
64 | public void modifyTestElement(TestElement sampler) {
65 | sampler.clear();
66 | sampler.addTestElement(tcpDefaultPanel.createTestElement());
67 | sampler.addTestElement(loginPanel.createTestElement());
68 | super.configureTestElement(sampler);
69 | }
70 |
71 | /**
72 | * Implements JMeterGUIComponent.clearGui
73 | */
74 | @Override
75 | public void clearGui() {
76 | super.clearGui();
77 |
78 | tcpDefaultPanel.clearGui();
79 | loginPanel.clearGui();
80 | }
81 |
82 | @Override
83 | public String getLabelResource() {
84 | return "tcp_sample_title"; // $NON-NLS-1$
85 | }
86 |
87 | private void init() { // WARNING: called from ctor so must not be overridden (i.e. must be private or final)
88 | setLayout(new BorderLayout(0, 5));
89 | setBorder(makeBorder());
90 |
91 | add(makeTitlePanel(), BorderLayout.NORTH);
92 |
93 | VerticalPanel mainPanel = new VerticalPanel();
94 |
95 | tcpDefaultPanel = new TCPConfigGui(false);
96 | mainPanel.add(tcpDefaultPanel);
97 |
98 | loginPanel = new LoginConfigGui(false);
99 | loginPanel.setBorder(BorderFactory.createTitledBorder(JMeterUtils.getResString("login_config"))); // $NON-NLS-1$
100 | mainPanel.add(loginPanel);
101 |
102 | add(mainPanel, BorderLayout.CENTER);
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/tcp/src/protocol/tcp/org/apache/jmeter/protocol/tcp/sampler/AbstractTCPClient.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 |
19 | package org.apache.jmeter.protocol.tcp.sampler;
20 |
21 | import java.io.InputStream;
22 |
23 | import org.apache.jmeter.samplers.SampleResult;
24 |
25 | /**
26 | * Basic implementation of TCPClient interface.
27 | */
28 | public abstract class AbstractTCPClient implements TCPClient {
29 | private String charset;
30 | protected byte eolByte;
31 | protected boolean useEolByte = false;
32 | protected int length = -1;
33 | /**
34 | * {@inheritDoc}
35 | */
36 | @Override
37 | public byte getEolByte() {
38 | return eolByte;
39 | }
40 |
41 | /**
42 | * {@inheritDoc}
43 | */
44 | @Override
45 | public void setEolByte(int eolInt) {
46 | if (eolInt >= Byte.MIN_VALUE && eolInt <= Byte.MAX_VALUE) {
47 | this.eolByte = (byte) eolInt;
48 | useEolByte = true;
49 | } else {
50 | useEolByte = false;
51 | }
52 | }
53 |
54 | /**
55 | * {@inheritDoc}
56 | */
57 | @Override
58 | public void setupTest() {
59 | }
60 |
61 | /**
62 | * {@inheritDoc}
63 | */
64 | @Override
65 | public void teardownTest() {
66 | }
67 |
68 | /**
69 | * @return the charset
70 | */
71 | @Override
72 | public String getCharset() {
73 | return charset;
74 | }
75 |
76 | /**
77 | * @param charset the charset to set
78 | */
79 | public void setCharset(String charset) {
80 | this.charset = charset;
81 | }
82 |
83 | /**
84 | * Default implementation calls {@link TCPClient#read(InputStream)} for backward compatibility
85 | * @see org.apache.jmeter.protocol.tcp.sampler.TCPClient#read(java.io.InputStream, org.apache.jmeter.samplers.SampleResult)
86 | */
87 | @Override
88 | public String read(InputStream is, SampleResult sampleResult) throws ReadException {
89 | return read(is);
90 | }
91 |
92 | @Override
93 | public int getLength() {
94 | if(useEolByte) {
95 | return -1;
96 | }
97 | return length;
98 | }
99 |
100 | @Override
101 | public void setLength(int length) {
102 | this.length = length;
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/tcp/src/protocol/tcp/org/apache/jmeter/protocol/tcp/sampler/BinaryTCPClientImpl.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 |
19 | /*
20 | * TCP Sampler Client implementation which reads and writes binary data.
21 | *
22 | * Input/Output strings are passed as hex-encoded binary strings.
23 | *
24 | */
25 | package org.apache.jmeter.protocol.tcp.sampler;
26 |
27 | import java.io.ByteArrayOutputStream;
28 | import java.io.IOException;
29 | import java.io.InputStream;
30 | import java.io.OutputStream;
31 |
32 | import org.apache.commons.io.IOUtils;
33 | import org.apache.jmeter.samplers.SampleResult;
34 | import org.apache.jmeter.util.JMeterUtils;
35 | import org.apache.jorphan.util.JOrphanUtils;
36 | import org.slf4j.Logger;
37 | import org.slf4j.LoggerFactory;
38 |
39 | /**
40 | * TCPClient implementation.
41 | * Reads data until the defined EOM byte is reached.
42 | * If there is no EOM byte defined, then reads until
43 | * the end of the stream is reached.
44 | * The EOM byte is defined by the property "tcp.BinaryTCPClient.eomByte".
45 | *
46 | * Input data is assumed to be in hex, and is converted to binary
47 | */
48 | public class BinaryTCPClientImpl extends AbstractTCPClient {
49 | private static final Logger log = LoggerFactory.getLogger(BinaryTCPClientImpl.class);
50 |
51 | private static final int EOM_INT = JMeterUtils.getPropDefault("tcp.BinaryTCPClient.eomByte", 1000); // $NON_NLS-1$
52 |
53 | public BinaryTCPClientImpl() {
54 | super();
55 | setEolByte(EOM_INT);
56 | if (useEolByte) {
57 | log.info("Using eomByte={}", eolByte);
58 | }
59 | }
60 |
61 | /**
62 | * Convert hex string to binary byte array.
63 | *
64 | * @param hexEncodedBinary - hex-encoded binary string
65 | * @return Byte array containing binary representation of input hex-encoded string
66 | * @throws IllegalArgumentException if string is not an even number of hex digits
67 | */
68 | public static byte[] hexStringToByteArray(String hexEncodedBinary) {
69 | if (hexEncodedBinary.length() % 2 == 0) {
70 | char[] sc = hexEncodedBinary.toCharArray();
71 | byte[] ba = new byte[sc.length / 2];
72 |
73 | for (int i = 0; i < ba.length; i++) {
74 | int nibble0 = Character.digit(sc[i * 2], 16);
75 | int nibble1 = Character.digit(sc[i * 2 + 1], 16);
76 | if (nibble0 == -1 || nibble1 == -1){
77 | throw new IllegalArgumentException(
78 | "Hex-encoded binary string contains an invalid hex digit in '"+sc[i * 2]+sc[i * 2 + 1]+"'");
79 | }
80 | ba[i] = (byte) ((nibble0 << 4) | nibble1);
81 | }
82 |
83 | return ba;
84 | } else {
85 | throw new IllegalArgumentException(
86 | "Hex-encoded binary string contains an uneven no. of digits");
87 | }
88 | }
89 |
90 | /**
91 | * Input (hex) string is converted to binary and written to the output stream.
92 | * @param os output stream
93 | * @param hexEncodedBinary hex-encoded binary
94 | */
95 | @Override
96 | public void write(OutputStream os, String hexEncodedBinary) throws IOException{
97 | os.write(hexStringToByteArray(hexEncodedBinary));
98 | os.flush();
99 | if(log.isDebugEnabled()) {
100 | log.debug("Wrote: " + hexEncodedBinary);
101 | }
102 | }
103 |
104 | /**
105 | * {@inheritDoc}
106 | */
107 | @Override
108 | public void write(OutputStream os, InputStream is) {
109 | throw new UnsupportedOperationException(
110 | "Method not supported for Length-Prefixed data.");
111 | }
112 |
113 | @Deprecated
114 | public String read(InputStream is) throws ReadException {
115 | log.warn("Deprecated method, use read(is, sampleResult) instead");
116 | return read(is, new SampleResult());
117 | }
118 |
119 | /**
120 | * Reads data until the defined EOM byte is reached.
121 | * If there is no EOM byte defined, then reads until
122 | * the end of the stream is reached.
123 | * Response data is converted to hex-encoded binary
124 | * @return hex-encoded binary string
125 | * @throws ReadException when reading fails
126 | */
127 | @Override
128 | public String read(InputStream is, SampleResult sampleResult) throws ReadException {
129 | ByteArrayOutputStream w = new ByteArrayOutputStream();
130 | try {
131 | byte[] buffer = new byte[4096];
132 | int x = 0;
133 | boolean first = true;
134 | if(getLength() == -1) {
135 | while ((x = is.read(buffer)) > -1) {
136 | if (first) {
137 | sampleResult.latencyEnd();
138 | first = false;
139 | }
140 | w.write(buffer, 0, x);
141 | if (useEolByte && (buffer[x - 1] == eolByte)) {
142 | break;
143 | }
144 | }
145 | } else {
146 | buffer = new byte[length];
147 | if ((x = is.read(buffer, 0, length)) > -1) {
148 | sampleResult.latencyEnd();
149 | w.write(buffer, 0, x);
150 | }
151 | }
152 |
153 | IOUtils.closeQuietly(w); // For completeness
154 | final String hexString = JOrphanUtils.baToHexString(w.toByteArray());
155 | if(log.isDebugEnabled()) {
156 | log.debug("Read: " + w.size() + "\n" + hexString);
157 | }
158 | return hexString;
159 | } catch (IOException e) {
160 | throw new ReadException("", e, JOrphanUtils.baToHexString(w.toByteArray()));
161 | }
162 | }
163 |
164 | }
165 |
--------------------------------------------------------------------------------
/tcp/src/protocol/tcp/org/apache/jmeter/protocol/tcp/sampler/LengthPrefixedBinaryTCPClientImpl.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 |
19 | /*
20 | * TCP Sampler Client implementation which reads and writes length-prefixed binary data.
21 | *
22 | * Input/Output strings are passed as hex-encoded binary strings.
23 | *
24 | * 2-Byte or 4-Byte length prefixes are supported.
25 | *
26 | * Length prefix is binary of length specified by property "tcp.length.prefix.length".
27 | *
28 | */
29 | package org.apache.jmeter.protocol.tcp.sampler;
30 |
31 | import java.io.IOException;
32 | import java.io.InputStream;
33 | import java.io.OutputStream;
34 |
35 | import org.apache.jmeter.samplers.SampleResult;
36 | import org.apache.jmeter.util.JMeterUtils;
37 | import org.apache.jorphan.util.JOrphanUtils;
38 | import org.slf4j.Logger;
39 | import org.slf4j.LoggerFactory;
40 |
41 | /**
42 | * Implements binary length-prefixed binary data.
43 | * This is used in ISO8583 for example.
44 | */
45 | public class LengthPrefixedBinaryTCPClientImpl extends TCPClientDecorator {
46 | private static final Logger log = LoggerFactory.getLogger(LengthPrefixedBinaryTCPClientImpl.class);
47 |
48 | private final int lengthPrefixLen = JMeterUtils.getPropDefault("tcp.binarylength.prefix.length", 2); // $NON-NLS-1$
49 |
50 | public LengthPrefixedBinaryTCPClientImpl() {
51 | super(new BinaryTCPClientImpl());
52 | tcpClient.setEolByte(Byte.MAX_VALUE+1);
53 | }
54 |
55 |
56 | /**
57 | * {@inheritDoc}
58 | */
59 | @Override
60 | public void write(OutputStream os, String s) throws IOException{
61 | os.write(intToByteArray(s.length()/2,lengthPrefixLen));
62 | if(log.isDebugEnabled()) {
63 | log.debug("Wrote: " + s.length()/2 + " bytes");
64 | }
65 | this.tcpClient.write(os, s);
66 | }
67 |
68 | /**
69 | * {@inheritDoc}
70 | */
71 | @Override
72 | public void write(OutputStream os, InputStream is) throws IOException {
73 | this.tcpClient.write(os, is);
74 | }
75 |
76 | @Deprecated
77 | public String read(InputStream is) throws ReadException {
78 | log.warn("Deprecated method, use read(is, sampleResult) instead");
79 | return read(is, new SampleResult());
80 | }
81 |
82 | /**
83 | * {@inheritDoc}
84 | */
85 | @Override
86 | public String read(InputStream is, SampleResult sampleResult) throws ReadException{
87 | byte[] msg = new byte[0];
88 | int msgLen = 0;
89 | byte[] lengthBuffer = new byte[lengthPrefixLen];
90 | try {
91 | if (is.read(lengthBuffer, 0, lengthPrefixLen) == lengthPrefixLen) {
92 | sampleResult.latencyEnd();
93 | msgLen = byteArrayToInt(lengthBuffer);
94 | msg = new byte[msgLen];
95 | int bytes = JOrphanUtils.read(is, msg, 0, msgLen);
96 | if (bytes < msgLen) {
97 | log.warn("Incomplete message read, expected: {} got: {}", msgLen, bytes);
98 | }
99 | }
100 |
101 | String buffer = JOrphanUtils.baToHexString(msg);
102 | if(log.isDebugEnabled()) {
103 | log.debug("Read: " + msgLen + "\n" + buffer);
104 | }
105 | return buffer;
106 | }
107 | catch(IOException e) {
108 | throw new ReadException("", e, JOrphanUtils.baToHexString(msg));
109 | }
110 | }
111 |
112 | /**
113 | * Not useful, as the byte is never used.
114 | *
115 | * {@inheritDoc}
116 | */
117 | @Override
118 | public byte getEolByte() {
119 | return tcpClient.getEolByte();
120 | }
121 |
122 | /**
123 | * {@inheritDoc}
124 | */
125 | @Override
126 | public void setEolByte(int eolInt) {
127 | throw new UnsupportedOperationException("Cannot set eomByte for prefixed messages");
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/tcp/src/protocol/tcp/org/apache/jmeter/protocol/tcp/sampler/ReadException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 | package org.apache.jmeter.protocol.tcp.sampler;
19 |
20 | /**
21 | * Exception that contains partial response (Text read until exception occurred)
22 | */
23 | public class ReadException extends Exception {
24 |
25 | private static final long serialVersionUID = -2770054697780959330L;
26 | private final String partialResponse;
27 |
28 | /**
29 | * @deprecated For use by test code only (serialisation tests)
30 | */
31 | @Deprecated
32 | public ReadException() {
33 | this(null, null, null);
34 | }
35 |
36 | /**
37 | * Constructor
38 | * @param message Message
39 | * @param cause Source cause
40 | * @param partialResponse Text read until error occurred
41 | */
42 | public ReadException(String message, Throwable cause, String partialResponse) {
43 | super(message, cause);
44 | this.partialResponse = partialResponse;
45 | }
46 |
47 | /**
48 | * @return the partialResponse Text read until error occurred
49 | */
50 | public String getPartialResponse() {
51 | return partialResponse;
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/tcp/src/protocol/tcp/org/apache/jmeter/protocol/tcp/sampler/TCPClient.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 |
19 | /*
20 | * Created on 24-Sep-2003
21 | *
22 | * Interface for generic TCP protocol handler
23 | *
24 | */
25 | package org.apache.jmeter.protocol.tcp.sampler;
26 |
27 | import java.io.IOException;
28 | import java.io.InputStream;
29 | import java.io.OutputStream;
30 |
31 | import org.apache.jmeter.samplers.SampleResult;
32 |
33 | /**
34 | * Interface required by TCPSampler for TCPClient implementations.
35 | */
36 | public interface TCPClient {
37 |
38 | /**
39 | * Invoked when the thread starts.
40 | */
41 | void setupTest();
42 |
43 | /**
44 | * Invoked when the thread ends
45 | */
46 | void teardownTest();
47 |
48 | /**
49 | *
50 | * @param os -
51 | * OutputStream for socket
52 | * @param is -
53 | * InputStream to be written to Socket
54 | * @throws IOException when writing fails
55 | */
56 | void write(OutputStream os, InputStream is) throws IOException;
57 |
58 | /**
59 | *
60 | * @param os -
61 | * OutputStream for socket
62 | * @param s -
63 | * String to write
64 | * @throws IOException when writing fails
65 | */
66 | void write(OutputStream os, String s) throws IOException;
67 |
68 | /**
69 | *
70 | * @param is -
71 | * InputStream for socket
72 | * @return String read from socket
73 | * @throws ReadException exception that can contain partial response (Response until error occurred)
74 | * @deprecated since 3.3, implement {@link TCPClient#read(InputStream, SampleResult)} instead, will be removed in future version
75 | */
76 | @Deprecated
77 | String read(InputStream is) throws ReadException;
78 |
79 | /**
80 | *
81 | * @param is -
82 | * InputStream for socket
83 | * @param sampleResult {@link SampleResult}
84 | * @return String read from socket
85 | * @throws ReadException exception that can contain partial response
86 | */
87 | String read(InputStream is, SampleResult sampleResult) throws ReadException;
88 |
89 | /**
90 | * Get the end-of-line/end-of-message byte.
91 | * @return Returns the eolByte.
92 | */
93 | byte getEolByte();
94 |
95 |
96 | /**
97 | * Get the charset.
98 | * @return Returns the charset.
99 | */
100 | String getCharset();
101 |
102 | /**
103 | * Set the end-of-line/end-of-message byte.
104 | * If the value is out of range of a byte, then it is to be ignored.
105 | *
106 | * @param eolInt
107 | * The value to set
108 | */
109 | void setEolByte(int eolInt);
110 |
111 | /**
112 | * Get the response length setting
113 | *
114 | * @return
115 | */
116 | int getLength();
117 |
118 |
119 | /**
120 | * Set the length of returned response.
121 | *
122 | * @param length
123 | */
124 | void setLength(int length);
125 | }
126 |
--------------------------------------------------------------------------------
/tcp/src/protocol/tcp/org/apache/jmeter/protocol/tcp/sampler/TCPClientDecorator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 |
19 | /*
20 | * TCP Sampler Client decorator to permit wrapping base client implementations with length prefixes.
21 | * For example, character data or binary data with character length or binary length
22 | *
23 | */
24 | package org.apache.jmeter.protocol.tcp.sampler;
25 |
26 | public abstract class TCPClientDecorator extends AbstractTCPClient {
27 |
28 | protected final TCPClient tcpClient; // the data implementation
29 |
30 | public TCPClientDecorator(TCPClient tcpClient) {
31 | this.tcpClient = tcpClient;
32 | }
33 |
34 | /**
35 | * Convert int to byte array.
36 | *
37 | * @param value
38 | * - int to be converted
39 | * @param len
40 | * - length of required byte array
41 | * @return Byte array representation of input value
42 | * @throws IllegalArgumentException if not length 2 or 4 or outside range of a short int.
43 | */
44 | public static byte[] intToByteArray(int value, int len) {
45 | if (len == 2 || len == 4) {
46 | if (len == 2 && (value < Short.MIN_VALUE || value > Short.MAX_VALUE)) {
47 | throw new IllegalArgumentException("Value outside range for signed short int.");
48 | } else {
49 | byte[] b = new byte[len];
50 | for (int i = 0; i < len; i++) {
51 | int offset = (b.length - 1 - i) * 8;
52 | b[i] = (byte) ((value >>> offset) & 0xFF);
53 | }
54 | return b;
55 | }
56 | } else {
57 | throw new IllegalArgumentException(
58 | "Length must be specified as either 2 or 4.");
59 | }
60 | }
61 |
62 | /**
63 | * Convert byte array to int.
64 | *
65 | * @param b
66 | * - Byte array to be converted
67 | * @return Integer value of input byte array
68 | * @throws IllegalArgumentException if ba is null or not length 2 or 4
69 | */
70 | public static int byteArrayToInt(byte[] b) {
71 | if (b != null && (b.length == 2 || b.length == 4)) {
72 | // Preserve sign on first byte
73 | int value = b[0] << ((b.length - 1) * 8);
74 |
75 | for (int i = 1; i < b.length; i++) {
76 | int offset = (b.length - 1 - i) * 8;
77 | value += (b[i] & 0xFF) << offset;
78 | }
79 | return value;
80 | } else {
81 | throw new IllegalArgumentException(
82 | "Byte array is null or invalid length.");
83 | }
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/tcp/src/protocol/tcp/org/apache/jmeter/protocol/tcp/sampler/TCPClientImpl.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 |
19 | /*
20 | * Basic TCP Sampler Client class
21 | *
22 | * Can be used to test the TCP Sampler against an HTTP server
23 | *
24 | * The protocol handler class name is defined by the property tcp.handler
25 | *
26 | */
27 | package org.apache.jmeter.protocol.tcp.sampler;
28 |
29 | import java.io.ByteArrayOutputStream;
30 | import java.io.IOException;
31 | import java.io.InputStream;
32 | import java.io.OutputStream;
33 | import java.nio.charset.Charset;
34 |
35 | import org.apache.commons.lang3.StringUtils;
36 | import org.apache.jmeter.samplers.SampleResult;
37 | import org.apache.jmeter.util.JMeterUtils;
38 | import org.slf4j.Logger;
39 | import org.slf4j.LoggerFactory;
40 |
41 | /**
42 | * Sample TCPClient implementation.
43 | * Reads data until the defined EOL byte is reached.
44 | * If there is no EOL byte defined, then reads until
45 | * the end of the stream is reached.
46 | * The EOL byte is defined by the property "tcp.eolByte".
47 | */
48 | public class TCPClientImpl extends AbstractTCPClient {
49 | private static final Logger log = LoggerFactory.getLogger(TCPClientImpl.class);
50 |
51 | private static final int EOL_INT = JMeterUtils.getPropDefault("tcp.eolByte", 1000); // $NON-NLS-1$
52 | private static final String CHARSET = JMeterUtils.getPropDefault("tcp.charset", Charset.defaultCharset().name()); // $NON-NLS-1$
53 | // default is not in range of a byte
54 |
55 | public TCPClientImpl() {
56 | super();
57 | setEolByte(EOL_INT);
58 | if (useEolByte) {
59 | log.info("Using eolByte={}", eolByte);
60 | }
61 | setCharset(CHARSET);
62 | String configuredCharset = JMeterUtils.getProperty("tcp.charset");
63 | if(StringUtils.isEmpty(configuredCharset)) {
64 | log.info("Using platform default charset:{}",CHARSET);
65 | } else {
66 | log.info("Using charset:{}", configuredCharset);
67 | }
68 | }
69 |
70 | /**
71 | * {@inheritDoc}
72 | */
73 | @Override
74 | public void write(OutputStream os, String s) throws IOException{
75 | if(log.isDebugEnabled()) {
76 | log.debug("WriteS: {}", showEOL(s));
77 | }
78 | os.write(s.getBytes(CHARSET));
79 | os.flush();
80 | }
81 |
82 | /**
83 | * {@inheritDoc}
84 | */
85 | @Override
86 | public void write(OutputStream os, InputStream is) throws IOException{
87 | byte[] buff = new byte[512];
88 | while(is.read(buff) > 0){
89 | if(log.isDebugEnabled()) {
90 | log.debug("WriteIS: {}", showEOL(new String(buff, CHARSET)));
91 | }
92 | os.write(buff);
93 | os.flush();
94 | }
95 | }
96 |
97 | @Deprecated
98 | public String read(InputStream is) throws ReadException {
99 | return read(is, new SampleResult());
100 | }
101 |
102 | /**
103 | * Reads data until the defined EOL byte is reached.
104 | * If there is no EOL byte defined, then reads until
105 | * the end of the stream is reached.
106 | */
107 | @Override
108 | public String read(InputStream is, SampleResult sampleResult) throws ReadException{
109 | ByteArrayOutputStream w = new ByteArrayOutputStream();
110 | try {
111 | byte[] buffer = new byte[4096];
112 | int x;
113 | boolean first = true;
114 | if(getLength() == -1) {
115 | while ((x = is.read(buffer)) > -1) {
116 | if (first) {
117 | sampleResult.latencyEnd();
118 | first = false;
119 | }
120 | w.write(buffer, 0, x);
121 | if (useEolByte && (buffer[x - 1] == eolByte)) {
122 | break;
123 | }
124 | }
125 | } else {
126 | buffer = new byte[length];
127 | if ((x = is.read(buffer, 0, length)) > -1) {
128 | sampleResult.latencyEnd();
129 | w.write(buffer, 0, x);
130 | }
131 | }
132 |
133 | // do we need to close byte array (or flush it?)
134 | if(log.isDebugEnabled()) {
135 | log.debug("Read: {}\n{}", w.size(), w.toString());
136 | }
137 | return w.toString(CHARSET);
138 | } catch (IOException e) {
139 | throw new ReadException("Error reading from server, bytes read: " + w.size(), e, w.toString());
140 | }
141 | }
142 |
143 | private String showEOL(final String input) {
144 | StringBuilder sb = new StringBuilder(input.length()*2);
145 | for(int i=0; i < input.length(); i++) {
146 | char ch = input.charAt(i);
147 | if (ch < ' ') {
148 | sb.append('[');
149 | sb.append((int)ch);
150 | sb.append(']');
151 | } else {
152 | sb.append(ch);
153 | }
154 | }
155 | return sb.toString();
156 | }
157 | }
158 |
--------------------------------------------------------------------------------
/tcp/src/protocol/tcp/org/apache/jmeter/protocol/tcp/sampler/TCPSampler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 |
19 | package org.apache.jmeter.protocol.tcp.sampler;
20 |
21 | import java.io.File;
22 | import java.io.FileInputStream;
23 | import java.io.FileNotFoundException;
24 | import java.io.IOException;
25 | import java.io.InputStream;
26 | import java.io.OutputStream;
27 | import java.net.InetSocketAddress;
28 | import java.net.Socket;
29 | import java.net.SocketAddress;
30 | import java.net.SocketException;
31 | import java.net.UnknownHostException;
32 | import java.util.Arrays;
33 | import java.util.HashMap;
34 | import java.util.HashSet;
35 | import java.util.Map;
36 | import java.util.Optional;
37 | import java.util.Properties;
38 | import java.util.Set;
39 |
40 | import org.apache.commons.lang3.StringUtils;
41 | import org.apache.jmeter.config.ConfigTestElement;
42 | import org.apache.jmeter.samplers.AbstractSampler;
43 | import org.apache.jmeter.samplers.Entry;
44 | import org.apache.jmeter.samplers.Interruptible;
45 | import org.apache.jmeter.samplers.SampleResult;
46 | import org.apache.jmeter.testelement.TestElement;
47 | import org.apache.jmeter.testelement.ThreadListener;
48 | import org.apache.jmeter.util.JMeterUtils;
49 | import org.slf4j.Logger;
50 | import org.slf4j.LoggerFactory;
51 |
52 | /**
53 | * A sampler which understands Tcp requests.
54 | *
55 | */
56 | public class TCPSampler extends AbstractSampler implements ThreadListener, Interruptible {
57 | private static final long serialVersionUID = 280L;
58 |
59 | private static final Logger log = LoggerFactory.getLogger(TCPSampler.class);
60 |
61 | private static final Set APPLIABLE_CONFIG_CLASSES = new HashSet<>(
62 | Arrays.asList(
63 | "org.apache.jmeter.config.gui.LoginConfigGui",
64 | "org.apache.jmeter.protocol.tcp.config.gui.TCPConfigGui",
65 | "org.apache.jmeter.config.gui.SimpleConfigGui"
66 | ));
67 |
68 | public static final String SERVER = "TCPSampler.server"; //$NON-NLS-1$
69 |
70 | public static final String PORT = "TCPSampler.port"; //$NON-NLS-1$
71 |
72 | public static final String FILENAME = "TCPSampler.filename"; //$NON-NLS-1$
73 |
74 | public static final String CLASSNAME = "TCPSampler.classname";//$NON-NLS-1$
75 |
76 | public static final String NODELAY = "TCPSampler.nodelay"; //$NON-NLS-1$
77 |
78 | public static final String TIMEOUT = "TCPSampler.timeout"; //$NON-NLS-1$
79 |
80 | public static final String TIMEOUT_CONNECT = "TCPSampler.ctimeout"; //$NON-NLS-1$
81 |
82 | public static final String REQUEST = "TCPSampler.request"; //$NON-NLS-1$
83 |
84 | public static final String RE_USE_CONNECTION = "TCPSampler.reUseConnection"; //$NON-NLS-1$
85 | public static final boolean RE_USE_CONNECTION_DEFAULT = true;
86 |
87 | public static final String CLOSE_CONNECTION = "TCPSampler.closeConnection"; //$NON-NLS-1$
88 | public static final boolean CLOSE_CONNECTION_DEFAULT = false;
89 |
90 | public static final String SO_LINGER = "TCPSampler.soLinger"; //$NON-NLS-1$
91 |
92 | public static final String EOL_BYTE = "TCPSampler.EolByte"; //$NON-NLS-1$
93 |
94 | public static final String LENGTH = "TCPSampler.length"; //$NON-NLS-1$
95 |
96 | private static final String TCPKEY = "TCP"; //$NON-NLS-1$ key for HashMap
97 |
98 | private static final String ERRKEY = "ERR"; //$NON-NLS-1$ key for HashMap
99 |
100 | // the response is scanned for these strings
101 | private static final String STATUS_PREFIX = JMeterUtils.getPropDefault("tcp.status.prefix", ""); //$NON-NLS-1$
102 |
103 | private static final String STATUS_SUFFIX = JMeterUtils.getPropDefault("tcp.status.suffix", ""); //$NON-NLS-1$
104 |
105 | private static final String STATUS_PROPERTIES = JMeterUtils.getPropDefault("tcp.status.properties", ""); //$NON-NLS-1$
106 |
107 | private static final Properties STATUS_PROPS = new Properties();
108 |
109 | private static final String PROTO_PREFIX = "org.apache.jmeter.protocol.tcp.sampler."; //$NON-NLS-1$
110 |
111 | private static final boolean HAVE_STATUS_PROPS;
112 |
113 | static {
114 | boolean hsp = false;
115 | log.debug("Status prefix={}, suffix={}, properties={}",
116 | STATUS_PREFIX, STATUS_SUFFIX, STATUS_PROPERTIES); //$NON-NLS-1$
117 | if (STATUS_PROPERTIES.length() > 0) {
118 | File f = new File(STATUS_PROPERTIES);
119 | try (FileInputStream fis = new FileInputStream(f)){
120 | STATUS_PROPS.load(fis);
121 | log.debug("Successfully loaded properties"); //$NON-NLS-1$
122 | hsp = true;
123 | } catch (FileNotFoundException e) {
124 | log.debug("Property file {} not found", STATUS_PROPERTIES); //$NON-NLS-1$
125 | } catch (IOException e) {
126 | log.debug("Error reading property file {} error {}", STATUS_PROPERTIES, e.toString()); //$NON-NLS-1$
127 | }
128 | }
129 | HAVE_STATUS_PROPS = hsp;
130 | }
131 |
132 | /** the cache of TCP Connections */
133 | // KEY = TCPKEY or ERRKEY, Entry= Socket or String
134 | private static final ThreadLocal