comparison dbutil.c @ 1025:02baa0b334e8 fastopen

async connections working
author Matt Johnston <matt@ucc.asn.au>
date Wed, 18 Feb 2015 22:46:15 +0800
parents aac0095dc3b4
children daf21fd50abf
comparison
equal deleted inserted replaced
1024:aac0095dc3b4 1025:02baa0b334e8
993 993
994 struct Queue *writequeue; /* A queue of encrypted packets to send with TCP fastopen, 994 struct Queue *writequeue; /* A queue of encrypted packets to send with TCP fastopen,
995 or NULL. */ 995 or NULL. */
996 996
997 int sock; 997 int sock;
998
999 char* errstring;
998 }; 1000 };
999 1001
1000 /* Deallocate a progress connection. Removes from the pending list if iter!=NULL. 1002 /* Deallocate a progress connection. Removes from the pending list if iter!=NULL.
1001 Does not close sockets */ 1003 Does not close sockets */
1002 static void remove_connect(struct dropbear_progress_connection *c, m_list_elem *iter) { 1004 static void remove_connect(struct dropbear_progress_connection *c, m_list_elem *iter) {
1003 if (c->res) { 1005 if (c->res) {
1004 freeaddrinfo(c->res); 1006 freeaddrinfo(c->res);
1005 } 1007 }
1006 m_free(c->remotehost); 1008 m_free(c->remotehost);
1007 m_free(c->remoteport); 1009 m_free(c->remoteport);
1010 m_free(c->errstring);
1008 m_free(c); 1011 m_free(c);
1009 1012
1010 if (iter) { 1013 if (iter) {
1011 list_remove(iter); 1014 list_remove(iter);
1012 } 1015 }
1013 } 1016 }
1014 1017
1015 static int connect_try_next(struct dropbear_progress_connection *c) { 1018 static void cancel_callback(int result, int sock, void* UNUSED(data), const char* UNUSED(errstring)) {
1019 if (result == DROPBEAR_SUCCESS)
1020 {
1021 m_close(sock);
1022 }
1023 }
1024
1025 void cancel_connect(struct dropbear_progress_connection *c) {
1026 c->cb = cancel_callback;
1027 c->cb_data = NULL;
1028 }
1029
1030 static void connect_try_next(struct dropbear_progress_connection *c) {
1016 int err = EADDRNOTAVAIL; 1031 int err = EADDRNOTAVAIL;
1017 struct addrinfo *r; 1032 struct addrinfo *r;
1018 1033
1019 if (!c->res_iter) { 1034 if (!c->res_iter) {
1020 return DROPBEAR_FAILURE; 1035 return;
1021 } 1036 }
1022 1037
1023 for (r = c->res_iter; r; r = r->ai_next) 1038 for (r = c->res_iter; r; r = r->ai_next)
1024 { 1039 {
1025 assert(c->sock == -1); 1040 assert(c->sock == -1);
1028 if (c->sock < 0) { 1043 if (c->sock < 0) {
1029 err = errno; 1044 err = errno;
1030 continue; 1045 continue;
1031 } 1046 }
1032 1047
1048 ses.maxfd = MAX(ses.maxfd, c->sock);
1033 setnonblocking(c->sock); 1049 setnonblocking(c->sock);
1034 1050
1035 #if defined(__linux__) && defined(TCP_DEFER_ACCEPT) 1051 #if defined(__linux__) && defined(TCP_DEFER_ACCEPT)
1036 set_piggyback_ack(sock); 1052 set_piggyback_ack(sock);
1037 #endif 1053 #endif
1058 } 1074 }
1059 1075
1060 if (c->sock >= 0 || (errno == EINPROGRESS)) { 1076 if (c->sock >= 0 || (errno == EINPROGRESS)) {
1061 /* Success */ 1077 /* Success */
1062 set_sock_nodelay(c->sock); 1078 set_sock_nodelay(c->sock);
1063 return DROPBEAR_SUCCESS; 1079 return;
1064 } else { 1080 } else {
1081 if (!c->res_iter)
1082 {
1083
1084 }
1065 /* XXX - returning error message through */ 1085 /* XXX - returning error message through */
1066 #if 0 1086 #if 0
1067 /* Failed */ 1087 /* Failed */
1068 if (errstring != NULL && *errstring == NULL) { 1088 if (errstring != NULL && *errstring == NULL) {
1069 int len; 1089 int len;
1071 *errstring = (char*)m_malloc(len); 1091 *errstring = (char*)m_malloc(len);
1072 snprintf(*errstring, len, "Error connecting: %s", strerror(err)); 1092 snprintf(*errstring, len, "Error connecting: %s", strerror(err));
1073 } 1093 }
1074 TRACE(("Error connecting: %s", strerror(err))) 1094 TRACE(("Error connecting: %s", strerror(err)))
1075 #endif 1095 #endif
1076 return DROPBEAR_FAILURE; 1096 }
1077 } 1097 }
1078 } 1098
1079 1099 /* Connect via TCP to a host. */
1080 /* Connect via TCP to a host. Connection will try ipv4 or ipv6, will
1081 * return immediately if nonblocking is set. On failure, if errstring
1082 * wasn't null, it will be a newly malloced error message */
1083
1084 /* TODO: maxfd */
1085 struct dropbear_progress_connection *connect_remote(const char* remotehost, const char* remoteport, 1100 struct dropbear_progress_connection *connect_remote(const char* remotehost, const char* remoteport,
1086 connect_callback cb, void* cb_data) 1101 connect_callback cb, void* cb_data)
1087 { 1102 {
1088 struct dropbear_progress_connection *c = NULL; 1103 struct dropbear_progress_connection *c = NULL;
1089 int err; 1104 int err;
1094 c->remoteport = m_strdup(remoteport); 1109 c->remoteport = m_strdup(remoteport);
1095 c->sock = -1; 1110 c->sock = -1;
1096 c->cb = cb; 1111 c->cb = cb;
1097 c->cb_data = cb_data; 1112 c->cb_data = cb_data;
1098 1113
1114 list_append(&ses.conn_pending, c);
1115
1099 memset(&hints, 0, sizeof(hints)); 1116 memset(&hints, 0, sizeof(hints));
1100 hints.ai_socktype = SOCK_STREAM; 1117 hints.ai_socktype = SOCK_STREAM;
1101 hints.ai_family = PF_UNSPEC; 1118 hints.ai_family = PF_UNSPEC;
1102 1119
1103 err = getaddrinfo(remotehost, remoteport, &hints, &c->res); 1120 err = getaddrinfo(remotehost, remoteport, &hints, &c->res);
1104 if (err) { 1121 if (err) {
1105 int len; 1122 int len;
1106 char *errstring;
1107 len = 100 + strlen(gai_strerror(err)); 1123 len = 100 + strlen(gai_strerror(err));
1108 errstring = (char*)m_malloc(len); 1124 c->errstring = (char*)m_malloc(len);
1109 snprintf(errstring, len, "Error resolving '%s' port '%s'. %s", 1125 snprintf(c->errstring, len, "Error resolving '%s' port '%s'. %s",
1110 remotehost, remoteport, gai_strerror(err)); 1126 remotehost, remoteport, gai_strerror(err));
1111 c->cb(DROPBEAR_FAILURE, -1, c->cb_data, errstring);
1112 m_free(errstring);
1113 TRACE(("Error resolving: %s", gai_strerror(err))) 1127 TRACE(("Error resolving: %s", gai_strerror(err)))
1114 remove_connect(c, NULL);
1115 return NULL; 1128 return NULL;
1116 } 1129 }
1117 1130
1118 c->res_iter = c->res; 1131 c->res_iter = c->res;
1119 1132
1120 if (connect_try_next(c) == DROPBEAR_FAILURE) { 1133 /* Set one going */
1121 /* Should not happen - getaddrinfo() should return failure if there are no addresses */ 1134 connect_try_next(c);
1122 c->cb(DROPBEAR_FAILURE, -1, c->cb_data, "No address to try");
1123 TRACE(("leave handle_connect_fds - failed"))
1124 remove_connect(c, NULL);
1125 return NULL;
1126 }
1127
1128 list_append(&ses.conn_pending, c);
1129 1135
1130 return c; 1136 return c;
1131 } 1137 }
1132 1138
1133 1139
1134 void set_connect_fds(fd_set *writefd) { 1140 void set_connect_fds(fd_set *writefd) {
1135 m_list_elem *iter; 1141 m_list_elem *iter;
1136 TRACE(("enter handle_connect_fds")) 1142 TRACE(("enter handle_connect_fds"))
1137 for (iter = ses.conn_pending.first; iter; iter = iter->next) { 1143 for (iter = ses.conn_pending.first; iter; iter = iter->next) {
1138 struct dropbear_progress_connection *c = iter->item; 1144 struct dropbear_progress_connection *c = iter->item;
1145 /* Set one going */
1146 while (c->res_iter && c->sock < 0)
1147 {
1148 connect_try_next(c);
1149 }
1139 if (c->sock >= 0) { 1150 if (c->sock >= 0) {
1140 FD_SET(c->sock, writefd); 1151 FD_SET(c->sock, writefd);
1141 } 1152 } else {
1142 else 1153 m_list_elem *remove_iter;
1143 { 1154 /* Final failure */
1144 1155 if (!c->errstring) {
1156 c->errstring = m_strdup("unexpected failure");
1157 }
1158 c->cb(DROPBEAR_FAILURE, -1, c->cb_data, c->errstring);
1159 /* Safely remove without invalidating iter */
1160 remove_iter = iter;
1161 iter = iter->prev;
1162 remove_connect(c, remove_iter);
1145 } 1163 }
1146 } 1164 }
1147 } 1165 }
1148 1166
1149 void handle_connect_fds(fd_set *writefd) { 1167 void handle_connect_fds(fd_set *writefd) {
1160 1178
1161 TRACE(("handling %s port %s socket %d", c->remotehost, c->remoteport, c->sock)); 1179 TRACE(("handling %s port %s socket %d", c->remotehost, c->remoteport, c->sock));
1162 1180
1163 if (getsockopt(c->sock, SOL_SOCKET, SO_ERROR, &val, &vallen) != 0) { 1181 if (getsockopt(c->sock, SOL_SOCKET, SO_ERROR, &val, &vallen) != 0) {
1164 TRACE(("handle_connect_fds getsockopt(%d) SO_ERROR failed: %s", c->sock, strerror(errno))) 1182 TRACE(("handle_connect_fds getsockopt(%d) SO_ERROR failed: %s", c->sock, strerror(errno)))
1183 /* This isn't expected to happen - Unix has surprises though, continue gracefully. */
1184 m_close(c->sock);
1185 c->sock = -1;
1165 } else if (val != 0) { 1186 } else if (val != 0) {
1166 /* Connect failed */ 1187 /* Connect failed */
1167 TRACE(("connect to %s port %s failed.", c->remotehost, c->remoteport)) 1188 TRACE(("connect to %s port %s failed.", c->remotehost, c->remoteport))
1168 m_close(c->sock); 1189 m_close(c->sock);
1169 c->sock = -1; 1190 c->sock = -1;
1170 1191
1171 if (connect_try_next(c) == DROPBEAR_FAILURE) { 1192 m_free(c->errstring);
1172 c->cb(DROPBEAR_FAILURE, -1, c->cb_data, strerror(val)); 1193 c->errstring = strerror(val);
1173 TRACE(("leave handle_connect_fds - failed")) 1194 } else {
1174 remove_connect(c, iter); 1195 /* New connection has been established */
1175 /* Must return here - remove_connect() invalidates iter */ 1196 c->cb(DROPBEAR_SUCCESS, c->sock, c->cb_data, NULL);
1176 return; 1197 remove_connect(c, iter);
1177 } else { 1198 TRACE(("leave handle_connect_fds - success"))
1178 /* new connection try was successfuly started, will be finished by a 1199 /* Must return here - remove_connect() invalidates iter */
1179 later call to handle_connect_fds() */ 1200 return;
1180 TRACE(("leave handle_connect_fds - new try")) 1201 }
1181 continue;
1182 }
1183 }
1184 /* New connection has been established */
1185 c->cb(DROPBEAR_SUCCESS, c->sock, c->cb_data, "");
1186 remove_connect(c, iter);
1187 TRACE(("leave handle_connect_fds - success"))
1188 /* Must return here - remove_connect() invalidates iter */
1189 return;
1190 } 1202 }
1191 TRACE(("leave handle_connect_fds - end iter")) 1203 TRACE(("leave handle_connect_fds - end iter"))
1192 } 1204 }