aboutsummaryrefslogtreecommitdiff
path: root/src/transport/plugin_transport_tcp.c
diff options
context:
space:
mode:
authorMatthias Wachs <wachs@net.in.tum.de>2012-02-13 16:02:44 +0000
committerMatthias Wachs <wachs@net.in.tum.de>2012-02-13 16:02:44 +0000
commit2e2e5b4a8e5cebd71b880da8c613be4a49f44fe2 (patch)
tree270c64858fd4494c0d62970b7aa5926d185cef46 /src/transport/plugin_transport_tcp.c
parent5b9e61b9c3832e69164ee8574fff6711b2f18ef6 (diff)
downloadgnunet-2e2e5b4a8e5cebd71b880da8c613be4a49f44fe2.tar.gz
gnunet-2e2e5b4a8e5cebd71b880da8c613be4a49f44fe2.zip
removing legacy send functions from plugins and renaming new send function
Diffstat (limited to 'src/transport/plugin_transport_tcp.c')
-rw-r--r--src/transport/plugin_transport_tcp.c335
1 files changed, 1 insertions, 334 deletions
diff --git a/src/transport/plugin_transport_tcp.c b/src/transport/plugin_transport_tcp.c
index 2ce3cc8c7..4157024c9 100644
--- a/src/transport/plugin_transport_tcp.c
+++ b/src/transport/plugin_transport_tcp.c
@@ -863,337 +863,6 @@ disconnect_session (struct Session *session)
863 863
864 864
865/** 865/**
866 * Given two otherwise equivalent sessions, pick the better one.
867 *
868 * @param s1 one session (also default)
869 * @param s2 other session
870 * @return "better" session (more active)
871 */
872static struct Session *
873select_better_session (struct Session *s1, struct Session *s2)
874{
875 if (s1 == NULL)
876 return s2;
877 if (s2 == NULL)
878 return s1;
879 if ((s1->expecting_welcome == GNUNET_NO) &&
880 (s2->expecting_welcome == GNUNET_YES))
881 return s1;
882 if ((s1->expecting_welcome == GNUNET_YES) &&
883 (s2->expecting_welcome == GNUNET_NO))
884 return s2;
885 if (s1->last_activity.abs_value < s2->last_activity.abs_value)
886 return s2;
887 if (s1->last_activity.abs_value > s2->last_activity.abs_value)
888 return s1;
889 if ((GNUNET_YES == s1->inbound) && (GNUNET_NO == s2->inbound))
890 return s1;
891 if ((GNUNET_NO == s1->inbound) && (GNUNET_YES == s2->inbound))
892 return s2;
893 return s1;
894}
895
896
897
898/**
899 * Function that can be used by the transport service to transmit
900 * a message using the plugin. Note that in the case of a
901 * peer disconnecting, the continuation MUST be called
902 * prior to the disconnect notification itself. This function
903 * will be called with this peer's HELLO message to initiate
904 * a fresh connection to another peer.
905 *
906 * @param cls closure
907 * @param target who should receive this message
908 * @param msg the message to transmit
909 * @param msgbuf_size number of bytes in 'msg'
910 * @param priority how important is the message (most plugins will
911 * ignore message priority and just FIFO)
912 * @param timeout how long to wait at most for the transmission (does not
913 * require plugins to discard the message after the timeout,
914 * just advisory for the desired delay; most plugins will ignore
915 * this as well)
916 * @param session which session must be used (or NULL for "any")
917 * @param addr the address to use (can be NULL if the plugin
918 * is "on its own" (i.e. re-use existing TCP connection))
919 * @param addrlen length of the address in bytes
920 * @param force_address GNUNET_YES if the plugin MUST use the given address,
921 * GNUNET_NO means the plugin may use any other address and
922 * GNUNET_SYSERR means that only reliable existing
923 * bi-directional connections should be used (regardless
924 * of address)
925 * @param cont continuation to call once the message has
926 * been transmitted (or if the transport is ready
927 * for the next transmission call; or if the
928 * peer disconnected...); can be NULL
929 * @param cont_cls closure for cont
930 * @return number of bytes used (on the physical network, with overheads);
931 * -1 on hard errors (i.e. address invalid); 0 is a legal value
932 * and does NOT mean that the message was not transmitted (DV and NAT)
933 */
934static ssize_t
935tcp_plugin_send_old (void *cls, const struct GNUNET_PeerIdentity *target,
936 const char *msg, size_t msgbuf_size, uint32_t priority,
937 struct GNUNET_TIME_Relative timeout, struct Session *session,
938 const void *addr, size_t addrlen, int force_address,
939 GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls)
940{
941 struct Plugin *plugin = cls;
942 struct Session *cand_session;
943 struct Session *next;
944 struct PendingMessage *pm;
945 struct GNUNET_CONNECTION_Handle *sa;
946 int af;
947 const void *sb;
948 size_t sbs;
949 struct sockaddr_in a4;
950 struct sockaddr_in6 a6;
951 const struct IPv4TcpAddress *t4;
952 const struct IPv6TcpAddress *t6;
953 unsigned int is_natd;
954
955 GNUNET_STATISTICS_update (plugin->env->stats,
956 gettext_noop ("# bytes TCP was asked to transmit"),
957 msgbuf_size, GNUNET_NO);
958 /* FIXME: we could do this cheaper with a hash table
959 * where we could restrict the iteration to entries that match
960 * the target peer... */
961 is_natd = GNUNET_NO;
962 if (session == NULL)
963 {
964 cand_session = NULL;
965 next = plugin->sessions;
966 while (NULL != (session = next))
967 {
968 next = session->next;
969 GNUNET_assert (session->client != NULL);
970 if (0 !=
971 memcmp (target, &session->target,
972 sizeof (struct GNUNET_PeerIdentity)))
973 continue;
974 if (((GNUNET_SYSERR == force_address) &&
975 (session->expecting_welcome == GNUNET_NO)) ||
976 (GNUNET_NO == force_address))
977 {
978 cand_session = select_better_session (cand_session, session);
979 continue;
980 }
981 if (GNUNET_SYSERR == force_address)
982 continue;
983 GNUNET_break (GNUNET_YES == force_address);
984 if (addr == NULL)
985 {
986 GNUNET_break (0);
987 break;
988 }
989 if ((addrlen != session->connect_alen) && (session->is_nat == GNUNET_NO))
990 continue;
991 if ((0 != memcmp (session->connect_addr, addr, addrlen)) &&
992 (session->is_nat == GNUNET_NO))
993 continue;
994 cand_session = select_better_session (cand_session, session);
995 }
996 session = cand_session;
997 }
998 if ((session == NULL) && (addrlen == 0))
999 {
1000#if DEBUG_TCP
1001 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp",
1002 "Asked to transmit to `%4s' without address and I have no existing connection (failing).\n",
1003 GNUNET_i2s (target));
1004#endif
1005 GNUNET_STATISTICS_update (plugin->env->stats,
1006 gettext_noop
1007 ("# bytes discarded by TCP (no address and no connection)"),
1008 msgbuf_size, GNUNET_NO);
1009 return -1;
1010 }
1011 if (session == NULL)
1012 {
1013 if (addrlen == sizeof (struct IPv6TcpAddress))
1014 {
1015 GNUNET_assert (NULL != addr); /* make static analysis happy */
1016 t6 = addr;
1017 af = AF_INET6;
1018 memset (&a6, 0, sizeof (a6));
1019#if HAVE_SOCKADDR_IN_SIN_LEN
1020 a6.sin6_len = sizeof (a6);
1021#endif
1022 a6.sin6_family = AF_INET6;
1023 a6.sin6_port = t6->t6_port;
1024 if (t6->t6_port == 0)
1025 is_natd = GNUNET_YES;
1026 memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof (struct in6_addr));
1027 sb = &a6;
1028 sbs = sizeof (a6);
1029 }
1030 else if (addrlen == sizeof (struct IPv4TcpAddress))
1031 {
1032 GNUNET_assert (NULL != addr); /* make static analysis happy */
1033 t4 = addr;
1034 af = AF_INET;
1035 memset (&a4, 0, sizeof (a4));
1036#if HAVE_SOCKADDR_IN_SIN_LEN
1037 a4.sin_len = sizeof (a4);
1038#endif
1039 a4.sin_family = AF_INET;
1040 a4.sin_port = t4->t4_port;
1041 if (t4->t4_port == 0)
1042 is_natd = GNUNET_YES;
1043 a4.sin_addr.s_addr = t4->ipv4_addr;
1044 sb = &a4;
1045 sbs = sizeof (a4);
1046 }
1047 else
1048 {
1049 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "tcp",
1050 _("Address of unexpected length: %u\n"), addrlen);
1051 GNUNET_break (0);
1052 return -1;
1053 }
1054
1055 if ((is_natd == GNUNET_YES) && (addrlen == sizeof (struct IPv6TcpAddress)))
1056 return -1; /* NAT client only works with IPv4 addresses */
1057 if (0 == plugin->max_connections)
1058 return -1; /* saturated */
1059
1060 if ((is_natd == GNUNET_YES) && (NULL != plugin->nat) &&
1061 (GNUNET_NO ==
1062 GNUNET_CONTAINER_multihashmap_contains (plugin->nat_wait_conns,
1063 &target->hashPubKey)))
1064 {
1065#if DEBUG_TCP_NAT
1066 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp",
1067 _("Found valid IPv4 NAT address (creating session)!\n"));
1068#endif
1069 session = create_session (plugin, target, NULL, GNUNET_YES);
1070 GNUNET_assert (session != NULL);
1071
1072 /* create new message entry */
1073 pm = GNUNET_malloc (sizeof (struct PendingMessage) + msgbuf_size);
1074 /* FIXME: the memset of this malloc can be up to 2% of our total runtime */
1075 pm->msg = (const char *) &pm[1];
1076 memcpy (&pm[1], msg, msgbuf_size);
1077 /* FIXME: this memcpy can be up to 7% of our total run-time
1078 * (for transport service) */
1079 pm->message_size = msgbuf_size;
1080 pm->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1081 pm->transmit_cont = cont;
1082 pm->transmit_cont_cls = cont_cls;
1083
1084 /* append pm to pending_messages list */
1085 GNUNET_CONTAINER_DLL_insert_tail (session->pending_messages_head,
1086 session->pending_messages_tail, pm);
1087
1088 GNUNET_assert (GNUNET_CONTAINER_multihashmap_put
1089 (plugin->nat_wait_conns, &target->hashPubKey, session,
1090 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY) ==
1091 GNUNET_OK);
1092#if DEBUG_TCP_NAT
1093 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp",
1094 "Created NAT WAIT connection to `%4s' at `%s'\n",
1095 GNUNET_i2s (target), GNUNET_a2s (sb, sbs));
1096#endif
1097 GNUNET_NAT_run_client (plugin->nat, &a4);
1098 return 0;
1099 }
1100 if ((is_natd == GNUNET_YES) &&
1101 (GNUNET_YES ==
1102 GNUNET_CONTAINER_multihashmap_contains (plugin->nat_wait_conns,
1103 &target->hashPubKey)))
1104 {
1105 /* Only do one NAT punch attempt per peer identity */
1106 return -1;
1107 }
1108 sa = GNUNET_CONNECTION_create_from_sockaddr (af, sb, sbs);
1109 if (sa == NULL)
1110 {
1111#if DEBUG_TCP
1112 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp",
1113 "Failed to create connection to `%4s' at `%s'\n",
1114 GNUNET_i2s (target), GNUNET_a2s (sb, sbs));
1115#endif
1116 GNUNET_STATISTICS_update (plugin->env->stats,
1117 gettext_noop
1118 ("# bytes discarded by TCP (failed to connect)"),
1119 msgbuf_size, GNUNET_NO);
1120 return -1;
1121 }
1122 GNUNET_assert (0 != plugin->max_connections);
1123 plugin->max_connections--;
1124#if DEBUG_TCP_NAT
1125 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp",
1126 "Asked to transmit to `%4s', creating fresh session using address `%s'.\n",
1127 GNUNET_i2s (target), GNUNET_a2s (sb, sbs));
1128#endif
1129 session =
1130 create_session (plugin, target,
1131 GNUNET_SERVER_connect_socket (plugin->server, sa),
1132 GNUNET_NO);
1133 session->connect_addr = GNUNET_malloc (addrlen);
1134 memcpy (session->connect_addr, addr, addrlen);
1135 session->connect_alen = addrlen;
1136 if (addrlen != 0)
1137 {
1138 struct GNUNET_ATS_Information ats;
1139 ats = plugin->env->get_address_type (plugin->env->cls, sb ,sbs);
1140 session->ats_address_network_type = ats.value;
1141 }
1142 else
1143 GNUNET_break (0);
1144 }
1145 else /* session != NULL */
1146 {
1147 /* check if session is valid */
1148 struct Session *ses = plugin->sessions;
1149
1150 if (0 !=
1151 memcmp (target, &session->target, sizeof (struct GNUNET_PeerIdentity)))
1152 {
1153 GNUNET_break (0);
1154 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1155 "Got session %p for `%s', but should be for peer `%s'!\n",
1156 session, GNUNET_i2s (&session->target),
1157 GNUNET_h2s (&target->hashPubKey));
1158 return -1;
1159 }
1160
1161 while ((ses != NULL) && (ses != session))
1162 ses = ses->next;
1163 if (ses == NULL)
1164 {
1165 return -1;
1166 }
1167 }
1168 GNUNET_assert (session != NULL);
1169 GNUNET_assert (session->client != NULL);
1170 GNUNET_SERVER_client_set_timeout (session->client,
1171 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1172 GNUNET_STATISTICS_update (plugin->env->stats,
1173 gettext_noop ("# bytes currently in TCP buffers"),
1174 msgbuf_size, GNUNET_NO);
1175 /* create new message entry */
1176 pm = GNUNET_malloc (sizeof (struct PendingMessage) + msgbuf_size);
1177 pm->msg = (const char *) &pm[1];
1178 memcpy (&pm[1], msg, msgbuf_size);
1179 pm->message_size = msgbuf_size;
1180 pm->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1181 pm->transmit_cont = cont;
1182 pm->transmit_cont_cls = cont_cls;
1183
1184 /* append pm to pending_messages list */
1185 GNUNET_CONTAINER_DLL_insert_tail (session->pending_messages_head,
1186 session->pending_messages_tail, pm);
1187#if DEBUG_TCP
1188 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp",
1189 "Asked to transmit %u bytes to `%s', added message to list.\n",
1190 msgbuf_size, GNUNET_i2s (target));
1191#endif
1192 process_pending_messages (session);
1193 return msgbuf_size;
1194}
1195
1196/**
1197 * Function that can be used by the transport service to transmit 866 * Function that can be used by the transport service to transmit
1198 * a message using the plugin. Note that in the case of a 867 * a message using the plugin. Note that in the case of a
1199 * peer disconnecting, the continuation MUST be called 868 * peer disconnecting, the continuation MUST be called
@@ -2285,9 +1954,7 @@ libgnunet_plugin_transport_tcp_init (void *cls)
2285 } 1954 }
2286 api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); 1955 api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
2287 api->cls = plugin; 1956 api->cls = plugin;
2288 api->send = &tcp_plugin_send_old; 1957 api->send = &tcp_plugin_send;
2289
2290 api->send_with_session = &tcp_plugin_send;
2291 api->get_session = &tcp_plugin_get_session; 1958 api->get_session = &tcp_plugin_get_session;
2292 1959
2293 api->disconnect = &tcp_plugin_disconnect; 1960 api->disconnect = &tcp_plugin_disconnect;