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