Newer
Older
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
***************************************************************************/
#include "curl_setup.h"
#include "urldata.h"
#include "transfer.h"
#include "url.h"
#include "connect.h"
#include "progress.h"
#include "easyif.h"
#include "multiif.h"
#include "sendf.h"
#include "timeval.h"
#include "http.h"
#include "select.h"
#include "warnless.h"
#include "speedcheck.h"
#include "conncache.h"
#include "bundles.h"
#include "multihandle.h"
#include "pipeline.h"
#define _MPRINTF_REPLACE /* use our functions only */
#include <curl/mprintf.h>
/* The last #include file should be: */
Daniel Stenberg
committed
/*
CURL_SOCKET_HASH_TABLE_SIZE should be a prime number. Increasing it from 97
to 911 takes on a 32-bit machine 4 x 804 = 3211 more bytes. Still, every
CURL handle takes 45-50 K memory, therefore this 3K are not significant.
*/
#ifndef CURL_SOCKET_HASH_TABLE_SIZE
#define CURL_SOCKET_HASH_TABLE_SIZE 911
#endif
#define CURL_MULTI_HANDLE 0x000bab1e
#define GOOD_MULTI_HANDLE(x) \
((x) && (((struct Curl_multi *)(x))->type == CURL_MULTI_HANDLE))
#define GOOD_EASY_HANDLE(x) \
((x) && (((struct SessionHandle *)(x))->magic == CURLEASY_MAGIC_NUMBER))
static void singlesocket(struct Curl_multi *multi,
struct Curl_one_easy *easy);
static int update_timer(struct Curl_multi *multi);
Daniel Stenberg
committed
static bool isHandleAtHead(struct SessionHandle *handle,
struct curl_llist *pipeline);
static CURLMcode add_next_timeout(struct timeval now,
struct Curl_multi *multi,
struct SessionHandle *d);
Daniel Stenberg
committed
static const char * const statename[]={
Daniel Stenberg
committed
"INIT",
"CONNECT_PEND",
Daniel Stenberg
committed
"CONNECT",
"WAITRESOLVE",
"WAITCONNECT",
"WAITPROXYCONNECT",
Daniel Stenberg
committed
"PROTOCONNECT",
"WAITDO",
"DO",
"DOING",
"DO_MORE",
"DO_DONE",
"WAITPERFORM",
"PERFORM",
"TOOFAST",
"DONE",
"COMPLETED",
Daniel Stenberg
committed
};
#endif
static void multi_freetimeout(void *a, void *b);
/* always use this function to change state, to make debugging easier */
static void mstate(struct Curl_one_easy *easy, CURLMstate state
#ifdef DEBUGBUILD
, int lineno
#endif
)
{
long connection_id = -5000;
#endif
CURLMstate oldstate = easy->state;
if(oldstate == state)
/* don't bother when the new state is the same as the old state */
return;
Daniel Stenberg
committed
easy->state = state;
if(easy->state >= CURLM_STATE_CONNECT_PEND &&
easy->state < CURLM_STATE_COMPLETED) {
if(easy->easy_conn)
connection_id = easy->easy_conn->connection_id;
infof(easy->easy_handle,
"STATE: %s => %s handle %p; line %d (connection #%ld) \n",
statename[oldstate], statename[easy->state],
(char *)easy, lineno, connection_id);
}
#endif
Daniel Stenberg
committed
if(state == CURLM_STATE_COMPLETED)
/* changing to COMPLETED means there's one less easy handle 'alive' */
easy->easy_handle->multi->num_alive--;
}
#ifndef DEBUGBUILD
#define multistate(x,y) mstate(x,y)
#else
#define multistate(x,y) mstate(x,y, __LINE__)
#endif
Daniel Stenberg
committed
/*
Daniel Stenberg
committed
* We add one of these structs to the sockhash for a particular socket
Daniel Stenberg
committed
*/
struct Curl_sh_entry {
struct SessionHandle *easy;
time_t timestamp;
Daniel Stenberg
committed
int action; /* what action READ/WRITE this socket waits for */
curl_socket_t socket; /* mainly to ease debugging */
Daniel Stenberg
committed
void *socketp; /* settable by users with curl_multi_assign() */
Daniel Stenberg
committed
};
Daniel Stenberg
committed
/* bits for 'action' having no bits means this socket is not expecting any
action */
#define SH_READ 1
#define SH_WRITE 2
Daniel Stenberg
committed
/* make sure this socket is present in the hash for this handle */
static struct Curl_sh_entry *sh_addentry(struct curl_hash *sh,
curl_socket_t s,
struct SessionHandle *data)
{
Daniel Stenberg
committed
struct Curl_sh_entry *there =
Curl_hash_pick(sh, (char *)&s, sizeof(curl_socket_t));
struct Curl_sh_entry *check;
Daniel Stenberg
committed
if(there)
/* it is present, return fine */
return there;
Daniel Stenberg
committed
/* not present, add it */
check = calloc(1, sizeof(struct Curl_sh_entry));
Daniel Stenberg
committed
if(!check)
return NULL; /* major failure */
Daniel Stenberg
committed
check->easy = data;
check->socket = s;
Daniel Stenberg
committed
/* make/add new hash entry */
if(NULL == Curl_hash_add(sh, (char *)&s, sizeof(curl_socket_t), check)) {
free(check);
return NULL; /* major failure */
}
Daniel Stenberg
committed
return check; /* things are good in sockhash land */
Daniel Stenberg
committed
}
/* delete the given socket + handle from the hash */
Daniel Stenberg
committed
static void sh_delentry(struct curl_hash *sh, curl_socket_t s)
Daniel Stenberg
committed
{
struct Curl_sh_entry *there =
Curl_hash_pick(sh, (char *)&s, sizeof(curl_socket_t));
Daniel Stenberg
committed
if(there) {
/* this socket is in the hash */
/* We remove the hash entry. (This'll end up in a call to
Loading
Loading full blame…