2 * This file is part of the PCEPlib, a PCEP protocol library.
4 * Copyright (C) 2020 Volta Networks https://voltanet.io/
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 * Author : Brady Johnson <brady@voltanet.io>
25 * Implementation of public API functions.
32 #include <netdb.h> // gethostbyname
35 #include <unistd.h> // close
37 #include <arpa/inet.h> // sockets etc.
38 #include <sys/types.h> // sockets etc.
39 #include <sys/socket.h> // sockets etc.
42 #include "pcep_socket_comm.h"
43 #include "pcep_socket_comm_internals.h"
44 #include "pcep_utils_logging.h"
45 #include "pcep_utils_memory.h"
46 #include "pcep_utils_ordered_list.h"
47 #include "pcep_utils_queue.h"
49 bool initialize_socket_comm_pre(void);
50 bool socket_comm_session_initialize_post(
51 pcep_socket_comm_session
*socket_comm_session
);
53 pcep_socket_comm_handle
*socket_comm_handle_
= NULL
;
56 /* simple compare method callback used by pcep_utils_ordered_list
57 * for ordered list insertion. */
58 int socket_fd_node_compare(void *list_entry
, void *new_entry
)
60 return ((pcep_socket_comm_session
*)new_entry
)->socket_fd
61 - ((pcep_socket_comm_session
*)list_entry
)->socket_fd
;
65 bool initialize_socket_comm_pre()
68 pceplib_malloc(PCEPLIB_INFRA
, sizeof(pcep_socket_comm_handle
));
69 memset(socket_comm_handle_
, 0, sizeof(pcep_socket_comm_handle
));
71 socket_comm_handle_
->active
= true;
72 socket_comm_handle_
->num_active_sessions
= 0;
73 socket_comm_handle_
->read_list
=
74 ordered_list_initialize(socket_fd_node_compare
);
75 socket_comm_handle_
->write_list
=
76 ordered_list_initialize(socket_fd_node_compare
);
77 socket_comm_handle_
->session_list
=
78 ordered_list_initialize(pointer_compare_function
);
79 FD_ZERO(&socket_comm_handle_
->except_master_set
);
80 FD_ZERO(&socket_comm_handle_
->read_master_set
);
81 FD_ZERO(&socket_comm_handle_
->write_master_set
);
83 if (pthread_mutex_init(&(socket_comm_handle_
->socket_comm_mutex
), NULL
)
85 pcep_log(LOG_ERR
, "%s: Cannot initialize socket_comm mutex.",
87 pceplib_free(PCEPLIB_INFRA
, socket_comm_handle_
);
88 socket_comm_handle_
= NULL
;
96 bool initialize_socket_comm_external_infra(
97 void *external_infra_data
, ext_socket_read socket_read_cb
,
98 ext_socket_write socket_write_cb
,
99 ext_socket_pthread_create_callback thread_create_func
)
101 if (socket_comm_handle_
!= NULL
) {
102 /* already initialized */
106 if (initialize_socket_comm_pre() == false) {
110 /* Notice: If the thread_create_func is set, then both the
111 * socket_read_cb and the socket_write_cb SHOULD be NULL. */
112 if (thread_create_func
!= NULL
) {
113 if (thread_create_func(
114 &(socket_comm_handle_
->socket_comm_thread
), NULL
,
115 socket_comm_loop
, socket_comm_handle_
,
119 "%s: Cannot initialize external socket_comm thread.",
125 socket_comm_handle_
->external_infra_data
= external_infra_data
;
126 socket_comm_handle_
->socket_write_func
= socket_write_cb
;
127 socket_comm_handle_
->socket_read_func
= socket_read_cb
;
132 bool initialize_socket_comm_loop()
134 if (socket_comm_handle_
!= NULL
) {
135 /* already initialized */
139 if (initialize_socket_comm_pre() == false) {
143 /* Launch socket comm loop pthread */
144 if (pthread_create(&(socket_comm_handle_
->socket_comm_thread
), NULL
,
145 socket_comm_loop
, socket_comm_handle_
)) {
146 pcep_log(LOG_ERR
, "%s: Cannot initialize socket_comm thread.",
155 bool destroy_socket_comm_loop()
157 socket_comm_handle_
->active
= false;
159 pthread_join(socket_comm_handle_
->socket_comm_thread
, NULL
);
160 ordered_list_destroy(socket_comm_handle_
->read_list
);
161 ordered_list_destroy(socket_comm_handle_
->write_list
);
162 ordered_list_destroy(socket_comm_handle_
->session_list
);
163 pthread_mutex_destroy(&(socket_comm_handle_
->socket_comm_mutex
));
165 pceplib_free(PCEPLIB_INFRA
, socket_comm_handle_
);
166 socket_comm_handle_
= NULL
;
171 /* Internal common init function */
172 static pcep_socket_comm_session
*socket_comm_session_initialize_pre(
173 message_received_handler message_handler
,
174 message_ready_to_read_handler message_ready_handler
,
175 message_sent_notifier msg_sent_notifier
,
176 connection_except_notifier notifier
, uint32_t connect_timeout_millis
,
177 const char *tcp_authentication_str
, bool is_tcp_auth_md5
,
180 /* check that not both message handlers were set */
181 if (message_handler
!= NULL
&& message_ready_handler
!= NULL
) {
184 "%s: Only one of <message_received_handler | message_ready_to_read_handler> can be set.",
189 /* check that at least one message handler was set */
190 if (message_handler
== NULL
&& message_ready_handler
== NULL
) {
193 "%s: At least one of <message_received_handler | message_ready_to_read_handler> must be set.",
198 if (!initialize_socket_comm_loop()) {
199 pcep_log(LOG_WARNING
,
200 "%s: ERROR: cannot initialize socket_comm_loop.",
206 /* initialize everything for a pcep_session socket_comm */
208 pcep_socket_comm_session
*socket_comm_session
=
209 pceplib_malloc(PCEPLIB_INFRA
, sizeof(pcep_socket_comm_session
));
210 memset(socket_comm_session
, 0, sizeof(pcep_socket_comm_session
));
212 socket_comm_handle_
->num_active_sessions
++;
213 socket_comm_session
->close_after_write
= false;
214 socket_comm_session
->session_data
= session_data
;
215 socket_comm_session
->message_handler
= message_handler
;
216 socket_comm_session
->message_ready_to_read_handler
=
217 message_ready_handler
;
218 socket_comm_session
->message_sent_handler
= msg_sent_notifier
;
219 socket_comm_session
->conn_except_notifier
= notifier
;
220 socket_comm_session
->message_queue
= queue_initialize();
221 socket_comm_session
->connect_timeout_millis
= connect_timeout_millis
;
222 socket_comm_session
->external_socket_data
= NULL
;
223 if (tcp_authentication_str
!= NULL
) {
224 socket_comm_session
->is_tcp_auth_md5
= is_tcp_auth_md5
;
225 strlcpy(socket_comm_session
->tcp_authentication_str
,
226 tcp_authentication_str
,
227 sizeof(socket_comm_session
->tcp_authentication_str
));
230 return socket_comm_session
;
233 /* Internal common init function */
234 bool socket_comm_session_initialize_post(
235 pcep_socket_comm_session
*socket_comm_session
)
237 /* If we dont use SO_REUSEADDR, the socket will take 2 TIME_WAIT
238 * periods before being closed in the kernel if bind() was called */
240 if (setsockopt(socket_comm_session
->socket_fd
, SOL_SOCKET
, SO_REUSEADDR
,
241 &reuse_addr
, sizeof(int))
245 "%s: Error in setsockopt() SO_REUSEADDR errno [%d %s].",
246 __func__
, errno
, strerror(errno
));
247 socket_comm_session_teardown(socket_comm_session
);
252 struct sockaddr
*src_sock_addr
=
253 (socket_comm_session
->is_ipv6
254 ? (struct sockaddr
*)&(
255 socket_comm_session
->src_sock_addr
257 : (struct sockaddr
*)&(
258 socket_comm_session
->src_sock_addr
259 .src_sock_addr_ipv4
));
260 int addr_len
= (socket_comm_session
->is_ipv6
261 ? sizeof(socket_comm_session
->src_sock_addr
263 : sizeof(socket_comm_session
->src_sock_addr
264 .src_sock_addr_ipv4
));
265 if (bind(socket_comm_session
->socket_fd
, src_sock_addr
, addr_len
)
267 pcep_log(LOG_WARNING
,
268 "%s: Cannot bind address to socket errno [%d %s].",
269 __func__
, errno
, strerror(errno
));
270 socket_comm_session_teardown(socket_comm_session
);
275 /* Register the session as active with the Socket Comm Loop */
276 pthread_mutex_lock(&(socket_comm_handle_
->socket_comm_mutex
));
277 ordered_list_add_node(socket_comm_handle_
->session_list
,
278 socket_comm_session
);
279 pthread_mutex_unlock(&(socket_comm_handle_
->socket_comm_mutex
));
281 /* dont connect to the destination yet, since the PCE will have a timer
282 * for max time between TCP connect and PCEP open. we'll connect later
283 * when we send the PCEP open. */
289 pcep_socket_comm_session
*socket_comm_session_initialize(
290 message_received_handler message_handler
,
291 message_ready_to_read_handler message_ready_handler
,
292 message_sent_notifier msg_sent_notifier
,
293 connection_except_notifier notifier
, struct in_addr
*dest_ip
,
294 short dest_port
, uint32_t connect_timeout_millis
,
295 const char *tcp_authentication_str
, bool is_tcp_auth_md5
,
298 return socket_comm_session_initialize_with_src(
299 message_handler
, message_ready_handler
, msg_sent_notifier
,
300 notifier
, NULL
, 0, dest_ip
, dest_port
, connect_timeout_millis
,
301 tcp_authentication_str
, is_tcp_auth_md5
, session_data
);
304 pcep_socket_comm_session
*socket_comm_session_initialize_ipv6(
305 message_received_handler message_handler
,
306 message_ready_to_read_handler message_ready_handler
,
307 message_sent_notifier msg_sent_notifier
,
308 connection_except_notifier notifier
, struct in6_addr
*dest_ip
,
309 short dest_port
, uint32_t connect_timeout_millis
,
310 const char *tcp_authentication_str
, bool is_tcp_auth_md5
,
313 return socket_comm_session_initialize_with_src_ipv6(
314 message_handler
, message_ready_handler
, msg_sent_notifier
,
315 notifier
, NULL
, 0, dest_ip
, dest_port
, connect_timeout_millis
,
316 tcp_authentication_str
, is_tcp_auth_md5
, session_data
);
320 pcep_socket_comm_session
*socket_comm_session_initialize_with_src(
321 message_received_handler message_handler
,
322 message_ready_to_read_handler message_ready_handler
,
323 message_sent_notifier msg_sent_notifier
,
324 connection_except_notifier notifier
, struct in_addr
*src_ip
,
325 short src_port
, struct in_addr
*dest_ip
, short dest_port
,
326 uint32_t connect_timeout_millis
, const char *tcp_authentication_str
,
327 bool is_tcp_auth_md5
, void *session_data
)
329 if (dest_ip
== NULL
) {
330 pcep_log(LOG_WARNING
, "%s: dest_ipv4 is NULL", __func__
);
334 pcep_socket_comm_session
*socket_comm_session
=
335 socket_comm_session_initialize_pre(
336 message_handler
, message_ready_handler
,
337 msg_sent_notifier
, notifier
, connect_timeout_millis
,
338 tcp_authentication_str
, is_tcp_auth_md5
, session_data
);
339 if (socket_comm_session
== NULL
) {
343 socket_comm_session
->socket_fd
=
344 socket(PF_INET
, SOCK_STREAM
, IPPROTO_TCP
);
345 if (socket_comm_session
->socket_fd
== -1) {
346 pcep_log(LOG_WARNING
,
347 "%s: Cannot create ipv4 socket errno [%d %s].",
348 __func__
, errno
, strerror(errno
));
349 socket_comm_session_teardown(
350 socket_comm_session
); // socket_comm_session freed
351 // inside fn so NOLINT next.
353 return NULL
; // NOLINT(clang-analyzer-unix.Malloc)
356 socket_comm_session
->is_ipv6
= false;
357 socket_comm_session
->dest_sock_addr
.dest_sock_addr_ipv4
.sin_family
=
359 socket_comm_session
->src_sock_addr
.src_sock_addr_ipv4
.sin_family
=
361 socket_comm_session
->dest_sock_addr
.dest_sock_addr_ipv4
.sin_port
=
363 socket_comm_session
->src_sock_addr
.src_sock_addr_ipv4
.sin_port
=
365 socket_comm_session
->dest_sock_addr
.dest_sock_addr_ipv4
.sin_addr
366 .s_addr
= dest_ip
->s_addr
;
367 if (src_ip
!= NULL
) {
368 socket_comm_session
->src_sock_addr
.src_sock_addr_ipv4
.sin_addr
369 .s_addr
= src_ip
->s_addr
;
371 socket_comm_session
->src_sock_addr
.src_sock_addr_ipv4
.sin_addr
372 .s_addr
= INADDR_ANY
;
375 if (socket_comm_session_initialize_post(socket_comm_session
) == false) {
379 return socket_comm_session
;
382 pcep_socket_comm_session
*socket_comm_session_initialize_with_src_ipv6(
383 message_received_handler message_handler
,
384 message_ready_to_read_handler message_ready_handler
,
385 message_sent_notifier msg_sent_notifier
,
386 connection_except_notifier notifier
, struct in6_addr
*src_ip
,
387 short src_port
, struct in6_addr
*dest_ip
, short dest_port
,
388 uint32_t connect_timeout_millis
, const char *tcp_authentication_str
,
389 bool is_tcp_auth_md5
, void *session_data
)
391 if (dest_ip
== NULL
) {
392 pcep_log(LOG_WARNING
, "%s: dest_ipv6 is NULL", __func__
);
396 pcep_socket_comm_session
*socket_comm_session
=
397 socket_comm_session_initialize_pre(
398 message_handler
, message_ready_handler
,
399 msg_sent_notifier
, notifier
, connect_timeout_millis
,
400 tcp_authentication_str
, is_tcp_auth_md5
, session_data
);
401 if (socket_comm_session
== NULL
) {
405 socket_comm_session
->socket_fd
=
406 socket(PF_INET6
, SOCK_STREAM
, IPPROTO_TCP
);
407 if (socket_comm_session
->socket_fd
== -1) {
408 pcep_log(LOG_WARNING
,
409 "%s: Cannot create ipv6 socket errno [%d %s].",
410 __func__
, errno
, strerror(errno
));
411 socket_comm_session_teardown(
412 socket_comm_session
); // socket_comm_session freed
413 // inside fn so NOLINT next.
415 return NULL
; // NOLINT(clang-analyzer-unix.Malloc)
418 socket_comm_session
->is_ipv6
= true;
419 socket_comm_session
->dest_sock_addr
.dest_sock_addr_ipv6
.sin6_family
=
421 socket_comm_session
->src_sock_addr
.src_sock_addr_ipv6
.sin6_family
=
423 socket_comm_session
->dest_sock_addr
.dest_sock_addr_ipv6
.sin6_port
=
425 socket_comm_session
->src_sock_addr
.src_sock_addr_ipv6
.sin6_port
=
427 memcpy(&socket_comm_session
->dest_sock_addr
.dest_sock_addr_ipv6
429 dest_ip
, sizeof(struct in6_addr
));
430 if (src_ip
!= NULL
) {
431 memcpy(&socket_comm_session
->src_sock_addr
.src_sock_addr_ipv6
433 src_ip
, sizeof(struct in6_addr
));
435 socket_comm_session
->src_sock_addr
.src_sock_addr_ipv6
436 .sin6_addr
= in6addr_any
;
439 if (socket_comm_session_initialize_post(socket_comm_session
) == false) {
443 return socket_comm_session
;
447 bool socket_comm_session_connect_tcp(
448 pcep_socket_comm_session
*socket_comm_session
)
450 if (socket_comm_session
== NULL
) {
453 "%s: socket_comm_session_connect_tcp NULL socket_comm_session.",
458 /* Set the socket to non-blocking, so connect() does not block */
460 if ((fcntl_arg
= fcntl(socket_comm_session
->socket_fd
, F_GETFL
, NULL
))
462 pcep_log(LOG_WARNING
, "%s: Error fcntl(..., F_GETFL) [%d %s]",
463 __func__
, errno
, strerror(errno
));
467 fcntl_arg
|= O_NONBLOCK
;
468 if (fcntl(socket_comm_session
->socket_fd
, F_SETFL
, fcntl_arg
) < 0) {
469 pcep_log(LOG_WARNING
, "%s: Error fcntl(..., F_SETFL) [%d %s]",
470 __func__
, errno
, strerror(errno
));
474 #if HAVE_DECL_TCP_MD5SIG
475 /* TCP authentication, currently only TCP MD5 RFC2385 is supported */
476 if (socket_comm_session
->tcp_authentication_str
[0] != '\0') {
477 #if defined(linux) || defined(GNU_LINUX)
478 struct tcp_md5sig sig
;
479 memset(&sig
, 0, sizeof(sig
));
480 if (socket_comm_session
->is_ipv6
) {
481 memcpy(&sig
.tcpm_addr
,
482 &socket_comm_session
->dest_sock_addr
483 .dest_sock_addr_ipv6
,
484 sizeof(struct sockaddr_in6
));
486 memcpy(&sig
.tcpm_addr
,
487 &socket_comm_session
->dest_sock_addr
488 .dest_sock_addr_ipv4
,
489 sizeof(struct sockaddr_in
));
492 strlen(socket_comm_session
->tcp_authentication_str
);
494 socket_comm_session
->tcp_authentication_str
,
499 if (setsockopt(socket_comm_session
->socket_fd
, IPPROTO_TCP
,
500 TCP_MD5SIG
, &sig
, sizeof(sig
))
502 pcep_log(LOG_ERR
, "%s: Failed to setsockopt(): [%d %s]",
503 __func__
, errno
, strerror(errno
));
509 int connect_result
= 0;
510 if (socket_comm_session
->is_ipv6
) {
511 connect_result
= connect(
512 socket_comm_session
->socket_fd
,
513 (struct sockaddr
*)&(socket_comm_session
->dest_sock_addr
514 .dest_sock_addr_ipv6
),
515 sizeof(socket_comm_session
->dest_sock_addr
516 .dest_sock_addr_ipv6
));
518 connect_result
= connect(
519 socket_comm_session
->socket_fd
,
520 (struct sockaddr
*)&(socket_comm_session
->dest_sock_addr
521 .dest_sock_addr_ipv4
),
522 sizeof(socket_comm_session
->dest_sock_addr
523 .dest_sock_addr_ipv4
));
526 if (connect_result
< 0) {
527 if (errno
== EINPROGRESS
) {
528 /* Calculate the configured timeout in seconds and
531 if (socket_comm_session
->connect_timeout_millis
533 tv
.tv_sec
= socket_comm_session
534 ->connect_timeout_millis
536 tv
.tv_usec
= (socket_comm_session
537 ->connect_timeout_millis
538 - (tv
.tv_sec
* 1000))
542 tv
.tv_usec
= socket_comm_session
543 ->connect_timeout_millis
547 /* Use select to wait a max timeout for connect
548 * https://stackoverflow.com/questions/2597608/c-socket-connection-timeout
552 FD_SET(socket_comm_session
->socket_fd
, &fdset
);
553 if (select(socket_comm_session
->socket_fd
+ 1, NULL
,
557 socklen_t len
= sizeof(so_error
);
558 getsockopt(socket_comm_session
->socket_fd
,
559 SOL_SOCKET
, SO_ERROR
, &so_error
,
564 "%s: TCP connect failed on socket_fd [%d].",
566 socket_comm_session
->socket_fd
);
572 "%s: TCP connect timed-out on socket_fd [%d].",
574 socket_comm_session
->socket_fd
);
580 "%s: TCP connect, error connecting on socket_fd [%d] errno [%d %s]",
581 __func__
, socket_comm_session
->socket_fd
, errno
,
587 pthread_mutex_lock(&(socket_comm_handle_
->socket_comm_mutex
));
588 /* once the TCP connection is open, we should be ready to read at any
590 ordered_list_add_node(socket_comm_handle_
->read_list
,
591 socket_comm_session
);
593 if (socket_comm_handle_
->socket_read_func
!= NULL
) {
594 socket_comm_handle_
->socket_read_func(
595 socket_comm_handle_
->external_infra_data
,
596 &socket_comm_session
->external_socket_data
,
597 socket_comm_session
->socket_fd
, socket_comm_handle_
);
599 pthread_mutex_unlock(&(socket_comm_handle_
->socket_comm_mutex
));
605 bool socket_comm_session_close_tcp(
606 pcep_socket_comm_session
*socket_comm_session
)
608 if (socket_comm_session
== NULL
) {
611 "%s: socket_comm_session_close_tcp NULL socket_comm_session.",
617 "%s: socket_comm_session_close_tcp close() socket fd [%d]",
618 __func__
, socket_comm_session
->socket_fd
);
620 pthread_mutex_lock(&(socket_comm_handle_
->socket_comm_mutex
));
621 ordered_list_remove_first_node_equals(socket_comm_handle_
->read_list
,
622 socket_comm_session
);
623 ordered_list_remove_first_node_equals(socket_comm_handle_
->write_list
,
624 socket_comm_session
);
625 // TODO should it be close() or shutdown()??
626 close(socket_comm_session
->socket_fd
);
627 socket_comm_session
->socket_fd
= -1;
628 pthread_mutex_unlock(&(socket_comm_handle_
->socket_comm_mutex
));
634 bool socket_comm_session_close_tcp_after_write(
635 pcep_socket_comm_session
*socket_comm_session
)
637 if (socket_comm_session
== NULL
) {
640 "%s: socket_comm_session_close_tcp_after_write NULL socket_comm_session.",
645 pthread_mutex_lock(&(socket_comm_handle_
->socket_comm_mutex
));
646 socket_comm_session
->close_after_write
= true;
647 pthread_mutex_unlock(&(socket_comm_handle_
->socket_comm_mutex
));
653 bool socket_comm_session_teardown(pcep_socket_comm_session
*socket_comm_session
)
655 if (socket_comm_handle_
== NULL
) {
656 pcep_log(LOG_WARNING
,
657 "%s: Cannot teardown NULL socket_comm_handle",
662 if (socket_comm_session
== NULL
) {
663 pcep_log(LOG_WARNING
, "%s: Cannot teardown NULL session",
668 if (comm_session_exists_locking(socket_comm_handle_
,
671 pcep_log(LOG_WARNING
,
672 "%s: Cannot teardown session that does not exist",
677 if (socket_comm_session
->socket_fd
>= 0) {
678 shutdown(socket_comm_session
->socket_fd
, SHUT_RDWR
);
679 close(socket_comm_session
->socket_fd
);
682 pthread_mutex_lock(&(socket_comm_handle_
->socket_comm_mutex
));
683 queue_destroy(socket_comm_session
->message_queue
);
684 ordered_list_remove_first_node_equals(socket_comm_handle_
->session_list
,
685 socket_comm_session
);
686 ordered_list_remove_first_node_equals(socket_comm_handle_
->read_list
,
687 socket_comm_session
);
688 ordered_list_remove_first_node_equals(socket_comm_handle_
->write_list
,
689 socket_comm_session
);
690 socket_comm_handle_
->num_active_sessions
--;
691 pthread_mutex_unlock(&(socket_comm_handle_
->socket_comm_mutex
));
695 "%s: [%ld-%ld] socket_comm_session fd [%d] destroyed, [%d] sessions remaining",
696 __func__
, time(NULL
), pthread_self(),
697 socket_comm_session
->socket_fd
,
698 socket_comm_handle_
->num_active_sessions
);
700 pceplib_free(PCEPLIB_INFRA
, socket_comm_session
);
702 /* It would be nice to call destroy_socket_comm_loop() here if
703 * socket_comm_handle_->num_active_sessions == 0, but this function
704 * will usually be called from the message_sent_notifier callback,
705 * which gets called in the middle of the socket_comm_loop, and that
706 * is dangerous, so destroy_socket_comm_loop() must be called upon
707 * application exit. */
713 void socket_comm_session_send_message(
714 pcep_socket_comm_session
*socket_comm_session
,
715 const char *encoded_message
, unsigned int msg_length
,
716 bool free_after_send
)
718 if (socket_comm_session
== NULL
) {
721 "%s: socket_comm_session_send_message NULL socket_comm_session.",
726 pcep_socket_comm_queued_message
*queued_message
= pceplib_malloc(
727 PCEPLIB_MESSAGES
, sizeof(pcep_socket_comm_queued_message
));
728 queued_message
->encoded_message
= encoded_message
;
729 queued_message
->msg_length
= msg_length
;
730 queued_message
->free_after_send
= free_after_send
;
732 pthread_mutex_lock(&(socket_comm_handle_
->socket_comm_mutex
));
734 /* Do not proceed if the socket_comm_session has been deleted */
735 if (ordered_list_find(socket_comm_handle_
->session_list
,
738 /* Should never get here, only if the session was deleted and
739 * someone still tries to write on it */
742 "%s: Cannot write a message on a deleted socket comm session, discarding message",
744 pthread_mutex_unlock(&(socket_comm_handle_
->socket_comm_mutex
));
745 pceplib_free(PCEPLIB_MESSAGES
, queued_message
);
750 /* Do not proceed if the socket has been closed */
751 if (socket_comm_session
->socket_fd
< 0) {
752 /* Should never get here, only if the session was deleted and
753 * someone still tries to write on it */
756 "%s: Cannot write a message on a closed socket, discarding message",
758 pthread_mutex_unlock(&(socket_comm_handle_
->socket_comm_mutex
));
759 pceplib_free(PCEPLIB_MESSAGES
, queued_message
);
764 queue_enqueue(socket_comm_session
->message_queue
, queued_message
);
766 /* Add it to the write list only if its not already there */
767 if (ordered_list_find(socket_comm_handle_
->write_list
,
770 ordered_list_add_node(socket_comm_handle_
->write_list
,
771 socket_comm_session
);
774 if (socket_comm_handle_
->socket_write_func
!= NULL
) {
775 socket_comm_handle_
->socket_write_func(
776 socket_comm_handle_
->external_infra_data
,
777 &socket_comm_session
->external_socket_data
,
778 socket_comm_session
->socket_fd
, socket_comm_handle_
);
780 pthread_mutex_unlock(&(socket_comm_handle_
->socket_comm_mutex
));