📄 multi.c
字号:
/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2003, 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. * * $Id: multi.c,v 1.39 2003/10/18 20:38:18 bagder Exp $ ***************************************************************************/#include "setup.h"#include <stdlib.h>#include <string.h>#ifdef HAVE_SYS_TYPES_H#include <sys/types.h>#endif#ifdef HAVE_SYS_SOCKET_H#include <sys/socket.h>#endif#ifdef HAVE_UNISTD_H#include <unistd.h>#endif#include <curl/curl.h>#include "urldata.h"#include "transfer.h"#include "url.h"#include "connect.h"#include "progress.h"/* The last #include file should be: */#ifdef CURLDEBUG#include "memdebug.h"#endifstruct Curl_message { /* the 'CURLMsg' is the part that is visible to the external user */ struct CURLMsg extmsg; struct Curl_message *next;};typedef enum { CURLM_STATE_INIT, CURLM_STATE_CONNECT, /* resolve/connect has been sent off */ CURLM_STATE_WAITRESOLVE, /* we're awaiting the resolve to finalize */ CURLM_STATE_WAITCONNECT, /* we're awaiting the connect to finalize */ CURLM_STATE_DO, /* send off the request (part 1) */ CURLM_STATE_DO_MORE, /* send off the request (part 2) */ CURLM_STATE_PERFORM, /* transfer data */ CURLM_STATE_DONE, /* post data transfer operation */ CURLM_STATE_COMPLETED, /* operation complete */ CURLM_STATE_LAST /* not a true state, never use this */} CURLMstate;struct Curl_one_easy { /* first, two fields for the linked list of these */ struct Curl_one_easy *next; struct Curl_one_easy *prev; struct SessionHandle *easy_handle; /* the easy handle for this unit */ struct connectdata *easy_conn; /* the "unit's" connection */ CURLMstate state; /* the handle's state */ CURLcode result; /* previous result */ struct Curl_message *msg; /* A pointer to one single posted message. Cleanup should be done on this pointer NOT on the linked list in Curl_multi. This message will be deleted when this handle is removed from the multi-handle */ int msg_num; /* number of messages left in 'msg' to return */};#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)/* This is the struct known as CURLM on the outside */struct Curl_multi { /* First a simple identifier to easier detect if a user mix up this multi handle with an easy handle. Set this to CURL_MULTI_HANDLE. */ long type; /* We have a linked list with easy handles */ struct Curl_one_easy easy; /* This is the amount of entries in the linked list above. */ int num_easy; int num_msgs; /* total amount of messages in the easy handles */ /* Hostname cache */ curl_hash *hostcache;};CURLM *curl_multi_init(void){ struct Curl_multi *multi; multi = (void *)malloc(sizeof(struct Curl_multi)); if(multi) { memset(multi, 0, sizeof(struct Curl_multi)); multi->type = CURL_MULTI_HANDLE; } multi->hostcache = Curl_hash_alloc(7, Curl_freednsinfo); if(!multi->hostcache) { /* failure, free mem and bail out */ free(multi); multi = NULL; } return (CURLM *) multi;}CURLMcode curl_multi_add_handle(CURLM *multi_handle, CURL *easy_handle){ struct Curl_multi *multi=(struct Curl_multi *)multi_handle; struct Curl_one_easy *easy; /* First, make some basic checks that the CURLM handle is a good handle */ if(!GOOD_MULTI_HANDLE(multi)) return CURLM_BAD_HANDLE; /* Verify that we got a somewhat good easy handle too */ if(!GOOD_EASY_HANDLE(easy_handle)) return CURLM_BAD_EASY_HANDLE; /* Now, time to add an easy handle to the multi stack */ easy = (struct Curl_one_easy *)malloc(sizeof(struct Curl_one_easy)); if(!easy) return CURLM_OUT_OF_MEMORY; /* clean it all first (just to be sure) */ memset(easy, 0, sizeof(struct Curl_one_easy)); /* set the easy handle */ easy->easy_handle = easy_handle; easy->state = CURLM_STATE_INIT; /* for multi interface connections, we share DNS cache automaticly */ easy->easy_handle->hostcache = multi->hostcache; /* We add this new entry first in the list. We make our 'next' point to the previous next and our 'prev' point back to the 'first' struct */ easy->next = multi->easy.next; easy->prev = &multi->easy; /* make 'easy' the first node in the chain */ multi->easy.next = easy; /* if there was a next node, make sure its 'prev' pointer links back to the new node */ if(easy->next) easy->next->prev = easy; /* increase the node-counter */ multi->num_easy++; return CURLM_CALL_MULTI_PERFORM;}CURLMcode curl_multi_remove_handle(CURLM *multi_handle, CURL *curl_handle){ struct Curl_multi *multi=(struct Curl_multi *)multi_handle; struct Curl_one_easy *easy; /* First, make some basic checks that the CURLM handle is a good handle */ if(!GOOD_MULTI_HANDLE(multi)) return CURLM_BAD_HANDLE; /* Verify that we got a somewhat good easy handle too */ if(!GOOD_EASY_HANDLE(curl_handle)) return CURLM_BAD_EASY_HANDLE; /* scan through the list and remove the 'curl_handle' */ easy = multi->easy.next; while(easy) { if(easy->easy_handle == curl_handle) break; easy=easy->next; } if(easy) { /* If the 'state' is not INIT or COMPLETED, we might need to do something nice to put the easy_handle in a good known state when this returns. */ /* clear out the usage of the shared DNS cache */ easy->easy_handle->hostcache = NULL; /* make the previous node point to our next */ if(easy->prev) easy->prev->next = easy->next; /* make our next point to our previous node */ if(easy->next) easy->next->prev = easy->prev; /* NOTE NOTE NOTE We do not touch the easy handle here! */ if (easy->msg) free(easy->msg); free(easy); multi->num_easy--; /* one less to care about now */ return CURLM_OK; } else return CURLM_BAD_EASY_HANDLE; /* twasn't found */}CURLMcode curl_multi_fdset(CURLM *multi_handle, fd_set *read_fd_set, fd_set *write_fd_set, fd_set *exc_fd_set, int *max_fd){ /* Scan through all the easy handles to get the file descriptors set. Some easy handles may not have connected to the remote host yet, and then we must make sure that is done. */ struct Curl_multi *multi=(struct Curl_multi *)multi_handle; struct Curl_one_easy *easy; int this_max_fd=-1; if(!GOOD_MULTI_HANDLE(multi)) return CURLM_BAD_HANDLE; *max_fd = -1; /* so far none! */ easy=multi->easy.next; while(easy) { switch(easy->state) { default: break; case CURLM_STATE_WAITRESOLVE: /* waiting for a resolve to complete */ Curl_multi_ares_fdset(easy->easy_conn, read_fd_set, write_fd_set, &this_max_fd); if(this_max_fd > *max_fd) *max_fd = this_max_fd; break; case CURLM_STATE_WAITCONNECT: case CURLM_STATE_DO_MORE: { /* when we're waiting for a connect, we wait for the socket to become writable */ struct connectdata *conn = easy->easy_conn; int sockfd; if(CURLM_STATE_WAITCONNECT == easy->state) { sockfd = conn->firstsocket; FD_SET(sockfd, write_fd_set); } else { /* When in DO_MORE state, we could be either waiting for us to connect to a remote site, or we could wait for that site to connect to us. It makes a difference in the way: if we connect to the site we wait for the socket to become writable, if the site connects to us we wait for it to become readable */ sockfd = conn->secondarysocket; FD_SET(sockfd, write_fd_set); } if(sockfd > *max_fd) *max_fd = sockfd; } break; case CURLM_STATE_PERFORM: /* This should have a set of file descriptors for us to set. */ /* after the transfer is done, go DONE */ Curl_single_fdset(easy->easy_conn, read_fd_set, write_fd_set, exc_fd_set, &this_max_fd); /* remember the maximum file descriptor */ if(this_max_fd > *max_fd) *max_fd = this_max_fd; break; } easy = easy->next; /* check next handle */ } return CURLM_OK;}CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles){ struct Curl_multi *multi=(struct Curl_multi *)multi_handle; struct Curl_one_easy *easy; bool done;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -