comparison freeDiameter/p_cnx.c @ 38:68c1890f7049

Fixed a small bug in SCTP close
author Sebastien Decugis <sdecugis@nict.go.jp>
date Thu, 05 Nov 2009 17:29:12 +0900
parents cc3c59fe98fe
children d7535cf7bab5
comparison
equal deleted inserted replaced
37:cc3c59fe98fe 38:68c1890f7049
35 35
36 #include "fD.h" 36 #include "fD.h"
37 37
38 /* This file contains code used by a peer state machine to initiate a connection to remote peer */ 38 /* This file contains code used by a peer state machine to initiate a connection to remote peer */
39 39
40 struct next_conn {
41 struct fd_list chain;
42 int proto; /* Protocol of the next attempt */
43 sSS ss; /* The address, only for TCP */
44 uint16_t port; /* The port, for SCTP (included in ss for TCP) */
45 int dotls; /* Handshake TLS after connection ? */
46 };
47
48 static int prepare_connection_list(struct fd_peer * peer)
49 {
50 /* Resolve peer address(es) if needed */
51 if (FD_IS_LIST_EMPTY(&peer->p_hdr.info.pi_endpoints)) {
52 struct addrinfo hints, *ai, *aip;
53 int ret;
54
55 memset(&hints, 0, sizeof(hints));
56 hints.ai_flags = AI_ADDRCONFIG;
57 ret = getaddrinfo(peer->p_hdr.info.pi_diamid, NULL, &hints, &ai);
58 if (ret) {
59 fd_log_debug("Unable to resolve address for peer '%s' (%s), aborting this connection\n", peer->p_hdr.info.pi_diamid, gai_strerror(ret));
60 fd_psm_terminate( peer );
61 return 0;
62 }
63
64 for (aip = ai; aip != NULL; aip = aip->ai_next) {
65 CHECK_FCT( fd_ep_add_merge( &peer->p_hdr.info.pi_endpoints, aip->ai_addr, aip->ai_addrlen, EP_FL_DISC ) );
66 }
67 freeaddrinfo(ai);
68 }
69
70 /* Remove addresses from unwanted family */
71 if (peer->p_hdr.info.config.pic_flags.pro3) {
72 CHECK_FCT( fd_ep_filter_family(
73 &peer->p_hdr.info.pi_endpoints,
74 (peer->p_hdr.info.config.pic_flags.pro3 == PI_P3_IP) ?
75 AF_INET
76 : AF_INET6));
77 }
78
79 TODO("Prepare the list in peer->p_connparams obeying the flags");
80
81 TODO("Return an error if the list is empty in the end");
82
83 return ENOTSUP;
84 }
85
86 static __inline__ void failed_connection_attempt(struct fd_peer * peer)
87 {
88 /* Simply remove the first item in the list */
89 struct fd_list * li = peer->p_connparams.next;
90 fd_list_unlink(li);
91 free(li);
92 }
93
94 static void empty_connection_list(struct fd_peer * peer)
95 {
96 /* Remove all items */
97 while (!FD_IS_LIST_EMPTY(&peer->p_connparams)) {
98 failed_connection_attempt(peer);
99 }
100 }
101
40 102
41 /* The thread that attempts the connection */ 103 /* The thread that attempts the connection */
42 static void * connect_thr(void * arg) 104 static void * connect_thr(void * arg)
43 { 105 {
44 struct fd_peer * peer = arg; 106 struct fd_peer * peer = arg;
45 struct cnxctx * cnx = NULL; 107 struct cnxctx * cnx = NULL;
46 108 struct next_conn * nc = NULL;
47 109
48 110 TRACE_ENTRY("%p", arg);
49 /* Use the flags in the peer to select the protocol */ 111 CHECK_PARAMS_DO( CHECK_PEER(peer), return NULL );
50 112
51 TODO("loop on fd_cnx_cli_connect_tcp or fd_cnx_cli_connect_sctp"); 113 do {
52 114 /* Rebuild the list if needed, if it is empty */
115 if (FD_IS_LIST_EMPTY(&peer->p_connparams)) {
116 CHECK_FCT_DO( prepare_connection_list(peer), goto fatal_error );
117 if (FD_IS_LIST_EMPTY(&peer->p_connparams))
118 /* Already logged and peer terminated */
119 return NULL;
120 }
121
122 /* Attempt connection to the first entry */
123 nc = (struct next_conn *)(peer->p_connparams.next);
124
125 switch (nc->proto) {
126 case IPPROTO_TCP:
127 cnx = fd_cnx_cli_connect_tcp((sSA *)&nc->ss, sSSlen(&nc->ss));
128 break;
129 #ifndef DISABLE_SCTP
130 case IPPROTO_SCTP:
131 cnx = fd_cnx_cli_connect_sctp((peer->p_hdr.info.config.pic_flags.pro3 == PI_P3_IP) ?: fd_g_config->cnf_flags.no_ip6, nc->port, &peer->p_hdr.info.pi_endpoints);
132 break;
133 #endif /* DISABLE_SCTP */
134 }
135
136 if (cnx)
137 break;
138
139 /* Pop these parameters and continue */
140 failed_connection_attempt(peer);
141
142 pthread_testcancel();
143
144 } while (!cnx); /* and until cancellation */
53 145
54 /* Now, we have an established connection in cnx */ 146 /* Now, we have an established connection in cnx */
55 147
56 pthread_cleanup_push((void *)fd_cnx_destroy, cnx); 148 pthread_cleanup_push((void *)fd_cnx_destroy, cnx);
57 149
58 /* Handshake if needed (secure port) */ 150 /* Handshake if needed (secure port) */
59 151 if (nc->dotls) {
60 152 CHECK_FCT_DO( fd_cnx_handshake(cnx, GNUTLS_CLIENT, peer->p_hdr.info.config.pic_priority, NULL),
153 {
154 /* Handshake failed ... */
155 fd_log_debug("TLS Handshake failed with peer '%s', resetting the connection\n", peer->p_hdr.info.pi_diamid);
156 fd_cnx_destroy(cnx);
157 empty_connection_list(peer);
158 fd_ep_filter(&peer->p_hdr.info.pi_endpoints, EP_FL_CONF);
159 return NULL;
160 } );
161 }
61 162
62 /* Upon success, generate FDEVP_CNX_ESTABLISHED */ 163 /* Upon success, generate FDEVP_CNX_ESTABLISHED */
63 CHECK_FCT_DO( fd_event_send(peer->p_events, FDEVP_CNX_ESTABLISHED, 0, cnx), goto fatal_error ); 164 CHECK_FCT_DO( fd_event_send(peer->p_events, FDEVP_CNX_ESTABLISHED, 0, cnx), goto fatal_error );
165
64 pthread_cleanup_pop(0); 166 pthread_cleanup_pop(0);
65 167
66 return NULL; 168 return NULL;
169
67 fatal_error: 170 fatal_error:
68 /* Cleanup the connection */ 171 /* Cleanup the connection */
69 fd_cnx_destroy(cnx); 172 if (cnx)
173 fd_cnx_destroy(cnx);
70 174
71 /* Generate a termination event */ 175 /* Generate a termination event */
72 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), ); 176 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), );
73 177
74 return NULL; 178 return NULL;
76 180
77 181
78 /* Initiate a connection attempt to a remote peer */ 182 /* Initiate a connection attempt to a remote peer */
79 int fd_p_cnx_init(struct fd_peer * peer) 183 int fd_p_cnx_init(struct fd_peer * peer)
80 { 184 {
185 TRACE_ENTRY("%p", peer);
186
81 /* Start the connect thread */ 187 /* Start the connect thread */
82 CHECK_FCT( pthread_create(&peer->p_ini_thr, NULL, connect_thr, peer) ); 188 CHECK_FCT( pthread_create(&peer->p_ini_thr, NULL, connect_thr, peer) );
83 return 0; 189 return 0;
84 } 190 }
191
192 /* Cancel a connection attempt */
193 void fd_p_cnx_abort(struct fd_peer * peer, int cleanup_all)
194 {
195 TRACE_ENTRY("%p %d", peer, cleanup_all);
196 CHECK_PARAMS_DO( CHECK_PEER(peer), return );
197
198 if (peer->p_ini_thr != (pthread_t)NULL) {
199 CHECK_FCT_DO( fd_thr_term(&peer->p_ini_thr), /* continue */);
200 failed_connection_attempt(peer);
201 }
202
203 if (cleanup_all) {
204 empty_connection_list(peer);
205 }
206 }
"Welcome to our mercurial repository"