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.2
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,
108  context->connection);
109 
110  //Check status code
111  if(!error)
112  {
113  //Perform TLS handshake
114  connection->state = MODBUS_CONNECTION_STATE_CONNECT_TLS;
115  }
116  else
117  {
118  //Close connection with the client
119  modbusServerCloseConnection(connection);
120  }
121  }
122  else
123 #endif
124  {
125  //Wait for incoming Modbus requests
126  connection->state = MODBUS_CONNECTION_STATE_RECEIVE;
127  }
128  }
129  else
130  {
131  //Debug message
132  TRACE_INFO("Modbus Server: Connection refused with client %s port %"
133  PRIu16 "...\r\n", ipAddrToString(&clientIpAddr, NULL), clientPort);
134 
135  //The Modbus/TCP server cannot accept the incoming connection request
137  }
138  }
139 }
140 
141 
142 /**
143  * @brief Shutdown network connection
144  * @param[in] connection Pointer to the client connection
145  * @return Error code
146  **/
147 
149 {
150  error_t error;
151 
152  //Initialize status code
153  error = NO_ERROR;
154 
155  //Check the state of the connection
156  if(connection->state == MODBUS_CONNECTION_STATE_RECEIVE)
157  {
158 #if (MODBUS_SERVER_TLS_SUPPORT == ENABLED)
159  //TLS-secured connection?
160  if(connection->tlsContext != NULL)
161  {
162  //Gracefully close TLS connection
163  connection->state = MODBUS_CONNECTION_STATE_SHUTDOWN_TLS;
164  }
165  else
166 #endif
167  {
168  //Shutdown transmission
169  error = socketShutdown(connection->socket, SOCKET_SD_SEND);
170  //Update connection state
171  connection->state = MODBUS_CONNECTION_STATE_SHUTDOWN_TX;
172  }
173  }
174  else if(connection->state == MODBUS_CONNECTION_STATE_SHUTDOWN_TLS)
175  {
176 #if (MODBUS_SERVER_TLS_SUPPORT == ENABLED)
177  //Gracefully close TLS session
178  error = tlsShutdown(connection->tlsContext);
179 
180  //Check status code
181  if(!error)
182  {
183  //Shutdown transmission
184  error = socketShutdown(connection->socket, SOCKET_SD_SEND);
185  //Update connection state
186  connection->state = MODBUS_CONNECTION_STATE_SHUTDOWN_TX;
187  }
188 #else
189  //Modbus/TCP security is not implemented
190  error = ERROR_WRONG_STATE;
191 #endif
192  }
193  else if(connection->state == MODBUS_CONNECTION_STATE_SHUTDOWN_TX)
194  {
195  //Shutdown reception
196  error = socketShutdown(connection->socket, SOCKET_SD_RECEIVE);
197  //Update connection state
198  connection->state = MODBUS_CONNECTION_STATE_SHUTDOWN_RX;
199  }
200  else
201  {
202  //Invalid state
203  error = ERROR_WRONG_STATE;
204  }
205 
206  //Return status code
207  return error;
208 }
209 
210 
211 /**
212  * @brief Close network connection
213  * @param[in] connection Pointer to the client connection
214  **/
215 
217 {
218  //Debug message
219  TRACE_INFO("Modbus Server: Closing connection...\r\n");
220 
221 #if (MODBUS_SERVER_TLS_SUPPORT == ENABLED)
222  //Release TLS context
223  if(connection->tlsContext != NULL)
224  {
225  tlsFree(connection->tlsContext);
226  connection->tlsContext = NULL;
227  }
228 #endif
229 
230  //Close TCP connection
231  if(connection->socket != NULL)
232  {
233  socketClose(connection->socket);
234  connection->socket = NULL;
235  }
236 
237  //Mark the connection as closed
238  connection->state = MODBUS_CONNECTION_STATE_CLOSED;
239 }
240 
241 
242 /**
243  * @brief Send data using the relevant transport protocol
244  * @param[in] connection Pointer to the client connection
245  * @param[in] data Pointer to a buffer containing the data to be transmitted
246  * @param[in] length Number of bytes to be transmitted
247  * @param[out] written Actual number of bytes written (optional parameter)
248  * @param[in] flags Set of flags that influences the behavior of this function
249  * @return Error code
250  **/
251 
253  const void *data, size_t length, size_t *written, uint_t flags)
254 {
255  error_t error;
256 
257 #if (MODBUS_SERVER_TLS_SUPPORT == ENABLED)
258  //TLS-secured connection?
259  if(connection->tlsContext != NULL)
260  {
261  //Send TLS-encrypted data
262  error = tlsWrite(connection->tlsContext, data, length, written, flags);
263  }
264  else
265 #endif
266  {
267  //Transmit data
268  error = socketSend(connection->socket, data, length, written, flags);
269  }
270 
271  //Return status code
272  return error;
273 }
274 
275 
276 /**
277  * @brief Receive data using the relevant transport protocol
278  * @param[in] connection Pointer to the client connection
279  * @param[out] data Buffer into which received data will be placed
280  * @param[in] size Maximum number of bytes that can be received
281  * @param[out] received Number of bytes that have been received
282  * @param[in] flags Set of flags that influences the behavior of this function
283  * @return Error code
284  **/
285 
287  void *data, size_t size, size_t *received, uint_t flags)
288 {
289  error_t error;
290 
291 #if (MODBUS_SERVER_TLS_SUPPORT == ENABLED)
292  //TLS-secured connection?
293  if(connection->tlsContext != NULL)
294  {
295  //Receive TLS-encrypted data
296  error = tlsRead(connection->tlsContext, data, size, received, flags);
297  }
298  else
299 #endif
300  {
301  //Receive data
302  error = socketReceive(connection->socket, data, size, received, flags);
303  }
304 
305  //Return status code
306  return error;
307 }
308 
309 #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:586
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:459
IP network address.
Definition: ip.h:59
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:799
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:218
#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:762
#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:492