Mercurial > dropbear
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 } |