upload_service_descriptor(rend_service_t *service)
{
  time_t now = time(NULL);
  int rendpostperiod;
  char serviceid[REND_SERVICE_ID_LEN_BASE32+1];
  int uploaded = 0;

  rendpostperiod = get_options()->RendPostPeriod;

  networkstatus_t *c = networkstatus_get_latest_consensus();
  if (c && smartlist_len(c->routerstatus_list) > 0) {
    int seconds_valid, i, j, num_descs;
    smartlist_t *descs = smartlist_new();
    smartlist_t *client_cookies = smartlist_new();
    /* Either upload a single descriptor (including replicas) or one
     * descriptor for each authorized client in case of authorization
     * type 'stealth'. */
    num_descs = service->auth_type == REND_STEALTH_AUTH ?
                    smartlist_len(service->clients) : 1;
    for (j = 0; j < num_descs; j++) {
      crypto_pk_t *client_key = NULL;
      rend_authorized_client_t *client = NULL;
      smartlist_clear(client_cookies);
      switch (service->auth_type) {
        case REND_NO_AUTH:
          /* Do nothing here. */
          break;
        case REND_BASIC_AUTH:
          SMARTLIST_FOREACH(service->clients, rend_authorized_client_t *,
              cl, smartlist_add(client_cookies, cl->descriptor_cookie));
          break;
        case REND_STEALTH_AUTH:
          client = smartlist_get(service->clients, j);
          client_key = client->client_key;
          smartlist_add(client_cookies, client->descriptor_cookie);
          break;
      }
      /* Encode the current descriptor. */
      seconds_valid = rend_encode_v2_descriptors(descs, service->desc,
                                                 now, 0,
                                                 service->auth_type,
                                                 client_key,
                                                 client_cookies);
      if (seconds_valid < 0) {
        log_warn(LD_BUG, "Internal error: couldn't encode service "
                 "descriptor; not uploading.");
        smartlist_free(descs);
        smartlist_free(client_cookies);
        return;
      }
      rend_get_service_id(service->desc->pk, serviceid);
      if (get_options()->PublishHidServDescriptors) {
        /* Post the current descriptors to the hidden service directories. */
        log_info(LD_REND, "Launching upload for hidden service %s",
                     serviceid);
        directory_post_to_hs_dir(service->desc, descs, NULL, serviceid,
                                 seconds_valid);
      }
      /* Free memory for descriptors. */
      for (i = 0; i < smartlist_len(descs); i++)
        rend_encoded_v2_service_descriptor_free(smartlist_get(descs, i));
      smartlist_clear(descs);
      /* Update next upload time. */
      if (seconds_valid - REND_TIME_PERIOD_OVERLAPPING_V2_DESCS
          > rendpostperiod)
        service->next_upload_time = now + rendpostperiod;
      else if (seconds_valid < REND_TIME_PERIOD_OVERLAPPING_V2_DESCS)
        service->next_upload_time = now + seconds_valid + 1;
      else
        service->next_upload_time = now + seconds_valid -
            REND_TIME_PERIOD_OVERLAPPING_V2_DESCS + 1;
      /* Post also the next descriptors, if necessary. */
      if (seconds_valid < REND_TIME_PERIOD_OVERLAPPING_V2_DESCS) {
        seconds_valid = rend_encode_v2_descriptors(descs, service->desc,
                                                   now, 1,
                                                   service->auth_type,
                                                   client_key,
                                                   client_cookies);
        if (seconds_valid < 0) {
          log_warn(LD_BUG, "Internal error: couldn't encode service "
                   "descriptor; not uploading.");
          smartlist_free(descs);
          smartlist_free(client_cookies);
          return;
        }
        if (get_options()->PublishHidServDescriptors) {
          directory_post_to_hs_dir(service->desc, descs, NULL, serviceid,
                                   seconds_valid);
        }
        /* Free memory for descriptors. */
        for (i = 0; i < smartlist_len(descs); i++)
          rend_encoded_v2_service_descriptor_free(smartlist_get(descs, i));
        smartlist_clear(descs);
      }
    }
    smartlist_free(descs);
    smartlist_free(client_cookies);
    uploaded = 1;
    if (get_options()->PublishHidServDescriptors) {
      log_info(LD_REND, "Successfully uploaded v2 rend descriptors!");
    } else {
      log_info(LD_REND, "Successfully stored created v2 rend descriptors!");
    }
  }

  /* If not uploaded, try again in one minute. */
  if (!uploaded)
    service->next_upload_time = now + 60;

  /* Unmark dirty flag of this service. */
  service->desc_is_dirty = 0;
}