session.cpp
Go to the documentation of this file.
1 
26 #include <boost/bind.hpp>
27 #include <boost/shared_ptr.hpp>
28 #include <boost/make_shared.hpp>
29 #include <boost/random/mersenne_twister.hpp>
30 #include <boost/random/uniform_int_distribution.hpp>
31 
40 
41 using boost::shared_ptr;
42 using boost::make_shared;
43 using std::cerr;
44 using std::cout;
45 using std::endl;
46 
47 namespace eip {
48 
49 using serialization::BufferReader;
50 using serialization::BufferWriter;
51 
52 Session::Session(shared_ptr<Socket> socket, shared_ptr<Socket> io_socket,
53  EIP_UINT vendor_id, EIP_UDINT serial_num)
54  : socket_(socket), io_socket_(io_socket), session_id_(0),
55  my_vendor_id_(vendor_id), my_serial_num_(serial_num)
56 {
57  // generate pseudo-random connection ID and connection SN starting points
58  boost::random::mt19937 gen;
59  gen.seed(std::time(0));
60  boost::random::uniform_int_distribution<> dist(0, 0xFFFF);
61  next_connection_id_ = gen();
62  next_connection_sn_ = dist(gen);
63  cout << "Generated starting connection ID " << next_connection_id_
64  << " and SN " << next_connection_sn_ << endl;;
65 }
66 
68 {
69  try
70  {
71  if (session_id_ != 0)
72  {
73  close();
74  }
75  }
76  catch (...)
77  {
78  // can't throw exceptions, but can't do anything either
79  }
80 }
81 
82 void Session::open(string hostname, string port, string io_port)
83 {
84  cout << "Resolving hostname and connecting socket" << endl;
85  socket_->open(hostname, port);
86  io_socket_->open(hostname, io_port);
87 
88  // create the registration message
89  cout << "Creating and sending the registration message" << endl;
90  shared_ptr<RegisterSessionData> reg_data = make_shared<RegisterSessionData>();
91  EncapPacket reg_msg(EIP_CMD_REGISTER_SESSION, 0, reg_data);
92 
93  // send the register session message and get response
94  EncapPacket response;
95  try
96  {
97  response = sendCommand(reg_msg);
98  }
99  catch (std::length_error ex)
100  {
101  socket_->close();
102  io_socket_->close();
103  cerr << "Could not parse response when registering session: " << ex.what() << endl;
104  throw std::runtime_error("Invalid response received registering session");
105  }
106  catch (std::logic_error ex)
107  {
108  socket_->close();
109  io_socket_->close();
110  cerr << "Error in registration response: " << ex.what() << endl;
111  throw std::runtime_error("Error in registration response");
112  }
113 
114  if (response.getHeader().length != reg_data->getLength())
115  {
116  cerr << "Warning: Registration message received with wrong size. Expected "
117  << reg_data->getLength() << " bytes, received "
118  << response.getHeader().length << endl;
119  }
120 
121  bool response_valid = false;
122  try
123  {
124  response.getPayloadAs(*reg_data);
125  response_valid = true;
126  }
127  catch (std::length_error ex)
128  {
129  cerr << "Warning: Registration message too short, ignoring" << endl;
130  }
131  catch (std::logic_error ex)
132  {
133  cerr << "Warning: could not parse registration response: " << ex.what() << endl;
134  }
135 
136  if (response_valid && reg_data->protocol_version != EIP_PROTOCOL_VERSION)
137  {
138  cerr << "Error: Wrong Ethernet Industrial Protocol Version. "
139  "Expected " << EIP_PROTOCOL_VERSION << " got "
140  << reg_data->protocol_version << endl;
141  socket_->close();
142  io_socket_->close();
143  throw std::runtime_error("Received wrong Ethernet IP Protocol Version on registration");
144  }
145  if (response_valid && reg_data->options != 0)
146  {
147  cerr << "Warning: Registration message included non-zero options flags: "
148  << reg_data->options << endl;
149  }
150 
151  session_id_ = response.getHeader().session_handle;
152  cout << "Successfully opened session ID " << session_id_ << endl;
153 }
154 
156 {
157  // TODO: should close all connections and the IO port
158  cout << "Closing session" << endl;
159 
160  // create the unregister session message
162  socket_->send(reg_msg);
163 
164  cout << "Session closed" << endl;
165 
166  socket_->close();
167  io_socket_->close();
168  session_id_ = 0;
169 }
170 
172 {
173  cout << "Sending Command" << endl;
174  socket_->send(req);
175 
176  cout << "Waiting for response" << endl;
177  size_t n = socket_->receive(buffer(recv_buffer_));
178  cout << "Received response of " << n << " bytes" << endl;
179 
180  BufferReader reader(buffer(recv_buffer_, n));
181  EncapPacket result;
182  result.deserialize(reader);
183 
184  if (reader.getByteCount() != n)
185  {
186  cerr << "Warning: packet received with " << n <<
187  " bytes, but only " << reader.getByteCount() << " bytes used" << endl;
188  }
189 
190  check_packet(result, req.getHeader().command);
191  return result;
192 }
193 
195 {
196  // verify that all fields are correct
197  if (pkt.getHeader().command != exp_cmd)
198  {
199  cerr << "Reply received with wrong command. Expected "
200  << exp_cmd << ", received " << pkt.getHeader().command << endl;
201  throw std::logic_error("Reply received with wrong command");
202  }
203  if (session_id_ == 0 && pkt.getHeader().session_handle == 0)
204  {
205  cerr << "Warning: Zero session handle received on registration: "
206  << pkt.getHeader().session_handle << endl;
207  throw std::logic_error("Zero session handle received on registration");
208  }
209  if (session_id_ != 0 && pkt.getHeader().session_handle != session_id_)
210  {
211  cerr << "Warning: reply received with wrong session ID. Expected "
212  << session_id_ << ", recieved " << pkt.getHeader().session_handle << endl;
213  throw std::logic_error("Wrong session ID received for command");
214  }
215  if (pkt.getHeader().status != 0)
216  {
217  cerr << "Warning: Non-zero status received: " << pkt.getHeader().status << endl;
218  }
219  if (pkt.getHeader().context[0] != 0 || pkt.getHeader().context[1] != 0)
220  {
221  cerr << "Warning: Non-zero sender context received: "
222  << pkt.getHeader().context[0] << " / " << pkt.getHeader().context[1] << endl;
223  }
224  if (pkt.getHeader().options != 0)
225  {
226  cerr << "Warning: Non-zero options received: " << pkt.getHeader().options << endl;
227  }
228 }
229 
231  EIP_USINT attribute_id, Serializable& result)
232 {
233  shared_ptr<Serializable> no_data;
234  RRDataResponse resp_data = sendRRDataCommand(0x0E,
235  Path(class_id, instance_id, attribute_id), no_data);
236 
237  resp_data.getResponseDataAs(result);
238 }
239 
241  EIP_USINT instance_id, EIP_USINT attribute_id, shared_ptr<Serializable> data)
242 {
243  RRDataResponse resp_data = sendRRDataCommand(0x10,
244  Path(class_id, instance_id, attribute_id), data);
245 }
246 
248  shared_ptr<Serializable> data)
249 {
250  cout << "Creating RR Data Request" << endl;
251  shared_ptr<RRDataRequest> req_data =
252  make_shared<RRDataRequest> (service, path, data);
253  EncapPacket encap_pkt(EIP_CMD_SEND_RR_DATA, session_id_, req_data);
254 
255  // send command and get response
256  EncapPacket response;
257  try
258  {
259  response = sendCommand(encap_pkt);
260  }
261  catch (std::length_error ex)
262  {
263  cerr << "Response packet to RR command too short: " << ex.what() << endl;
264  throw std::runtime_error("Packet response to RR Data Command too short");
265  }
266  catch (std::logic_error ex)
267  {
268  cerr << "Invalid response to RR command: " << ex.what() << endl;
269  throw std::runtime_error("Invalid packet response to RR Data Command");
270  }
271 
272  RRDataResponse resp_data;
273  try
274  {
275  response.getPayloadAs(resp_data);
276  }
277  catch (std::length_error ex)
278  {
279  cerr << "Response data to RR command too short: " << ex.what() << endl;
280  throw std::runtime_error("Response data to RR Command too short");
281  }
282  catch (std::logic_error ex)
283  {
284  cerr << "Invalid data to RR command: " << ex.what() << endl;
285  throw std::runtime_error("Invalid data in response to RR command");
286  }
287 
288  // check that responses are valid
289  if (resp_data.getServiceCode() != (service | 0x80))
290  {
291  cerr << "Warning: Wrong service code returned for RR Data command. Expected: "
292  << (int)service << " but received " << (int)resp_data.getServiceCode() << endl;
293  // throw std::runtime_error("Wrong service code returned for RR Data command");
294  }
295  if (resp_data.getGeneralStatus())
296  {
297  cerr << "RR Data Command failed with status " << (int)resp_data.getGeneralStatus() << endl;
298  throw std::runtime_error("RR Data Command Failed");
299  }
300  return resp_data;
301 }
302 
304  const EIP_CONNECTION_INFO_T& t_to_o)
305 {
306  Connection conn(o_to_t, t_to_o);
312 
313  shared_ptr<ForwardOpenRequest> req = conn.createForwardOpenRequest();
314  RRDataResponse resp_data = sendRRDataCommand(0x5B, Path(0x06, 1), req);
315  ForwardOpenSuccess result;
316  resp_data.getResponseDataAs(result);
317  if (!conn.verifyForwardOpenResult(result))
318  {
319  cerr << "Received invalid response to forward open request" << endl;
320  throw std::logic_error("Forward Open Response Invalid");
321  }
322 
323  connections_.push_back(conn);
324  return connections_.size() - 1;
325 }
326 
328 {
329  shared_ptr<ForwardCloseRequest> req = connections_[n].createForwardCloseRequest();
330  RRDataResponse resp_data = sendRRDataCommand(0x4E, Path(0x06, 1), req);
331  ForwardCloseSuccess result;
332  resp_data.getResponseDataAs(result);
333  if (!connections_[n].verifyForwardCloseResult(result))
334  {
335  cerr << "Received invalid response to forward close request" << endl;
336  throw std::logic_error("Forward Close Response Invalid");
337  }
338  // remove the connection from the list
339  connections_.erase(connections_.begin() + n);
340 }
341 
343 {
344  // cout << "Receiving IO packet" << endl;
345  size_t n = io_socket_->receive(buffer(recv_buffer_));
346  // cout << "Received IO of " << n << " bytes" << endl;
347 
348  BufferReader reader(buffer(recv_buffer_, n));
349  CPFPacket result;
350  result.deserialize(reader);
351 
352  if (reader.getByteCount() != n)
353  {
354  cerr << "Warning: IO packet received with " << n <<
355  " bytes, but only " << reader.getByteCount() << " bytes used" << endl;
356  }
357 
358  return result;
359 }
360 
362 {
363  // cout << "Sending CPF Packet on IO Socket" << endl;
364  io_socket_->send(pkt);
365 }
366 
367 
368 } // namespace eip
uint8_t EIP_USINT
Definition: eip_types.h:36
EIP_USINT getServiceCode() const
EIP_BYTE recv_buffer_[4 *1024]
Definition: session.h:212
EIP_UDINT session_id_
Definition: session.h:211
EncapHeader & getHeader()
Definition: encap_packet.h:78
shared_ptr< Socket > io_socket_
Definition: session.h:210
virtual ~Session()
Definition: session.cpp:67
CPFPacket receiveIOPacket()
Definition: session.cpp:342
RRDataResponse sendRRDataCommand(EIP_USINT service, const Path &path, shared_ptr< Serializable > data)
Definition: session.cpp:247
EIP_UINT command
Definition: encap_header.h:47
shared_ptr< ForwardOpenRequest > createForwardOpenRequest()
Definition: connection.cpp:61
EIP_UDINT t_to_o_connection_id
Definition: connection.h:55
void closeConnection(size_t n)
Definition: session.cpp:327
bool verifyForwardOpenResult(const ForwardOpenSuccess &result)
Definition: connection.cpp:105
Reader & deserialize(Reader &reader, size_t length)
void open(string hostname, string port="44818", string io_port="2222")
Definition: session.cpp:82
virtual Reader & deserialize(Reader &reader, size_t length)
Definition: cpf_packet.h:89
EIP_DWORD context[2]
Definition: encap_header.h:51
void check_packet(EncapPacket &pkt, EIP_UINT exp_cmd)
Definition: session.cpp:194
void sendIOPacket(CPFPacket &pkt)
Definition: session.cpp:361
#define EIP_PROTOCOL_VERSION
Definition: eip_types.h:31
void close()
Definition: session.cpp:155
EIP_UDINT session_handle
Definition: encap_header.h:49
EIP_UDINT originator_sn
Definition: connection.h:51
EIP_UDINT o_to_t_connection_id
Definition: connection.h:54
EIP_UDINT next_connection_id_
Definition: session.h:217
void getPayloadAs(Serializable &result)
Definition: path.h:50
Definition: connection.h:41
vector< Connection > connections_
Definition: session.h:219
void setSingleAttributeSerializable(EIP_USINT class_id, EIP_USINT instance_id, EIP_USINT attribute_id, shared_ptr< Serializable > data)
Definition: session.cpp:240
int createConnection(const EIP_CONNECTION_INFO_T &o_to_t, const EIP_CONNECTION_INFO_T &t_to_o)
Definition: session.cpp:303
uint16_t EIP_UINT
Definition: eip_types.h:39
EIP_UINT next_connection_sn_
Definition: session.h:216
EIP_DWORD options
Definition: encap_header.h:52
EIP_UDINT my_serial_num_
Definition: session.h:215
void getResponseDataAs(Serializable &result)
uint32_t EIP_UDINT
Definition: eip_types.h:42
EIP_UINT my_vendor_id_
Definition: session.h:214
Session(shared_ptr< Socket > socket, shared_ptr< Socket > io_socket, EIP_UINT vendor_id=DEFAULT_VENDOR_ID, EIP_UDINT serial_num=DEFAULT_SERIAL_NUM)
Definition: session.cpp:52
void getSingleAttributeSerializable(EIP_USINT class_id, EIP_USINT instance_id, EIP_USINT attribute_id, Serializable &result)
Definition: session.cpp:230
EIP_USINT getGeneralStatus() const
EIP_UINT originator_vendor_id
Definition: connection.h:50
EIP_DWORD status
Definition: encap_header.h:50
EncapPacket sendCommand(EncapPacket &req)
Definition: session.cpp:171
EIP_UINT connection_sn
Definition: connection.h:52
shared_ptr< Socket > socket_
Definition: session.h:209


odva_ethernetip
Author(s): Kareem Shehata
autogenerated on Mon Jun 10 2019 14:00:16