multi: forbid curl_easy_pause from within multi socket callback
No binary (build failed)
—
(log yok)
| @@ -28,8 +28,8 @@ CURLcode curl_easy_pause(CURL *handle, int action); | |
| Using this function, you can explicitly mark a running connection to get | |
| paused, and you can unpause a connection that was previously paused. Unlike | |
| - | most other libcurl functions, curl_easy_pause(3) can be used from within |
| - | callbacks. |
| + | most other libcurl functions, curl_easy_pause(3) can be used from within all |
| + | callbacks except the socket callback set with CURLMOPT_SOCKETFUNCTION(3). |
| A connection can be paused by using this function or by letting the read or | |
| the write callbacks return the proper return code (*CURL_READFUNC_PAUSE* and | |
| @@ -1138,18 +1138,19 @@ void curl_easy_reset(CURL *curl) | |
| CURLcode curl_easy_pause(CURL *curl, int action) | |
| { | |
| CURLcode result = CURLE_OK; | |
| - | bool recursive = FALSE; |
| bool changed = FALSE; | |
| struct Curl_easy *data = curl; | |
| bool recv_paused, recv_paused_new; | |
| bool send_paused, send_paused_new; | |
| + | uint8_t in_c; |
| if(!GOOD_EASY_HANDLE(data) || !data->conn) | |
| /* crazy input, do not continue */ | |
| return CURLE_BAD_FUNCTION_ARGUMENT; | |
| - | if(Curl_is_in_callback(data)) |
| - | recursive = TRUE; |
| + | in_c = Curl_is_in_callback(data); |
| + | if(in_c == IN_CALLBACK_FORBID_EASY_PAUSE) |
| + | return CURLE_RECURSIVE_API_CALL; |
| recv_paused = Curl_xfer_recv_is_paused(data); | |
| recv_paused_new = (action & CURLPAUSE_RECV); | |
| @@ -1188,10 +1189,10 @@ CURLcode curl_easy_pause(CURL *curl, int action) | |
| if(Curl_multi_ev_assess_xfer(data->multi, data) && !result) | |
| result = CURLE_ABORTED_BY_CALLBACK; | |
| - | if(recursive) |
| + | if(in_c) |
| /* this might have called a callback recursively which might have set this | |
| to false again on exit */ | |
| - | Curl_set_in_callback(data, TRUE); |
| + | Curl_set_in_callback(data, in_c); |
| return result; | |
| } | |
| @@ -3906,15 +3906,16 @@ static void process_pending_handles(struct Curl_multi *multi) | |
| } | |
| } | |
| - | void Curl_set_in_callback(struct Curl_easy *data, bool value) |
| + | /* 'value' used to be a boolean but can now also contain more info */ |
| + | void Curl_set_in_callback(struct Curl_easy *data, uint8_t value) |
| { | |
| if(data && data->multi) | |
| data->multi->in_callback = value; | |
| } | |
| - | bool Curl_is_in_callback(struct Curl_easy *data) |
| + | uint8_t Curl_is_in_callback(struct Curl_easy *data) |
| { | |
| - | return data && data->multi && data->multi->in_callback; |
| + | return (data && data->multi) ? data->multi->in_callback : IN_CALLBACK_NO; |
| } | |
| unsigned int Curl_multi_max_concurrent_streams(struct Curl_multi *multi) | |
| @@ -34,8 +34,7 @@ | |
| #include "uint-spbset.h" | |
| #include "multihandle.h" | |
| - | |
| - | static void mev_in_callback(struct Curl_multi *multi, bool value) |
| + | static void mev_in_callback(struct Curl_multi *multi, uint8_t value) |
| { | |
| multi->in_callback = value; | |
| } | |
| @@ -209,12 +208,10 @@ static CURLMcode mev_forget_socket(struct Curl_multi *multi, | |
| if(entry->announced && multi->socket_cb) { | |
| NOVERBOSE((void)cause); | |
| CURL_TRC_M(data, "ev %s, call(fd=%" FMT_SOCKET_T ", ev=REMOVE)", cause, s); | |
| - | mev_in_callback(multi, TRUE); |
| + | mev_in_callback(multi, IN_CALLBACK_FORBID_EASY_PAUSE); |
| rc = multi->socket_cb(data, s, CURL_POLL_REMOVE, | |
| multi->socket_userp, entry->user_data); | |
| - | mev_in_callback(multi, FALSE); |
| - | /* curl_easy_pause() is documented as callable from any callback; it |
| - | * re-enters mev_assess() which may free this 'entry'. Re-fetch. */ |
| + | mev_in_callback(multi, IN_CALLBACK_NO); |
| entry = mev_sh_entry_get(&multi->ev.sh_entries, s); | |
| if(entry) | |
| entry->announced = FALSE; | |
| @@ -285,10 +282,10 @@ static CURLMcode mev_sh_entry_update(struct Curl_multi *multi, | |
| CURL_TRC_M(data, "ev update call(fd=%" FMT_SOCKET_T ", ev=%s%s)", | |
| s, (comboaction & CURL_POLL_IN) ? "IN" : "", | |
| (comboaction & CURL_POLL_OUT) ? "OUT" : ""); | |
| - | mev_in_callback(multi, TRUE); |
| + | mev_in_callback(multi, IN_CALLBACK_FORBID_EASY_PAUSE); |
| rc = multi->socket_cb(data, s, comboaction, multi->socket_userp, | |
| entry->user_data); | |
| - | mev_in_callback(multi, FALSE); |
| + | mev_in_callback(multi, IN_CALLBACK_NO); |
| if(rc == -1) { | |
| multi->dead = TRUE; | |
| return CURLM_ABORTED_BY_CALLBACK; | |
| @@ -45,6 +45,10 @@ struct Curl_message { | |
| struct CURLMsg extmsg; | |
| }; | |
| + | #define IN_CALLBACK_NO 0 |
| + | #define IN_CALLBACK_YES 1 |
| + | #define IN_CALLBACK_FORBID_EASY_PAUSE 2 |
| + | |
| /* NOTE: if you add a state here, add the name to the statenames[] array | |
| * in curl_trc.c as well! | |
| */ | |
| @@ -179,10 +183,10 @@ struct Curl_multi { | |
| #endif | |
| uint32_t last_pending_mid; /* mid of last pending transfer rescheduled */ | |
| uint32_t last_resolv_id; /* id of the last DNS resolve operation */ | |
| + | uint8_t in_callback; /* conditions for executing in callbacks */ |
| BIT(ipv6_works); | |
| BIT(multiplexing); /* multiplexing wanted */ | |
| BIT(recheckstate); /* see Curl_multi_connchanged */ | |
| - | BIT(in_callback); /* true while executing a callback */ |
| BIT(in_ntfy_callback); /* true while dispatching notifications */ | |
| #ifdef USE_OPENSSL | |
| BIT(ssl_seeded); | |
| @@ -37,8 +37,8 @@ void Curl_attach_connection(struct Curl_easy *data, | |
| struct connectdata *conn); | |
| void Curl_detach_connection(struct Curl_easy *data); | |
| bool Curl_multiplex_wanted(const struct Curl_multi *multi); | |
| - | void Curl_set_in_callback(struct Curl_easy *data, bool value); |
| - | bool Curl_is_in_callback(struct Curl_easy *data); |
| + | void Curl_set_in_callback(struct Curl_easy *data, uint8_t value); |
| + | uint8_t Curl_is_in_callback(struct Curl_easy *data); |
| CURLcode Curl_preconnect(struct Curl_easy *data); | |
| bool Curl_is_connecting(struct Curl_easy *data); | |
| @@ -147,6 +147,7 @@ static int t758_curlSocketCallback(CURL *curl, curl_socket_t s, int action, | |
| void *userp, void *socketp) | |
| { | |
| struct t758_ReadWriteSockets *sockets = userp; | |
| + | CURLcode result; |
| (void)curl; | |
| (void)socketp; | |
| @@ -158,6 +159,14 @@ static int t758_curlSocketCallback(CURL *curl, curl_socket_t s, int action, | |
| return -1; | |
| } | |
| + | /* Pause is forbidden in this callback. This also returns |
| + | CURLE_BAD_FUNCTION_ARGUMENT before the connection has been setup. */ |
| + | result = curl_easy_pause(curl, CURLPAUSE_ALL); |
| + | if(!result) { |
| + | t758_msg("<- curl_easy_pause should return error!"); |
| + | return -1; |
| + | } |
| + | |
| if(action == CURL_POLL_IN || action == CURL_POLL_INOUT) | |
| if(t758_addFd(&sockets->read, s, "read")) | |
| return -1; /* bail out */ | |