diff options
author | Matthias Wachs <wachs@net.in.tum.de> | 2011-12-20 12:58:58 +0000 |
---|---|---|
committer | Matthias Wachs <wachs@net.in.tum.de> | 2011-12-20 12:58:58 +0000 |
commit | 4a2c36e42252c354e3e67d7cb92f3c6dbc514f9a (patch) | |
tree | 0f78195886cd4e148e5c590c18f7ec51c79c2244 /src/transport/plugin_transport_tcp.c | |
parent | d09139b8de9fad1ea9c926f7e7324360f59dbe6e (diff) | |
download | gnunet-4a2c36e42252c354e3e67d7cb92f3c6dbc514f9a.tar.gz gnunet-4a2c36e42252c354e3e67d7cb92f3c6dbc514f9a.zip |
first changes for new plugin api
Diffstat (limited to 'src/transport/plugin_transport_tcp.c')
-rw-r--r-- | src/transport/plugin_transport_tcp.c | 273 |
1 files changed, 273 insertions, 0 deletions
diff --git a/src/transport/plugin_transport_tcp.c b/src/transport/plugin_transport_tcp.c index 347ff8d14..1024b8008 100644 --- a/src/transport/plugin_transport_tcp.c +++ b/src/transport/plugin_transport_tcp.c | |||
@@ -327,6 +327,8 @@ struct Plugin | |||
327 | */ | 327 | */ |
328 | struct Session *sessions; | 328 | struct Session *sessions; |
329 | 329 | ||
330 | struct GNUNET_CONTAINER_MultiHashMap * sessionmap; | ||
331 | |||
330 | /** | 332 | /** |
331 | * Handle to the network service. | 333 | * Handle to the network service. |
332 | */ | 334 | */ |
@@ -1161,7 +1163,86 @@ tcp_plugin_send (void *cls, const struct GNUNET_PeerIdentity *target, | |||
1161 | } | 1163 | } |
1162 | GNUNET_assert (session != NULL); | 1164 | GNUNET_assert (session != NULL); |
1163 | GNUNET_assert (session->client != NULL); | 1165 | GNUNET_assert (session->client != NULL); |
1166 | GNUNET_SERVER_client_set_timeout (session->client, | ||
1167 | GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT); | ||
1168 | GNUNET_STATISTICS_update (plugin->env->stats, | ||
1169 | gettext_noop ("# bytes currently in TCP buffers"), | ||
1170 | msgbuf_size, GNUNET_NO); | ||
1171 | /* create new message entry */ | ||
1172 | pm = GNUNET_malloc (sizeof (struct PendingMessage) + msgbuf_size); | ||
1173 | pm->msg = (const char *) &pm[1]; | ||
1174 | memcpy (&pm[1], msg, msgbuf_size); | ||
1175 | pm->message_size = msgbuf_size; | ||
1176 | pm->timeout = GNUNET_TIME_relative_to_absolute (timeout); | ||
1177 | pm->transmit_cont = cont; | ||
1178 | pm->transmit_cont_cls = cont_cls; | ||
1179 | |||
1180 | /* append pm to pending_messages list */ | ||
1181 | GNUNET_CONTAINER_DLL_insert_tail (session->pending_messages_head, | ||
1182 | session->pending_messages_tail, pm); | ||
1183 | #if DEBUG_TCP | ||
1184 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", | ||
1185 | "Asked to transmit %u bytes to `%s', added message to list.\n", | ||
1186 | msgbuf_size, GNUNET_i2s (target)); | ||
1187 | #endif | ||
1188 | process_pending_messages (session); | ||
1189 | return msgbuf_size; | ||
1190 | } | ||
1191 | |||
1192 | /** | ||
1193 | * Function that can be used by the transport service to transmit | ||
1194 | * a message using the plugin. Note that in the case of a | ||
1195 | * peer disconnecting, the continuation MUST be called | ||
1196 | * prior to the disconnect notification itself. This function | ||
1197 | * will be called with this peer's HELLO message to initiate | ||
1198 | * a fresh connection to another peer. | ||
1199 | * | ||
1200 | * @param cls closure | ||
1201 | * @param target who should receive this message | ||
1202 | * @param msg the message to transmit | ||
1203 | * @param msgbuf_size number of bytes in 'msg' | ||
1204 | * @param priority how important is the message (most plugins will | ||
1205 | * ignore message priority and just FIFO) | ||
1206 | * @param timeout how long to wait at most for the transmission (does not | ||
1207 | * require plugins to discard the message after the timeout, | ||
1208 | * just advisory for the desired delay; most plugins will ignore | ||
1209 | * this as well) | ||
1210 | * @param session which session must be used (or NULL for "any") | ||
1211 | * @param addr the address to use (can be NULL if the plugin | ||
1212 | * is "on its own" (i.e. re-use existing TCP connection)) | ||
1213 | * @param addrlen length of the address in bytes | ||
1214 | * @param force_address GNUNET_YES if the plugin MUST use the given address, | ||
1215 | * GNUNET_NO means the plugin may use any other address and | ||
1216 | * GNUNET_SYSERR means that only reliable existing | ||
1217 | * bi-directional connections should be used (regardless | ||
1218 | * of address) | ||
1219 | * @param cont continuation to call once the message has | ||
1220 | * been transmitted (or if the transport is ready | ||
1221 | * for the next transmission call; or if the | ||
1222 | * peer disconnected...); can be NULL | ||
1223 | * @param cont_cls closure for cont | ||
1224 | * @return number of bytes used (on the physical network, with overheads); | ||
1225 | * -1 on hard errors (i.e. address invalid); 0 is a legal value | ||
1226 | * and does NOT mean that the message was not transmitted (DV and NAT) | ||
1227 | */ | ||
1228 | static ssize_t | ||
1229 | tcp_plugin_send_new (void *cls, | ||
1230 | const struct | ||
1231 | GNUNET_PeerIdentity * | ||
1232 | target, | ||
1233 | const char *msg, | ||
1234 | size_t msgbuf_size, | ||
1235 | uint32_t priority, | ||
1236 | struct GNUNET_TIME_Relative timeout, | ||
1237 | struct Session * session, | ||
1238 | GNUNET_TRANSPORT_TransmitContinuation | ||
1239 | cont, void *cont_cls) | ||
1240 | { | ||
1241 | struct Plugin * plugin = cls; | ||
1242 | struct PendingMessage *pm; | ||
1164 | 1243 | ||
1244 | GNUNET_assert (session != NULL); | ||
1245 | GNUNET_assert (session->client != NULL); | ||
1165 | 1246 | ||
1166 | GNUNET_SERVER_client_set_timeout (session->client, | 1247 | GNUNET_SERVER_client_set_timeout (session->client, |
1167 | GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT); | 1248 | GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT); |
@@ -1189,6 +1270,192 @@ tcp_plugin_send (void *cls, const struct GNUNET_PeerIdentity *target, | |||
1189 | return msgbuf_size; | 1270 | return msgbuf_size; |
1190 | } | 1271 | } |
1191 | 1272 | ||
1273 | struct SessionItCtx | ||
1274 | { | ||
1275 | void * addr; | ||
1276 | size_t addrlen; | ||
1277 | struct Session * result; | ||
1278 | }; | ||
1279 | |||
1280 | int session_it (void *cls, | ||
1281 | const GNUNET_HashCode * key, | ||
1282 | void *value) | ||
1283 | { | ||
1284 | struct SessionItCtx * si_ctx = cls; | ||
1285 | struct Session * session = value; | ||
1286 | |||
1287 | if (session->connect_alen != si_ctx->addrlen) | ||
1288 | return GNUNET_YES; | ||
1289 | if (0 != memcmp (&session->connect_addr, si_ctx->addr, si_ctx->addrlen)) | ||
1290 | return GNUNET_YES; | ||
1291 | |||
1292 | /* Found existing session */ | ||
1293 | si_ctx->result = session; | ||
1294 | return GNUNET_NO; | ||
1295 | } | ||
1296 | |||
1297 | |||
1298 | /** | ||
1299 | * Create a new session to transmit data to the target | ||
1300 | * This session will used to send data to this peer and the plugin will | ||
1301 | * notify us by calling the env->session_end function | ||
1302 | * | ||
1303 | * @param cls closure | ||
1304 | * @param target the neighbour id | ||
1305 | * @param addr pointer to the address | ||
1306 | * @param addrlen length of addr | ||
1307 | * @return the session if the address is valid, NULL otherwise | ||
1308 | */ | ||
1309 | const void * tcp_plugin_create_session (void *cls, | ||
1310 | const struct GNUNET_PeerIdentity *target, | ||
1311 | const void *addr, | ||
1312 | size_t addrlen) | ||
1313 | { | ||
1314 | struct Plugin * plugin = cls; | ||
1315 | struct Session * session = NULL; | ||
1316 | |||
1317 | int af; | ||
1318 | const void *sb; | ||
1319 | size_t sbs; | ||
1320 | struct GNUNET_CONNECTION_Handle *sa; | ||
1321 | struct sockaddr_in a4; | ||
1322 | struct sockaddr_in6 a6; | ||
1323 | const struct IPv4TcpAddress *t4; | ||
1324 | const struct IPv6TcpAddress *t6; | ||
1325 | unsigned int is_natd; | ||
1326 | |||
1327 | if (addrlen == sizeof (struct IPv6TcpAddress)) | ||
1328 | { | ||
1329 | GNUNET_assert (NULL != addr); /* make static analysis happy */ | ||
1330 | t6 = addr; | ||
1331 | af = AF_INET6; | ||
1332 | memset (&a6, 0, sizeof (a6)); | ||
1333 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
1334 | a6.sin6_len = sizeof (a6); | ||
1335 | #endif | ||
1336 | a6.sin6_family = AF_INET6; | ||
1337 | a6.sin6_port = t6->t6_port; | ||
1338 | if (t6->t6_port == 0) | ||
1339 | is_natd = GNUNET_YES; | ||
1340 | memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof (struct in6_addr)); | ||
1341 | sb = &a6; | ||
1342 | sbs = sizeof (a6); | ||
1343 | } | ||
1344 | else if (addrlen == sizeof (struct IPv4TcpAddress)) | ||
1345 | { | ||
1346 | GNUNET_assert (NULL != addr); /* make static analysis happy */ | ||
1347 | t4 = addr; | ||
1348 | af = AF_INET; | ||
1349 | memset (&a4, 0, sizeof (a4)); | ||
1350 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
1351 | a4.sin_len = sizeof (a4); | ||
1352 | #endif | ||
1353 | a4.sin_family = AF_INET; | ||
1354 | a4.sin_port = t4->t4_port; | ||
1355 | if (t4->t4_port == 0) | ||
1356 | is_natd = GNUNET_YES; | ||
1357 | a4.sin_addr.s_addr = t4->ipv4_addr; | ||
1358 | sb = &a4; | ||
1359 | sbs = sizeof (a4); | ||
1360 | } | ||
1361 | else | ||
1362 | { | ||
1363 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "tcp", | ||
1364 | _("Address of unexpected length: %u\n"), addrlen); | ||
1365 | GNUNET_break (0); | ||
1366 | return NULL; | ||
1367 | } | ||
1368 | |||
1369 | /* look for existing session */ | ||
1370 | if (GNUNET_CONTAINER_multihashmap_contains(plugin->sessionmap, &target->hashPubKey)) | ||
1371 | { | ||
1372 | struct SessionItCtx si_ctx; | ||
1373 | si_ctx.addr = &sbs; | ||
1374 | si_ctx.addrlen = sbs; | ||
1375 | GNUNET_CONTAINER_multihashmap_get_multiple(plugin->sessionmap, &target->hashPubKey, &session_it, &si_ctx); | ||
1376 | if (si_ctx.result != NULL) | ||
1377 | session = si_ctx.result; | ||
1378 | return session; | ||
1379 | } | ||
1380 | |||
1381 | if ((is_natd == GNUNET_YES) && (addrlen == sizeof (struct IPv6TcpAddress))) | ||
1382 | return NULL; /* NAT client only works with IPv4 addresses */ | ||
1383 | |||
1384 | if (0 == plugin->max_connections) | ||
1385 | return NULL; /* saturated */ | ||
1386 | |||
1387 | if ((is_natd == GNUNET_YES) && | ||
1388 | (GNUNET_YES == | ||
1389 | GNUNET_CONTAINER_multihashmap_contains (plugin->nat_wait_conns, | ||
1390 | &target->hashPubKey))) | ||
1391 | return NULL; /* Only do one NAT punch attempt per peer identity */ | ||
1392 | |||
1393 | if ((is_natd == GNUNET_YES) && (NULL != plugin->nat) && | ||
1394 | (GNUNET_NO == | ||
1395 | GNUNET_CONTAINER_multihashmap_contains (plugin->nat_wait_conns, | ||
1396 | &target->hashPubKey))) | ||
1397 | { | ||
1398 | #if DEBUG_TCP_NAT | ||
1399 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", | ||
1400 | _("Found valid IPv4 NAT address (creating session)!\n")); | ||
1401 | #endif | ||
1402 | session = create_session (plugin, target, NULL, GNUNET_YES); | ||
1403 | GNUNET_assert (session != NULL); | ||
1404 | |||
1405 | GNUNET_assert (GNUNET_CONTAINER_multihashmap_put | ||
1406 | (plugin->nat_wait_conns, &target->hashPubKey, session, | ||
1407 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY) == GNUNET_OK); | ||
1408 | #if DEBUG_TCP_NAT | ||
1409 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", | ||
1410 | "Created NAT WAIT connection to `%4s' at `%s'\n", | ||
1411 | GNUNET_i2s (target), GNUNET_a2s (sb, sbs)); | ||
1412 | #endif | ||
1413 | GNUNET_NAT_run_client (plugin->nat, &a4); | ||
1414 | return session; | ||
1415 | } | ||
1416 | |||
1417 | /* create new outbound session */ | ||
1418 | GNUNET_assert (0 != plugin->max_connections); | ||
1419 | sa = GNUNET_CONNECTION_create_from_sockaddr (af, sb, sbs); | ||
1420 | if (sa == NULL) | ||
1421 | { | ||
1422 | #if DEBUG_TCP | ||
1423 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", | ||
1424 | "Failed to create connection to `%4s' at `%s'\n", | ||
1425 | GNUNET_i2s (target), GNUNET_a2s (sb, sbs)); | ||
1426 | #endif | ||
1427 | return NULL; | ||
1428 | } | ||
1429 | plugin->max_connections--; | ||
1430 | #if DEBUG_TCP_NAT | ||
1431 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", | ||
1432 | "Asked to transmit to `%4s', creating fresh session using address `%s'.\n", | ||
1433 | GNUNET_i2s (target), GNUNET_a2s (sb, sbs)); | ||
1434 | #endif | ||
1435 | session = create_session (plugin, | ||
1436 | target, | ||
1437 | GNUNET_SERVER_connect_socket (plugin->server, sa), | ||
1438 | GNUNET_NO); | ||
1439 | session->connect_addr = GNUNET_malloc (addrlen); | ||
1440 | memcpy (session->connect_addr, addr, addrlen); | ||
1441 | session->connect_alen = addrlen; | ||
1442 | if (addrlen != 0) | ||
1443 | { | ||
1444 | struct GNUNET_ATS_Information ats; | ||
1445 | ats = plugin->env->get_address_type (plugin->env->cls, sb ,sbs); | ||
1446 | session->ats_address_network_type = ats.value; | ||
1447 | } | ||
1448 | else | ||
1449 | GNUNET_break (0); | ||
1450 | |||
1451 | GNUNET_CONTAINER_multihashmap_put(plugin->sessionmap, &target->hashPubKey, session, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); | ||
1452 | |||
1453 | /* Send TCP Welcome */ | ||
1454 | process_pending_messages (session); | ||
1455 | |||
1456 | return session; | ||
1457 | } | ||
1458 | |||
1192 | 1459 | ||
1193 | /** | 1460 | /** |
1194 | * Function that can be called to force a disconnect from the | 1461 | * Function that can be called to force a disconnect from the |
@@ -1978,6 +2245,7 @@ libgnunet_plugin_transport_tcp_init (void *cls) | |||
1978 | 2245 | ||
1979 | 2246 | ||
1980 | plugin = GNUNET_malloc (sizeof (struct Plugin)); | 2247 | plugin = GNUNET_malloc (sizeof (struct Plugin)); |
2248 | plugin->sessionmap = GNUNET_CONTAINER_multihashmap_create(max_connections); | ||
1981 | plugin->max_connections = max_connections; | 2249 | plugin->max_connections = max_connections; |
1982 | plugin->open_port = bport; | 2250 | plugin->open_port = bport; |
1983 | plugin->adv_port = aport; | 2251 | plugin->adv_port = aport; |
@@ -2012,6 +2280,10 @@ libgnunet_plugin_transport_tcp_init (void *cls) | |||
2012 | api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); | 2280 | api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); |
2013 | api->cls = plugin; | 2281 | api->cls = plugin; |
2014 | api->send = &tcp_plugin_send; | 2282 | api->send = &tcp_plugin_send; |
2283 | |||
2284 | api->send_with_session = &tcp_plugin_send_new; | ||
2285 | api->create_session = &tcp_plugin_create_session; | ||
2286 | |||
2015 | api->disconnect = &tcp_plugin_disconnect; | 2287 | api->disconnect = &tcp_plugin_disconnect; |
2016 | api->address_pretty_printer = &tcp_plugin_address_pretty_printer; | 2288 | api->address_pretty_printer = &tcp_plugin_address_pretty_printer; |
2017 | api->check_address = &tcp_plugin_check_address; | 2289 | api->check_address = &tcp_plugin_check_address; |
@@ -2093,6 +2365,7 @@ libgnunet_plugin_transport_tcp_done (void *cls) | |||
2093 | GNUNET_free (tcp_probe); | 2365 | GNUNET_free (tcp_probe); |
2094 | } | 2366 | } |
2095 | GNUNET_CONTAINER_multihashmap_destroy (plugin->nat_wait_conns); | 2367 | GNUNET_CONTAINER_multihashmap_destroy (plugin->nat_wait_conns); |
2368 | GNUNET_CONTAINER_multihashmap_destroy (plugin->sessionmap); | ||
2096 | GNUNET_free (plugin); | 2369 | GNUNET_free (plugin); |
2097 | GNUNET_free (api); | 2370 | GNUNET_free (api); |
2098 | return NULL; | 2371 | return NULL; |