|
1 /* |
|
2 * Copyright (c) 2002,2016 Mario de Sousa (msousa@fe.up.pt) |
|
3 * |
|
4 * This file is part of the Modbus library for Beremiz and matiec. |
|
5 * |
|
6 * This Modbus library is free software: you can redistribute it and/or modify |
|
7 * it under the terms of the GNU Lesser General Public License as published by |
|
8 * the Free Software Foundation, either version 3 of the License, or |
|
9 * (at your option) any later version. |
|
10 * |
|
11 * This program is distributed in the hope that it will be useful, but |
|
12 * WITHOUT ANY WARRANTY; without even the implied warranty of |
|
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser |
|
14 * General Public License for more details. |
|
15 * |
|
16 * You should have received a copy of the GNU Lesser General Public License |
|
17 * along with this Modbus library. If not, see <http://www.gnu.org/licenses/>. |
|
18 * |
|
19 * This code is made available on the understanding that it will not be |
|
20 * used in safety-critical situations without a full and competent review. |
|
21 */ |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 #include <fcntl.h> /* File control definitions */ |
|
28 #include <stdio.h> /* Standard input/output */ |
|
29 #include <string.h> |
|
30 #include <stdlib.h> |
|
31 #include <termio.h> /* POSIX terminal control definitions */ |
|
32 #include <sys/time.h> /* Time structures for select() */ |
|
33 #include <unistd.h> /* POSIX Symbolic Constants */ |
|
34 #include <assert.h> |
|
35 #include <errno.h> /* Error definitions */ |
|
36 #include <time.h> /* clock_gettime() */ |
|
37 #include <sys/types.h> |
|
38 #include <sys/socket.h> |
|
39 #include <netinet/in.h> /* required for htons() and ntohs() */ |
|
40 #include <netinet/tcp.h> /* TCP level socket options */ |
|
41 #include <netinet/ip.h> /* IP level socket options */ |
|
42 |
|
43 #include <pthread.h> |
|
44 #include <sched.h> /* sched_yield() */ |
|
45 |
|
46 |
|
47 |
|
48 #include "sin_util.h" /* internet socket utility functions... */ |
|
49 #include "mb_layer1.h" /* The public interface this file implements... */ |
|
50 #include "mb_tcp_private.h" |
|
51 |
|
52 |
|
53 |
|
54 /************************************/ |
|
55 /** **/ |
|
56 /** Include common code... **/ |
|
57 /** **/ |
|
58 /************************************/ |
|
59 |
|
60 #include "mb_time_util.h" |
|
61 |
|
62 |
|
63 //#define ERRMSG |
|
64 #define ERRMSG_HEAD "Modbus/TCP: " |
|
65 |
|
66 |
|
67 // #define DEBUG /* uncomment to see the data sent and received */ |
|
68 |
|
69 |
|
70 #ifdef DEBUG |
|
71 #ifndef ERRMSG |
|
72 #define ERRMSG |
|
73 #endif |
|
74 #endif |
|
75 |
|
76 |
|
77 |
|
78 /**************************************************************/ |
|
79 /**************************************************************/ |
|
80 /**** ****/ |
|
81 /**** ****/ |
|
82 /**** Forward Declarations ****/ |
|
83 /**** and Defaults ****/ |
|
84 /**** ****/ |
|
85 /**************************************************************/ |
|
86 /**************************************************************/ |
|
87 |
|
88 |
|
89 /* A Node Descriptor metadata, |
|
90 * Due to the fact that modbus TCP is connection oriented, |
|
91 * and that if the client detects an error the connection |
|
92 * must be shut down and re-established automatically, |
|
93 * the modbus TCP layer needs to keep the address of the remote server. |
|
94 * |
|
95 * We do this by implementing a node descriptor table, in which each |
|
96 * entry will have the remote address, and the file descriptor |
|
97 * of the socket currently in use. |
|
98 * |
|
99 * We do not pass the file descriptor up to the next higher layer. We |
|
100 * send them the node descriptor instead... |
|
101 */ |
|
102 #define MB_MASTER_NODE 12 |
|
103 #define MB_LISTEN_NODE 14 |
|
104 #define MB_SLAVE_NODE 16 |
|
105 #define MB_FREE_NODE 18 |
|
106 typedef sa_family_t nd_type_t; |
|
107 |
|
108 typedef struct { |
|
109 int fd; /* socket descriptor == file descriptor */ |
|
110 /* NOTE: |
|
111 * Modbus TCP says that on error, we should close |
|
112 * a connection and retry with a new connection. |
|
113 * Since it takes time for a socket to close |
|
114 * a connection if the remote server is down, |
|
115 * we close the connection on the socket, close the |
|
116 * socket itself, and create a new one for the new |
|
117 * connection. There will be times when the node will |
|
118 * not have any valid socket, and it will have to |
|
119 * be created on the fly. |
|
120 * When the node does not have a valid socket, |
|
121 * fd will be set to -1 |
|
122 */ |
|
123 int node_type; /* What kind of use we are giving to this node... |
|
124 * If node_type == MB_MASTER_NODE |
|
125 * The node descriptor was initialised by the |
|
126 * modbus_connect() function. |
|
127 * The node descriptor is being used by a master |
|
128 * device, and the addr contains the address of the slave. |
|
129 * Remember that in this case fd may be >= 0 while |
|
130 * we have a valid connection, or it may be < 0 when |
|
131 * the connection needs to be reset. |
|
132 * If node_type == MB_LISTEN_NODE |
|
133 * The node descriptor was initialised by the |
|
134 * modbus_listen() function. |
|
135 * The node is merely used to accept() new connection |
|
136 * requests. The new slave connections will use another |
|
137 * node to transfer data. |
|
138 * In this case fd must be >= 0. |
|
139 * fd < 0 is an ilegal state and should never occur. |
|
140 * If node_type == MB_SLAVE_NODE |
|
141 * The node descriptor was initialised when a new |
|
142 * connection request arrived on a MB_LISTEN type node. |
|
143 * The node descriptor is being used by a slave device, |
|
144 * and is currently being used to connect to a master. |
|
145 * In this case fd must be >= 0. |
|
146 * fd < 0 is an ilegal state and should never occur. |
|
147 * If node_type == FREE_ND |
|
148 * The node descriptor is currently not being used. |
|
149 * In this case fd is set to -1, but is really irrelevant. |
|
150 */ |
|
151 struct sockaddr_in addr; /* The internet adress we are using. |
|
152 * If node_type == MB_MASTER_NODE |
|
153 * addr will be the address of the remote slave |
|
154 * If node_type == MB_LISTEN_NODE |
|
155 * addr will be the address of the local listening port and network interface |
|
156 * If node_type == MB_SLAVE_NODE |
|
157 * addr will be the address of the local port and network interface |
|
158 * of the connection to the specific client. |
|
159 */ |
|
160 int listen_node; /* When a slave accepts a connection through a MB_LISTEN_NODE, it will |
|
161 * will use an empty node for the new connection, and configure this new node |
|
162 * to use the type MB_SLAVE_NODE. |
|
163 * The listen_node entry is only used by nodes of type MB_SLAVE_NODE. |
|
164 * In this case, listen_node will be the node of type MB_LISTEN_NODE through |
|
165 * which the connection request came through... |
|
166 */ |
|
167 int close_on_silence; /* A flag used only by Master Nodes. |
|
168 * When (close_on_silence > 0), then the connection to the |
|
169 * slave device will be shut down whenever the |
|
170 * modbus_tcp_silence_init() function is called. |
|
171 * Remember that the connection will be automatically |
|
172 * re-established the next time the user wishes to communicate |
|
173 * with the same slave (using this same node descripto). |
|
174 * If the user wishes to comply with the sugestion |
|
175 * in the OpenModbus Spec, (s)he should set this flag |
|
176 * if a silence interval longer than 1 second is expected. |
|
177 */ |
|
178 int print_connect_error; /* flag to guarantee we only print an error the first time we |
|
179 * attempt to connect to a emote server. |
|
180 * Stops us from generting a cascade of errors while the slave |
|
181 * is down. |
|
182 * Flag will get reset every time we successfully |
|
183 * establish a connection, so a message is once again generated |
|
184 * on the next error. |
|
185 */ |
|
186 u8 *recv_buf; /* This node's receive buffer |
|
187 * The library supports multiple simultaneous connections, |
|
188 * and may need to receive multiple frames through mutiple nodes concurrently. |
|
189 * To make the library thread-safe, we use one buffer for each node. |
|
190 */ |
|
191 } nd_entry_t; |
|
192 |
|
193 |
|
194 /* please make sure to lock the node table mutex before calling this function */ |
|
195 static int nd_entry_init(nd_entry_t *nde) { |
|
196 nde->addr.sin_family = AF_INET ; |
|
197 nde->node_type = MB_FREE_NODE; |
|
198 nde->fd = -1; /* not currently connected... */ |
|
199 /* initialise recv buffer */ |
|
200 nde->recv_buf = malloc(sizeof(u8) * RECV_BUFFER_SIZE); |
|
201 if (nde->recv_buf == NULL) |
|
202 return -1; |
|
203 return 0; |
|
204 } |
|
205 |
|
206 /* please make sure to lock the node table mutex before calling this function */ |
|
207 static int nd_entry_done(nd_entry_t *nde) { |
|
208 free(nde->recv_buf); |
|
209 return 0; |
|
210 } |
|
211 |
|
212 |
|
213 |
|
214 typedef struct { |
|
215 /* the array of node descriptors, and current size... */ |
|
216 nd_entry_t *node; /* array of node entries. if NULL => node table not initialized */ |
|
217 int node_count; /* total number of nodes in the node[] array */ |
|
218 int free_node_count; /* number of free nodes in the node[] array */ |
|
219 pthread_mutex_t mutex; |
|
220 } nd_table_t; |
|
221 |
|
222 |
|
223 |
|
224 static int nd_table_done(nd_table_t *ndt) { |
|
225 int count; |
|
226 |
|
227 if (ndt->node == NULL) |
|
228 return 0; |
|
229 |
|
230 /* lock the mutex */ |
|
231 while (pthread_mutex_lock(&ndt->mutex) != 0) sched_yield(); |
|
232 |
|
233 /* initialise the state of each node in the array... */ |
|
234 for (count = 0; count < ndt->node_count; count++) { |
|
235 nd_entry_done(&ndt->node[count]); |
|
236 } /* for() */ |
|
237 |
|
238 free(ndt->node); |
|
239 pthread_mutex_unlock (&ndt->mutex); |
|
240 pthread_mutex_destroy(&ndt->mutex); |
|
241 *ndt = (nd_table_t){.node=NULL, .node_count=0, .free_node_count=0}; |
|
242 |
|
243 return 0; |
|
244 } |
|
245 |
|
246 |
|
247 |
|
248 |
|
249 #if 1 |
|
250 /* nd_table_init() |
|
251 * Version 1 of the nd_table_init() function. |
|
252 * If called more than once, 2nd and any subsequent calls will |
|
253 * be interpreted as a request to confirm that it was already correctly |
|
254 * initialized with the requested number of nodes. |
|
255 */ |
|
256 static int nd_table_init(nd_table_t *ndt, int nd_count) { |
|
257 int count; |
|
258 |
|
259 if (ndt->node != NULL) { |
|
260 /* this function has already been called, and the node table is already initialised */ |
|
261 return (ndt->node_count == nd_count)?0:-1; |
|
262 } |
|
263 |
|
264 /* initialise the node table mutex... */ |
|
265 pthread_mutex_init(&ndt->mutex, NULL); |
|
266 if (pthread_mutex_lock(&ndt->mutex) != 0) { |
|
267 #ifdef DEBUG |
|
268 perror("pthread_mutex_lock()"); |
|
269 fprintf(stderr, "[%lu] Unable to lock newly crated mutex while creating new node table!\n", pthread_self()); |
|
270 #endif |
|
271 pthread_mutex_destroy(&ndt->mutex); |
|
272 return -1; |
|
273 } |
|
274 |
|
275 /* initialise the node descriptor metadata array... */ |
|
276 ndt->node = malloc(sizeof(nd_entry_t) * nd_count); |
|
277 if (ndt->node == NULL) { |
|
278 #ifdef DEBUG |
|
279 perror("malloc()"); |
|
280 fprintf(stderr, "[%lu] Out of memory: error initializing node address buffer\n", pthread_self()); |
|
281 #endif |
|
282 #ifdef ERRMSG |
|
283 perror("malloc()"); |
|
284 fprintf(stderr, ERRMSG_HEAD "Out of memory. Error initializing node address buffer\n"); |
|
285 #endif |
|
286 pthread_mutex_unlock (&ndt->mutex); |
|
287 pthread_mutex_destroy(&ndt->mutex); |
|
288 return -1; |
|
289 } |
|
290 |
|
291 /* initialise the state of each node in the array... */ |
|
292 for (count = 0; count < nd_count; count++) { |
|
293 if (nd_entry_init(&ndt->node[count]) < 0) { |
|
294 pthread_mutex_unlock(&ndt->mutex); |
|
295 nd_table_done(ndt); |
|
296 return -1; |
|
297 } |
|
298 ndt->node_count = count+1; |
|
299 ndt->free_node_count = count+1; |
|
300 } /* for() */ |
|
301 |
|
302 ndt->node_count = nd_count; |
|
303 ndt->free_node_count = nd_count; |
|
304 |
|
305 pthread_mutex_unlock(&ndt->mutex); |
|
306 return nd_count; /* number of succesfully created nodes! */ |
|
307 } |
|
308 |
|
309 |
|
310 #else |
|
311 /* nd_table_init() |
|
312 * Version 2 of the nd_table_init() function. |
|
313 * If called more than once, 2nd and any subsequent calls will |
|
314 * be interpreted as a request to reserve an extra new_nd_count |
|
315 * number of nodes. This will be done using realloc(). |
|
316 */ |
|
317 static int nd_table_init(nd_table_t *ndt, int new_nd_count) { |
|
318 int count; |
|
319 |
|
320 if (ndt->node == NULL) { |
|
321 /* Node table nt yet initialized => we must initialise the node table mutex... */ |
|
322 pthread_mutex_init(&ndt->mutex, NULL); |
|
323 } |
|
324 |
|
325 /* lock the mutex */ |
|
326 while (pthread_mutex_lock(&ndt->mutex) != 0) sched_yield(); |
|
327 |
|
328 /* initialise the node descriptor metadata array... */ |
|
329 ndt->node = realloc(ndt->node, sizeof(nd_entry_t) * (ndt->node_count + new_nd_count)); |
|
330 if (ndt->node == NULL) { |
|
331 #ifdef DEBUG |
|
332 perror("malloc()"); |
|
333 fprintf(stderr, "[%lu] Out of memory: error initializing node address buffer\n", pthread_self()); |
|
334 #endif |
|
335 #ifdef ERRMSG |
|
336 perror("malloc()"); |
|
337 fprintf(stderr, ERRMSG_HEAD "Out of memory. Error initializing node address buffer\n"); |
|
338 #endif |
|
339 pthread_mutex_unlock (&ndt->mutex); |
|
340 pthread_mutex_destroy(&ndt->mutex); |
|
341 return -1; |
|
342 } |
|
343 |
|
344 /* initialise the state of each newly added node in the array... */ |
|
345 for (count = ndt->node_count; count < ndt->node_count + new_nd_count; count++) { |
|
346 if (nd_entry_init(&ndt->node[count]) < 0) { |
|
347 pthread_mutex_unlock(&ndt->mutex); |
|
348 return -1; |
|
349 } |
|
350 } /* for() */ |
|
351 ndt->node_count += new_nd_count; |
|
352 ndt->free_node_count += new_nd_count; |
|
353 |
|
354 pthread_mutex_unlock(&ndt->mutex); |
|
355 return new_nd_count; /* number of succesfully created nodes! */ |
|
356 } |
|
357 #endif |
|
358 |
|
359 |
|
360 static int nd_table_get_free_node(nd_table_t *ndt, nd_type_t nd_type) { |
|
361 int count; |
|
362 |
|
363 /* lock the mutex */ |
|
364 while (pthread_mutex_lock(&ndt->mutex) != 0) sched_yield(); |
|
365 |
|
366 /* check for free nodes... */ |
|
367 if (ndt->free_node_count <= 0) { |
|
368 /* no free nodes... */ |
|
369 pthread_mutex_unlock(&ndt->mutex); |
|
370 return -1; |
|
371 } |
|
372 |
|
373 /* Decrement the free node counter...*/ |
|
374 ndt->free_node_count--; |
|
375 |
|
376 /* search for a free node... */ |
|
377 for (count = 0; count < ndt->node_count; count++) { |
|
378 if(ndt->node[count].node_type == MB_FREE_NODE) { |
|
379 /* found one!! Allocate it to the new type! */ |
|
380 ndt->node[count].node_type = nd_type; |
|
381 pthread_mutex_unlock(&ndt->mutex); |
|
382 return count; |
|
383 } |
|
384 } /* for() */ |
|
385 |
|
386 /* Strange... We should have free nodes, but we didn't finda any! */ |
|
387 /* Let's try to get into a consistent state, and return an error! */ |
|
388 ndt->free_node_count = 0; |
|
389 pthread_mutex_unlock(&ndt->mutex); |
|
390 return -1; |
|
391 } |
|
392 |
|
393 |
|
394 |
|
395 static void nd_table_close_node(nd_table_t *ndt, int nd) { |
|
396 |
|
397 /* lock the mutex */ |
|
398 while (pthread_mutex_lock(&ndt->mutex) != 0) sched_yield(); |
|
399 |
|
400 if(ndt->node[nd].node_type == MB_FREE_NODE) { |
|
401 /* Node already free... */ |
|
402 pthread_mutex_unlock(&ndt->mutex); |
|
403 return; |
|
404 } |
|
405 |
|
406 /* Increment the free node counter...*/ |
|
407 ndt->free_node_count++; |
|
408 /* Mark the node as being free. */ |
|
409 ndt->node[nd].node_type = MB_FREE_NODE; |
|
410 |
|
411 pthread_mutex_unlock(&ndt->mutex); |
|
412 return; |
|
413 } |
|
414 |
|
415 |
|
416 |
|
417 /**************************************************************/ |
|
418 /**************************************************************/ |
|
419 /**** ****/ |
|
420 /**** ****/ |
|
421 /**** Global Library State ****/ |
|
422 /**** ****/ |
|
423 /**** ****/ |
|
424 /**************************************************************/ |
|
425 /**************************************************************/ |
|
426 |
|
427 |
|
428 /* The node descriptor table... */ |
|
429 /* NOTE: The node_table_ Must be initialized correctly here! */ |
|
430 static nd_table_t nd_table_ = {.node=NULL, .node_count=0, .free_node_count=0}; |
|
431 |
|
432 |
|
433 /**************************************************************/ |
|
434 /**************************************************************/ |
|
435 /**** ****/ |
|
436 /**** ****/ |
|
437 /**** Local Utility functions... ****/ |
|
438 /**** ****/ |
|
439 /**** ****/ |
|
440 /**************************************************************/ |
|
441 /**************************************************************/ |
|
442 |
|
443 |
|
444 #define min(a,b) ((a<b)?a:b) |
|
445 #define max(a,b) ((a>b)?a:b) |
|
446 |
|
447 /************************************/ |
|
448 /** **/ |
|
449 /** Configure socket for Modbus **/ |
|
450 /** **/ |
|
451 /************************************/ |
|
452 |
|
453 |
|
454 static int configure_socket(int socket_id) { |
|
455 |
|
456 /* configure the socket */ |
|
457 /* Set it to be non-blocking. This is safe because we always use select() before reading from it! |
|
458 * It is also required for the connect() call. The default timeout in the TCP stack is much too long |
|
459 * (typically blocks for 128 s ??) when the connect does not succedd imediately! |
|
460 */ |
|
461 if (fcntl(socket_id, F_SETFL, O_NONBLOCK) < 0) { |
|
462 #ifdef ERRMSG |
|
463 perror("fcntl()"); |
|
464 fprintf(stderr, ERRMSG_HEAD "Error configuring socket 'non-blocking' option.\n"); |
|
465 #endif |
|
466 return -1; |
|
467 } |
|
468 |
|
469 /* configure the socket */ |
|
470 /* set the TCP no delay flag. */ |
|
471 {int bool_opt = 1; |
|
472 if (setsockopt(socket_id, SOL_TCP, TCP_NODELAY, |
|
473 (const void *)&bool_opt, sizeof(bool_opt)) |
|
474 < 0) { |
|
475 #ifdef ERRMSG |
|
476 perror("setsockopt()"); |
|
477 fprintf(stderr, ERRMSG_HEAD "Error configuring socket 'TCP no delay' option.\n"); |
|
478 #endif |
|
479 return -1; |
|
480 } |
|
481 } |
|
482 |
|
483 /* set the IP low delay option. */ |
|
484 {int priority_opt = IPTOS_LOWDELAY; |
|
485 if (setsockopt(socket_id, SOL_IP, IP_TOS, |
|
486 (const void *)&priority_opt, sizeof(priority_opt)) |
|
487 < 0) { |
|
488 #ifdef ERRMSG |
|
489 perror("setsockopt()"); |
|
490 fprintf(stderr, ERRMSG_HEAD "Error configuring socket 'IP low delay' option.\n"); |
|
491 #endif |
|
492 return -1; |
|
493 } |
|
494 } |
|
495 |
|
496 #if 0 |
|
497 /* send buffer */ |
|
498 /* NOTE: For slave devices, that may be receiving multiple |
|
499 * requests before they have a chance to reply to the first, |
|
500 * it probably is a good idea to have a large receive buffer. |
|
501 * So it is best to leave it with the default configuration, as it is |
|
502 * larger than the largest Modbus TCP frame. |
|
503 * |
|
504 * For the send buffer, a smaller buffer should suffice. |
|
505 * However, it probably does not make sense to |
|
506 * waste time asking for a smaller buffer, since the larger |
|
507 * default buffer has already been allocated (the socket has already |
|
508 * been created!) |
|
509 * |
|
510 * We might just as well leave out the configuration of the socket |
|
511 * buffer size... |
|
512 */ |
|
513 #define SOCK_BUF_SIZE 300 /* The size proposed in the Modbus TCP spec. */ |
|
514 {int sock_buf_size; |
|
515 sock_buf_size = SOCK_BUF_SIZE; |
|
516 if (setsockopt(socket_id, SOL_SOCKET, SO_SNDBUF, |
|
517 (const void *)&sock_buf_size, sizeof(sock_buf_size)) |
|
518 < 0) |
|
519 return -1; |
|
520 /* recv buffer */ |
|
521 sock_buf_size = SOCK_BUF_SIZE; |
|
522 if (setsockopt(socket_id, SOL_SOCKET, SO_RCVBUF, |
|
523 (const void *)&sock_buf_size, sizeof(sock_buf_size)) |
|
524 < 0) |
|
525 return -1; |
|
526 } |
|
527 #endif |
|
528 |
|
529 return 0; |
|
530 } |
|
531 |
|
532 |
|
533 /************************************/ |
|
534 /** **/ |
|
535 /** Connect socket to remote host **/ |
|
536 /** **/ |
|
537 /************************************/ |
|
538 |
|
539 /* This function will create a new socket, and connect it to a remote host... */ |
|
540 static inline int open_connection(int nd, const struct timespec *timeout) { |
|
541 int socket_id, con_res; |
|
542 |
|
543 #ifdef DEBUG |
|
544 printf("[%lu] open_connection(): called, nd = %d\n", pthread_self(), nd); |
|
545 #endif |
|
546 |
|
547 if (nd_table_.node[nd].fd >= 0) |
|
548 /* nd already connected) */ |
|
549 return nd_table_.node[nd].fd; |
|
550 |
|
551 if (nd_table_.node[nd].addr.sin_family != AF_INET) |
|
552 /* invalid remote address, or invalid nd */ |
|
553 return -1; |
|
554 |
|
555 /* lets try to connect... */ |
|
556 /* create the socket */ |
|
557 if ((socket_id = socket(PF_INET, DEF_TYPE, 0 /* protocol_num */)) < 0) { |
|
558 #ifdef DEBUG |
|
559 perror("socket()"); |
|
560 fprintf(stderr, "[%lu] Error creating socket\n", pthread_self()); |
|
561 #endif |
|
562 #ifdef ERRMSG |
|
563 perror("socket()"); |
|
564 fprintf(stderr, ERRMSG_HEAD "Error creating socket\n"); |
|
565 #endif |
|
566 return -1; |
|
567 } |
|
568 |
|
569 /* configure the socket - includes setting non-blocking option! */ |
|
570 if (configure_socket(socket_id) < 0) { |
|
571 close(socket_id); |
|
572 return -1; |
|
573 }; |
|
574 |
|
575 /* establish the connection to remote host */ |
|
576 con_res = connect(socket_id, |
|
577 (struct sockaddr *)&(nd_table_.node[nd].addr), |
|
578 sizeof(nd_table_.node[nd].addr)); |
|
579 |
|
580 /* The following condition is not strictly necessary |
|
581 * (we could let the code fall through) |
|
582 * but it does make the code easier to read/understand... |
|
583 */ |
|
584 if (con_res >= 0) |
|
585 goto success_exit; /* connected succesfully on first try! */ |
|
586 |
|
587 if (con_res < 0) { |
|
588 if ((errno != EINPROGRESS) && (errno != EALREADY)) |
|
589 goto error_exit; /* error in connection request! */ |
|
590 |
|
591 /* connection request is ongoing */ |
|
592 /* EINPROGRESS -> first call to connect, EALREADY -> subsequent calls to connect */ |
|
593 /* Must wait for connect to complete at most 'timeout' seconds */ |
|
594 {fd_set fdset; |
|
595 int res, so_error; |
|
596 socklen_t len; |
|
597 struct timespec end_time, *et_ptr; |
|
598 |
|
599 et_ptr = NULL; |
|
600 if (timeout != NULL) { |
|
601 et_ptr = &end_time; |
|
602 *et_ptr = timespec_add_curtime(*timeout); |
|
603 } |
|
604 |
|
605 FD_ZERO(&fdset); |
|
606 FD_SET(socket_id, &fdset); |
|
607 |
|
608 res = my_select(socket_id+1, NULL, &fdset, et_ptr); |
|
609 if (res < 0) goto error_exit; /* error on call to select */ |
|
610 if (res == 0) goto error_exit; /* timeout */ |
|
611 /* (res > 0) -> connection attemt completed. May have been success or failure! */ |
|
612 |
|
613 len = sizeof(so_error); |
|
614 res = getsockopt(socket_id, SOL_SOCKET, SO_ERROR, &so_error, &len); |
|
615 if (res < 0) goto error_exit; /* error on call to getsockopt */ |
|
616 if (so_error != 0) goto error_exit; /* error on connection attempt */ |
|
617 goto success_exit; /* succesfully completed connection attempt! */ |
|
618 /* goto sucess_exit is not strcitly necessary - we could let the code fall through! */ |
|
619 } |
|
620 } |
|
621 |
|
622 success_exit: |
|
623 nd_table_.node[nd].fd = socket_id; |
|
624 /* Succesfully established connection => print a message next time we have error. */ |
|
625 nd_table_.node[nd].print_connect_error = 1; |
|
626 |
|
627 #ifdef DEBUG |
|
628 printf("[%lu] open_connection(): returning...\n", pthread_self()); |
|
629 #endif |
|
630 return socket_id; |
|
631 |
|
632 error_exit: |
|
633 #ifdef ERRMSG |
|
634 if (nd_table_.node[nd].print_connect_error > 0) { |
|
635 perror("connect()"); |
|
636 fprintf(stderr, ERRMSG_HEAD "Error establishing socket connection.\n"); |
|
637 /* do not print more error messages for this node... */ |
|
638 nd_table_.node[nd].print_connect_error = 0; |
|
639 } |
|
640 #endif |
|
641 close(socket_id); |
|
642 return -1; |
|
643 } |
|
644 |
|
645 |
|
646 /* This function will accept a new connection request, and attribute it to a new node... */ |
|
647 static inline int accept_connection(int nd) { |
|
648 int socket_id, new_nd; |
|
649 |
|
650 #ifdef DEBUG |
|
651 printf("[%lu] accept_connection(): called, nd = %d\n", pthread_self(), nd); |
|
652 #endif |
|
653 |
|
654 /* NOTE: We MUST accccept8) all connection requests, even if no new node is available. |
|
655 * => We first accept the connection request, and only later look for a node. |
|
656 * If no node is free/available for this new connections request, the |
|
657 * connection will be accepted and immediately closed. |
|
658 * Reason: |
|
659 * When the library is used for a Modbus/TCP server and no free node is |
|
660 * available, if we do not accept() all newly arrived connection requests |
|
661 * we would enter an infinite loop calling |
|
662 * - select() (in modbus_tcp_read()) |
|
663 * - and accept_connection(). |
|
664 * Note that select() will continue to return immediately if the |
|
665 * connection request is not accept()ted! |
|
666 */ |
|
667 /* lets accept new connection request... */ |
|
668 if ((socket_id = accept(nd_table_.node[nd].fd, NULL, NULL)) < 0) { |
|
669 #ifdef ERRMSG |
|
670 perror("accept()"); |
|
671 fprintf(stderr, ERRMSG_HEAD "Error while waiting for connection request from new client\n"); |
|
672 #endif |
|
673 /* error establishing new connection... */ |
|
674 return -1; |
|
675 } |
|
676 |
|
677 /* find a free node */ |
|
678 if ((new_nd = nd_table_get_free_node(&nd_table_, MB_SLAVE_NODE)) < 0) { |
|
679 /* no available free nodes for the new connection... */ |
|
680 close(socket_id); |
|
681 return -1; |
|
682 } |
|
683 |
|
684 /* configure the socket - includes setting the non-blocking option! */ |
|
685 if (configure_socket(socket_id) < 0) { |
|
686 nd_table_close_node(&nd_table_, new_nd); /* first free up the un-used node. */ |
|
687 close(socket_id); |
|
688 return -1; |
|
689 } |
|
690 |
|
691 /* set up the node entry and update the fd sets */ |
|
692 nd_table_.node[new_nd].fd = socket_id; |
|
693 nd_table_.node[new_nd].listen_node = nd; |
|
694 |
|
695 #ifdef DEBUG |
|
696 printf("[%lu] accept_connection(): returning new_nd = %d\n", pthread_self(), new_nd); |
|
697 #endif |
|
698 return new_nd; |
|
699 } |
|
700 |
|
701 |
|
702 static inline void close_connection(int nd) { |
|
703 if (nd_table_.node[nd].fd >= 0) { |
|
704 /* disconnect the tcp connection */ |
|
705 shutdown(nd_table_.node[nd].fd, SHUT_RDWR); |
|
706 #ifdef ERRMSG |
|
707 int res = |
|
708 #endif |
|
709 close(nd_table_.node[nd].fd); |
|
710 #ifdef ERRMSG |
|
711 if (res < 0) { |
|
712 perror("close()"); |
|
713 fprintf(stderr, ERRMSG_HEAD "Error closing socket\n"); |
|
714 } |
|
715 #endif |
|
716 nd_table_.node[nd].fd = -1; |
|
717 } |
|
718 |
|
719 if (nd_table_.node[nd].node_type == MB_SLAVE_NODE) { |
|
720 /* If it is a slave node, we will not be receiving any more data over this disconnected node, |
|
721 * (MB_SLAVE_NODE do not get re-connected!), so we free the node... |
|
722 */ |
|
723 nd_table_close_node(&nd_table_, nd); |
|
724 } |
|
725 } |
|
726 |
|
727 |
|
728 |
|
729 /************************************/ |
|
730 /** **/ |
|
731 /** Data format conversion **/ |
|
732 /** **/ |
|
733 /************************************/ |
|
734 |
|
735 /* |
|
736 * Functions to convert u16 variables |
|
737 * between network and host byte order |
|
738 * |
|
739 * NOTE: Modbus uses MSByte first, just like |
|
740 * tcp/ip, so we use the htons() and |
|
741 * ntoh() functions to guarantee |
|
742 * code portability. |
|
743 */ |
|
744 |
|
745 static inline u16 mb_hton(u16 h_value) { |
|
746 /* return h_value; */ |
|
747 return htons(h_value); |
|
748 } |
|
749 |
|
750 static inline u16 mb_ntoh(u16 m_value) { |
|
751 /* return m_value; */ |
|
752 return ntohs(m_value); |
|
753 } |
|
754 |
|
755 static inline u8 msb(u16 value) { |
|
756 /* return Most Significant Byte of value; */ |
|
757 return (value >> 8) & 0xFF; |
|
758 } |
|
759 |
|
760 static inline u8 lsb(u16 value) { |
|
761 /* return Least Significant Byte of value; */ |
|
762 return value & 0xFF; |
|
763 } |
|
764 |
|
765 #define u16_v(char_ptr) (*((u16 *)(&(char_ptr)))) |
|
766 |
|
767 |
|
768 /************************************/ |
|
769 /** **/ |
|
770 /** Build/Check a frame header **/ |
|
771 /** **/ |
|
772 /************************************/ |
|
773 |
|
774 /* A modbus TCP frame header has 6 bytes... |
|
775 * header[0-1] -> transaction id |
|
776 * header[2-3] -> must be 0 |
|
777 * header[4-5] -> frame data length (must be <= 255) |
|
778 */ |
|
779 #if TCP_HEADER_LENGTH < 6 |
|
780 #error This code assumes a header size of 6 bytes, but TCP_HEADER_LENGTH < 6 |
|
781 #endif |
|
782 |
|
783 static inline void build_header(u8 *header, |
|
784 u16 transaction_id, |
|
785 u16 byte_count) |
|
786 { |
|
787 u16_v(header[0]) = mb_hton(transaction_id); |
|
788 header[2] = 0; |
|
789 header[3] = 0; |
|
790 u16_v(header[4]) = mb_hton(byte_count); |
|
791 } |
|
792 |
|
793 |
|
794 static inline int check_header(u8 *header, |
|
795 u16 *transaction_id, |
|
796 u16 *byte_count) |
|
797 { |
|
798 if ((header[2] != 0) || (header[3] != 0)) |
|
799 return -1; |
|
800 |
|
801 *transaction_id = mb_ntoh(*(u16 *)(header + 0)); |
|
802 *byte_count = mb_ntoh(*(u16 *)(header + 4)); |
|
803 |
|
804 if (*byte_count > MAX_L2_FRAME_LENGTH) |
|
805 return -1; |
|
806 |
|
807 return 0; |
|
808 } |
|
809 |
|
810 |
|
811 |
|
812 |
|
813 |
|
814 /**************************************************************/ |
|
815 /**************************************************************/ |
|
816 /**** ****/ |
|
817 /**** ****/ |
|
818 /**** Sending of Modbus TCP Frames ****/ |
|
819 /**** ****/ |
|
820 /**** ****/ |
|
821 /**************************************************************/ |
|
822 /**************************************************************/ |
|
823 |
|
824 // pthread_mutex_t sendmsg_mutex = PTHREAD_MUTEX_INITIALIZER; |
|
825 |
|
826 /* NOTE: this function MUST be thread safe!! */ |
|
827 int modbus_tcp_write(int nd, /* node descriptor */ |
|
828 u8 *data, |
|
829 size_t data_length, |
|
830 u16 transaction_id, |
|
831 const struct timespec *transmit_timeout |
|
832 ) |
|
833 { |
|
834 #define data_vector_size 2 |
|
835 |
|
836 u8 header[TCP_HEADER_LENGTH]; |
|
837 struct iovec data_vector[data_vector_size] = { |
|
838 {(void *)header, TCP_HEADER_LENGTH}, |
|
839 {NULL, 0}}; |
|
840 struct msghdr msg = {NULL, 0, data_vector, data_vector_size, NULL, 0, 0}; |
|
841 int res, bytes_sent; |
|
842 |
|
843 #ifdef DEBUG |
|
844 printf("[%lu] modbus_tcp_write(): called... nd=%d\n", pthread_self(), nd); |
|
845 #endif |
|
846 |
|
847 if ((nd >= nd_table_.node_count) || (nd < 0)) |
|
848 /* invalid node descriptor... */ |
|
849 return -1; |
|
850 |
|
851 #ifdef DEBUG |
|
852 // printf("[%lu] locking mutex...\n", pthread_self()); |
|
853 #endif |
|
854 // while (pthread_mutex_lock(&sendmsg_mutex) != 0); |
|
855 |
|
856 /************************* |
|
857 * prepare the header... * |
|
858 *************************/ |
|
859 build_header(header, transaction_id, data_length); |
|
860 #ifdef DEBUG |
|
861 /* Print the hex value of each character that is about to be |
|
862 * sent over the bus. |
|
863 */ |
|
864 { int i; |
|
865 printf("modbus_tcp_write(): sending data...\n"); |
|
866 for(i = 0; i < TCP_HEADER_LENGTH; i++) |
|
867 printf("[0x%2X]", header[i]); |
|
868 for(i = 0; i < data_length; i++) |
|
869 printf("[0x%2X]", data[i]); |
|
870 printf("\n"); |
|
871 } |
|
872 #endif |
|
873 |
|
874 /****************************************** |
|
875 * do we need to re-establish connection? * |
|
876 ******************************************/ |
|
877 if (open_connection(nd, transmit_timeout) < 0) { |
|
878 #ifdef DEBUG |
|
879 fprintf(stderr, "[%lu] modbus_tcp_write(): could not establish connection...\n", pthread_self()); |
|
880 #endif |
|
881 #ifdef ERRMSG |
|
882 fprintf(stderr, ERRMSG_HEAD "could not establish connection...\n"); |
|
883 #endif |
|
884 return -1; |
|
885 } |
|
886 |
|
887 /********************** |
|
888 * write to output... * |
|
889 **********************/ |
|
890 /* TWO ALTERNATIVE IMPLEMENTATIONS !!! */ |
|
891 #if 0 |
|
892 /* write header */ |
|
893 bytes_sent = 0; |
|
894 while (1) { |
|
895 res = write(nd_table_.node[nd].fd, header+bytes_sent, TCP_HEADER_LENGTH-bytes_sent); |
|
896 if (res < 0) { |
|
897 if ((errno != EAGAIN ) && (errno != EINTR )) { |
|
898 /* error sending message... */ |
|
899 close_connection(nd); |
|
900 return -1; |
|
901 } else { |
|
902 continue; |
|
903 } |
|
904 } else { |
|
905 /* res >= 0 */ |
|
906 bytes_sent += res; |
|
907 if (bytes_sent >= TCP_HEADER_LENGTH) { |
|
908 break; |
|
909 } |
|
910 } |
|
911 } |
|
912 |
|
913 /* write data */ |
|
914 bytes_sent = 0; |
|
915 while (1) { |
|
916 res = write(nd_table_.node[nd].fd, data+bytes_sent, data_length-bytes_sent); |
|
917 if (res < 0) { |
|
918 if ((errno != EAGAIN ) && (errno != EINTR )) { |
|
919 /* error sending message... */ |
|
920 close_connection(nd); |
|
921 return -1; |
|
922 } else { |
|
923 continue; |
|
924 } |
|
925 } else { |
|
926 /* res >= 0 */ |
|
927 bytes_sent += res; |
|
928 if (bytes_sent >= data_length) { |
|
929 /* query succesfully sent! */ |
|
930 #ifdef DEBUG |
|
931 printf("[%lu] modbus_tcp_write(): sent %d bytes\n", pthread_self(), TCP_HEADER_LENGTH+data_length); |
|
932 #endif |
|
933 return data_length; |
|
934 } |
|
935 } |
|
936 } |
|
937 |
|
938 /********************** |
|
939 * write to output... * |
|
940 **********************/ |
|
941 #else |
|
942 /* We are optimising for the most likely case, and in doing that |
|
943 * we are making the least likely case have worse behaviour! |
|
944 * Read on for an explanation... |
|
945 * |
|
946 * - The optimised behaviour for the most likely case: |
|
947 * We have set the NO_DELAY flag on the socket, so the IP datagram |
|
948 * is not delayed and is therefore sent as soon as any data is written to |
|
949 * the socket. |
|
950 * In order to send the whole message in a single IP datagram, we have to |
|
951 * write both the the header and the data with a single call to write() |
|
952 * In order to not to have to copy the data around just to add the |
|
953 * message header, we use sendmsg() instead of write()! |
|
954 * |
|
955 * - The worse behaviour for the least likely case: |
|
956 * If for some reason only part of the data is sent with the first call to |
|
957 * write(), a datagram is sent right away, and the subsequent data will |
|
958 * be sent in another datagram. :-( |
|
959 */ |
|
960 /* NOTE: since snedmsg() is not thread safe, we use a mutex to protect access to this function... */ |
|
961 |
|
962 data_vector[data_vector_size - 1].iov_base = data; |
|
963 data_vector[data_vector_size - 1].iov_len = data_length; |
|
964 data_vector[ 0].iov_base = header; |
|
965 data_vector[ 0].iov_len = TCP_HEADER_LENGTH; |
|
966 bytes_sent = 0; |
|
967 while (1) { |
|
968 int sendmsg_errno; |
|
969 /* Please see the comment just above the main loop!! */ |
|
970 res = sendmsg(nd_table_.node[nd].fd, &msg, 0); |
|
971 sendmsg_errno = errno; |
|
972 if (res < 0) { |
|
973 if ((sendmsg_errno != EAGAIN ) && (sendmsg_errno != EINTR )) { |
|
974 /* error sending message... */ |
|
975 close_connection(nd); |
|
976 return -1; |
|
977 } else { |
|
978 continue; |
|
979 } |
|
980 } else { |
|
981 /* res >= 0 */ |
|
982 bytes_sent += res; |
|
983 if (bytes_sent >= data_length + TCP_HEADER_LENGTH) { |
|
984 /* query succesfully sent! */ |
|
985 #ifdef DEBUG |
|
986 printf("[%lu] modbus_tcp_write(): sent %d bytes\n", pthread_self(), bytes_sent); |
|
987 #endif |
|
988 // pthread_mutex_unlock(&sendmsg_mutex); |
|
989 #ifdef DEBUG |
|
990 // printf("[%lu] unlocked mutex...\n", pthread_self()); |
|
991 #endif |
|
992 return data_length; |
|
993 } |
|
994 |
|
995 /* adjust the data_vector... */ |
|
996 if (res < data_vector[0].iov_len) { |
|
997 u8* tmp = data_vector[0].iov_base; |
|
998 tmp += res; |
|
999 data_vector[0].iov_len -= res; |
|
1000 data_vector[0].iov_base = tmp; |
|
1001 } else { |
|
1002 u8* tmp = data_vector[1].iov_base; |
|
1003 tmp += res; |
|
1004 res -= data_vector[0].iov_len; |
|
1005 data_vector[0].iov_len = 0; |
|
1006 data_vector[1].iov_len -= res; |
|
1007 data_vector[1].iov_base = tmp; |
|
1008 } |
|
1009 } |
|
1010 } /* while (1) */ |
|
1011 #endif |
|
1012 |
|
1013 /* humour the compiler... */ |
|
1014 // pthread_mutex_unlock(&sendmsg_mutex); |
|
1015 #ifdef DEBUG |
|
1016 // printf("[%lu] unlocked mutex...\n", pthread_self()); |
|
1017 #endif |
|
1018 return -1; |
|
1019 } |
|
1020 |
|
1021 |
|
1022 |
|
1023 /**************************************************************/ |
|
1024 /**************************************************************/ |
|
1025 /**** ****/ |
|
1026 /**** ****/ |
|
1027 /**** Receiving Modbus TCP Frames ****/ |
|
1028 /**** ****/ |
|
1029 /**** ****/ |
|
1030 /**************************************************************/ |
|
1031 /**************************************************************/ |
|
1032 |
|
1033 |
|
1034 /* A helper function to modbus_tcp_read() |
|
1035 * |
|
1036 * WARNING: The semantics of this function are not what you would expect! |
|
1037 * |
|
1038 * if (data_already_available != 0) |
|
1039 * It assumes that select() has already been called before |
|
1040 * this function got called, and we are therefore guaranteed |
|
1041 * to have at least one byte to read off the socket (the fd). |
|
1042 * |
|
1043 * if (data_already_available == 0) |
|
1044 * it starts off by calling select()! |
|
1045 * |
|
1046 * |
|
1047 * NOTE: Ususal select semantics for (a: end_time == NULL) and |
|
1048 * (b: *end_time == 0) also apply. |
|
1049 * |
|
1050 * (a) Indefinite timeout |
|
1051 * (b) Try once, and and quit if no data available. |
|
1052 */ |
|
1053 /* RETURNS: number of bytes read |
|
1054 * -1 read error! |
|
1055 * -2 timeout |
|
1056 */ |
|
1057 static int read_bytes(int fd, |
|
1058 u8 *data, |
|
1059 int max_data_count, |
|
1060 const struct timespec *end_time, |
|
1061 int data_already_available) |
|
1062 { |
|
1063 fd_set rfds; |
|
1064 int res, data_count; |
|
1065 |
|
1066 data_count = 0; |
|
1067 |
|
1068 while (data_count < max_data_count) { |
|
1069 /*============================* |
|
1070 * wait for data availability * |
|
1071 *============================*/ |
|
1072 if (data_already_available == 0) { |
|
1073 int sel_res; |
|
1074 FD_ZERO(&rfds); |
|
1075 FD_SET(fd, &rfds); |
|
1076 sel_res = my_select(fd + 1, &rfds, NULL, end_time); |
|
1077 if (sel_res < 0) |
|
1078 return -1; |
|
1079 if (sel_res == 0) |
|
1080 /* timeout! */ |
|
1081 return -2; |
|
1082 } |
|
1083 |
|
1084 /*============================* |
|
1085 * read the available data... * |
|
1086 *============================*/ |
|
1087 res = read(fd, data + data_count, max_data_count - data_count); |
|
1088 if (res == 0) { |
|
1089 /* We are guaranteed to have data to read off the fd since we called |
|
1090 * select(), but read() returned 0 bytes. |
|
1091 * This means that the remote process has closed down the connection, |
|
1092 * so we return 0. |
|
1093 */ |
|
1094 return 0; |
|
1095 } |
|
1096 |
|
1097 if (res < 0) { |
|
1098 if (errno != EINTR) |
|
1099 return -1; |
|
1100 else |
|
1101 res = 0; |
|
1102 } |
|
1103 #ifdef DEBUG |
|
1104 {/* display the hex code of each character received */ |
|
1105 int i; |
|
1106 for (i=0; i < res; i++) |
|
1107 printf("<0x%2X>", *(data + data_count + i)); |
|
1108 } |
|
1109 #endif |
|
1110 data_count += res; |
|
1111 data_already_available = 0; |
|
1112 } /* while ()*/ |
|
1113 |
|
1114 /* data read succesfully... */ |
|
1115 return data_count; |
|
1116 } |
|
1117 |
|
1118 |
|
1119 |
|
1120 /***************************************/ |
|
1121 /** **/ |
|
1122 /** Read a Modbus TCP frame **/ |
|
1123 /** off a single identified node. **/ |
|
1124 /** **/ |
|
1125 /***************************************/ |
|
1126 |
|
1127 /* This private function will read a Modbus TCP frame off a single identified node |
|
1128 * that we know before hand that has data ready to be read off it. The data may or may not be |
|
1129 * a valid Modbus TCP frame. It is up to this function to figure that out. |
|
1130 */ |
|
1131 /* NOTES: |
|
1132 * - We re-use the recv_buf_ to load the frame header, so we have to make |
|
1133 * sure that the buffer is large enough to take it... |
|
1134 */ |
|
1135 /* RETURNS: number of bytes read |
|
1136 * -1 on read from file/node error |
|
1137 * -2 on timeout |
|
1138 */ |
|
1139 #if RECV_BUFFER_SIZE < TCP_HEADER_LENGTH |
|
1140 #error The receive buffer is smaller than the frame header length. |
|
1141 #endif |
|
1142 |
|
1143 static int modbus_tcp_read_frame(int nd, |
|
1144 u16 *transaction_id, |
|
1145 struct timespec *ts_ptr) { |
|
1146 int fd, res; |
|
1147 u16 frame_length; |
|
1148 |
|
1149 #ifdef DEBUG |
|
1150 printf("[%lu] modbus_tcp_read_frame(): reading off nd=%d\n", pthread_self(), nd); |
|
1151 #endif |
|
1152 /*=========================* |
|
1153 * read a Modbus TCP frame * |
|
1154 *=========================*/ |
|
1155 /* assume error... */ |
|
1156 fd = nd_table_.node[nd].fd; |
|
1157 |
|
1158 /*-------------* |
|
1159 * read header * |
|
1160 *-------------*/ |
|
1161 if ((res = read_bytes(fd, nd_table_.node[nd].recv_buf, TCP_HEADER_LENGTH, ts_ptr, 1)) != TCP_HEADER_LENGTH) { |
|
1162 #ifdef DEBUG |
|
1163 printf("[%lu] modbus_tcp_read_frame(): frame with insuficient bytes for a valid header...\n", pthread_self()); |
|
1164 #endif |
|
1165 if (res < 0) return res; |
|
1166 return -1; |
|
1167 } |
|
1168 |
|
1169 /* let's check for header consistency... */ |
|
1170 if (check_header(nd_table_.node[nd].recv_buf, transaction_id, &frame_length) < 0) { |
|
1171 #ifdef DEBUG |
|
1172 printf("[%lu] modbus_tcp_read_frame(): frame with non valid header...\n", pthread_self()); |
|
1173 #endif |
|
1174 return -1; |
|
1175 } |
|
1176 |
|
1177 /*-----------* |
|
1178 * read data * |
|
1179 *-----------*/ |
|
1180 if ((res = read_bytes(fd, nd_table_.node[nd].recv_buf, frame_length, ts_ptr, 0)) != frame_length) { |
|
1181 #ifdef DEBUG |
|
1182 printf("[%lu] modbus_tcp_read_frame(): frame with non valid frame length...\n", pthread_self()); |
|
1183 #endif |
|
1184 if (res < 0) return res; |
|
1185 return -1; |
|
1186 } |
|
1187 |
|
1188 /* frame received succesfully... */ |
|
1189 #ifdef DEBUG |
|
1190 printf("\n"); |
|
1191 #endif |
|
1192 return frame_length; |
|
1193 } |
|
1194 |
|
1195 |
|
1196 |
|
1197 |
|
1198 /***************************************/ |
|
1199 /** **/ |
|
1200 /** Read a Modbus TCP frame **/ |
|
1201 /** OR Accept connection requests **/ |
|
1202 /** off possibly multiple node... **/ |
|
1203 /** **/ |
|
1204 /***************************************/ |
|
1205 |
|
1206 /* The public function that reads a valid modbus frame. |
|
1207 * The frame is read from...: |
|
1208 * - if (nd >= 0) and (nd is of type MB_MASTER_NODE or MB_SLAVE_NODE) |
|
1209 * The frame is read from the node descriptor nd |
|
1210 * - if (nd >= 0) and (nd is of type MB_LISTEN_NODE) |
|
1211 * The frame is read from the all node descriptors of type MB_SLAVE_NODE that were |
|
1212 * opened as a consequence of a connection request to the nd slave. |
|
1213 * In this case, new connection requests to nd will also be accepted! |
|
1214 * - if (nd == -1) |
|
1215 * The frame is read from any valid and initialised node descriptor. |
|
1216 * In this case, new connection requests to any nd of type MB_LISTEN_NODE will also be accepted! |
|
1217 * In this case, the node where the data is eventually read from is returned in *nd. |
|
1218 * |
|
1219 * The send_data and send_length parameters are ignored... |
|
1220 * (However, these parameters must stay in order to keep the function |
|
1221 * interface identical to the ASCII and RTU versons!) |
|
1222 * |
|
1223 * return value: The length (in bytes) of the valid frame, |
|
1224 * -1 on error |
|
1225 * |
|
1226 * NOTE: Ususal select semantics for (a: recv_timeout == NULL) and |
|
1227 * (b: *recv_timeout == 0) also apply. |
|
1228 * |
|
1229 * (a) Indefinite timeout |
|
1230 * (b) Try once, and and quit if no data available. |
|
1231 */ |
|
1232 |
|
1233 /* RETURNS: number of bytes read |
|
1234 * -1 on read from file/node error |
|
1235 * -2 on timeout |
|
1236 */ |
|
1237 int modbus_tcp_read(int *nd, /* node descriptor */ |
|
1238 u8 **recv_data_ptr, |
|
1239 u16 *transaction_id, |
|
1240 const u8 *send_data, /* ignored ! */ |
|
1241 int send_length, /* ignored ! */ |
|
1242 const struct timespec *recv_timeout) { |
|
1243 |
|
1244 struct timespec end_time, *ts_ptr; |
|
1245 u8 *local_recv_data_ptr; |
|
1246 u16 local_transaction_id = 0; |
|
1247 |
|
1248 #ifdef DEBUG |
|
1249 printf("[%lu] modbus_tcp_read(): called... nd=%d\n", pthread_self(), *nd); |
|
1250 #endif |
|
1251 |
|
1252 if (nd == NULL) |
|
1253 return -1; |
|
1254 |
|
1255 if (*nd >= nd_table_.node_count) |
|
1256 /* invalid *nd */ |
|
1257 /* remember that *nd < 0 is valid!! */ |
|
1258 return -1; |
|
1259 |
|
1260 if (recv_data_ptr == NULL) |
|
1261 recv_data_ptr = &local_recv_data_ptr; |
|
1262 if (transaction_id == NULL) |
|
1263 transaction_id = &local_transaction_id; |
|
1264 |
|
1265 /* We will potentially call read() multiple times to read in a single frame. |
|
1266 * We therefore determine the absolute time_out, and use this as a parameter |
|
1267 * for each call to read_bytes() instead of using a relative timeout. |
|
1268 * |
|
1269 * NOTE: see also the timeout related comment in the read_bytes() function! |
|
1270 */ |
|
1271 ts_ptr = NULL; |
|
1272 if (recv_timeout != NULL) { |
|
1273 ts_ptr = &end_time; |
|
1274 *ts_ptr = timespec_add_curtime(*recv_timeout); |
|
1275 } |
|
1276 |
|
1277 /* If we must read off a single node... */ |
|
1278 if (*nd >= 0) |
|
1279 /* but the node does not have a valid fd */ |
|
1280 if ((nd_table_.node[*nd].node_type == MB_FREE_NODE) || |
|
1281 (nd_table_.node[*nd].fd < 0)) |
|
1282 /* then we return an error... */ |
|
1283 return -1; |
|
1284 |
|
1285 /* We will loop forever... |
|
1286 * We jump out of the loop and return from the function as soon as: |
|
1287 * - we receive a valid modbus message; |
|
1288 * OR |
|
1289 * - we time out. |
|
1290 * |
|
1291 * NOTE: This loop will close connections through which we receive invalid frames. |
|
1292 * This means that the set of nodes through which we may receive data may change with each |
|
1293 * loop iteration. => We need to re-calculate the fds in each loop iteration! |
|
1294 */ |
|
1295 |
|
1296 while (1) { |
|
1297 int nd_count, fd_high; |
|
1298 fd_set rfds; |
|
1299 |
|
1300 /* We prepare our fd sets here so we can later call select() */ |
|
1301 FD_ZERO(&rfds); |
|
1302 fd_high = -1; |
|
1303 |
|
1304 for (nd_count = 0; nd_count < nd_table_.node_count; nd_count++) { |
|
1305 if (nd_table_.node[nd_count].node_type != MB_FREE_NODE) |
|
1306 { |
|
1307 if ((*nd < 0) // we select from all nodes |
|
1308 || (*nd == nd_count) // we select from this specific node |
|
1309 // we are listening on a MB_LISTEN_NODE, so we must also receive requests sent to slave nodes |
|
1310 // whose connection requests arrived through this MB_LISTEN_NDODE |
|
1311 || ((nd_table_.node[nd_count].node_type == MB_SLAVE_NODE) && (nd_table_.node[nd_count].listen_node == *nd))) |
|
1312 { |
|
1313 /* check if valid fd */ |
|
1314 if (nd_table_.node[nd_count].fd >= 0) { |
|
1315 /* Add the descriptor to the fd set... */ |
|
1316 FD_SET(nd_table_.node[nd_count].fd, &rfds); |
|
1317 fd_high = max(fd_high, nd_table_.node[nd_count].fd); |
|
1318 } |
|
1319 } |
|
1320 } |
|
1321 } /* for(;;) */ |
|
1322 |
|
1323 #ifdef DEBUG |
|
1324 printf("[%lu] modbus_tcp_read(): while(1) looping. fd_high = %d, nd=%d\n", pthread_self(), fd_high, *nd); |
|
1325 #endif |
|
1326 |
|
1327 if (fd_high == -1) |
|
1328 /* we will not be reading from any node! */ |
|
1329 return -1; |
|
1330 |
|
1331 /* We now call select and wait for activity on the nodes we are listening to */ |
|
1332 { int sel_res = my_select(fd_high + 1, &rfds, NULL, ts_ptr); |
|
1333 if (sel_res < 0) |
|
1334 return -1; |
|
1335 if (sel_res == 0) |
|
1336 /* timeout! */ |
|
1337 return -2; |
|
1338 } |
|
1339 |
|
1340 /* figure out which nd is ready to be read... */ |
|
1341 for (nd_count = 0; nd_count < nd_table_.node_count; nd_count++) { |
|
1342 if ((nd_table_.node[nd_count].node_type != MB_FREE_NODE) && |
|
1343 (nd_table_.node[nd_count].fd >= 0)) { |
|
1344 if (FD_ISSET(nd_table_.node[nd_count].fd, &rfds)) { |
|
1345 /* Found the node descriptor... */ |
|
1346 #ifdef DEBUG |
|
1347 printf("[%lu] modbus_tcp_read(): my_select() returned due to activity on node nd=%d\n", pthread_self(), nd_count); |
|
1348 #endif |
|
1349 if (nd_table_.node[nd_count].node_type == MB_LISTEN_NODE) { |
|
1350 /* We must accept a new connection... |
|
1351 * No need to check for errors. |
|
1352 * If one occurs, there is nothing we can do... |
|
1353 */ |
|
1354 accept_connection(nd_count); |
|
1355 } else { |
|
1356 /* it is a MB_SLAVE_NODE or a MB_MASTER_NODE */ |
|
1357 /* We will read a frame off this nd */ |
|
1358 int res; |
|
1359 res = modbus_tcp_read_frame(nd_count, transaction_id, ts_ptr); |
|
1360 if (res > 0) { |
|
1361 *nd = nd_count; |
|
1362 *recv_data_ptr = nd_table_.node[nd_count].recv_buf; |
|
1363 return res; |
|
1364 } |
|
1365 if (res < 0) { |
|
1366 /* We had an error reading the frame... |
|
1367 * We handle it by closing the connection, as specified by |
|
1368 * the modbus TCP protocol! |
|
1369 * |
|
1370 * NOTE: The error may have been a timeout, which means this function should return immediately. |
|
1371 * However, in this case we let the execution loop once again |
|
1372 * in the while(1) loop. My_select() will be called again |
|
1373 * and the timeout detected. The timeout error code (-2) |
|
1374 * will then be returned correctly! |
|
1375 */ |
|
1376 #ifdef DEBUG |
|
1377 printf("[%lu] modbus_tcp_read(): error reading frame. Closing connection...\n", pthread_self()); |
|
1378 #endif |
|
1379 /* We close the socket... */ |
|
1380 close_connection(nd_count); |
|
1381 } |
|
1382 } |
|
1383 /* we have found the node descriptor, so let's jump out of the for(;;) loop */ |
|
1384 break; |
|
1385 } |
|
1386 } |
|
1387 } /* for(;;) */ |
|
1388 |
|
1389 /* We were unsuccesfull reading a frame, so we try again... */ |
|
1390 } /* while (1) */ |
|
1391 |
|
1392 /* humour the compiler... */ |
|
1393 return -1; |
|
1394 } |
|
1395 |
|
1396 |
|
1397 |
|
1398 |
|
1399 |
|
1400 /**************************************************************/ |
|
1401 /**************************************************************/ |
|
1402 /**** ****/ |
|
1403 /**** ****/ |
|
1404 /**** Initialising and Shutting Down Library ****/ |
|
1405 /**** ****/ |
|
1406 /**** ****/ |
|
1407 /**************************************************************/ |
|
1408 /**************************************************************/ |
|
1409 |
|
1410 |
|
1411 /* Ugly hack... |
|
1412 * Beremiz will be calling modbus_tcp_init() multiple times (through modbus_init() ) |
|
1413 * (once for each plugin instance) |
|
1414 * It will also be calling modbus_tcp_done() the same number of times |
|
1415 * We only want to really shutdown the library the last time it is called. |
|
1416 * We therefore keep a counter of how many times modbus_tcp_init() is called, |
|
1417 * and decrement it in modbus_tcp_done() |
|
1418 */ |
|
1419 int modbus_tcp_init_counter = 0; |
|
1420 |
|
1421 /******************************/ |
|
1422 /** **/ |
|
1423 /** Load Default Values **/ |
|
1424 /** **/ |
|
1425 /******************************/ |
|
1426 |
|
1427 static void set_defaults(const char **service) { |
|
1428 /* Set the default values, if required... */ |
|
1429 if (*service == NULL) |
|
1430 *service = DEF_SERVICE; |
|
1431 } |
|
1432 |
|
1433 |
|
1434 /******************************/ |
|
1435 /** **/ |
|
1436 /** Initialise Library **/ |
|
1437 /** **/ |
|
1438 /******************************/ |
|
1439 /* returns the number of nodes succesfully initialised... |
|
1440 * returns -1 on error. |
|
1441 */ |
|
1442 int modbus_tcp_init(int nd_count, |
|
1443 optimization_t opt /* ignored... */, |
|
1444 int *extra_bytes) { |
|
1445 #ifdef DEBUG |
|
1446 printf("[%lu] modbus_tcp_init(): called...\n", pthread_self()); |
|
1447 printf("[%lu] creating %d nodes:\n", pthread_self(), nd_count); |
|
1448 #endif |
|
1449 |
|
1450 modbus_tcp_init_counter++; |
|
1451 |
|
1452 /* set the extra_bytes value... */ |
|
1453 /* Please see note before the modbus_rtu_write() function for a |
|
1454 * better understanding of this extremely ugly hack... This will be |
|
1455 * in the mb_rtu.c file!! |
|
1456 * |
|
1457 * The number of extra bytes that must be allocated to the data buffer |
|
1458 * before calling modbus_tcp_write() |
|
1459 */ |
|
1460 if (extra_bytes != NULL) |
|
1461 *extra_bytes = 0; |
|
1462 |
|
1463 if (0 == nd_count) |
|
1464 /* no need to initialise this layer! */ |
|
1465 return 0; |
|
1466 if (nd_count <= 0) |
|
1467 /* invalid node count... */ |
|
1468 goto error_exit_1; |
|
1469 |
|
1470 /* initialise the node table... */ |
|
1471 if (nd_table_init(&nd_table_, nd_count) < 0) |
|
1472 goto error_exit_1; |
|
1473 |
|
1474 #ifdef DEBUG |
|
1475 printf("[%lu] modbus_tcp_init(): %d node(s) opened succesfully\n", pthread_self(), nd_count); |
|
1476 #endif |
|
1477 return nd_count; /* number of succesfully created nodes! */ |
|
1478 |
|
1479 /* |
|
1480 error_exit_2: |
|
1481 nd_table_done(&nd_table_); |
|
1482 */ |
|
1483 error_exit_1: |
|
1484 if (extra_bytes != NULL) |
|
1485 *extra_bytes = 0; |
|
1486 return -1; |
|
1487 } |
|
1488 |
|
1489 |
|
1490 |
|
1491 |
|
1492 |
|
1493 |
|
1494 /******************************/ |
|
1495 /** **/ |
|
1496 /** Open a Master Node **/ |
|
1497 /** **/ |
|
1498 /******************************/ |
|
1499 int modbus_tcp_connect(node_addr_t node_addr) { |
|
1500 int node_descriptor; |
|
1501 struct sockaddr_in tmp_addr; |
|
1502 |
|
1503 #ifdef DEBUG |
|
1504 printf("[%lu] modbus_tcp_connect(): called...\n", pthread_self()); |
|
1505 printf("[%lu] %s:%s\n", pthread_self(), |
|
1506 node_addr.addr.tcp.host, |
|
1507 node_addr.addr.tcp.service); |
|
1508 #endif |
|
1509 |
|
1510 /* Check for valid address family */ |
|
1511 if (node_addr.naf != naf_tcp) |
|
1512 /* wrong address type... */ |
|
1513 return -1; |
|
1514 |
|
1515 /* set the default values... */ |
|
1516 set_defaults(&(node_addr.addr.tcp.service)); |
|
1517 |
|
1518 /* Check the parameters we were passed... */ |
|
1519 if(sin_initaddr(&tmp_addr, |
|
1520 node_addr.addr.tcp.host, 0, |
|
1521 node_addr.addr.tcp.service, 0, |
|
1522 DEF_PROTOCOL) |
|
1523 < 0) { |
|
1524 #ifdef ERRMSG |
|
1525 fprintf(stderr, ERRMSG_HEAD "Error parsing/resolving address %s:%s\n", |
|
1526 node_addr.addr.tcp.host, |
|
1527 node_addr.addr.tcp.service); |
|
1528 #endif |
|
1529 return -1; |
|
1530 } |
|
1531 |
|
1532 /* find a free node descriptor */ |
|
1533 if ((node_descriptor = nd_table_get_free_node(&nd_table_, MB_MASTER_NODE)) < 0) |
|
1534 /* if no free nodes to initialize, then we are finished... */ |
|
1535 return -1; |
|
1536 |
|
1537 nd_table_.node[node_descriptor].addr = tmp_addr; |
|
1538 nd_table_.node[node_descriptor].fd = -1; /* not currently connected... */ |
|
1539 nd_table_.node[node_descriptor].close_on_silence = node_addr.addr.tcp.close_on_silence; |
|
1540 |
|
1541 if (nd_table_.node[node_descriptor].close_on_silence < 0) |
|
1542 nd_table_.node[node_descriptor].close_on_silence = DEF_CLOSE_ON_SILENCE; |
|
1543 |
|
1544 /* WE have never tried to connect, so print an error the next time we try to connect */ |
|
1545 nd_table_.node[node_descriptor].print_connect_error = 1; |
|
1546 |
|
1547 #ifdef DEBUG |
|
1548 printf("[%lu] modbus_tcp_connect(): returning nd=%d\n", pthread_self(), node_descriptor); |
|
1549 #endif |
|
1550 return node_descriptor; |
|
1551 } |
|
1552 |
|
1553 |
|
1554 |
|
1555 /******************************/ |
|
1556 /** **/ |
|
1557 /** Open a Slave Node **/ |
|
1558 /** **/ |
|
1559 /******************************/ |
|
1560 |
|
1561 int modbus_tcp_listen(node_addr_t node_addr) { |
|
1562 int fd, nd; |
|
1563 |
|
1564 #ifdef DEBUG |
|
1565 printf("[%lu] modbus_tcp_listen(): called...\n", pthread_self()); |
|
1566 printf("[%lu] %s:%s\n", pthread_self(), |
|
1567 node_addr.addr.tcp.host, |
|
1568 node_addr.addr.tcp.service); |
|
1569 #endif |
|
1570 |
|
1571 /* Check for valid address family */ |
|
1572 if (node_addr.naf != naf_tcp) |
|
1573 /* wrong address type... */ |
|
1574 goto error_exit_0; |
|
1575 |
|
1576 /* set the default values... */ |
|
1577 set_defaults(&(node_addr.addr.tcp.service)); |
|
1578 |
|
1579 /* create a socket and bind it to the appropriate port... */ |
|
1580 fd = sin_bindsock(node_addr.addr.tcp.host, |
|
1581 node_addr.addr.tcp.service, |
|
1582 DEF_PROTOCOL); |
|
1583 if (fd < 0) { |
|
1584 #ifdef ERRMSG |
|
1585 fprintf(stderr, ERRMSG_HEAD "Could not bind to socket %s:%s\n", |
|
1586 ((node_addr.addr.tcp.host==NULL)?"#ANY#":node_addr.addr.tcp.host), |
|
1587 node_addr.addr.tcp.service); |
|
1588 #endif |
|
1589 goto error_exit_0; |
|
1590 } |
|
1591 if (listen(fd, DEF_MAX_PENDING_CONNECTION_REQUESTS) < 0) |
|
1592 goto error_exit_0; |
|
1593 |
|
1594 /* find a free node descriptor */ |
|
1595 if ((nd = nd_table_get_free_node(&nd_table_, MB_LISTEN_NODE)) < 0) { |
|
1596 /* if no free nodes to initialize, then we are finished... */ |
|
1597 goto error_exit_1; |
|
1598 } |
|
1599 |
|
1600 /* nd_table_.node[nd].addr = tmp_addr; */ /* does not apply for MB_LISTEN_NODE */ |
|
1601 nd_table_.node[nd].fd = fd; /* not currently connected... */ |
|
1602 |
|
1603 #ifdef DEBUG |
|
1604 printf("[%lu] modbus_tcp_listen(): returning nd=%d\n", pthread_self(), nd); |
|
1605 #endif |
|
1606 return nd; |
|
1607 |
|
1608 error_exit_1: |
|
1609 close(fd); |
|
1610 error_exit_0: |
|
1611 return -1; |
|
1612 } |
|
1613 |
|
1614 |
|
1615 |
|
1616 /******************************/ |
|
1617 /** **/ |
|
1618 /** Close a node **/ |
|
1619 /** **/ |
|
1620 /******************************/ |
|
1621 |
|
1622 int modbus_tcp_close(int nd) { |
|
1623 #ifdef DEBUG |
|
1624 fprintf(stderr, "[%lu] modbus_tcp_close(): called... nd=%d\n", pthread_self(), nd); |
|
1625 #endif |
|
1626 |
|
1627 if ((nd < 0) || (nd >= nd_table_.node_count)) { |
|
1628 /* invalid nd */ |
|
1629 #ifdef DEBUG |
|
1630 fprintf(stderr, "[%lu] modbus_tcp_close(): invalid node %d. Should be < %d\n", pthread_self(), nd, nd_table_.node_count); |
|
1631 #endif |
|
1632 return -1; |
|
1633 } |
|
1634 |
|
1635 if (nd_table_.node[nd].node_type == MB_FREE_NODE) |
|
1636 /* already free node */ |
|
1637 return 0; |
|
1638 |
|
1639 close_connection(nd); |
|
1640 |
|
1641 nd_table_close_node(&nd_table_, nd); |
|
1642 |
|
1643 return 0; |
|
1644 } |
|
1645 |
|
1646 |
|
1647 |
|
1648 /**********************************/ |
|
1649 /** **/ |
|
1650 /** Close all open connections **/ |
|
1651 /** **/ |
|
1652 /**********************************/ |
|
1653 |
|
1654 int modbus_tcp_silence_init(void) { |
|
1655 int nd; |
|
1656 |
|
1657 #ifdef DEBUG |
|
1658 printf("[%lu] modbus_tcp_silence_init(): called...\n", pthread_self()); |
|
1659 #endif |
|
1660 |
|
1661 /* close all master connections that remain open... */ |
|
1662 for (nd = 0; nd < nd_table_.node_count; nd++) |
|
1663 if (nd_table_.node[nd].node_type == MB_MASTER_NODE) |
|
1664 if (nd_table_.node[nd].close_on_silence > 0) |
|
1665 /* node is is being used for a master device, |
|
1666 * and wishes to be closed... ...so we close it! |
|
1667 */ |
|
1668 close_connection(nd); |
|
1669 |
|
1670 return 0; |
|
1671 } |
|
1672 |
|
1673 |
|
1674 |
|
1675 /******************************/ |
|
1676 /** **/ |
|
1677 /** Shutdown the Library **/ |
|
1678 /** **/ |
|
1679 /******************************/ |
|
1680 |
|
1681 int modbus_tcp_done(void) { |
|
1682 int i; |
|
1683 |
|
1684 modbus_tcp_init_counter--; |
|
1685 if (modbus_tcp_init_counter != 0) return 0; /* ignore this request */ |
|
1686 |
|
1687 /* close all the connections... */ |
|
1688 for (i = 0; i < nd_table_.node_count; i++) |
|
1689 modbus_tcp_close(i); |
|
1690 |
|
1691 /* Free memory... */ |
|
1692 nd_table_done(&nd_table_); |
|
1693 |
|
1694 return 0; |
|
1695 } |
|
1696 |
|
1697 |
|
1698 |
|
1699 |
|
1700 double modbus_tcp_get_min_timeout(int baud, |
|
1701 int parity, |
|
1702 int data_bits, |
|
1703 int stop_bits) { |
|
1704 return 0; |
|
1705 } |