Changeset 4392 for pjproject/branches/1.x/pjlib/src/pj/ssl_sock_ossl.c
- Timestamp:
- Feb 27, 2013 11:42:24 AM (12 years ago)
- Location:
- pjproject/branches/1.x
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/branches/1.x
- Property svn:mergeinfo changed
/pjproject/trunk merged: 4247-4249
- Property svn:mergeinfo changed
-
pjproject/branches/1.x/pjlib/src/pj/ssl_sock_ossl.c
r4376 r4392 106 106 107 107 /* 108 * Structure of SSL socket write buffer.108 * Structure of SSL socket write data. 109 109 */ 110 110 typedef struct write_data_t { 111 PJ_DECL_LIST_MEMBER(struct write_data_t); 111 112 pj_ioqueue_op_key_t key; 112 113 pj_size_t record_len; … … 122 123 123 124 /* 124 * Structure of SSL socket write state.125 */ 126 typedef struct write_state_t {125 * Structure of SSL socket write buffer (circular buffer). 126 */ 127 typedef struct send_buf_t { 127 128 char *buf; 128 129 pj_size_t max_len; 129 130 char *start; 130 131 pj_size_t len; 131 write_data_t *last_data; 132 } write_state_t; 133 134 /* 135 * Structure of write data pending. 136 */ 137 typedef struct write_pending_t { 138 PJ_DECL_LIST_MEMBER(struct write_pending_t); 139 write_data_t data; 140 } write_pending_t; 132 } send_buf_t; 141 133 142 134 /* … … 174 166 read_data_t *ssock_rbuf; 175 167 176 write_state_t write_state; 177 write_pending_t write_pending; 178 write_pending_t write_pending_empty; 179 pj_lock_t *write_mutex; /* protect write BIO and write_state */ 168 write_data_t write_pending;/* list of pending write to OpenSSL */ 169 write_data_t write_pending_empty; /* cache for write_pending */ 170 pj_bool_t flushing_write_pend; /* flag of flushing is ongoing*/ 171 send_buf_t send_buf; 172 write_data_t send_pending; /* list of pending write to network */ 173 pj_lock_t *write_mutex; /* protect write BIO and send_buf */ 180 174 181 175 SSL_CTX *ossl_ctx; … … 198 192 199 193 194 static write_data_t* alloc_send_data(pj_ssl_sock_t *ssock, pj_size_t len); 195 static void free_send_data(pj_ssl_sock_t *ssock, write_data_t *wdata); 200 196 static pj_status_t flush_delayed_send(pj_ssl_sock_t *ssock); 201 197 … … 1055 1051 } 1056 1052 1053 static write_data_t* alloc_send_data(pj_ssl_sock_t *ssock, pj_size_t len) 1054 { 1055 send_buf_t *send_buf = &ssock->send_buf; 1056 pj_size_t avail_len, skipped_len = 0; 1057 char *reg1, *reg2; 1058 pj_size_t reg1_len, reg2_len; 1059 write_data_t *p; 1060 1061 /* Check buffer availability */ 1062 avail_len = send_buf->max_len - send_buf->len; 1063 if (avail_len < len) 1064 return NULL; 1065 1066 /* If buffer empty, reset start pointer and return it */ 1067 if (send_buf->len == 0) { 1068 send_buf->start = send_buf->buf; 1069 send_buf->len = len; 1070 p = (write_data_t*)send_buf->start; 1071 goto init_send_data; 1072 } 1073 1074 /* Free space may be wrapped/splitted into two regions, so let's 1075 * analyze them if any region can hold the write data. 1076 */ 1077 reg1 = send_buf->start + send_buf->len; 1078 if (reg1 >= send_buf->buf + send_buf->max_len) 1079 reg1 -= send_buf->max_len; 1080 reg1_len = send_buf->max_len - send_buf->len; 1081 if (reg1 + reg1_len > send_buf->buf + send_buf->max_len) { 1082 reg1_len = send_buf->buf + send_buf->max_len - reg1; 1083 reg2 = send_buf->buf; 1084 reg2_len = send_buf->start - send_buf->buf; 1085 } else { 1086 reg2 = NULL; 1087 reg2_len = 0; 1088 } 1089 1090 /* More buffer availability check, note that the write data must be in 1091 * a contigue buffer. 1092 */ 1093 avail_len = PJ_MAX(reg1_len, reg2_len); 1094 if (avail_len < len) 1095 return NULL; 1096 1097 /* Get the data slot */ 1098 if (reg1_len >= len) { 1099 p = (write_data_t*)reg1; 1100 } else { 1101 p = (write_data_t*)reg2; 1102 skipped_len = reg1_len; 1103 } 1104 1105 /* Update buffer length */ 1106 send_buf->len += len + skipped_len; 1107 1108 init_send_data: 1109 /* Init the new send data */ 1110 pj_bzero(p, sizeof(*p)); 1111 pj_list_init(p); 1112 pj_list_push_back(&ssock->send_pending, p); 1113 1114 return p; 1115 } 1116 1117 static void free_send_data(pj_ssl_sock_t *ssock, write_data_t *wdata) 1118 { 1119 send_buf_t *buf = &ssock->send_buf; 1120 write_data_t *spl = &ssock->send_pending; 1121 1122 pj_assert(!pj_list_empty(&ssock->send_pending)); 1123 1124 /* Free slot from the buffer */ 1125 if (spl->next == wdata && spl->prev == wdata) { 1126 /* This is the only data, reset the buffer */ 1127 buf->start = buf->buf; 1128 buf->len = 0; 1129 } else if (spl->next == wdata) { 1130 /* This is the first data, shift start pointer of the buffer and 1131 * adjust the buffer length. 1132 */ 1133 buf->start = (char*)wdata->next; 1134 if (wdata->next > wdata) { 1135 buf->len -= ((char*)wdata->next - buf->start); 1136 } else { 1137 /* Overlapped */ 1138 unsigned right_len, left_len; 1139 right_len = buf->buf + buf->max_len - (char*)wdata; 1140 left_len = (char*)wdata->next - buf->buf; 1141 buf->len -= (right_len + left_len); 1142 } 1143 } else if (spl->prev == wdata) { 1144 /* This is the last data, just adjust the buffer length */ 1145 if (wdata->prev < wdata) { 1146 unsigned jump_len; 1147 jump_len = (char*)wdata - 1148 ((char*)wdata->prev + wdata->prev->record_len); 1149 buf->len -= (wdata->record_len + jump_len); 1150 } else { 1151 /* Overlapped */ 1152 unsigned right_len, left_len; 1153 right_len = buf->buf + buf->max_len - 1154 ((char*)wdata->prev + wdata->prev->record_len); 1155 left_len = (char*)wdata + wdata->record_len - buf->buf; 1156 buf->len -= (right_len + left_len); 1157 } 1158 } 1159 /* For data in the middle buffer, just do nothing on the buffer. The slot 1160 * will be freed later when freeing the first/last data. 1161 */ 1162 1163 /* Remove the data from send pending list */ 1164 pj_list_erase(wdata); 1165 } 1166 1167 #if 0 1168 /* Just for testing send buffer alloc/free */ 1169 #include <pj/rand.h> 1170 pj_status_t pj_ssl_sock_ossl_test_send_buf(pj_pool_t *pool) 1171 { 1172 enum { MAX_CHUNK_NUM = 20 }; 1173 unsigned chunk_size, chunk_cnt, i; 1174 write_data_t *wdata[MAX_CHUNK_NUM] = {0}; 1175 pj_time_val now; 1176 pj_ssl_sock_t *ssock = NULL; 1177 pj_ssl_sock_param param; 1178 pj_status_t status; 1179 1180 pj_gettimeofday(&now); 1181 pj_srand((unsigned)now.sec); 1182 1183 pj_ssl_sock_param_default(¶m); 1184 status = pj_ssl_sock_create(pool, ¶m, &ssock); 1185 if (status != PJ_SUCCESS) { 1186 return status; 1187 } 1188 1189 if (ssock->send_buf.max_len == 0) { 1190 ssock->send_buf.buf = (char*) 1191 pj_pool_alloc(ssock->pool, 1192 ssock->param.send_buffer_size); 1193 ssock->send_buf.max_len = ssock->param.send_buffer_size; 1194 ssock->send_buf.start = ssock->send_buf.buf; 1195 ssock->send_buf.len = 0; 1196 } 1197 1198 chunk_size = ssock->param.send_buffer_size / MAX_CHUNK_NUM / 2; 1199 chunk_cnt = 0; 1200 for (i = 0; i < MAX_CHUNK_NUM; i++) { 1201 wdata[i] = alloc_send_data(ssock, pj_rand() % chunk_size + 321); 1202 if (wdata[i]) 1203 chunk_cnt++; 1204 else 1205 break; 1206 } 1207 1208 while (chunk_cnt) { 1209 i = pj_rand() % MAX_CHUNK_NUM; 1210 if (wdata[i]) { 1211 free_send_data(ssock, wdata[i]); 1212 wdata[i] = NULL; 1213 chunk_cnt--; 1214 } 1215 } 1216 1217 if (ssock->send_buf.len != 0) 1218 status = PJ_EBUG; 1219 1220 pj_ssl_sock_close(ssock); 1221 return status; 1222 } 1223 #endif 1224 1225 1057 1226 /* Flush write BIO to network socket. Note that any access to write BIO 1058 1227 * MUST be serialized, so mutex protection must cover any call to OpenSSL … … 1068 1237 char *data; 1069 1238 pj_ssize_t len; 1070 1071 write_state_t *write_st = &ssock->write_state;1072 1239 write_data_t *wdata; 1073 pj_size_t avail_len, needed_len, skipped_len = 0;1240 pj_size_t needed_len; 1074 1241 pj_status_t status; 1075 1242 1243 pj_lock_acquire(ssock->write_mutex); 1244 1076 1245 /* Check if there is data in write BIO, flush it if any */ 1077 if (!BIO_pending(ssock->ossl_wbio)) 1246 if (!BIO_pending(ssock->ossl_wbio)) { 1247 pj_lock_release(ssock->write_mutex); 1078 1248 return PJ_SUCCESS; 1249 } 1079 1250 1080 1251 /* Get data and its length */ 1081 1252 len = BIO_get_mem_data(ssock->ossl_wbio, &data); 1082 if (len == 0) 1253 if (len == 0) { 1254 pj_lock_release(ssock->write_mutex); 1083 1255 return PJ_SUCCESS; 1256 } 1084 1257 1085 1258 /* Calculate buffer size needed, and align it to 8 */ … … 1087 1260 needed_len = ((needed_len + 7) >> 3) << 3; 1088 1261 1089 /* Check buffer availability */ 1090 avail_len = write_st->max_len - write_st->len; 1091 if (avail_len < needed_len) 1262 /* Allocate buffer for send data */ 1263 wdata = alloc_send_data(ssock, needed_len); 1264 if (wdata == NULL) { 1265 pj_lock_release(ssock->write_mutex); 1092 1266 return PJ_ENOMEM; 1093 1094 /* More buffer availability check, note that the write data must be in 1095 * a contigue buffer. 1096 */ 1097 if (write_st->len == 0) { 1098 1099 write_st->start = write_st->buf; 1100 wdata = (write_data_t*)write_st->start; 1101 1102 } else { 1103 1104 char *reg1, *reg2; 1105 pj_size_t reg1_len, reg2_len; 1106 1107 /* Unused slots may be wrapped/splitted into two regions, so let's 1108 * analyze them if any region can hold the write data. 1109 */ 1110 reg1 = write_st->start + write_st->len; 1111 if (reg1 >= write_st->buf + write_st->max_len) 1112 reg1 -= write_st->max_len; 1113 reg1_len = write_st->max_len - write_st->len; 1114 if (reg1 + reg1_len > write_st->buf + write_st->max_len) { 1115 reg1_len = write_st->buf + write_st->max_len - reg1; 1116 reg2 = write_st->buf; 1117 reg2_len = write_st->start - write_st->buf; 1118 } else { 1119 reg2 = NULL; 1120 reg2_len = 0; 1121 } 1122 avail_len = PJ_MAX(reg1_len, reg2_len); 1123 if (avail_len < needed_len) 1124 return PJ_ENOMEM; 1125 1126 /* Get write data pointer and update buffer length */ 1127 if (reg1_len >= needed_len) { 1128 wdata = (write_data_t*)reg1; 1129 } else { 1130 wdata = (write_data_t*)reg2; 1131 /* Unused slot in region 1 is skipped as current write data 1132 * doesn't fit it. 1133 */ 1134 skipped_len = reg1_len; 1135 } 1136 } 1137 1138 /* Copy the data and set its properties into the buffer */ 1139 pj_bzero(wdata, sizeof(write_data_t)); 1267 } 1268 1269 /* Copy the data and set its properties into the send data */ 1270 pj_ioqueue_op_key_init(&wdata->key, sizeof(pj_ioqueue_op_key_t)); 1271 wdata->key.user_data = wdata; 1140 1272 wdata->app_key = send_key; 1141 1273 wdata->record_len = needed_len; … … 1144 1276 wdata->flags = flags; 1145 1277 pj_memcpy(&wdata->data, data, len); 1278 1279 /* Reset write BIO */ 1280 BIO_reset(ssock->ossl_wbio); 1281 1282 /* Ticket #1573: Don't hold mutex while calling PJLIB socket send(). */ 1283 pj_lock_release(ssock->write_mutex); 1146 1284 1147 1285 /* Send it */ … … 1158 1296 } 1159 1297 1160 /* Oh no, EWOULDBLOCK! */ 1161 if (status == PJ_STATUS_FROM_OS(OSERR_EWOULDBLOCK)) { 1162 /* Just return PJ_SUCCESS here, the pending data will be sent in next 1163 * call of this function since the data is still stored in write BIO. 1298 if (status != PJ_EPENDING) { 1299 /* When the sending is not pending, remove the wdata from send 1300 * pending list. 1164 1301 */ 1165 return PJ_SUCCESS; 1166 } 1167 1168 /* Reset write BIO after flushed */ 1169 BIO_reset(ssock->ossl_wbio); 1170 1171 if (status == PJ_EPENDING) { 1172 /* Update write state */ 1173 pj_assert(skipped_len==0 || write_st->last_data); 1174 write_st->len += needed_len + skipped_len; 1175 if (write_st->last_data) 1176 write_st->last_data->record_len += skipped_len; 1177 write_st->last_data = wdata; 1302 pj_lock_acquire(ssock->write_mutex); 1303 free_send_data(ssock, wdata); 1304 pj_lock_release(ssock->write_mutex); 1178 1305 } 1179 1306 … … 1214 1341 int err; 1215 1342 1343 /* Perform SSL handshake */ 1216 1344 pj_lock_acquire(ssock->write_mutex); 1217 1218 /* Perform SSL handshake */1219 1345 err = SSL_do_handshake(ssock->ossl_ssl); 1346 pj_lock_release(ssock->write_mutex); 1220 1347 1221 1348 /* SSL_do_handshake() may put some pending data into SSL write BIO, … … 1224 1351 status = flush_write_bio(ssock, &ssock->handshake_op_key, 0, 0); 1225 1352 if (status != PJ_SUCCESS && status != PJ_EPENDING) { 1226 pj_lock_release(ssock->write_mutex);1227 1353 return status; 1228 1354 } 1229 1230 pj_lock_release(ssock->write_mutex);1231 1355 1232 1356 if (err < 0) { … … 1357 1481 update_certs_info(ssock); 1358 1482 1359 pj_lock_acquire(ssock->write_mutex); 1483 // Ticket #1573: Don't hold mutex while calling 1484 // PJLIB socket send(). 1485 //pj_lock_acquire(ssock->write_mutex); 1360 1486 status = flush_delayed_send(ssock); 1361 pj_lock_release(ssock->write_mutex); 1487 //pj_lock_release(ssock->write_mutex); 1488 1489 /* If flushing is ongoing, treat it as success */ 1490 if (status == PJ_EBUSY) 1491 status = PJ_SUCCESS; 1362 1492 1363 1493 if (status != PJ_SUCCESS && status != PJ_EPENDING) { … … 1419 1549 } else if (send_key != &ssock->handshake_op_key) { 1420 1550 /* Some data has been sent, notify application */ 1421 write_data_t *wdata = (write_data_t*)send_key ;1551 write_data_t *wdata = (write_data_t*)send_key->user_data; 1422 1552 if (ssock->param.cb.on_data_sent) { 1423 1553 pj_bool_t ret; … … 1432 1562 /* Update write buffer state */ 1433 1563 pj_lock_acquire(ssock->write_mutex); 1434 ssock->write_state.start += wdata->record_len; 1435 ssock->write_state.len -= wdata->record_len; 1436 if (ssock->write_state.last_data == wdata) { 1437 pj_assert(ssock->write_state.len == 0); 1438 ssock->write_state.last_data = NULL; 1439 } 1564 free_send_data(ssock, wdata); 1440 1565 pj_lock_release(ssock->write_mutex); 1441 1566 … … 1548 1673 1549 1674 /* Prepare write/send state */ 1550 pj_assert(ssock-> write_state.max_len == 0);1551 ssock-> write_state.buf = (char*)1552 1553 1554 ssock-> write_state.max_len = ssock->param.send_buffer_size;1555 ssock-> write_state.start = ssock->write_state.buf;1556 ssock-> write_state.len = 0;1675 pj_assert(ssock->send_buf.max_len == 0); 1676 ssock->send_buf.buf = (char*) 1677 pj_pool_alloc(ssock->pool, 1678 ssock->param.send_buffer_size); 1679 ssock->send_buf.max_len = ssock->param.send_buffer_size; 1680 ssock->send_buf.start = ssock->send_buf.buf; 1681 ssock->send_buf.len = 0; 1557 1682 1558 1683 /* Start handshake timer */ … … 1627 1752 1628 1753 /* Prepare write/send state */ 1629 pj_assert(ssock-> write_state.max_len == 0);1630 ssock-> write_state.buf = (char*)1754 pj_assert(ssock->send_buf.max_len == 0); 1755 ssock->send_buf.buf = (char*) 1631 1756 pj_pool_alloc(ssock->pool, 1632 1757 ssock->param.send_buffer_size); 1633 ssock-> write_state.max_len = ssock->param.send_buffer_size;1634 ssock-> write_state.start = ssock->write_state.buf;1635 ssock-> write_state.len = 0;1758 ssock->send_buf.max_len = ssock->param.send_buffer_size; 1759 ssock->send_buf.start = ssock->send_buf.buf; 1760 ssock->send_buf.len = 0; 1636 1761 1637 1762 #ifdef SSL_set_tlsext_host_name … … 1806 1931 pj_list_init(&ssock->write_pending); 1807 1932 pj_list_init(&ssock->write_pending_empty); 1933 pj_list_init(&ssock->send_pending); 1808 1934 pj_timer_entry_init(&ssock->timer, 0, ssock, &on_timer); 1935 pj_ioqueue_op_key_init(&ssock->handshake_op_key, 1936 sizeof(pj_ioqueue_op_key_t)); 1809 1937 1810 1938 /* Create secure socket mutex */ … … 2039 2167 } 2040 2168 2041 /* Write plain data to SSL and flush write BIO. Note that accessing 2042 * write BIO must be serialized, so a call to this function must be 2043 * protected by write mutex of SSL socket. 2044 */ 2169 /* Write plain data to SSL and flush write BIO. */ 2045 2170 static pj_status_t ssl_write(pj_ssl_sock_t *ssock, 2046 2171 pj_ioqueue_op_key_t *send_key, … … 2057 2182 * until re-negotiation is completed. 2058 2183 */ 2184 pj_lock_acquire(ssock->write_mutex); 2059 2185 nwritten = SSL_write(ssock->ossl_ssl, data, size); 2186 pj_lock_release(ssock->write_mutex); 2060 2187 2061 2188 if (nwritten == size) { … … 2088 2215 } 2089 2216 2090 /* Flush delayed data sending in the write pending list. Note that accessing 2091 * write pending list must be serialized, so a call to this function must be 2092 * protected by write mutex of SSL socket. 2093 */ 2217 /* Flush delayed data sending in the write pending list. */ 2094 2218 static pj_status_t flush_delayed_send(pj_ssl_sock_t *ssock) 2095 2219 { 2220 /* Check for another ongoing flush */ 2221 if (ssock->flushing_write_pend) 2222 return PJ_EBUSY; 2223 2224 pj_lock_acquire(ssock->write_mutex); 2225 2226 /* Again, check for another ongoing flush */ 2227 if (ssock->flushing_write_pend) { 2228 pj_lock_release(ssock->write_mutex); 2229 return PJ_EBUSY; 2230 } 2231 2232 /* Set ongoing flush flag */ 2233 ssock->flushing_write_pend = PJ_TRUE; 2234 2096 2235 while (!pj_list_empty(&ssock->write_pending)) { 2097 write_ pending_t *wp;2236 write_data_t *wp; 2098 2237 pj_status_t status; 2099 2238 2100 2239 wp = ssock->write_pending.next; 2101 2240 2102 status = ssl_write(ssock, &wp->data.key, wp->data.data.ptr, 2103 wp->data.plain_data_len, wp->data.flags); 2104 if (status != PJ_SUCCESS) 2241 /* Ticket #1573: Don't hold mutex while calling socket send. */ 2242 pj_lock_release(ssock->write_mutex); 2243 2244 status = ssl_write(ssock, &wp->key, wp->data.ptr, 2245 wp->plain_data_len, wp->flags); 2246 if (status != PJ_SUCCESS) { 2247 /* Reset ongoing flush flag first. */ 2248 ssock->flushing_write_pend = PJ_FALSE; 2105 2249 return status; 2106 2250 } 2251 2252 pj_lock_acquire(ssock->write_mutex); 2107 2253 pj_list_erase(wp); 2108 2254 pj_list_push_back(&ssock->write_pending_empty, wp); 2109 2255 } 2110 2256 2257 /* Reset ongoing flush flag */ 2258 ssock->flushing_write_pend = PJ_FALSE; 2259 2260 pj_lock_release(ssock->write_mutex); 2261 2111 2262 return PJ_SUCCESS; 2112 2263 } 2113 2264 2114 /* Sending is delayed, push back the sending data into pending list. Note that 2115 * accessing write pending list must be serialized, so a call to this function 2116 * must be protected by write mutex of SSL socket. 2117 */ 2265 /* Sending is delayed, push back the sending data into pending list. */ 2118 2266 static pj_status_t delay_send (pj_ssl_sock_t *ssock, 2119 2267 pj_ioqueue_op_key_t *send_key, … … 2122 2270 unsigned flags) 2123 2271 { 2124 write_pending_t *wp; 2272 write_data_t *wp; 2273 2274 pj_lock_acquire(ssock->write_mutex); 2125 2275 2126 2276 /* Init write pending instance */ … … 2129 2279 pj_list_erase(wp); 2130 2280 } else { 2131 wp = PJ_POOL_ZALLOC_T(ssock->pool, write_ pending_t);2132 } 2133 2134 wp-> data.app_key = send_key;2135 wp-> data.plain_data_len = size;2136 wp->data. data.ptr = data;2137 wp-> data.flags = flags;2281 wp = PJ_POOL_ZALLOC_T(ssock->pool, write_data_t); 2282 } 2283 2284 wp->app_key = send_key; 2285 wp->plain_data_len = size; 2286 wp->data.ptr = data; 2287 wp->flags = flags; 2138 2288 2139 2289 pj_list_push_back(&ssock->write_pending, wp); 2290 2291 pj_lock_release(ssock->write_mutex); 2140 2292 2141 2293 /* Must return PJ_EPENDING */ … … 2157 2309 PJ_ASSERT_RETURN(ssock->ssl_state==SSL_STATE_ESTABLISHED, PJ_EINVALIDOP); 2158 2310 2159 pj_lock_acquire(ssock->write_mutex); 2311 // Ticket #1573: Don't hold mutex while calling PJLIB socket send(). 2312 //pj_lock_acquire(ssock->write_mutex); 2160 2313 2161 2314 /* Flush delayed send first. Sending data might be delayed when … … 2164 2317 status = flush_delayed_send(ssock); 2165 2318 if (status == PJ_EBUSY) { 2166 /* Re-negotiation is on progress, delay sending */2319 /* Re-negotiation or flushing is on progress, delay sending */ 2167 2320 status = delay_send(ssock, send_key, data, *size, flags); 2168 2321 goto on_return; … … 2179 2332 2180 2333 on_return: 2181 pj_lock_release(ssock->write_mutex);2334 //pj_lock_release(ssock->write_mutex); 2182 2335 return status; 2183 2336 }
Note: See TracChangeset
for help on using the changeset viewer.