Mercurial > hg > freeDiameter
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 } |