aboutsummaryrefslogtreecommitdiff
path: root/src/transport/plugin_transport_tcp.c
diff options
context:
space:
mode:
authorMatthias Wachs <wachs@net.in.tum.de>2011-12-20 12:58:58 +0000
committerMatthias Wachs <wachs@net.in.tum.de>2011-12-20 12:58:58 +0000
commit4a2c36e42252c354e3e67d7cb92f3c6dbc514f9a (patch)
tree0f78195886cd4e148e5c590c18f7ec51c79c2244 /src/transport/plugin_transport_tcp.c
parentd09139b8de9fad1ea9c926f7e7324360f59dbe6e (diff)
downloadgnunet-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.c273
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 */
1228static ssize_t
1229tcp_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
1273struct SessionItCtx
1274{
1275 void * addr;
1276 size_t addrlen;
1277 struct Session * result;
1278};
1279
1280int 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 */
1309const 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;