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-2026 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 2.6.0
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  error_t error;
53  uint_t i;
54  Socket *socket;
55  IpAddr clientIpAddr;
56  uint16_t clientPort;
57  ModbusClientConnection *connection;
58 
59  //Accept incoming connection
60  socket = socketAccept(context->socket, &clientIpAddr, &clientPort);
61 
62  //Make sure the socket handle is valid
63  if(socket != NULL)
64  {
65  //Force the socket to operate in non-blocking mode
67 
68  //Initialize pointer
69  connection = NULL;
70 
71  //Loop through the connection table
72  for(i = 0; i < MODBUS_SERVER_MAX_CONNECTIONS; i++)
73  {
74  //Check the state of the current connection
75  if(context->connection[i].state == MODBUS_CONNECTION_STATE_CLOSED)
76  {
77  //The current entry is free
78  connection = &context->connection[i];
79  break;
80  }
81  }
82 
83  //If the connection table runs out of space, then the client's connection
84  //request is rejected
85  if(connection != NULL)
86  {
87  //Debug message
88  TRACE_INFO("Modbus Server: Connection established with client %s port %"
89  PRIu16 "...\r\n", ipAddrToString(&clientIpAddr, NULL), clientPort);
90 
91  //Clear the structure describing the connection
92  osMemset(connection, 0, sizeof(ModbusClientConnection));
93 
94  //Attach Modbus/TCP server context
95  connection->context = context;
96  //Save socket handle
97  connection->socket = socket;
98  //Initialize time stamp
99  connection->timestamp = osGetSystemTime();
100 
101  //Any registered callback?
102  if(context->openCallback != NULL)
103  {
104  //Invoke callback function
105  error = context->openCallback(connection, clientIpAddr, clientPort);
106  }
107  else
108  {
109  //No callback function registered
110  error = NO_ERROR;
111  }
112 
113  //Check status code
114  if(!error)
115  {
116 #if (MODBUS_SERVER_TLS_SUPPORT == ENABLED)
117  //TLS-secured connection?
118  if(context->tlsInitCallback != NULL)
119  {
120  //TLS initialization
121  error = modbusServerOpenSecureConnection(context, connection);
122 
123  //Check status code
124  if(!error)
125  {
126  //Perform TLS handshake
127  connection->state = MODBUS_CONNECTION_STATE_CONNECT_TLS;
128  }
129  else
130  {
131  //Close connection with the client
132  modbusServerCloseConnection(connection);
133  }
134  }
135  else
136 #endif
137  {
138  //Wait for incoming Modbus requests
139  connection->state = MODBUS_CONNECTION_STATE_RECEIVE;
140  }
141  }
142  else
143  {
144  //Reject the incoming connection request
145  modbusServerCloseConnection(connection);
146  }
147  }
148  else
149  {
150  //Debug message
151  TRACE_INFO("Modbus Server: Connection refused with client %s port %"
152  PRIu16 "...\r\n", ipAddrToString(&clientIpAddr, NULL), clientPort);
153 
154  //The Modbus/TCP server cannot accept the incoming connection request
156  }
157  }
158 }
159 
160 
161 /**
162  * @brief Shutdown network connection
163  * @param[in] connection Pointer to the client connection
164  * @return Error code
165  **/
166 
168 {
169  error_t error;
170 
171  //Initialize status code
172  error = NO_ERROR;
173 
174  //Check the state of the connection
175  if(connection->state == MODBUS_CONNECTION_STATE_RECEIVE)
176  {
177 #if (MODBUS_SERVER_TLS_SUPPORT == ENABLED)
178  //TLS-secured connection?
179  if(connection->tlsContext != NULL)
180  {
181  //Gracefully close TLS connection
182  connection->state = MODBUS_CONNECTION_STATE_SHUTDOWN_TLS;
183  }
184  else
185 #endif
186  {
187  //Shutdown transmission
188  error = socketShutdown(connection->socket, SOCKET_SD_SEND);
189  //Update connection state
190  connection->state = MODBUS_CONNECTION_STATE_SHUTDOWN_TX;
191  }
192  }
193  else if(connection->state == MODBUS_CONNECTION_STATE_SHUTDOWN_TLS)
194  {
195 #if (MODBUS_SERVER_TLS_SUPPORT == ENABLED)
196  //Gracefully close TLS session
197  error = tlsShutdown(connection->tlsContext);
198 
199  //Check status code
200  if(!error)
201  {
202  //Shutdown transmission
203  error = socketShutdown(connection->socket, SOCKET_SD_SEND);
204  //Update connection state
205  connection->state = MODBUS_CONNECTION_STATE_SHUTDOWN_TX;
206  }
207 #else
208  //Modbus/TCP security is not implemented
209  error = ERROR_WRONG_STATE;
210 #endif
211  }
212  else if(connection->state == MODBUS_CONNECTION_STATE_SHUTDOWN_TX)
213  {
214  //Shutdown reception
215  error = socketShutdown(connection->socket, SOCKET_SD_RECEIVE);
216  //Update connection state
217  connection->state = MODBUS_CONNECTION_STATE_SHUTDOWN_RX;
218  }
219  else
220  {
221  //Invalid state
222  error = ERROR_WRONG_STATE;
223  }
224 
225  //Return status code
226  return error;
227 }
228 
229 
230 /**
231  * @brief Close network connection
232  * @param[in] connection Pointer to the client connection
233  **/
234 
236 {
237  ModbusServerContext *context;
238 
239  //Debug message
240  TRACE_INFO("Modbus Server: Closing connection...\r\n");
241 
242  //Point to the Modbus/TCP server context
243  context = connection->context;
244 
245 #if (MODBUS_SERVER_TLS_SUPPORT == ENABLED)
246  //Release TLS context
247  if(connection->tlsContext != NULL)
248  {
249  tlsFree(connection->tlsContext);
250  connection->tlsContext = NULL;
251  }
252 #endif
253 
254  //Close TCP connection
255  if(connection->socket != NULL)
256  {
257  socketClose(connection->socket);
258  connection->socket = NULL;
259  }
260 
261  //Any registered callback?
262  if(context->closeCallback != NULL)
263  {
264  //Invoke callback function
265  context->closeCallback(connection);
266  }
267 
268  //Mark the connection as closed
269  connection->state = MODBUS_CONNECTION_STATE_CLOSED;
270 }
271 
272 
273 /**
274  * @brief Send data using the relevant transport protocol
275  * @param[in] connection Pointer to the client connection
276  * @param[in] data Pointer to a buffer containing the data to be transmitted
277  * @param[in] length Number of bytes to be transmitted
278  * @param[out] written Actual number of bytes written (optional parameter)
279  * @param[in] flags Set of flags that influences the behavior of this function
280  * @return Error code
281  **/
282 
284  const void *data, size_t length, size_t *written, uint_t flags)
285 {
286  error_t error;
287 
288 #if (MODBUS_SERVER_TLS_SUPPORT == ENABLED)
289  //TLS-secured connection?
290  if(connection->tlsContext != NULL)
291  {
292  //Send TLS-encrypted data
293  error = tlsWrite(connection->tlsContext, data, length, written, flags);
294  }
295  else
296 #endif
297  {
298  //Transmit data
299  error = socketSend(connection->socket, data, length, written, flags);
300  }
301 
302  //Return status code
303  return error;
304 }
305 
306 
307 /**
308  * @brief Receive data using the relevant transport protocol
309  * @param[in] connection Pointer to the client connection
310  * @param[out] data Buffer into which received data will be placed
311  * @param[in] size Maximum number of bytes that can be received
312  * @param[out] received Number of bytes that have been received
313  * @param[in] flags Set of flags that influences the behavior of this function
314  * @return Error code
315  **/
316 
318  void *data, size_t size, size_t *received, uint_t flags)
319 {
320  error_t error;
321 
322 #if (MODBUS_SERVER_TLS_SUPPORT == ENABLED)
323  //TLS-secured connection?
324  if(connection->tlsContext != NULL)
325  {
326  //Receive TLS-encrypted data
327  error = tlsRead(connection->tlsContext, data, size, received, flags);
328  }
329  else
330 #endif
331  {
332  //Receive data
333  error = socketReceive(connection->socket, data, size, received, flags);
334  }
335 
336  //Return status code
337  return error;
338 }
339 
340 #endif
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:1514
void modbusServerCloseConnection(ModbusClientConnection *connection)
Close network connection.
IP network address.
Definition: ip.h:90
@ MODBUS_CONNECTION_STATE_CONNECT_TLS
uint8_t data[]
Definition: ethernet.h:224
void socketClose(Socket *socket)
Close an existing socket.
Definition: socket.c:2094
Modbus/TCP security layer.
char_t * ipAddrToString(const IpAddr *ipAddr, char_t *str)
Convert a binary IP address to a string representation.
Definition: ip.c:810
@ MODBUS_CONNECTION_STATE_RECEIVE
@ MODBUS_CONNECTION_STATE_SHUTDOWN_TLS
@ ERROR_WRONG_STATE
Definition: error.h:210
#define ModbusClientConnection
@ SOCKET_SD_SEND
Definition: socket.h:160
error_t tlsShutdown(TlsContext *context)
Gracefully close TLS session.
Definition: tls.c:2603
error_t
Error codes.
Definition: error.h:43
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:1724
Modbus/TCP server.
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:65
@ MODBUS_CONNECTION_STATE_SHUTDOWN_RX
error_t modbusServerOpenSecureConnection(ModbusServerContext *context, ModbusClientConnection *connection)
Open secure connection.
Transport protocol abstraction layer.
error_t socketShutdown(Socket *socket, uint_t how)
Disable reception, transmission, or both.
Definition: socket.c:2052
error_t modbusServerShutdownConnection(ModbusClientConnection *connection)
Shutdown network connection.
#define TRACE_INFO(...)
Definition: debug.h:105
void modbusServerAcceptConnection(ModbusServerContext *context)
Accept connection request.
uint8_t length
Definition: tcp.h:375
@ MODBUS_CONNECTION_STATE_CLOSED
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:2285
error_t modbusServerReceiveData(ModbusClientConnection *connection, void *data, size_t size, size_t *received, uint_t flags)
Receive data using the relevant transport protocol.
Socket * socketAccept(Socket *socket, IpAddr *clientIpAddr, uint16_t *clientPort)
Permit an incoming connection attempt on a socket.
Definition: socket.c:1479
error_t modbusServerSendData(ModbusClientConnection *connection, const void *data, size_t length, size_t *written, uint_t flags)
Send data using the relevant transport protocol.
@ SOCKET_SD_RECEIVE
Definition: socket.h:159
#define Socket
Definition: socket.h:36
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:2148
void tlsFree(TlsContext *context)
Release TLS context.
Definition: tls.c:2765
uint8_t flags
Definition: tcp.h:358
#define MODBUS_SERVER_MAX_CONNECTIONS
Definition: modbus_server.h:73
unsigned int uint_t
Definition: compiler_port.h:57
#define osMemset(p, value, length)
Definition: os_port.h:138
TCP/IP stack core.
#define ModbusServerContext
@ MODBUS_CONNECTION_STATE_SHUTDOWN_TX
error_t socketSetTimeout(Socket *socket, systime_t timeout)
Set timeout value for blocking operations.
Definition: socket.c:169
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
systime_t osGetSystemTime(void)
Retrieve system time.