1 // SPDX-License-Identifier: LGPL-2.1-or-later
3 * This file is part of the PCEPlib, a PCEP protocol library.
5 * Copyright (C) 2020 Volta Networks https://voltanet.io/
7 * Author : Brady Johnson <brady@voltanet.io>
13 * Implementation of public API functions.
20 #include <netdb.h> // gethostbyname
23 #include <unistd.h> // close
25 #include <arpa/inet.h> // sockets etc.
26 #include <sys/types.h> // sockets etc.
27 #include <sys/socket.h> // sockets etc.
30 #include "pcep_socket_comm.h"
31 #include "pcep_socket_comm_internals.h"
32 #include "pcep_utils_logging.h"
33 #include "pcep_utils_memory.h"
34 #include "pcep_utils_ordered_list.h"
35 #include "pcep_utils_queue.h"
37 bool initialize_socket_comm_pre(void);
38 bool socket_comm_session_initialize_post(
39 pcep_socket_comm_session
*socket_comm_session
);
41 pcep_socket_comm_handle
*socket_comm_handle_
= NULL
;
44 /* simple compare method callback used by pcep_utils_ordered_list
45 * for ordered list insertion. */
46 int socket_fd_node_compare(void *list_entry
, void *new_entry
)
48 return ((pcep_socket_comm_session
*)new_entry
)->socket_fd
49 - ((pcep_socket_comm_session
*)list_entry
)->socket_fd
;
53 bool initialize_socket_comm_pre(void)
56 pceplib_malloc(PCEPLIB_INFRA
, sizeof(pcep_socket_comm_handle
));
57 memset(socket_comm_handle_
, 0, sizeof(pcep_socket_comm_handle
));
59 socket_comm_handle_
->active
= true;
60 socket_comm_handle_
->num_active_sessions
= 0;
61 socket_comm_handle_
->read_list
=
62 ordered_list_initialize(socket_fd_node_compare
);
63 socket_comm_handle_
->write_list
=
64 ordered_list_initialize(socket_fd_node_compare
);
65 socket_comm_handle_
->session_list
=
66 ordered_list_initialize(pointer_compare_function
);
67 FD_ZERO(&socket_comm_handle_
->except_master_set
);
68 FD_ZERO(&socket_comm_handle_
->read_master_set
);
69 FD_ZERO(&socket_comm_handle_
->write_master_set
);
71 if (pthread_mutex_init(&(socket_comm_handle_
->socket_comm_mutex
), NULL
)
73 pcep_log(LOG_ERR
, "%s: Cannot initialize socket_comm mutex.",
75 pceplib_free(PCEPLIB_INFRA
, socket_comm_handle_
);
76 socket_comm_handle_
= NULL
;
84 bool initialize_socket_comm_external_infra(
85 void *external_infra_data
, ext_socket_read socket_read_cb
,
86 ext_socket_write socket_write_cb
,
87 ext_socket_pthread_create_callback thread_create_func
)
89 if (socket_comm_handle_
!= NULL
) {
90 /* already initialized */
94 if (initialize_socket_comm_pre() == false) {
98 /* Notice: If the thread_create_func is set, then both the
99 * socket_read_cb and the socket_write_cb SHOULD be NULL. */
100 if (thread_create_func
!= NULL
) {
101 if (thread_create_func(
102 &(socket_comm_handle_
->socket_comm_thread
), NULL
,
103 socket_comm_loop
, socket_comm_handle_
,
107 "%s: Cannot initialize external socket_comm thread.",
113 socket_comm_handle_
->external_infra_data
= external_infra_data
;
114 socket_comm_handle_
->socket_write_func
= socket_write_cb
;
115 socket_comm_handle_
->socket_read_func
= socket_read_cb
;
120 bool initialize_socket_comm_loop(void)
122 if (socket_comm_handle_
!= NULL
) {
123 /* already initialized */
127 if (initialize_socket_comm_pre() == false) {
131 /* Launch socket comm loop pthread */
132 if (pthread_create(&(socket_comm_handle_
->socket_comm_thread
), NULL
,
133 socket_comm_loop
, socket_comm_handle_
)) {
134 pcep_log(LOG_ERR
, "%s: Cannot initialize socket_comm thread.",
143 bool destroy_socket_comm_loop(void)
145 socket_comm_handle_
->active
= false;
147 pthread_join(socket_comm_handle_
->socket_comm_thread
, NULL
);
148 ordered_list_destroy(socket_comm_handle_
->read_list
);
149 ordered_list_destroy(socket_comm_handle_
->write_list
);
150 ordered_list_destroy(socket_comm_handle_
->session_list
);
151 pthread_mutex_destroy(&(socket_comm_handle_
->socket_comm_mutex
));
153 pceplib_free(PCEPLIB_INFRA
, socket_comm_handle_
);
154 socket_comm_handle_
= NULL
;
159 /* Internal common init function */
160 static pcep_socket_comm_session
*socket_comm_session_initialize_pre(
161 message_received_handler message_handler
,
162 message_ready_to_read_handler message_ready_handler
,
163 message_sent_notifier msg_sent_notifier
,
164 connection_except_notifier notifier
, uint32_t connect_timeout_millis
,
165 const char *tcp_authentication_str
, bool is_tcp_auth_md5
,
168 /* check that not both message handlers were set */
169 if (message_handler
!= NULL
&& message_ready_handler
!= NULL
) {
172 "%s: Only one of <message_received_handler | message_ready_to_read_handler> can be set.",
177 /* check that at least one message handler was set */
178 if (message_handler
== NULL
&& message_ready_handler
== NULL
) {
181 "%s: At least one of <message_received_handler | message_ready_to_read_handler> must be set.",
186 if (!initialize_socket_comm_loop()) {
187 pcep_log(LOG_WARNING
,
188 "%s: ERROR: cannot initialize socket_comm_loop.",
194 /* initialize everything for a pcep_session socket_comm */
196 pcep_socket_comm_session
*socket_comm_session
=
197 pceplib_malloc(PCEPLIB_INFRA
, sizeof(pcep_socket_comm_session
));
198 memset(socket_comm_session
, 0, sizeof(pcep_socket_comm_session
));
200 socket_comm_handle_
->num_active_sessions
++;
201 socket_comm_session
->close_after_write
= false;
202 socket_comm_session
->session_data
= session_data
;
203 socket_comm_session
->message_handler
= message_handler
;
204 socket_comm_session
->message_ready_to_read_handler
=
205 message_ready_handler
;
206 socket_comm_session
->message_sent_handler
= msg_sent_notifier
;
207 socket_comm_session
->conn_except_notifier
= notifier
;
208 socket_comm_session
->message_queue
= queue_initialize();
209 socket_comm_session
->connect_timeout_millis
= connect_timeout_millis
;
210 socket_comm_session
->external_socket_data
= NULL
;
211 if (tcp_authentication_str
!= NULL
) {
212 socket_comm_session
->is_tcp_auth_md5
= is_tcp_auth_md5
;
213 strlcpy(socket_comm_session
->tcp_authentication_str
,
214 tcp_authentication_str
,
215 sizeof(socket_comm_session
->tcp_authentication_str
));
218 return socket_comm_session
;
221 /* Internal common init function */
222 bool socket_comm_session_initialize_post(
223 pcep_socket_comm_session
*socket_comm_session
)
225 /* If we dont use SO_REUSEADDR, the socket will take 2 TIME_WAIT
226 * periods before being closed in the kernel if bind() was called */
228 if (setsockopt(socket_comm_session
->socket_fd
, SOL_SOCKET
, SO_REUSEADDR
,
229 &reuse_addr
, sizeof(int))
233 "%s: Error in setsockopt() SO_REUSEADDR errno [%d %s].",
234 __func__
, errno
, strerror(errno
));
235 socket_comm_session_teardown(socket_comm_session
);
240 struct sockaddr
*src_sock_addr
=
241 (socket_comm_session
->is_ipv6
242 ? (struct sockaddr
*)&(
243 socket_comm_session
->src_sock_addr
245 : (struct sockaddr
*)&(
246 socket_comm_session
->src_sock_addr
247 .src_sock_addr_ipv4
));
248 int addr_len
= (socket_comm_session
->is_ipv6
249 ? sizeof(socket_comm_session
->src_sock_addr
251 : sizeof(socket_comm_session
->src_sock_addr
252 .src_sock_addr_ipv4
));
253 if (bind(socket_comm_session
->socket_fd
, src_sock_addr
, addr_len
)
255 pcep_log(LOG_WARNING
,
256 "%s: Cannot bind address to socket errno [%d %s].",
257 __func__
, errno
, strerror(errno
));
258 socket_comm_session_teardown(socket_comm_session
);
263 /* Register the session as active with the Socket Comm Loop */
264 pthread_mutex_lock(&(socket_comm_handle_
->socket_comm_mutex
));
265 ordered_list_add_node(socket_comm_handle_
->session_list
,
266 socket_comm_session
);
267 pthread_mutex_unlock(&(socket_comm_handle_
->socket_comm_mutex
));
269 /* dont connect to the destination yet, since the PCE will have a timer
270 * for max time between TCP connect and PCEP open. we'll connect later
271 * when we send the PCEP open. */
277 pcep_socket_comm_session
*socket_comm_session_initialize(
278 message_received_handler message_handler
,
279 message_ready_to_read_handler message_ready_handler
,
280 message_sent_notifier msg_sent_notifier
,
281 connection_except_notifier notifier
, struct in_addr
*dest_ip
,
282 short dest_port
, uint32_t connect_timeout_millis
,
283 const char *tcp_authentication_str
, bool is_tcp_auth_md5
,
286 return socket_comm_session_initialize_with_src(
287 message_handler
, message_ready_handler
, msg_sent_notifier
,
288 notifier
, NULL
, 0, dest_ip
, dest_port
, connect_timeout_millis
,
289 tcp_authentication_str
, is_tcp_auth_md5
, session_data
);
292 pcep_socket_comm_session
*socket_comm_session_initialize_ipv6(
293 message_received_handler message_handler
,
294 message_ready_to_read_handler message_ready_handler
,
295 message_sent_notifier msg_sent_notifier
,
296 connection_except_notifier notifier
, struct in6_addr
*dest_ip
,
297 short dest_port
, uint32_t connect_timeout_millis
,
298 const char *tcp_authentication_str
, bool is_tcp_auth_md5
,
301 return socket_comm_session_initialize_with_src_ipv6(
302 message_handler
, message_ready_handler
, msg_sent_notifier
,
303 notifier
, NULL
, 0, dest_ip
, dest_port
, connect_timeout_millis
,
304 tcp_authentication_str
, is_tcp_auth_md5
, session_data
);
308 pcep_socket_comm_session
*socket_comm_session_initialize_with_src(
309 message_received_handler message_handler
,
310 message_ready_to_read_handler message_ready_handler
,
311 message_sent_notifier msg_sent_notifier
,
312 connection_except_notifier notifier
, struct in_addr
*src_ip
,
313 short src_port
, struct in_addr
*dest_ip
, short dest_port
,
314 uint32_t connect_timeout_millis
, const char *tcp_authentication_str
,
315 bool is_tcp_auth_md5
, void *session_data
)
317 if (dest_ip
== NULL
) {
318 pcep_log(LOG_WARNING
, "%s: dest_ipv4 is NULL", __func__
);
322 pcep_socket_comm_session
*socket_comm_session
=
323 socket_comm_session_initialize_pre(
324 message_handler
, message_ready_handler
,
325 msg_sent_notifier
, notifier
, connect_timeout_millis
,
326 tcp_authentication_str
, is_tcp_auth_md5
, session_data
);
327 if (socket_comm_session
== NULL
) {
331 socket_comm_session
->socket_fd
=
332 socket(PF_INET
, SOCK_STREAM
, IPPROTO_TCP
);
333 if (socket_comm_session
->socket_fd
== -1) {
334 pcep_log(LOG_WARNING
,
335 "%s: Cannot create ipv4 socket errno [%d %s].",
336 __func__
, errno
, strerror(errno
));
337 socket_comm_session_teardown(
338 socket_comm_session
); // socket_comm_session freed
339 // inside fn so NOLINT next.
341 return NULL
; // NOLINT(clang-analyzer-unix.Malloc)
344 socket_comm_session
->is_ipv6
= false;
345 socket_comm_session
->dest_sock_addr
.dest_sock_addr_ipv4
.sin_family
=
347 socket_comm_session
->src_sock_addr
.src_sock_addr_ipv4
.sin_family
=
349 socket_comm_session
->dest_sock_addr
.dest_sock_addr_ipv4
.sin_port
=
351 socket_comm_session
->src_sock_addr
.src_sock_addr_ipv4
.sin_port
=
353 socket_comm_session
->dest_sock_addr
.dest_sock_addr_ipv4
.sin_addr
354 .s_addr
= dest_ip
->s_addr
;
355 if (src_ip
!= NULL
) {
356 socket_comm_session
->src_sock_addr
.src_sock_addr_ipv4
.sin_addr
357 .s_addr
= src_ip
->s_addr
;
359 socket_comm_session
->src_sock_addr
.src_sock_addr_ipv4
.sin_addr
360 .s_addr
= INADDR_ANY
;
363 if (socket_comm_session_initialize_post(socket_comm_session
) == false) {
367 return socket_comm_session
;
370 pcep_socket_comm_session
*socket_comm_session_initialize_with_src_ipv6(
371 message_received_handler message_handler
,
372 message_ready_to_read_handler message_ready_handler
,
373 message_sent_notifier msg_sent_notifier
,
374 connection_except_notifier notifier
, struct in6_addr
*src_ip
,
375 short src_port
, struct in6_addr
*dest_ip
, short dest_port
,
376 uint32_t connect_timeout_millis
, const char *tcp_authentication_str
,
377 bool is_tcp_auth_md5
, void *session_data
)
379 if (dest_ip
== NULL
) {
380 pcep_log(LOG_WARNING
, "%s: dest_ipv6 is NULL", __func__
);
384 pcep_socket_comm_session
*socket_comm_session
=
385 socket_comm_session_initialize_pre(
386 message_handler
, message_ready_handler
,
387 msg_sent_notifier
, notifier
, connect_timeout_millis
,
388 tcp_authentication_str
, is_tcp_auth_md5
, session_data
);
389 if (socket_comm_session
== NULL
) {
393 socket_comm_session
->socket_fd
=
394 socket(PF_INET6
, SOCK_STREAM
, IPPROTO_TCP
);
395 if (socket_comm_session
->socket_fd
== -1) {
396 pcep_log(LOG_WARNING
,
397 "%s: Cannot create ipv6 socket errno [%d %s].",
398 __func__
, errno
, strerror(errno
));
399 socket_comm_session_teardown(
400 socket_comm_session
); // socket_comm_session freed
401 // inside fn so NOLINT next.
403 return NULL
; // NOLINT(clang-analyzer-unix.Malloc)
406 socket_comm_session
->is_ipv6
= true;
407 socket_comm_session
->dest_sock_addr
.dest_sock_addr_ipv6
.sin6_family
=
409 socket_comm_session
->src_sock_addr
.src_sock_addr_ipv6
.sin6_family
=
411 socket_comm_session
->dest_sock_addr
.dest_sock_addr_ipv6
.sin6_port
=
413 socket_comm_session
->src_sock_addr
.src_sock_addr_ipv6
.sin6_port
=
415 memcpy(&socket_comm_session
->dest_sock_addr
.dest_sock_addr_ipv6
417 dest_ip
, sizeof(struct in6_addr
));
418 if (src_ip
!= NULL
) {
419 memcpy(&socket_comm_session
->src_sock_addr
.src_sock_addr_ipv6
421 src_ip
, sizeof(struct in6_addr
));
423 socket_comm_session
->src_sock_addr
.src_sock_addr_ipv6
424 .sin6_addr
= in6addr_any
;
427 if (socket_comm_session_initialize_post(socket_comm_session
) == false) {
431 return socket_comm_session
;
435 bool socket_comm_session_connect_tcp(
436 pcep_socket_comm_session
*socket_comm_session
)
438 if (socket_comm_session
== NULL
) {
441 "%s: socket_comm_session_connect_tcp NULL socket_comm_session.",
446 /* Set the socket to non-blocking, so connect() does not block */
448 if ((fcntl_arg
= fcntl(socket_comm_session
->socket_fd
, F_GETFL
, NULL
))
450 pcep_log(LOG_WARNING
, "%s: Error fcntl(..., F_GETFL) [%d %s]",
451 __func__
, errno
, strerror(errno
));
455 fcntl_arg
|= O_NONBLOCK
;
456 if (fcntl(socket_comm_session
->socket_fd
, F_SETFL
, fcntl_arg
) < 0) {
457 pcep_log(LOG_WARNING
, "%s: Error fcntl(..., F_SETFL) [%d %s]",
458 __func__
, errno
, strerror(errno
));
462 #if HAVE_DECL_TCP_MD5SIG
463 /* TCP authentication, currently only TCP MD5 RFC2385 is supported */
464 if (socket_comm_session
->tcp_authentication_str
[0] != '\0') {
465 #if defined(linux) || defined(GNU_LINUX)
466 struct tcp_md5sig sig
;
467 memset(&sig
, 0, sizeof(sig
));
468 if (socket_comm_session
->is_ipv6
) {
469 memcpy(&sig
.tcpm_addr
,
470 &socket_comm_session
->dest_sock_addr
471 .dest_sock_addr_ipv6
,
472 sizeof(struct sockaddr_in6
));
474 memcpy(&sig
.tcpm_addr
,
475 &socket_comm_session
->dest_sock_addr
476 .dest_sock_addr_ipv4
,
477 sizeof(struct sockaddr_in
));
480 strlen(socket_comm_session
->tcp_authentication_str
);
482 socket_comm_session
->tcp_authentication_str
,
487 if (setsockopt(socket_comm_session
->socket_fd
, IPPROTO_TCP
,
488 TCP_MD5SIG
, &sig
, sizeof(sig
))
490 pcep_log(LOG_ERR
, "%s: Failed to setsockopt(): [%d %s]",
491 __func__
, errno
, strerror(errno
));
497 int connect_result
= 0;
498 if (socket_comm_session
->is_ipv6
) {
499 connect_result
= connect(
500 socket_comm_session
->socket_fd
,
501 (struct sockaddr
*)&(socket_comm_session
->dest_sock_addr
502 .dest_sock_addr_ipv6
),
503 sizeof(socket_comm_session
->dest_sock_addr
504 .dest_sock_addr_ipv6
));
506 connect_result
= connect(
507 socket_comm_session
->socket_fd
,
508 (struct sockaddr
*)&(socket_comm_session
->dest_sock_addr
509 .dest_sock_addr_ipv4
),
510 sizeof(socket_comm_session
->dest_sock_addr
511 .dest_sock_addr_ipv4
));
514 if (connect_result
< 0) {
515 if (errno
== EINPROGRESS
) {
516 /* Calculate the configured timeout in seconds and
519 if (socket_comm_session
->connect_timeout_millis
521 tv
.tv_sec
= socket_comm_session
522 ->connect_timeout_millis
524 tv
.tv_usec
= (socket_comm_session
525 ->connect_timeout_millis
526 - (tv
.tv_sec
* 1000))
530 tv
.tv_usec
= socket_comm_session
531 ->connect_timeout_millis
535 /* Use select to wait a max timeout for connect
536 * https://stackoverflow.com/questions/2597608/c-socket-connection-timeout
540 FD_SET(socket_comm_session
->socket_fd
, &fdset
);
541 if (select(socket_comm_session
->socket_fd
+ 1, NULL
,
545 socklen_t len
= sizeof(so_error
);
546 getsockopt(socket_comm_session
->socket_fd
,
547 SOL_SOCKET
, SO_ERROR
, &so_error
,
552 "%s: TCP connect failed on socket_fd [%d].",
554 socket_comm_session
->socket_fd
);
560 "%s: TCP connect timed-out on socket_fd [%d].",
562 socket_comm_session
->socket_fd
);
568 "%s: TCP connect, error connecting on socket_fd [%d] errno [%d %s]",
569 __func__
, socket_comm_session
->socket_fd
, errno
,
575 pthread_mutex_lock(&(socket_comm_handle_
->socket_comm_mutex
));
576 /* once the TCP connection is open, we should be ready to read at any
578 ordered_list_add_node(socket_comm_handle_
->read_list
,
579 socket_comm_session
);
581 if (socket_comm_handle_
->socket_read_func
!= NULL
) {
582 socket_comm_handle_
->socket_read_func(
583 socket_comm_handle_
->external_infra_data
,
584 &socket_comm_session
->external_socket_data
,
585 socket_comm_session
->socket_fd
, socket_comm_handle_
);
587 pthread_mutex_unlock(&(socket_comm_handle_
->socket_comm_mutex
));
593 bool socket_comm_session_close_tcp(
594 pcep_socket_comm_session
*socket_comm_session
)
596 if (socket_comm_session
== NULL
) {
599 "%s: socket_comm_session_close_tcp NULL socket_comm_session.",
605 "%s: socket_comm_session_close_tcp close() socket fd [%d]",
606 __func__
, socket_comm_session
->socket_fd
);
608 pthread_mutex_lock(&(socket_comm_handle_
->socket_comm_mutex
));
609 ordered_list_remove_first_node_equals(socket_comm_handle_
->read_list
,
610 socket_comm_session
);
611 ordered_list_remove_first_node_equals(socket_comm_handle_
->write_list
,
612 socket_comm_session
);
613 // TODO should it be close() or shutdown()??
614 close(socket_comm_session
->socket_fd
);
615 socket_comm_session
->socket_fd
= -1;
616 pthread_mutex_unlock(&(socket_comm_handle_
->socket_comm_mutex
));
622 bool socket_comm_session_close_tcp_after_write(
623 pcep_socket_comm_session
*socket_comm_session
)
625 if (socket_comm_session
== NULL
) {
628 "%s: socket_comm_session_close_tcp_after_write NULL socket_comm_session.",
633 pthread_mutex_lock(&(socket_comm_handle_
->socket_comm_mutex
));
634 socket_comm_session
->close_after_write
= true;
635 pthread_mutex_unlock(&(socket_comm_handle_
->socket_comm_mutex
));
641 bool socket_comm_session_teardown(pcep_socket_comm_session
*socket_comm_session
)
643 if (socket_comm_handle_
== NULL
) {
644 pcep_log(LOG_WARNING
,
645 "%s: Cannot teardown NULL socket_comm_handle",
650 if (socket_comm_session
== NULL
) {
651 pcep_log(LOG_WARNING
, "%s: Cannot teardown NULL session",
656 if (comm_session_exists_locking(socket_comm_handle_
,
659 pcep_log(LOG_WARNING
,
660 "%s: Cannot teardown session that does not exist",
665 if (socket_comm_session
->socket_fd
>= 0) {
666 shutdown(socket_comm_session
->socket_fd
, SHUT_RDWR
);
667 close(socket_comm_session
->socket_fd
);
670 pthread_mutex_lock(&(socket_comm_handle_
->socket_comm_mutex
));
671 queue_destroy(socket_comm_session
->message_queue
);
672 ordered_list_remove_first_node_equals(socket_comm_handle_
->session_list
,
673 socket_comm_session
);
674 ordered_list_remove_first_node_equals(socket_comm_handle_
->read_list
,
675 socket_comm_session
);
676 ordered_list_remove_first_node_equals(socket_comm_handle_
->write_list
,
677 socket_comm_session
);
678 socket_comm_handle_
->num_active_sessions
--;
679 pthread_mutex_unlock(&(socket_comm_handle_
->socket_comm_mutex
));
683 "%s: [%ld-%ld] socket_comm_session fd [%d] destroyed, [%d] sessions remaining",
684 __func__
, time(NULL
), pthread_self(),
685 socket_comm_session
->socket_fd
,
686 socket_comm_handle_
->num_active_sessions
);
688 pceplib_free(PCEPLIB_INFRA
, socket_comm_session
);
690 /* It would be nice to call destroy_socket_comm_loop() here if
691 * socket_comm_handle_->num_active_sessions == 0, but this function
692 * will usually be called from the message_sent_notifier callback,
693 * which gets called in the middle of the socket_comm_loop, and that
694 * is dangerous, so destroy_socket_comm_loop() must be called upon
695 * application exit. */
701 void socket_comm_session_send_message(
702 pcep_socket_comm_session
*socket_comm_session
,
703 const char *encoded_message
, unsigned int msg_length
,
704 bool free_after_send
)
706 if (socket_comm_session
== NULL
) {
709 "%s: socket_comm_session_send_message NULL socket_comm_session.",
714 pcep_socket_comm_queued_message
*queued_message
= pceplib_malloc(
715 PCEPLIB_MESSAGES
, sizeof(pcep_socket_comm_queued_message
));
716 queued_message
->encoded_message
= encoded_message
;
717 queued_message
->msg_length
= msg_length
;
718 queued_message
->free_after_send
= free_after_send
;
720 pthread_mutex_lock(&(socket_comm_handle_
->socket_comm_mutex
));
722 /* Do not proceed if the socket_comm_session has been deleted */
723 if (ordered_list_find(socket_comm_handle_
->session_list
,
726 /* Should never get here, only if the session was deleted and
727 * someone still tries to write on it */
730 "%s: Cannot write a message on a deleted socket comm session, discarding message",
732 pthread_mutex_unlock(&(socket_comm_handle_
->socket_comm_mutex
));
733 pceplib_free(PCEPLIB_MESSAGES
, queued_message
);
738 /* Do not proceed if the socket has been closed */
739 if (socket_comm_session
->socket_fd
< 0) {
740 /* Should never get here, only if the session was deleted and
741 * someone still tries to write on it */
744 "%s: Cannot write a message on a closed socket, discarding message",
746 pthread_mutex_unlock(&(socket_comm_handle_
->socket_comm_mutex
));
747 pceplib_free(PCEPLIB_MESSAGES
, queued_message
);
752 queue_enqueue(socket_comm_session
->message_queue
, queued_message
);
754 /* Add it to the write list only if its not already there */
755 if (ordered_list_find(socket_comm_handle_
->write_list
,
758 ordered_list_add_node(socket_comm_handle_
->write_list
,
759 socket_comm_session
);
762 if (socket_comm_handle_
->socket_write_func
!= NULL
) {
763 socket_comm_handle_
->socket_write_func(
764 socket_comm_handle_
->external_infra_data
,
765 &socket_comm_session
->external_socket_data
,
766 socket_comm_session
->socket_fd
, socket_comm_handle_
);
768 pthread_mutex_unlock(&(socket_comm_handle_
->socket_comm_mutex
));