modbus_server_transport.c
Go to the documentation of this file.
1 /**
2  * @file modbus_server_transport.c
3  * @brief Transport protocol abstraction layer
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2019 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 1.9.4
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL MODBUS_TRACE_LEVEL
33 
34 //Dependencies
35 #include "core/net.h"
36 #include "modbus/modbus_server.h"
39 #include "debug.h"
40 
41 //Check TCP/IP stack configuration
42 #if (MODBUS_SERVER_SUPPORT == ENABLED)
43 
44 
45 /**
46  * @brief Accept connection request
47  * @param[in] context Pointer to the Modbus/TCP server context
48  **/
49 
51 {
52  uint_t i;
53  Socket *socket;
54  IpAddr clientIpAddr;
55  uint16_t clientPort;
56  ModbusClientConnection *connection;
57 
58  //Accept incoming connection
59  socket = socketAccept(context->socket, &clientIpAddr, &clientPort);
60 
61  //Make sure the socket handle is valid
62  if(socket != NULL)
63  {
64  //Force the socket to operate in non-blocking mode
66 
67  //Initialize pointer
68  connection = NULL;
69 
70  //Loop through the connection table
71  for(i = 0; i < MODBUS_SERVER_MAX_CONNECTIONS; i++)
72  {
73  //Check the state of the current connection
74  if(context->connection[i].state == MODBUS_CONNECTION_STATE_CLOSED)
75  {
76  //The current entry is free
77  connection = &context->connection[i];
78  break;
79  }
80  }
81 
82  //If the connection table runs out of space, then the client's connection
83  //request is rejected
84  if(connection != NULL)
85  {
86  //Debug message
87  TRACE_INFO("Modbus Server: Connection established with client %s port %"
88  PRIu16 "...\r\n", ipAddrToString(&clientIpAddr, NULL), clientPort);
89 
90  //Clear the structure describing the connection
91  memset(connection, 0, sizeof(ModbusClientConnection));
92 
93  //Attach Modbus/TCP server context
94  connection->context = context;
95  //Save socket handle
96  connection->socket = socket;
97  //Initialize time stamp
98  connection->timestamp = osGetSystemTime();
99 
100 #if (MODBUS_SERVER_TLS_SUPPORT == ENABLED)
101  //TLS-secured connection?
102  if(context->settings.tlsInitCallback != NULL)
103  {
104  error_t error;
105 
106  //TLS initialization
107  error = modbusServerOpenSecureConnection(context, connection);
108 
109  //Check status code
110  if(!error)
111  {
112  //Perform TLS handshake
113  connection->state = MODBUS_CONNECTION_STATE_CONNECT_TLS;
114  }
115  else
116  {
117  //Close connection with the client
118  modbusServerCloseConnection(connection);
119  }
120  }
121  else
122 #endif
123  {
124  //Wait for incoming Modbus requests
125  connection->state = MODBUS_CONNECTION_STATE_RECEIVE;
126  }
127  }
128  else
129  {
130  //Debug message
131  TRACE_INFO("Modbus Server: Connection refused with client %s port %"
132  PRIu16 "...\r\n", ipAddrToString(&clientIpAddr, NULL), clientPort);
133 
134  //The Modbus/TCP server cannot accept the incoming connection request
136  }
137  }
138 }
139 
140 
141 /**
142  * @brief Shutdown network connection
143  * @param[in] connection Pointer to the client connection
144  * @return Error code
145  **/
146 
148 {
149  error_t error;
150 
151  //Initialize status code
152  error = NO_ERROR;
153 
154  //Check the state of the connection
155  if(connection->state == MODBUS_CONNECTION_STATE_RECEIVE)
156  {
157 #if (MODBUS_SERVER_TLS_SUPPORT == ENABLED)
158  //TLS-secured connection?
159  if(connection->tlsContext != NULL)
160  {
161  //Gracefully close TLS connection
162  connection->state = MODBUS_CONNECTION_STATE_SHUTDOWN_TLS;
163  }
164  else
165 #endif
166  {
167  //Shutdown transmission
168  error = socketShutdown(connection->socket, SOCKET_SD_SEND);
169  //Update connection state
170  connection->state = MODBUS_CONNECTION_STATE_SHUTDOWN_TX;
171  }
172  }
173  else if(connection->state == MODBUS_CONNECTION_STATE_SHUTDOWN_TLS)
174  {
175 #if (MODBUS_SERVER_TLS_SUPPORT == ENABLED)
176  //Gracefully close TLS session
177  error = tlsShutdown(connection->tlsContext);
178 
179  //Check status code
180  if(!error)
181  {
182  //Shutdown transmission
183  error = socketShutdown(connection->socket, SOCKET_SD_SEND);
184  //Update connection state
185  connection->state = MODBUS_CONNECTION_STATE_SHUTDOWN_TX;
186  }
187 #else
188  //Modbus/TCP security is not implemented
189  error = ERROR_WRONG_STATE;
190 #endif
191  }
192  else if(connection->state == MODBUS_CONNECTION_STATE_SHUTDOWN_TX)
193  {
194  //Shutdown reception
195  error = socketShutdown(connection->socket, SOCKET_SD_RECEIVE);
196  //Update connection state
197  connection->state = MODBUS_CONNECTION_STATE_SHUTDOWN_RX;
198  }
199  else
200  {
201  //Invalid state
202  error = ERROR_WRONG_STATE;
203  }
204 
205  //Return status code
206  return error;
207 }
208 
209 
210 /**
211  * @brief Close network connection
212  * @param[in] connection Pointer to the client connection
213  **/
214 
216 {
217  //Debug message
218  TRACE_INFO("Modbus Server: Closing connection...\r\n");
219 
220 #if (MODBUS_SERVER_TLS_SUPPORT == ENABLED)
221  //Release TLS context
222  if(connection->tlsContext != NULL)
223  {
224  tlsFree(connection->tlsContext);
225  connection->tlsContext = NULL;
226  }
227 #endif
228 
229  //Close TCP connection
230  if(connection->socket != NULL)
231  {
232  socketClose(connection->socket);
233  connection->socket = NULL;
234  }
235 
236  //Mark the connection as closed
237  connection->state = MODBUS_CONNECTION_STATE_CLOSED;
238 }
239 
240 
241 /**
242  * @brief Send data using the relevant transport protocol
243  * @param[in] connection Pointer to the client connection
244  * @param[in] data Pointer to a buffer containing the data to be transmitted
245  * @param[in] length Number of bytes to be transmitted
246  * @param[out] written Actual number of bytes written (optional parameter)
247  * @param[in] flags Set of flags that influences the behavior of this function
248  * @return Error code
249  **/
250 
252  const void *data, size_t length, size_t *written, uint_t flags)
253 {
254  error_t error;
255 
256 #if (MODBUS_SERVER_TLS_SUPPORT == ENABLED)
257  //TLS-secured connection?
258  if(connection->tlsContext != NULL)
259  {
260  //Send TLS-encrypted data
261  error = tlsWrite(connection->tlsContext, data, length, written, flags);
262  }
263  else
264 #endif
265  {
266  //Transmit data
267  error = socketSend(connection->socket, data, length, written, flags);
268  }
269 
270  //Return status code
271  return error;
272 }
273 
274 
275 /**
276  * @brief Receive data using the relevant transport protocol
277  * @param[in] connection Pointer to the client connection
278  * @param[out] data Buffer into which received data will be placed
279  * @param[in] size Maximum number of bytes that can be received
280  * @param[out] received Number of bytes that have been received
281  * @param[in] flags Set of flags that influences the behavior of this function
282  * @return Error code
283  **/
284 
286  void *data, size_t size, size_t *received, uint_t flags)
287 {
288  error_t error;
289 
290 #if (MODBUS_SERVER_TLS_SUPPORT == ENABLED)
291  //TLS-secured connection?
292  if(connection->tlsContext != NULL)
293  {
294  //Receive TLS-encrypted data
295  error = tlsRead(connection->tlsContext, data, size, received, flags);
296  }
297  else
298 #endif
299  {
300  //Receive data
301  error = socketReceive(connection->socket, data, size, received, flags);
302  }
303 
304  //Return status code
305  return error;
306 }
307 
308 #endif
error_t tlsWrite(TlsContext *context, const void *data, size_t length, size_t *written, uint_t flags)
Send application data to the remote host using TLS.
Definition: tls.c:1651
error_t socketReceive(Socket *socket, void *data, size_t size, size_t *received, uint_t flags)
Receive data from a connected socket.
Definition: socket.c:588
Modbus/TCP server.
Modbus/TCP security layer.
uint8_t flags
Definition: tcp.h:314
systime_t osGetSystemTime(void)
Retrieve system time.
TCP/IP stack core.
void modbusServerCloseConnection(ModbusClientConnection *connection)
Close network connection.
Debugging facilities.
error_t modbusServerOpenSecureConnection(ModbusServerContext *context, ModbusClientConnection *connection)
Open secure connection.
Socket * socketAccept(Socket *socket, IpAddr *clientIpAddr, uint16_t *clientPort)
Permit an incoming connection attempt on a socket.
Definition: socket.c:460
IP network address.
Definition: ip.h:71
error_t tlsRead(TlsContext *context, void *data, size_t size, size_t *received, uint_t flags)
Receive application data from a the remote host using TLS.
Definition: tls.c:1786
void socketClose(Socket *socket)
Close an existing socket.
Definition: socket.c:801
char_t * ipAddrToString(const IpAddr *ipAddr, char_t *str)
Convert a binary IP address to a string representation.
Definition: ip.c:688
#define ModbusClientConnection
int_t socket(int_t family, int_t type, int_t protocol)
Create a socket that is bound to a specific transport service provider.
Definition: bsd_socket.c:108
error_t socketSetTimeout(Socket *socket, systime_t timeout)
Set timeout value for blocking operations.
Definition: socket.c:219
#define Socket
Definition: socket.h:36
void modbusServerAcceptConnection(ModbusServerContext *context)
Accept connection request.
error_t tlsShutdown(TlsContext *context)
Gracefully close TLS session.
Definition: tls.c:2100
void tlsFree(TlsContext *context)
Release TLS context.
Definition: tls.c:2260
error_t modbusServerSendData(ModbusClientConnection *connection, const void *data, size_t length, size_t *written, uint_t flags)
Send data using the relevant transport protocol.
error_t socketShutdown(Socket *socket, uint_t how)
Disable reception, transmission, or both.
Definition: socket.c:764
#define TRACE_INFO(...)
Definition: debug.h:94
Success.
Definition: error.h:44
Transport protocol abstraction layer.
#define ModbusServerContext
error_t
Error codes.
Definition: error.h:42
unsigned int uint_t
Definition: compiler_port.h:45
error_t modbusServerShutdownConnection(ModbusClientConnection *connection)
Shutdown network connection.
uint8_t data[]
Definition: dtls_misc.h:169
error_t modbusServerReceiveData(ModbusClientConnection *connection, void *data, size_t size, size_t *received, uint_t flags)
Receive data using the relevant transport protocol.
#define MODBUS_SERVER_MAX_CONNECTIONS
Definition: modbus_server.h:66
uint8_t length
Definition: dtls_misc.h:142
error_t socketSend(Socket *socket, const void *data, size_t length, size_t *written, uint_t flags)
Send data to a connected socket.
Definition: socket.c:493