c93716c72f09bb690281d70ce1e8036cce9d1eb9
   1#include "http.h"
   2#include "pack.h"
   3#include "sideband.h"
   4#include "run-command.h"
   5#include "url.h"
   6
   7int data_received;
   8int active_requests;
   9int http_is_verbose;
  10size_t http_post_buffer = 16 * LARGE_PACKET_MAX;
  11
  12#if LIBCURL_VERSION_NUM >= 0x070a06
  13#define LIBCURL_CAN_HANDLE_AUTH_ANY
  14#endif
  15
  16static int min_curl_sessions = 1;
  17static int curl_session_count;
  18#ifdef USE_CURL_MULTI
  19static int max_requests = -1;
  20static CURLM *curlm;
  21#endif
  22#ifndef NO_CURL_EASY_DUPHANDLE
  23static CURL *curl_default;
  24#endif
  25
  26#define PREV_BUF_SIZE 4096
  27#define RANGE_HEADER_SIZE 30
  28
  29char curl_errorstr[CURL_ERROR_SIZE];
  30
  31static int curl_ssl_verify = -1;
  32static const char *ssl_cert;
  33#if LIBCURL_VERSION_NUM >= 0x070903
  34static const char *ssl_key;
  35#endif
  36#if LIBCURL_VERSION_NUM >= 0x070908
  37static const char *ssl_capath;
  38#endif
  39static const char *ssl_cainfo;
  40static long curl_low_speed_limit = -1;
  41static long curl_low_speed_time = -1;
  42static int curl_ftp_no_epsv;
  43static const char *curl_http_proxy;
  44static const char *curl_cookie_file;
  45static char *user_name, *user_pass;
  46static const char *user_agent;
  47
  48#if LIBCURL_VERSION_NUM >= 0x071700
  49/* Use CURLOPT_KEYPASSWD as is */
  50#elif LIBCURL_VERSION_NUM >= 0x070903
  51#define CURLOPT_KEYPASSWD CURLOPT_SSLKEYPASSWD
  52#else
  53#define CURLOPT_KEYPASSWD CURLOPT_SSLCERTPASSWD
  54#endif
  55
  56static char *ssl_cert_password;
  57static int ssl_cert_password_required;
  58
  59static struct curl_slist *pragma_header;
  60static struct curl_slist *no_pragma_header;
  61
  62static struct active_request_slot *active_queue_head;
  63
  64size_t fread_buffer(char *ptr, size_t eltsize, size_t nmemb, void *buffer_)
  65{
  66        size_t size = eltsize * nmemb;
  67        struct buffer *buffer = buffer_;
  68
  69        if (size > buffer->buf.len - buffer->posn)
  70                size = buffer->buf.len - buffer->posn;
  71        memcpy(ptr, buffer->buf.buf + buffer->posn, size);
  72        buffer->posn += size;
  73
  74        return size;
  75}
  76
  77#ifndef NO_CURL_IOCTL
  78curlioerr ioctl_buffer(CURL *handle, int cmd, void *clientp)
  79{
  80        struct buffer *buffer = clientp;
  81
  82        switch (cmd) {
  83        case CURLIOCMD_NOP:
  84                return CURLIOE_OK;
  85
  86        case CURLIOCMD_RESTARTREAD:
  87                buffer->posn = 0;
  88                return CURLIOE_OK;
  89
  90        default:
  91                return CURLIOE_UNKNOWNCMD;
  92        }
  93}
  94#endif
  95
  96size_t fwrite_buffer(char *ptr, size_t eltsize, size_t nmemb, void *buffer_)
  97{
  98        size_t size = eltsize * nmemb;
  99        struct strbuf *buffer = buffer_;
 100
 101        strbuf_add(buffer, ptr, size);
 102        data_received++;
 103        return size;
 104}
 105
 106size_t fwrite_null(char *ptr, size_t eltsize, size_t nmemb, void *strbuf)
 107{
 108        data_received++;
 109        return eltsize * nmemb;
 110}
 111
 112#ifdef USE_CURL_MULTI
 113static void process_curl_messages(void)
 114{
 115        int num_messages;
 116        struct active_request_slot *slot;
 117        CURLMsg *curl_message = curl_multi_info_read(curlm, &num_messages);
 118
 119        while (curl_message != NULL) {
 120                if (curl_message->msg == CURLMSG_DONE) {
 121                        int curl_result = curl_message->data.result;
 122                        slot = active_queue_head;
 123                        while (slot != NULL &&
 124                               slot->curl != curl_message->easy_handle)
 125                                slot = slot->next;
 126                        if (slot != NULL) {
 127                                curl_multi_remove_handle(curlm, slot->curl);
 128                                slot->curl_result = curl_result;
 129                                finish_active_slot(slot);
 130                        } else {
 131                                fprintf(stderr, "Received DONE message for unknown request!\n");
 132                        }
 133                } else {
 134                        fprintf(stderr, "Unknown CURL message received: %d\n",
 135                                (int)curl_message->msg);
 136                }
 137                curl_message = curl_multi_info_read(curlm, &num_messages);
 138        }
 139}
 140#endif
 141
 142static int http_options(const char *var, const char *value, void *cb)
 143{
 144        if (!strcmp("http.sslverify", var)) {
 145                curl_ssl_verify = git_config_bool(var, value);
 146                return 0;
 147        }
 148        if (!strcmp("http.sslcert", var))
 149                return git_config_string(&ssl_cert, var, value);
 150#if LIBCURL_VERSION_NUM >= 0x070903
 151        if (!strcmp("http.sslkey", var))
 152                return git_config_string(&ssl_key, var, value);
 153#endif
 154#if LIBCURL_VERSION_NUM >= 0x070908
 155        if (!strcmp("http.sslcapath", var))
 156                return git_config_string(&ssl_capath, var, value);
 157#endif
 158        if (!strcmp("http.sslcainfo", var))
 159                return git_config_string(&ssl_cainfo, var, value);
 160        if (!strcmp("http.sslcertpasswordprotected", var)) {
 161                if (git_config_bool(var, value))
 162                        ssl_cert_password_required = 1;
 163                return 0;
 164        }
 165        if (!strcmp("http.minsessions", var)) {
 166                min_curl_sessions = git_config_int(var, value);
 167#ifndef USE_CURL_MULTI
 168                if (min_curl_sessions > 1)
 169                        min_curl_sessions = 1;
 170#endif
 171                return 0;
 172        }
 173#ifdef USE_CURL_MULTI
 174        if (!strcmp("http.maxrequests", var)) {
 175                max_requests = git_config_int(var, value);
 176                return 0;
 177        }
 178#endif
 179        if (!strcmp("http.lowspeedlimit", var)) {
 180                curl_low_speed_limit = (long)git_config_int(var, value);
 181                return 0;
 182        }
 183        if (!strcmp("http.lowspeedtime", var)) {
 184                curl_low_speed_time = (long)git_config_int(var, value);
 185                return 0;
 186        }
 187
 188        if (!strcmp("http.noepsv", var)) {
 189                curl_ftp_no_epsv = git_config_bool(var, value);
 190                return 0;
 191        }
 192        if (!strcmp("http.proxy", var))
 193                return git_config_string(&curl_http_proxy, var, value);
 194
 195        if (!strcmp("http.cookiefile", var))
 196                return git_config_string(&curl_cookie_file, var, value);
 197
 198        if (!strcmp("http.postbuffer", var)) {
 199                http_post_buffer = git_config_int(var, value);
 200                if (http_post_buffer < LARGE_PACKET_MAX)
 201                        http_post_buffer = LARGE_PACKET_MAX;
 202                return 0;
 203        }
 204
 205        if (!strcmp("http.useragent", var))
 206                return git_config_string(&user_agent, var, value);
 207
 208        /* Fall back on the default ones */
 209        return git_default_config(var, value, cb);
 210}
 211
 212static void init_curl_http_auth(CURL *result)
 213{
 214        if (user_name) {
 215                struct strbuf up = STRBUF_INIT;
 216                if (!user_pass)
 217                        user_pass = xstrdup(git_getpass("Password: "));
 218                strbuf_addf(&up, "%s:%s", user_name, user_pass);
 219                curl_easy_setopt(result, CURLOPT_USERPWD,
 220                                 strbuf_detach(&up, NULL));
 221        }
 222}
 223
 224static int has_cert_password(void)
 225{
 226        if (ssl_cert_password != NULL)
 227                return 1;
 228        if (ssl_cert == NULL || ssl_cert_password_required != 1)
 229                return 0;
 230        /* Only prompt the user once. */
 231        ssl_cert_password_required = -1;
 232        ssl_cert_password = git_getpass("Certificate Password: ");
 233        if (ssl_cert_password != NULL) {
 234                ssl_cert_password = xstrdup(ssl_cert_password);
 235                return 1;
 236        } else
 237                return 0;
 238}
 239
 240static CURL *get_curl_handle(void)
 241{
 242        CURL *result = curl_easy_init();
 243
 244        if (!curl_ssl_verify) {
 245                curl_easy_setopt(result, CURLOPT_SSL_VERIFYPEER, 0);
 246                curl_easy_setopt(result, CURLOPT_SSL_VERIFYHOST, 0);
 247        } else {
 248                /* Verify authenticity of the peer's certificate */
 249                curl_easy_setopt(result, CURLOPT_SSL_VERIFYPEER, 1);
 250                /* The name in the cert must match whom we tried to connect */
 251                curl_easy_setopt(result, CURLOPT_SSL_VERIFYHOST, 2);
 252        }
 253
 254#if LIBCURL_VERSION_NUM >= 0x070907
 255        curl_easy_setopt(result, CURLOPT_NETRC, CURL_NETRC_OPTIONAL);
 256#endif
 257#ifdef LIBCURL_CAN_HANDLE_AUTH_ANY
 258        curl_easy_setopt(result, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
 259#endif
 260
 261        init_curl_http_auth(result);
 262
 263        if (ssl_cert != NULL)
 264                curl_easy_setopt(result, CURLOPT_SSLCERT, ssl_cert);
 265        if (has_cert_password())
 266                curl_easy_setopt(result, CURLOPT_KEYPASSWD, ssl_cert_password);
 267#if LIBCURL_VERSION_NUM >= 0x070903
 268        if (ssl_key != NULL)
 269                curl_easy_setopt(result, CURLOPT_SSLKEY, ssl_key);
 270#endif
 271#if LIBCURL_VERSION_NUM >= 0x070908
 272        if (ssl_capath != NULL)
 273                curl_easy_setopt(result, CURLOPT_CAPATH, ssl_capath);
 274#endif
 275        if (ssl_cainfo != NULL)
 276                curl_easy_setopt(result, CURLOPT_CAINFO, ssl_cainfo);
 277        curl_easy_setopt(result, CURLOPT_FAILONERROR, 1);
 278
 279        if (curl_low_speed_limit > 0 && curl_low_speed_time > 0) {
 280                curl_easy_setopt(result, CURLOPT_LOW_SPEED_LIMIT,
 281                                 curl_low_speed_limit);
 282                curl_easy_setopt(result, CURLOPT_LOW_SPEED_TIME,
 283                                 curl_low_speed_time);
 284        }
 285
 286        curl_easy_setopt(result, CURLOPT_FOLLOWLOCATION, 1);
 287#if LIBCURL_VERSION_NUM >= 0x071301
 288        curl_easy_setopt(result, CURLOPT_POSTREDIR, CURL_REDIR_POST_ALL);
 289#elif LIBCURL_VERSION_NUM >= 0x071101
 290        curl_easy_setopt(result, CURLOPT_POST301, 1);
 291#endif
 292
 293        if (getenv("GIT_CURL_VERBOSE"))
 294                curl_easy_setopt(result, CURLOPT_VERBOSE, 1);
 295
 296        curl_easy_setopt(result, CURLOPT_USERAGENT,
 297                user_agent ? user_agent : GIT_HTTP_USER_AGENT);
 298
 299        if (curl_ftp_no_epsv)
 300                curl_easy_setopt(result, CURLOPT_FTP_USE_EPSV, 0);
 301
 302        if (curl_http_proxy)
 303                curl_easy_setopt(result, CURLOPT_PROXY, curl_http_proxy);
 304
 305        return result;
 306}
 307
 308static void http_auth_init(const char *url)
 309{
 310        char *at, *colon, *cp, *slash;
 311
 312        cp = strstr(url, "://");
 313        if (!cp)
 314                return;
 315
 316        /*
 317         * Ok, the URL looks like "proto://something".  Which one?
 318         * "proto://<user>:<pass>@<host>/...",
 319         * "proto://<user>@<host>/...", or just
 320         * "proto://<host>/..."?
 321         */
 322        cp += 3;
 323        at = strchr(cp, '@');
 324        colon = strchr(cp, ':');
 325        slash = strchrnul(cp, '/');
 326        if (!at || slash <= at)
 327                return; /* No credentials */
 328        if (!colon || at <= colon) {
 329                /* Only username */
 330                user_name = url_decode_mem(cp, at - cp);
 331                user_pass = NULL;
 332        } else {
 333                user_name = url_decode_mem(cp, colon - cp);
 334                user_pass = url_decode_mem(colon + 1, at - (colon + 1));
 335        }
 336}
 337
 338static void set_from_env(const char **var, const char *envname)
 339{
 340        const char *val = getenv(envname);
 341        if (val)
 342                *var = val;
 343}
 344
 345void http_init(struct remote *remote)
 346{
 347        char *low_speed_limit;
 348        char *low_speed_time;
 349
 350        http_is_verbose = 0;
 351
 352        git_config(http_options, NULL);
 353
 354        curl_global_init(CURL_GLOBAL_ALL);
 355
 356        if (remote && remote->http_proxy)
 357                curl_http_proxy = xstrdup(remote->http_proxy);
 358
 359        pragma_header = curl_slist_append(pragma_header, "Pragma: no-cache");
 360        no_pragma_header = curl_slist_append(no_pragma_header, "Pragma:");
 361
 362#ifdef USE_CURL_MULTI
 363        {
 364                char *http_max_requests = getenv("GIT_HTTP_MAX_REQUESTS");
 365                if (http_max_requests != NULL)
 366                        max_requests = atoi(http_max_requests);
 367        }
 368
 369        curlm = curl_multi_init();
 370        if (curlm == NULL) {
 371                fprintf(stderr, "Error creating curl multi handle.\n");
 372                exit(1);
 373        }
 374#endif
 375
 376        if (getenv("GIT_SSL_NO_VERIFY"))
 377                curl_ssl_verify = 0;
 378
 379        set_from_env(&ssl_cert, "GIT_SSL_CERT");
 380#if LIBCURL_VERSION_NUM >= 0x070903
 381        set_from_env(&ssl_key, "GIT_SSL_KEY");
 382#endif
 383#if LIBCURL_VERSION_NUM >= 0x070908
 384        set_from_env(&ssl_capath, "GIT_SSL_CAPATH");
 385#endif
 386        set_from_env(&ssl_cainfo, "GIT_SSL_CAINFO");
 387
 388        set_from_env(&user_agent, "GIT_HTTP_USER_AGENT");
 389
 390        low_speed_limit = getenv("GIT_HTTP_LOW_SPEED_LIMIT");
 391        if (low_speed_limit != NULL)
 392                curl_low_speed_limit = strtol(low_speed_limit, NULL, 10);
 393        low_speed_time = getenv("GIT_HTTP_LOW_SPEED_TIME");
 394        if (low_speed_time != NULL)
 395                curl_low_speed_time = strtol(low_speed_time, NULL, 10);
 396
 397        if (curl_ssl_verify == -1)
 398                curl_ssl_verify = 1;
 399
 400        curl_session_count = 0;
 401#ifdef USE_CURL_MULTI
 402        if (max_requests < 1)
 403                max_requests = DEFAULT_MAX_REQUESTS;
 404#endif
 405
 406        if (getenv("GIT_CURL_FTP_NO_EPSV"))
 407                curl_ftp_no_epsv = 1;
 408
 409        if (remote && remote->url && remote->url[0]) {
 410                http_auth_init(remote->url[0]);
 411                if (!ssl_cert_password_required &&
 412                    getenv("GIT_SSL_CERT_PASSWORD_PROTECTED") &&
 413                    !prefixcmp(remote->url[0], "https://"))
 414                        ssl_cert_password_required = 1;
 415        }
 416
 417#ifndef NO_CURL_EASY_DUPHANDLE
 418        curl_default = get_curl_handle();
 419#endif
 420}
 421
 422void http_cleanup(void)
 423{
 424        struct active_request_slot *slot = active_queue_head;
 425
 426        while (slot != NULL) {
 427                struct active_request_slot *next = slot->next;
 428                if (slot->curl != NULL) {
 429#ifdef USE_CURL_MULTI
 430                        curl_multi_remove_handle(curlm, slot->curl);
 431#endif
 432                        curl_easy_cleanup(slot->curl);
 433                }
 434                free(slot);
 435                slot = next;
 436        }
 437        active_queue_head = NULL;
 438
 439#ifndef NO_CURL_EASY_DUPHANDLE
 440        curl_easy_cleanup(curl_default);
 441#endif
 442
 443#ifdef USE_CURL_MULTI
 444        curl_multi_cleanup(curlm);
 445#endif
 446        curl_global_cleanup();
 447
 448        curl_slist_free_all(pragma_header);
 449        pragma_header = NULL;
 450
 451        curl_slist_free_all(no_pragma_header);
 452        no_pragma_header = NULL;
 453
 454        if (curl_http_proxy) {
 455                free((void *)curl_http_proxy);
 456                curl_http_proxy = NULL;
 457        }
 458
 459        if (ssl_cert_password != NULL) {
 460                memset(ssl_cert_password, 0, strlen(ssl_cert_password));
 461                free(ssl_cert_password);
 462                ssl_cert_password = NULL;
 463        }
 464        ssl_cert_password_required = 0;
 465}
 466
 467struct active_request_slot *get_active_slot(void)
 468{
 469        struct active_request_slot *slot = active_queue_head;
 470        struct active_request_slot *newslot;
 471
 472#ifdef USE_CURL_MULTI
 473        int num_transfers;
 474
 475        /* Wait for a slot to open up if the queue is full */
 476        while (active_requests >= max_requests) {
 477                curl_multi_perform(curlm, &num_transfers);
 478                if (num_transfers < active_requests)
 479                        process_curl_messages();
 480        }
 481#endif
 482
 483        while (slot != NULL && slot->in_use)
 484                slot = slot->next;
 485
 486        if (slot == NULL) {
 487                newslot = xmalloc(sizeof(*newslot));
 488                newslot->curl = NULL;
 489                newslot->in_use = 0;
 490                newslot->next = NULL;
 491
 492                slot = active_queue_head;
 493                if (slot == NULL) {
 494                        active_queue_head = newslot;
 495                } else {
 496                        while (slot->next != NULL)
 497                                slot = slot->next;
 498                        slot->next = newslot;
 499                }
 500                slot = newslot;
 501        }
 502
 503        if (slot->curl == NULL) {
 504#ifdef NO_CURL_EASY_DUPHANDLE
 505                slot->curl = get_curl_handle();
 506#else
 507                slot->curl = curl_easy_duphandle(curl_default);
 508#endif
 509                curl_session_count++;
 510        }
 511
 512        active_requests++;
 513        slot->in_use = 1;
 514        slot->local = NULL;
 515        slot->results = NULL;
 516        slot->finished = NULL;
 517        slot->callback_data = NULL;
 518        slot->callback_func = NULL;
 519        curl_easy_setopt(slot->curl, CURLOPT_COOKIEFILE, curl_cookie_file);
 520        curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, pragma_header);
 521        curl_easy_setopt(slot->curl, CURLOPT_ERRORBUFFER, curl_errorstr);
 522        curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, NULL);
 523        curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, NULL);
 524        curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, NULL);
 525        curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDS, NULL);
 526        curl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 0);
 527        curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1);
 528
 529        return slot;
 530}
 531
 532int start_active_slot(struct active_request_slot *slot)
 533{
 534#ifdef USE_CURL_MULTI
 535        CURLMcode curlm_result = curl_multi_add_handle(curlm, slot->curl);
 536        int num_transfers;
 537
 538        if (curlm_result != CURLM_OK &&
 539            curlm_result != CURLM_CALL_MULTI_PERFORM) {
 540                active_requests--;
 541                slot->in_use = 0;
 542                return 0;
 543        }
 544
 545        /*
 546         * We know there must be something to do, since we just added
 547         * something.
 548         */
 549        curl_multi_perform(curlm, &num_transfers);
 550#endif
 551        return 1;
 552}
 553
 554#ifdef USE_CURL_MULTI
 555struct fill_chain {
 556        void *data;
 557        int (*fill)(void *);
 558        struct fill_chain *next;
 559};
 560
 561static struct fill_chain *fill_cfg;
 562
 563void add_fill_function(void *data, int (*fill)(void *))
 564{
 565        struct fill_chain *new = xmalloc(sizeof(*new));
 566        struct fill_chain **linkp = &fill_cfg;
 567        new->data = data;
 568        new->fill = fill;
 569        new->next = NULL;
 570        while (*linkp)
 571                linkp = &(*linkp)->next;
 572        *linkp = new;
 573}
 574
 575void fill_active_slots(void)
 576{
 577        struct active_request_slot *slot = active_queue_head;
 578
 579        while (active_requests < max_requests) {
 580                struct fill_chain *fill;
 581                for (fill = fill_cfg; fill; fill = fill->next)
 582                        if (fill->fill(fill->data))
 583                                break;
 584
 585                if (!fill)
 586                        break;
 587        }
 588
 589        while (slot != NULL) {
 590                if (!slot->in_use && slot->curl != NULL
 591                        && curl_session_count > min_curl_sessions) {
 592                        curl_easy_cleanup(slot->curl);
 593                        slot->curl = NULL;
 594                        curl_session_count--;
 595                }
 596                slot = slot->next;
 597        }
 598}
 599
 600void step_active_slots(void)
 601{
 602        int num_transfers;
 603        CURLMcode curlm_result;
 604
 605        do {
 606                curlm_result = curl_multi_perform(curlm, &num_transfers);
 607        } while (curlm_result == CURLM_CALL_MULTI_PERFORM);
 608        if (num_transfers < active_requests) {
 609                process_curl_messages();
 610                fill_active_slots();
 611        }
 612}
 613#endif
 614
 615void run_active_slot(struct active_request_slot *slot)
 616{
 617#ifdef USE_CURL_MULTI
 618        long last_pos = 0;
 619        long current_pos;
 620        fd_set readfds;
 621        fd_set writefds;
 622        fd_set excfds;
 623        int max_fd;
 624        struct timeval select_timeout;
 625        int finished = 0;
 626
 627        slot->finished = &finished;
 628        while (!finished) {
 629                data_received = 0;
 630                step_active_slots();
 631
 632                if (!data_received && slot->local != NULL) {
 633                        current_pos = ftell(slot->local);
 634                        if (current_pos > last_pos)
 635                                data_received++;
 636                        last_pos = current_pos;
 637                }
 638
 639                if (slot->in_use && !data_received) {
 640                        max_fd = 0;
 641                        FD_ZERO(&readfds);
 642                        FD_ZERO(&writefds);
 643                        FD_ZERO(&excfds);
 644                        select_timeout.tv_sec = 0;
 645                        select_timeout.tv_usec = 50000;
 646                        select(max_fd, &readfds, &writefds,
 647                               &excfds, &select_timeout);
 648                }
 649        }
 650#else
 651        while (slot->in_use) {
 652                slot->curl_result = curl_easy_perform(slot->curl);
 653                finish_active_slot(slot);
 654        }
 655#endif
 656}
 657
 658static void closedown_active_slot(struct active_request_slot *slot)
 659{
 660        active_requests--;
 661        slot->in_use = 0;
 662}
 663
 664static void release_active_slot(struct active_request_slot *slot)
 665{
 666        closedown_active_slot(slot);
 667        if (slot->curl && curl_session_count > min_curl_sessions) {
 668#ifdef USE_CURL_MULTI
 669                curl_multi_remove_handle(curlm, slot->curl);
 670#endif
 671                curl_easy_cleanup(slot->curl);
 672                slot->curl = NULL;
 673                curl_session_count--;
 674        }
 675#ifdef USE_CURL_MULTI
 676        fill_active_slots();
 677#endif
 678}
 679
 680void finish_active_slot(struct active_request_slot *slot)
 681{
 682        closedown_active_slot(slot);
 683        curl_easy_getinfo(slot->curl, CURLINFO_HTTP_CODE, &slot->http_code);
 684
 685        if (slot->finished != NULL)
 686                (*slot->finished) = 1;
 687
 688        /* Store slot results so they can be read after the slot is reused */
 689        if (slot->results != NULL) {
 690                slot->results->curl_result = slot->curl_result;
 691                slot->results->http_code = slot->http_code;
 692        }
 693
 694        /* Run callback if appropriate */
 695        if (slot->callback_func != NULL)
 696                slot->callback_func(slot->callback_data);
 697}
 698
 699void finish_all_active_slots(void)
 700{
 701        struct active_request_slot *slot = active_queue_head;
 702
 703        while (slot != NULL)
 704                if (slot->in_use) {
 705                        run_active_slot(slot);
 706                        slot = active_queue_head;
 707                } else {
 708                        slot = slot->next;
 709                }
 710}
 711
 712/* Helpers for modifying and creating URLs */
 713static inline int needs_quote(int ch)
 714{
 715        if (((ch >= 'A') && (ch <= 'Z'))
 716                        || ((ch >= 'a') && (ch <= 'z'))
 717                        || ((ch >= '0') && (ch <= '9'))
 718                        || (ch == '/')
 719                        || (ch == '-')
 720                        || (ch == '.'))
 721                return 0;
 722        return 1;
 723}
 724
 725static inline int hex(int v)
 726{
 727        if (v < 10)
 728                return '0' + v;
 729        else
 730                return 'A' + v - 10;
 731}
 732
 733static char *quote_ref_url(const char *base, const char *ref)
 734{
 735        struct strbuf buf = STRBUF_INIT;
 736        const char *cp;
 737        int ch;
 738
 739        end_url_with_slash(&buf, base);
 740
 741        for (cp = ref; (ch = *cp) != 0; cp++)
 742                if (needs_quote(ch))
 743                        strbuf_addf(&buf, "%%%02x", ch);
 744                else
 745                        strbuf_addch(&buf, *cp);
 746
 747        return strbuf_detach(&buf, NULL);
 748}
 749
 750void append_remote_object_url(struct strbuf *buf, const char *url,
 751                              const char *hex,
 752                              int only_two_digit_prefix)
 753{
 754        end_url_with_slash(buf, url);
 755
 756        strbuf_addf(buf, "objects/%.*s/", 2, hex);
 757        if (!only_two_digit_prefix)
 758                strbuf_addf(buf, "%s", hex+2);
 759}
 760
 761char *get_remote_object_url(const char *url, const char *hex,
 762                            int only_two_digit_prefix)
 763{
 764        struct strbuf buf = STRBUF_INIT;
 765        append_remote_object_url(&buf, url, hex, only_two_digit_prefix);
 766        return strbuf_detach(&buf, NULL);
 767}
 768
 769/* http_request() targets */
 770#define HTTP_REQUEST_STRBUF     0
 771#define HTTP_REQUEST_FILE       1
 772
 773static int http_request(const char *url, void *result, int target, int options)
 774{
 775        struct active_request_slot *slot;
 776        struct slot_results results;
 777        struct curl_slist *headers = NULL;
 778        struct strbuf buf = STRBUF_INIT;
 779        int ret;
 780
 781        slot = get_active_slot();
 782        slot->results = &results;
 783        curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1);
 784
 785        if (result == NULL) {
 786                curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 1);
 787        } else {
 788                curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 0);
 789                curl_easy_setopt(slot->curl, CURLOPT_FILE, result);
 790
 791                if (target == HTTP_REQUEST_FILE) {
 792                        long posn = ftell(result);
 793                        curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION,
 794                                         fwrite);
 795                        if (posn > 0) {
 796                                strbuf_addf(&buf, "Range: bytes=%ld-", posn);
 797                                headers = curl_slist_append(headers, buf.buf);
 798                                strbuf_reset(&buf);
 799                        }
 800                        slot->local = result;
 801                } else
 802                        curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION,
 803                                         fwrite_buffer);
 804        }
 805
 806        strbuf_addstr(&buf, "Pragma:");
 807        if (options & HTTP_NO_CACHE)
 808                strbuf_addstr(&buf, " no-cache");
 809
 810        headers = curl_slist_append(headers, buf.buf);
 811
 812        curl_easy_setopt(slot->curl, CURLOPT_URL, url);
 813        curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, headers);
 814
 815        if (start_active_slot(slot)) {
 816                run_active_slot(slot);
 817                if (results.curl_result == CURLE_OK)
 818                        ret = HTTP_OK;
 819                else if (missing_target(&results))
 820                        ret = HTTP_MISSING_TARGET;
 821                else if (results.http_code == 401) {
 822                        if (user_name) {
 823                                ret = HTTP_NOAUTH;
 824                        } else {
 825                                /*
 826                                 * git_getpass is needed here because its very likely stdin/stdout are
 827                                 * pipes to our parent process.  So we instead need to use /dev/tty,
 828                                 * but that is non-portable.  Using git_getpass() can at least be stubbed
 829                                 * on other platforms with a different implementation if/when necessary.
 830                                 */
 831                                user_name = xstrdup(git_getpass("Username: "));
 832                                init_curl_http_auth(slot->curl);
 833                                ret = HTTP_REAUTH;
 834                        }
 835                } else
 836                        ret = HTTP_ERROR;
 837        } else {
 838                error("Unable to start HTTP request for %s", url);
 839                ret = HTTP_START_FAILED;
 840        }
 841
 842        slot->local = NULL;
 843        curl_slist_free_all(headers);
 844        strbuf_release(&buf);
 845
 846        return ret;
 847}
 848
 849int http_get_strbuf(const char *url, struct strbuf *result, int options)
 850{
 851        int http_ret = http_request(url, result, HTTP_REQUEST_STRBUF, options);
 852        if (http_ret == HTTP_REAUTH) {
 853                http_ret = http_request(url, result, HTTP_REQUEST_STRBUF, options);
 854        }
 855        return http_ret;
 856}
 857
 858/*
 859 * Downloads an url and stores the result in the given file.
 860 *
 861 * If a previous interrupted download is detected (i.e. a previous temporary
 862 * file is still around) the download is resumed.
 863 */
 864static int http_get_file(const char *url, const char *filename, int options)
 865{
 866        int ret;
 867        struct strbuf tmpfile = STRBUF_INIT;
 868        FILE *result;
 869
 870        strbuf_addf(&tmpfile, "%s.temp", filename);
 871        result = fopen(tmpfile.buf, "a");
 872        if (! result) {
 873                error("Unable to open local file %s", tmpfile.buf);
 874                ret = HTTP_ERROR;
 875                goto cleanup;
 876        }
 877
 878        ret = http_request(url, result, HTTP_REQUEST_FILE, options);
 879        fclose(result);
 880
 881        if ((ret == HTTP_OK) && move_temp_to_file(tmpfile.buf, filename))
 882                ret = HTTP_ERROR;
 883cleanup:
 884        strbuf_release(&tmpfile);
 885        return ret;
 886}
 887
 888int http_error(const char *url, int ret)
 889{
 890        /* http_request has already handled HTTP_START_FAILED. */
 891        if (ret != HTTP_START_FAILED)
 892                error("%s while accessing %s\n", curl_errorstr, url);
 893
 894        return ret;
 895}
 896
 897int http_fetch_ref(const char *base, struct ref *ref)
 898{
 899        char *url;
 900        struct strbuf buffer = STRBUF_INIT;
 901        int ret = -1;
 902
 903        url = quote_ref_url(base, ref->name);
 904        if (http_get_strbuf(url, &buffer, HTTP_NO_CACHE) == HTTP_OK) {
 905                strbuf_rtrim(&buffer);
 906                if (buffer.len == 40)
 907                        ret = get_sha1_hex(buffer.buf, ref->old_sha1);
 908                else if (!prefixcmp(buffer.buf, "ref: ")) {
 909                        ref->symref = xstrdup(buffer.buf + 5);
 910                        ret = 0;
 911                }
 912        }
 913
 914        strbuf_release(&buffer);
 915        free(url);
 916        return ret;
 917}
 918
 919/* Helpers for fetching packs */
 920static char *fetch_pack_index(unsigned char *sha1, const char *base_url)
 921{
 922        char *url, *tmp;
 923        struct strbuf buf = STRBUF_INIT;
 924
 925        if (http_is_verbose)
 926                fprintf(stderr, "Getting index for pack %s\n", sha1_to_hex(sha1));
 927
 928        end_url_with_slash(&buf, base_url);
 929        strbuf_addf(&buf, "objects/pack/pack-%s.idx", sha1_to_hex(sha1));
 930        url = strbuf_detach(&buf, NULL);
 931
 932        strbuf_addf(&buf, "%s.temp", sha1_pack_index_name(sha1));
 933        tmp = strbuf_detach(&buf, NULL);
 934
 935        if (http_get_file(url, tmp, 0) != HTTP_OK) {
 936                error("Unable to get pack index %s\n", url);
 937                free(tmp);
 938                tmp = NULL;
 939        }
 940
 941        free(url);
 942        return tmp;
 943}
 944
 945static int fetch_and_setup_pack_index(struct packed_git **packs_head,
 946        unsigned char *sha1, const char *base_url)
 947{
 948        struct packed_git *new_pack;
 949        char *tmp_idx = NULL;
 950        int ret;
 951
 952        if (has_pack_index(sha1)) {
 953                new_pack = parse_pack_index(sha1, NULL);
 954                if (!new_pack)
 955                        return -1; /* parse_pack_index() already issued error message */
 956                goto add_pack;
 957        }
 958
 959        tmp_idx = fetch_pack_index(sha1, base_url);
 960        if (!tmp_idx)
 961                return -1;
 962
 963        new_pack = parse_pack_index(sha1, tmp_idx);
 964        if (!new_pack) {
 965                unlink(tmp_idx);
 966                free(tmp_idx);
 967
 968                return -1; /* parse_pack_index() already issued error message */
 969        }
 970
 971        ret = verify_pack_index(new_pack);
 972        if (!ret) {
 973                close_pack_index(new_pack);
 974                ret = move_temp_to_file(tmp_idx, sha1_pack_index_name(sha1));
 975        }
 976        free(tmp_idx);
 977        if (ret)
 978                return -1;
 979
 980add_pack:
 981        new_pack->next = *packs_head;
 982        *packs_head = new_pack;
 983        return 0;
 984}
 985
 986int http_get_info_packs(const char *base_url, struct packed_git **packs_head)
 987{
 988        int ret = 0, i = 0;
 989        char *url, *data;
 990        struct strbuf buf = STRBUF_INIT;
 991        unsigned char sha1[20];
 992
 993        end_url_with_slash(&buf, base_url);
 994        strbuf_addstr(&buf, "objects/info/packs");
 995        url = strbuf_detach(&buf, NULL);
 996
 997        ret = http_get_strbuf(url, &buf, HTTP_NO_CACHE);
 998        if (ret != HTTP_OK)
 999                goto cleanup;
1000
1001        data = buf.buf;
1002        while (i < buf.len) {
1003                switch (data[i]) {
1004                case 'P':
1005                        i++;
1006                        if (i + 52 <= buf.len &&
1007                            !prefixcmp(data + i, " pack-") &&
1008                            !prefixcmp(data + i + 46, ".pack\n")) {
1009                                get_sha1_hex(data + i + 6, sha1);
1010                                fetch_and_setup_pack_index(packs_head, sha1,
1011                                                      base_url);
1012                                i += 51;
1013                                break;
1014                        }
1015                default:
1016                        while (i < buf.len && data[i] != '\n')
1017                                i++;
1018                }
1019                i++;
1020        }
1021
1022cleanup:
1023        free(url);
1024        return ret;
1025}
1026
1027void release_http_pack_request(struct http_pack_request *preq)
1028{
1029        if (preq->packfile != NULL) {
1030                fclose(preq->packfile);
1031                preq->packfile = NULL;
1032                preq->slot->local = NULL;
1033        }
1034        if (preq->range_header != NULL) {
1035                curl_slist_free_all(preq->range_header);
1036                preq->range_header = NULL;
1037        }
1038        preq->slot = NULL;
1039        free(preq->url);
1040}
1041
1042int finish_http_pack_request(struct http_pack_request *preq)
1043{
1044        struct packed_git **lst;
1045        struct packed_git *p = preq->target;
1046        char *tmp_idx;
1047        struct child_process ip;
1048        const char *ip_argv[8];
1049
1050        close_pack_index(p);
1051
1052        fclose(preq->packfile);
1053        preq->packfile = NULL;
1054        preq->slot->local = NULL;
1055
1056        lst = preq->lst;
1057        while (*lst != p)
1058                lst = &((*lst)->next);
1059        *lst = (*lst)->next;
1060
1061        tmp_idx = xstrdup(preq->tmpfile);
1062        strcpy(tmp_idx + strlen(tmp_idx) - strlen(".pack.temp"),
1063               ".idx.temp");
1064
1065        ip_argv[0] = "index-pack";
1066        ip_argv[1] = "-o";
1067        ip_argv[2] = tmp_idx;
1068        ip_argv[3] = preq->tmpfile;
1069        ip_argv[4] = NULL;
1070
1071        memset(&ip, 0, sizeof(ip));
1072        ip.argv = ip_argv;
1073        ip.git_cmd = 1;
1074        ip.no_stdin = 1;
1075        ip.no_stdout = 1;
1076
1077        if (run_command(&ip)) {
1078                unlink(preq->tmpfile);
1079                unlink(tmp_idx);
1080                free(tmp_idx);
1081                return -1;
1082        }
1083
1084        unlink(sha1_pack_index_name(p->sha1));
1085
1086        if (move_temp_to_file(preq->tmpfile, sha1_pack_name(p->sha1))
1087         || move_temp_to_file(tmp_idx, sha1_pack_index_name(p->sha1))) {
1088                free(tmp_idx);
1089                return -1;
1090        }
1091
1092        install_packed_git(p);
1093        free(tmp_idx);
1094        return 0;
1095}
1096
1097struct http_pack_request *new_http_pack_request(
1098        struct packed_git *target, const char *base_url)
1099{
1100        long prev_posn = 0;
1101        char range[RANGE_HEADER_SIZE];
1102        struct strbuf buf = STRBUF_INIT;
1103        struct http_pack_request *preq;
1104
1105        preq = xmalloc(sizeof(*preq));
1106        preq->target = target;
1107        preq->range_header = NULL;
1108
1109        end_url_with_slash(&buf, base_url);
1110        strbuf_addf(&buf, "objects/pack/pack-%s.pack",
1111                sha1_to_hex(target->sha1));
1112        preq->url = strbuf_detach(&buf, NULL);
1113
1114        snprintf(preq->tmpfile, sizeof(preq->tmpfile), "%s.temp",
1115                sha1_pack_name(target->sha1));
1116        preq->packfile = fopen(preq->tmpfile, "a");
1117        if (!preq->packfile) {
1118                error("Unable to open local file %s for pack",
1119                      preq->tmpfile);
1120                goto abort;
1121        }
1122
1123        preq->slot = get_active_slot();
1124        preq->slot->local = preq->packfile;
1125        curl_easy_setopt(preq->slot->curl, CURLOPT_FILE, preq->packfile);
1126        curl_easy_setopt(preq->slot->curl, CURLOPT_WRITEFUNCTION, fwrite);
1127        curl_easy_setopt(preq->slot->curl, CURLOPT_URL, preq->url);
1128        curl_easy_setopt(preq->slot->curl, CURLOPT_HTTPHEADER,
1129                no_pragma_header);
1130
1131        /*
1132         * If there is data present from a previous transfer attempt,
1133         * resume where it left off
1134         */
1135        prev_posn = ftell(preq->packfile);
1136        if (prev_posn>0) {
1137                if (http_is_verbose)
1138                        fprintf(stderr,
1139                                "Resuming fetch of pack %s at byte %ld\n",
1140                                sha1_to_hex(target->sha1), prev_posn);
1141                sprintf(range, "Range: bytes=%ld-", prev_posn);
1142                preq->range_header = curl_slist_append(NULL, range);
1143                curl_easy_setopt(preq->slot->curl, CURLOPT_HTTPHEADER,
1144                        preq->range_header);
1145        }
1146
1147        return preq;
1148
1149abort:
1150        free(preq->url);
1151        free(preq);
1152        return NULL;
1153}
1154
1155/* Helpers for fetching objects (loose) */
1156static size_t fwrite_sha1_file(char *ptr, size_t eltsize, size_t nmemb,
1157                               void *data)
1158{
1159        unsigned char expn[4096];
1160        size_t size = eltsize * nmemb;
1161        int posn = 0;
1162        struct http_object_request *freq =
1163                (struct http_object_request *)data;
1164        do {
1165                ssize_t retval = xwrite(freq->localfile,
1166                                        (char *) ptr + posn, size - posn);
1167                if (retval < 0)
1168                        return posn;
1169                posn += retval;
1170        } while (posn < size);
1171
1172        freq->stream.avail_in = size;
1173        freq->stream.next_in = (void *)ptr;
1174        do {
1175                freq->stream.next_out = expn;
1176                freq->stream.avail_out = sizeof(expn);
1177                freq->zret = git_inflate(&freq->stream, Z_SYNC_FLUSH);
1178                git_SHA1_Update(&freq->c, expn,
1179                                sizeof(expn) - freq->stream.avail_out);
1180        } while (freq->stream.avail_in && freq->zret == Z_OK);
1181        data_received++;
1182        return size;
1183}
1184
1185struct http_object_request *new_http_object_request(const char *base_url,
1186        unsigned char *sha1)
1187{
1188        char *hex = sha1_to_hex(sha1);
1189        char *filename;
1190        char prevfile[PATH_MAX];
1191        int prevlocal;
1192        char prev_buf[PREV_BUF_SIZE];
1193        ssize_t prev_read = 0;
1194        long prev_posn = 0;
1195        char range[RANGE_HEADER_SIZE];
1196        struct curl_slist *range_header = NULL;
1197        struct http_object_request *freq;
1198
1199        freq = xmalloc(sizeof(*freq));
1200        hashcpy(freq->sha1, sha1);
1201        freq->localfile = -1;
1202
1203        filename = sha1_file_name(sha1);
1204        snprintf(freq->tmpfile, sizeof(freq->tmpfile),
1205                 "%s.temp", filename);
1206
1207        snprintf(prevfile, sizeof(prevfile), "%s.prev", filename);
1208        unlink_or_warn(prevfile);
1209        rename(freq->tmpfile, prevfile);
1210        unlink_or_warn(freq->tmpfile);
1211
1212        if (freq->localfile != -1)
1213                error("fd leakage in start: %d", freq->localfile);
1214        freq->localfile = open(freq->tmpfile,
1215                               O_WRONLY | O_CREAT | O_EXCL, 0666);
1216        /*
1217         * This could have failed due to the "lazy directory creation";
1218         * try to mkdir the last path component.
1219         */
1220        if (freq->localfile < 0 && errno == ENOENT) {
1221                char *dir = strrchr(freq->tmpfile, '/');
1222                if (dir) {
1223                        *dir = 0;
1224                        mkdir(freq->tmpfile, 0777);
1225                        *dir = '/';
1226                }
1227                freq->localfile = open(freq->tmpfile,
1228                                       O_WRONLY | O_CREAT | O_EXCL, 0666);
1229        }
1230
1231        if (freq->localfile < 0) {
1232                error("Couldn't create temporary file %s: %s",
1233                      freq->tmpfile, strerror(errno));
1234                goto abort;
1235        }
1236
1237        memset(&freq->stream, 0, sizeof(freq->stream));
1238
1239        git_inflate_init(&freq->stream);
1240
1241        git_SHA1_Init(&freq->c);
1242
1243        freq->url = get_remote_object_url(base_url, hex, 0);
1244
1245        /*
1246         * If a previous temp file is present, process what was already
1247         * fetched.
1248         */
1249        prevlocal = open(prevfile, O_RDONLY);
1250        if (prevlocal != -1) {
1251                do {
1252                        prev_read = xread(prevlocal, prev_buf, PREV_BUF_SIZE);
1253                        if (prev_read>0) {
1254                                if (fwrite_sha1_file(prev_buf,
1255                                                     1,
1256                                                     prev_read,
1257                                                     freq) == prev_read) {
1258                                        prev_posn += prev_read;
1259                                } else {
1260                                        prev_read = -1;
1261                                }
1262                        }
1263                } while (prev_read > 0);
1264                close(prevlocal);
1265        }
1266        unlink_or_warn(prevfile);
1267
1268        /*
1269         * Reset inflate/SHA1 if there was an error reading the previous temp
1270         * file; also rewind to the beginning of the local file.
1271         */
1272        if (prev_read == -1) {
1273                memset(&freq->stream, 0, sizeof(freq->stream));
1274                git_inflate_init(&freq->stream);
1275                git_SHA1_Init(&freq->c);
1276                if (prev_posn>0) {
1277                        prev_posn = 0;
1278                        lseek(freq->localfile, 0, SEEK_SET);
1279                        if (ftruncate(freq->localfile, 0) < 0) {
1280                                error("Couldn't truncate temporary file %s: %s",
1281                                          freq->tmpfile, strerror(errno));
1282                                goto abort;
1283                        }
1284                }
1285        }
1286
1287        freq->slot = get_active_slot();
1288
1289        curl_easy_setopt(freq->slot->curl, CURLOPT_FILE, freq);
1290        curl_easy_setopt(freq->slot->curl, CURLOPT_WRITEFUNCTION, fwrite_sha1_file);
1291        curl_easy_setopt(freq->slot->curl, CURLOPT_ERRORBUFFER, freq->errorstr);
1292        curl_easy_setopt(freq->slot->curl, CURLOPT_URL, freq->url);
1293        curl_easy_setopt(freq->slot->curl, CURLOPT_HTTPHEADER, no_pragma_header);
1294
1295        /*
1296         * If we have successfully processed data from a previous fetch
1297         * attempt, only fetch the data we don't already have.
1298         */
1299        if (prev_posn>0) {
1300                if (http_is_verbose)
1301                        fprintf(stderr,
1302                                "Resuming fetch of object %s at byte %ld\n",
1303                                hex, prev_posn);
1304                sprintf(range, "Range: bytes=%ld-", prev_posn);
1305                range_header = curl_slist_append(range_header, range);
1306                curl_easy_setopt(freq->slot->curl,
1307                                 CURLOPT_HTTPHEADER, range_header);
1308        }
1309
1310        return freq;
1311
1312abort:
1313        free(filename);
1314        free(freq->url);
1315        free(freq);
1316        return NULL;
1317}
1318
1319void process_http_object_request(struct http_object_request *freq)
1320{
1321        if (freq->slot == NULL)
1322                return;
1323        freq->curl_result = freq->slot->curl_result;
1324        freq->http_code = freq->slot->http_code;
1325        freq->slot = NULL;
1326}
1327
1328int finish_http_object_request(struct http_object_request *freq)
1329{
1330        struct stat st;
1331
1332        close(freq->localfile);
1333        freq->localfile = -1;
1334
1335        process_http_object_request(freq);
1336
1337        if (freq->http_code == 416) {
1338                warning("requested range invalid; we may already have all the data.");
1339        } else if (freq->curl_result != CURLE_OK) {
1340                if (stat(freq->tmpfile, &st) == 0)
1341                        if (st.st_size == 0)
1342                                unlink_or_warn(freq->tmpfile);
1343                return -1;
1344        }
1345
1346        git_inflate_end(&freq->stream);
1347        git_SHA1_Final(freq->real_sha1, &freq->c);
1348        if (freq->zret != Z_STREAM_END) {
1349                unlink_or_warn(freq->tmpfile);
1350                return -1;
1351        }
1352        if (hashcmp(freq->sha1, freq->real_sha1)) {
1353                unlink_or_warn(freq->tmpfile);
1354                return -1;
1355        }
1356        freq->rename =
1357                move_temp_to_file(freq->tmpfile, sha1_file_name(freq->sha1));
1358
1359        return freq->rename;
1360}
1361
1362void abort_http_object_request(struct http_object_request *freq)
1363{
1364        unlink_or_warn(freq->tmpfile);
1365
1366        release_http_object_request(freq);
1367}
1368
1369void release_http_object_request(struct http_object_request *freq)
1370{
1371        if (freq->localfile != -1) {
1372                close(freq->localfile);
1373                freq->localfile = -1;
1374        }
1375        if (freq->url != NULL) {
1376                free(freq->url);
1377                freq->url = NULL;
1378        }
1379        if (freq->slot != NULL) {
1380                freq->slot->callback_func = NULL;
1381                freq->slot->callback_data = NULL;
1382                release_active_slot(freq->slot);
1383                freq->slot = NULL;
1384        }
1385}