示例#1
0
/* This function creates the (default) directory configuration. Well, we have
 * no defaults to set so we simply alloc the memory...
 */
static void*
mapserver_create_dir_config (apr_pool_t *p, char *dir)
{
  mapserver_dir_config *newconf;
  newconf = (mapserver_dir_config*) apr_pcalloc (p, sizeof (mapserver_dir_config));
  newconf->config_pool = p;
  newconf->uri = apr_pstrdup (p, dir);
  newconf->map = NULL;
  newconf->mapfile_name = NULL;
  newconf->mtime = apr_time_from_sec (0);

  if (dir) {
    int len = strlen (dir);
    if (len > 1 && dir [len - 1] == '/' )
      newconf->uri [len - 1] = '\0';
  }
  return newconf;
}
示例#2
0
APREQ_DECLARE(void) apreq_cookie_expires(apreq_cookie_t *c,
                                         const char *time_str)
{
    if (time_str == NULL) {
        c->max_age = -1;
        return;
    }

    if (!strcasecmp(time_str, "now"))
        c->max_age = 0;
    else {
        c->max_age = apr_date_parse_rfc(time_str);
        if (c->max_age == APR_DATE_BAD)
            c->max_age = apr_time_from_sec(apreq_atoi64t(time_str));
        else
            c->max_age -= apr_time_now();
    }
}
示例#3
0
static void do_write(void)
{
    apr_file_t *file;
    apr_status_t rv;

    if (apr_file_open(&file, testfile, APR_WRITE|APR_CREATE, APR_OS_DEFAULT,
                 pool) != APR_SUCCESS)
        errmsg("Could not create file.\n");
    printf("Test file created.\n");

    if ((rv = apr_file_lock(file, APR_FLOCK_EXCLUSIVE)) != APR_SUCCESS)
        errmsg2("Could not lock the file", rv);
    printf("Lock created.\nSleeping...");
    fflush(stdout);

    apr_sleep(apr_time_from_sec(30));

    (void) apr_file_close(file);
    printf(" done.\nExiting.\n");
}
示例#4
0
/* do a HTTP/1.1 age calculation */
CACHE_DECLARE(apr_int64_t) ap_cache_current_age(cache_info *info,
                                                const apr_time_t age_value,
                                                apr_time_t now)
{
    apr_time_t apparent_age, corrected_received_age, response_delay,
               corrected_initial_age, resident_time, current_age,
               age_value_usec;

    age_value_usec = apr_time_from_sec(age_value);

    /* Perform an HTTP/1.1 age calculation. (RFC2616 13.2.3) */

    apparent_age = MAX(0, info->response_time - info->date);
    corrected_received_age = MAX(apparent_age, age_value_usec);
    response_delay = info->response_time - info->request_time;
    corrected_initial_age = corrected_received_age + response_delay;
    resident_time = now - info->response_time;
    current_age = corrected_initial_age + resident_time;

    return apr_time_sec(current_age);
}
示例#5
0
文件: testshm.c 项目: 0jpq0/kbengine
static int msgwait(int sleep_sec, int first_box, int last_box)
{
    int i;
    int recvd = 0;
    apr_time_t start = apr_time_now();
    apr_interval_time_t sleep_duration = apr_time_from_sec(sleep_sec);
    while (apr_time_now() - start < sleep_duration) {
        for (i = first_box; i < last_box; i++) {
            if (boxes[i].msgavail && !strcmp(boxes[i].msg, MSG)) {
                recvd++;
                boxes[i].msgavail = 0; /* reset back to 0 */
                /* reset the msg field.  1024 is a magic number and it should
                 * be a macro, but I am being lazy.
                 */
                memset(boxes[i].msg, 0, 1024);
            }
        }
        apr_sleep(apr_time_make(0, 10000)); /* 10ms */
    }
    return recvd;
}
示例#6
0
void *rss_check_thread(apr_thread_t *th, void *data)
{
    resource_service_fn_t *rs = (resource_service_fn_t *)data;
    rs_simple_priv_t *rss = (rs_simple_priv_t *)rs->priv;
    int do_notify, map_version, status_change;
    apr_interval_time_t dt;

    dt = apr_time_from_sec(rss->check_interval);

    apr_thread_mutex_lock(rss->lock);
    rss->current_check = 0;  //** Triggers a reload
    do {
        log_printf(5, "LOOP START\n");
        _rs_simple_refresh(rs);  //** Do a quick check and see if the file has changed

        do_notify = 0;
        if (rss->current_check != rss->modify_time) { //** Need to reload
            rss->current_check = rss->modify_time;
            do_notify = 1;
            // _rss_make_check_table(rs);
        }
        map_version = rss->modify_time;
        apr_thread_mutex_unlock(rss->lock);

        status_change = (rss->check_timeout <= 0) ? 0 : rss_perform_check(rs);

        if (((do_notify == 1) && (rss->dynamic_mapping == 1)) || (status_change != 0))  rss_mapping_notify(rs, map_version, status_change);

        log_printf(5, "LOOP END\n");

        apr_thread_mutex_lock(rss->lock);
        if (rss->shutdown == 0) apr_thread_cond_timedwait(rss->cond, rss->lock, dt);
    } while (rss->shutdown == 0);

    //** Clean up
    _rss_clear_check_table(rss->ds, rss->rid_mapping, rss->mpool);
    apr_thread_mutex_unlock(rss->lock);

    return(NULL);
}
示例#7
0
/**
 * Creates a new auth_vas_cache, allocated from the given memory pool
 * because the vas_ctx_t must be the same.
 *
 * The vas_ctx and vas_serverid are convenience pointers for cache users -- they
 * can be NULL or unused if the cached items don't need them.
 *
 * @param parent_pool Memory pool to be used as the parent of the cache's pool.
 * @param vas_ctx libvas context to be used by cached items.
 * @param vas_serverid Server ID to associate with cached items (optional).
 * @param unref_cb Function to call immediately after removing an item from the
 *                 cache, for example to free or unref an object. May be NULL.
 * @param get_key_cb Function to get the item's key. See the auth_vas_cache
 *                   documentation for details.
 */
auth_vas_cache * auth_vas_cache_new(apr_pool_t *parent_pool,
	vas_ctx_t *vas_ctx,
	vas_id_t *vas_serverid,
	void (*ref_cb)(void *),
	void (*unref_cb)(void *),
	const char *(*get_key_cb)(void *))
{
    auth_vas_cache *cache = NULL;
	apr_status_t aprerr;

    /* Should we allocate the cache out of the cache subpool instead?
     * Only necessary if caches are destroyed more frequently than processes
     * exit. */
    cache = apr_pcalloc(parent_pool, sizeof(*cache));
    if (!cache) {
        MAV_LOG_P(APLOG_ERR, parent_pool, "Failed to allocate cache structure");
    	return NULL;
    }


	aprerr = apr_pool_create(&cache->pool, parent_pool);
	if (aprerr) {
        MAV_LOG_PERRNO(APLOG_ERR, parent_pool, aprerr, "Failed to create cache memory pool");
	    return NULL;
	}

    cache->table = apr_hash_make(cache->pool);

    cache->vas_ctx = vas_ctx;
    cache->vas_serverid = vas_serverid;
    cache->ref_item_cb = ref_cb;
    cache->unref_item_cb = unref_cb;
    cache->get_key_cb = get_key_cb;

    cache->max_age_us = apr_time_from_sec(DEFAULT_EXPIRE_SECONDS);
    cache->max_size = DEFAULT_MAX_CACHE_SIZE;

    return cache;
}
示例#8
0
static void read_write(abts_case *tc, void *data)
{
    apr_status_t rv;
    char *buf;
    apr_size_t nbytes;
    
    nbytes = strlen("this is a test");
    buf = (char *)apr_palloc(p, nbytes + 1);

    rv = apr_file_pipe_create(&readp, &writep, p);
    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
    ABTS_PTR_NOTNULL(tc, readp);
    ABTS_PTR_NOTNULL(tc, writep);

    rv = apr_file_pipe_timeout_set(readp, apr_time_from_sec(1));
    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);

    if (!rv) {
        rv = apr_file_read(readp, buf, &nbytes);
        ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_TIMEUP(rv));
        ABTS_INT_EQUAL(tc, 0, nbytes);
    }
}
示例#9
0
static void read_write(CuTest *tc)
{
    apr_status_t rv;
    char *buf;
    apr_size_t nbytes;
    
    nbytes = strlen("this is a test");
    buf = (char *)apr_palloc(p, nbytes + 1);

    rv = apr_file_pipe_create(&readp, &writep, p);
    CuAssertIntEquals(tc, APR_SUCCESS, rv);
    CuAssertPtrNotNull(tc, readp);
    CuAssertPtrNotNull(tc, writep);

    rv = apr_file_pipe_timeout_set(readp, apr_time_from_sec(1));
    CuAssertIntEquals(tc, APR_SUCCESS, rv);

    rv = apr_file_read(readp, buf, &nbytes);
    if (!rv) {
      CuAssertIntEquals(tc, 1, APR_STATUS_IS_TIMEUP(rv));
      CuAssertIntEquals(tc, 0, nbytes);
    }
}
static void test_timeoutcond(abts_case *tc, void *data)
{
    apr_status_t s;
    apr_interval_time_t timeout;
    apr_time_t begin, end;
    int i;

    s = apr_thread_mutex_create(&timeout_mutex, APR_THREAD_MUTEX_DEFAULT, p);
    ABTS_INT_EQUAL(tc, APR_SUCCESS, s);
    ABTS_PTR_NOTNULL(tc, timeout_mutex);

    s = apr_thread_cond_create(&timeout_cond, p);
    ABTS_INT_EQUAL(tc, APR_SUCCESS, s);
    ABTS_PTR_NOTNULL(tc, timeout_cond);

    timeout = apr_time_from_sec(5);

    for (i = 0; i < MAX_RETRY; i++) {
        apr_thread_mutex_lock(timeout_mutex);

        begin = apr_time_now();
        s = apr_thread_cond_timedwait(timeout_cond, timeout_mutex, timeout);
        end = apr_time_now();
        apr_thread_mutex_unlock(timeout_mutex);
        
        if (s != APR_SUCCESS && !APR_STATUS_IS_TIMEUP(s)) {
            continue;
        }
        ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_TIMEUP(s));
        ABTS_ASSERT(tc, "Timer returned too late", end - begin - timeout < 500000);
        break;
    }
    ABTS_ASSERT(tc, "Too many retries", i < MAX_RETRY);
    APR_ASSERT_SUCCESS(tc, "Unable to destroy the conditional",
                       apr_thread_cond_destroy(timeout_cond));
}
示例#11
0
static logsql_query_ret safe_sql_insert(request_rec *r, logsql_tabletype table_type,
		const char *table_name, const char *query) {

	logsql_query_ret result;
	logsql_state *cls = ap_get_module_config(r->server->module_config,
									&log_sql_module);

	if (!global_config.db.connected || global_config.driver == NULL) {
		/* preserve query */
		return LOGSQL_QUERY_NOLINK;
	}

	result = global_config.driver->insert(r,&global_config.db,query);

	/* If we ran the query and it returned an error, try to be robust.
	* (After all, the module thought it had a valid mysql_log connection but the query
	* could have failed for a number of reasons, so we have to be extra-safe and check.) */
	switch (result) {
	case LOGSQL_QUERY_SUCCESS:
		return LOGSQL_QUERY_SUCCESS;
	case LOGSQL_QUERY_NOLINK:
		return LOGSQL_QUERY_FAIL;
		/* TODO: What do we do here */
	case LOGSQL_QUERY_FAIL:
		global_config.driver->disconnect(&global_config.db);
		global_config.db.connected = 0;
		/* re-open the connection and try again */
		if (log_sql_opendb_link(r->server) != LOGSQL_OPENDB_FAIL) {
			log_error(APLOG_MARK,APLOG_NOTICE,0, r->server,"db reconnect successful");
#			if defined(WITH_APACHE20)
			apr_sleep(apr_time_from_sec(0.25)); /* pause for a quarter second */
#			elif defined(WITH_APACHE13)
#            if defined(WIN32)
            Sleep((DWORD)0.25);
#            else
			{
				struct timespec delay, remainder;
				int nanoret;
				delay.tv_sec = 0;
				delay.tv_nsec = 250000000; /* pause for a quarter second */
				nanoret = nanosleep(&delay, &remainder);
				if (nanoret && errno != EINTR) {
					log_error(APLOG_MARK,APLOG_ERR, errno, r->server,"nanosleep unsuccessful");
				}
			}
#			 endif /* win32 */
#			endif
			result = global_config.driver->insert(r,&global_config.db,query);
			if (result == LOGSQL_QUERY_SUCCESS) {
				return LOGSQL_QUERY_SUCCESS;
			} else {
				log_error(APLOG_MARK,APLOG_ERR,0,r->server,"second attempt failed");
				preserve_entry(r, query);
				return LOGSQL_QUERY_PRESERVED;
			}
		} else {
			log_error(APLOG_MARK,APLOG_ERR,0,r->server,
				"reconnect failed, unable to reach database. SQL logging stopped until child regains a db connection.");
			log_error(APLOG_MARK,APLOG_ERR,0,r->server,
				"log entries are being preserved in %s",cls->preserve_file);
			preserve_entry(r, query);
			return LOGSQL_QUERY_PRESERVED;
		}
		break;
	case LOGSQL_QUERY_NOTABLE:
		if (global_config.createtables) {
			log_error(APLOG_MARK,APLOG_ERR,0,r->server,
					"table doesn't exist...creating now");
			if ((result = global_config.driver->create_table(r, &global_config.db, table_type,
				table_name))!=LOGSQL_TABLE_SUCCESS) {
				log_error(APLOG_MARK,APLOG_ERR,result,r->server,
					"child attempted but failed to create one or more tables for %s, preserving query", ap_get_server_name(r));
				preserve_entry(r, query);
				return LOGSQL_QUERY_PRESERVED;
			} else {
				log_error(APLOG_MARK,APLOG_ERR,result, r->server,
					"tables successfully created - retrying query");
				if ((result = global_config.driver->insert(r,&global_config.db,query))!=LOGSQL_QUERY_SUCCESS) {
					log_error(APLOG_MARK,APLOG_ERR,result, r->server,
						"giving up, preserving query");
					preserve_entry(r, query);
					return LOGSQL_QUERY_PRESERVED;
				} else {
					log_error(APLOG_MARK,APLOG_NOTICE,0, r->server,
						"query successful after table creation");
					return LOGSQL_QUERY_SUCCESS;
				}
			}
		} else {
			log_error(APLOG_MARK,APLOG_ERR,0,r->server,
				"table doesn't exist, creation denied by configuration, preserving query");
			preserve_entry(r, query);
			return LOGSQL_QUERY_PRESERVED;
		}
		break;
	default:
		log_error(APLOG_MARK,APLOG_ERR,0, r->server,
				"Invalid return code from mog_log_query");
		return LOGSQL_QUERY_FAIL;
		break;
	}
	return LOGSQL_QUERY_FAIL;
}
示例#12
0
AP_DECLARE(void) ap_reclaim_child_processes(int terminate,
                                            ap_reclaim_callback_fn_t *mpm_callback)
{
    apr_time_t waittime = 1024 * 16;
    int i;
    extra_process_t *cur_extra;
    int not_dead_yet;
    int max_daemons;
    apr_time_t starttime = apr_time_now();
    /* this table of actions and elapsed times tells what action is taken
     * at which elapsed time from starting the reclaim
     */
    struct {
        action_t action;
        apr_time_t action_time;
    } action_table[] = {
        {DO_NOTHING, 0}, /* dummy entry for iterations where we reap
                          * children but take no action against
                          * stragglers
                          */
        {SEND_SIGTERM, apr_time_from_sec(3)},
        {SEND_SIGTERM, apr_time_from_sec(5)},
        {SEND_SIGTERM, apr_time_from_sec(7)},
        {SEND_SIGKILL, apr_time_from_sec(9)},
        {GIVEUP,       apr_time_from_sec(10)}
    };
    int cur_action;      /* index of action we decided to take this
                          * iteration
                          */
    int next_action = 1; /* index of first real action */

    ap_mpm_query(AP_MPMQ_MAX_DAEMON_USED, &max_daemons);

    do {
        apr_sleep(waittime);
        /* don't let waittime get longer than 1 second; otherwise, we don't
         * react quickly to the last child exiting, and taking action can
         * be delayed
         */
        waittime = waittime * 4;
        if (waittime > apr_time_from_sec(1)) {
            waittime = apr_time_from_sec(1);
        }

        /* see what action to take, if any */
        if (action_table[next_action].action_time <= apr_time_now() - starttime) {
            cur_action = next_action;
            ++next_action;
        }
        else {
            cur_action = 0; /* nothing to do */
        }

        /* now see who is done */
        not_dead_yet = 0;
        for (i = 0; i < max_daemons; ++i) {
            process_score *ps = ap_get_scoreboard_process(i);
            pid_t pid = ps->pid;

            if (pid == 0) {
                continue; /* not every scoreboard entry is in use */
            }

            if (reclaim_one_pid(pid, action_table[cur_action].action)) {
                mpm_callback(i, 0, 0);
            }
            else {
                ++not_dead_yet;
            }
        }

        cur_extra = extras;
        while (cur_extra) {
            ap_generation_t old_gen;
            extra_process_t *next = cur_extra->next;

            if (reclaim_one_pid(cur_extra->pid, action_table[cur_action].action)) {
                if (ap_unregister_extra_mpm_process(cur_extra->pid, &old_gen) == 1) {
                    mpm_callback(-1, cur_extra->pid, old_gen);
                }
                else {
                    AP_DEBUG_ASSERT(1 == 0);
                }
            }
            else {
                ++not_dead_yet;
            }
            cur_extra = next;
        }
#if APR_HAS_OTHER_CHILD
        apr_proc_other_child_refresh_all(APR_OC_REASON_RESTART);
#endif

    } while (not_dead_yet > 0 &&
             action_table[cur_action].action != GIVEUP);
}
示例#13
0
int main(int argc, char *argv[])
{
    apr_pool_t *p;
    apr_socket_t *sock;
    apr_status_t rv;
    apr_sockaddr_t *remote_sa;

    apr_initialize();
    atexit(apr_terminate);
    apr_pool_create(&p, NULL);

    if (argc < 3) {
        exit(-1);
    }

    rv = apr_sockaddr_info_get(&remote_sa, argv[2], APR_UNSPEC, 8021, 0, p);
    if (rv != APR_SUCCESS) {
        exit(-1);
    }

    if (apr_socket_create(&sock, remote_sa->family, SOCK_STREAM, 0,
                p) != APR_SUCCESS) {
        exit(-1);
    }

    rv = apr_socket_timeout_set(sock, apr_time_from_sec(3));
    if (rv) {
        exit(-1);
    }

    apr_socket_connect(sock, remote_sa);
        
    if (!strcmp("read", argv[1])) {
        char datarecv[STRLEN];
        apr_size_t length = STRLEN;
        apr_status_t rv;

        memset(datarecv, 0, STRLEN);
        rv = apr_socket_recv(sock, datarecv, &length);
        apr_socket_close(sock);
        if (APR_STATUS_IS_TIMEUP(rv)) {
            exit(SOCKET_TIMEOUT); 
        }

        if (strcmp(datarecv, DATASTR)) {
            exit(-1);
        }
        
        exit((int)length);
    }
    else if (!strcmp("write", argv[1])
             || !strcmp("write_after_delay", argv[1])) {
        apr_size_t length = strlen(DATASTR);

        if (!strcmp("write_after_delay", argv[1])) {
            apr_sleep(apr_time_from_sec(2));
        }

        apr_socket_send(sock, DATASTR, &length);

        apr_socket_close(sock);
        exit((int)length);
    }
    else if (!strcmp("close", argv[1])) {
        apr_socket_close(sock);
        exit(0);
    }
    exit(-1);
}
示例#14
0
void
auth_vas_cache_set_max_age(auth_vas_cache *cache, unsigned int seconds) {
    cache->max_age_us = apr_time_from_sec(seconds);
}
示例#15
0
文件: core.c 项目: shigekun/mapcache
mapcache_http_response *mapcache_core_get_tile(mapcache_context *ctx, mapcache_request_get_tile *req_tile)
{
  int expires = 0;
  mapcache_http_response *response;
  int i,first = -1;
  int ntiles_with_data = 0;
  char *timestr;
  mapcache_image *base=NULL,*overlay;
  mapcache_image_format *format = NULL;

#ifdef DEBUG
  if(req_tile->ntiles ==0) {
    ctx->set_error(ctx,500,"BUG: get_tile called with 0 tiles");
    return NULL;
  }
#endif
  expires = 0;
  response = mapcache_http_response_create(ctx->pool);


  mapcache_prefetch_tiles(ctx,req_tile->tiles,req_tile->ntiles);
  if(GC_HAS_ERROR(ctx))
    return NULL;

  /* count how many tiles actually contain data */
  for(i=0; i<req_tile->ntiles; i++) {
    /* add 1 if tile->nodata == 0 */
    ntiles_with_data -= req_tile->tiles[i]->nodata - 1;
  }
  if(ntiles_with_data == 0) {
    ctx->set_error(ctx,404,
                   "no tiles containing image data could be retrieved (not in cache, and read-only tileset or no source configured)");
    return NULL;
  }
  /* this loop retrieves the tiles from the caches, and eventually decodes and merges them together
   * if multiple tiles were asked for */
  for(i=0; i<req_tile->ntiles; i++) {
    mapcache_tile *tile = req_tile->tiles[i];
    if(tile->nodata) continue;
    if(first == -1) {
      first = i;
      response->mtime = tile->mtime;
      expires = tile->expires;
      /* if we have multiple tiles to merge, decode the image data */
      if(ntiles_with_data>1) {
        if(!tile->raw_image) {
          tile->raw_image = mapcache_imageio_decode(ctx, tile->encoded_data);
          if(!tile->raw_image) return NULL;
        }
        base = tile->raw_image;
      }
    } else {
      if(response->mtime < tile->mtime)
        response->mtime = tile->mtime;
      if(tile->expires < expires) {
        expires = tile->expires;
      }
      if(!tile->raw_image) {
        tile->raw_image = mapcache_imageio_decode(ctx, tile->encoded_data);
        if(!tile->raw_image) return NULL;
      }
      overlay = tile->raw_image;
      mapcache_image_merge(ctx, base, overlay);
      if(GC_HAS_ERROR(ctx)) {
        return NULL;
      }
    }
  }
  format = NULL;

  /* if we had more than one tile, we need to encode the raw image data into a mapcache_buffer */
  if(ntiles_with_data > 1) {
    if(req_tile->format) {
      format = req_tile->format;
    } else {
      format = req_tile->tiles[first]->tileset->format;
      if(!format) {
        format = ctx->config->default_image_format; /* this one is always defined */
      }
    }
    response->data = format->write(ctx, base, format);
    if(GC_HAS_ERROR(ctx)) {
      return NULL;
    }
  } else {
    response->data = req_tile->tiles[first]->encoded_data;
    format = req_tile->tiles[first]->tileset->format;
  }

  /* compute the content-type */
  if(format && format->mime_type) {
    apr_table_set(response->headers,"Content-Type",format->mime_type);
  } else {
    mapcache_image_format_type t = mapcache_imageio_header_sniff(ctx,response->data);
    if(t == GC_PNG)
      apr_table_set(response->headers,"Content-Type","image/png");
    else if(t == GC_JPEG)
      apr_table_set(response->headers,"Content-Type","image/jpeg");
  }

  /* compute expiry headers */
  if(expires) {
    apr_time_t now = apr_time_now();
    apr_time_t additional = apr_time_from_sec(expires);
    apr_time_t texpires = now + additional;
    apr_table_set(response->headers, "Cache-Control",apr_psprintf(ctx->pool, "max-age=%d", expires));
    timestr = apr_palloc(ctx->pool, APR_RFC822_DATE_LEN);
    apr_rfc822_date(timestr, texpires);
    apr_table_setn(response->headers, "Expires", timestr);
  }

  return response;
}
static void test_mech_mode(apr_lockmech_e mech, const char *mech_name,
                           test_mode_e test_mode)
{
  apr_thread_t *threads[20];
  int numThreads = 5;
  int i;
  apr_status_t rv;

  printf("Trying %s mutexes with mechanism `%s'...\n",
         test_mode == TEST_GLOBAL ? "global" : "proc", mech_name);

  assert(numThreads <= sizeof(threads) / sizeof(threads[0]));

  assert(apr_pool_create(&p, NULL) == APR_SUCCESS);

  assert(apr_thread_mutex_create(&thread_mutex, 0, p) == APR_SUCCESS);
  assert(apr_thread_mutex_lock(thread_mutex) == APR_SUCCESS);
  
  lock_init(mech, test_mode);

  counter = 0;

  i = 0;
  while (i < numThreads)
  {
    rv = apr_thread_create(&threads[i],
                           NULL,
                           eachThread,
                           (void *)test_mode,
                           p);
    if (rv != APR_SUCCESS) {
      fprintf(stderr, "apr_thread_create->%d\n", rv);
      exit(1);
    }
    ++i;
  }

  apr_sleep(apr_time_from_sec(5));

  if (test_mode == TEST_PROC) {
      printf("  Mutex mechanism `%s' is %sglobal in scope on this platform.\n",
             mech_name, counter == 1 ? "" : "not ");
  }
  else {
      if (counter != 1) {
          fprintf(stderr, "\n!!!apr_global_mutex operations are broken on this "
                  "platform for mutex mechanism `%s'!\n"
                  "They don't block out threads within the same process.\n",
                  mech_name);
          fprintf(stderr, "counter value: %d\n", counter);
          exit(1);
      }
      else {
          printf("  no problems encountered...\n");
      }
  }
  
  assert(apr_thread_mutex_unlock(thread_mutex) == APR_SUCCESS);

  i = 0;
  while (i < numThreads)
  {
    apr_status_t ignored;

    rv = apr_thread_join(&ignored,
                         threads[i]);
    assert(rv == APR_SUCCESS);
    ++i;
  }

  lock_destroy(test_mode);
  apr_thread_mutex_destroy(thread_mutex);
  apr_pool_destroy(p);
}
// See here for the structure of request_rec:
// http://ci.apache.org/projects/httpd/trunk/doxygen/structrequest__rec.html
static int hook(request_rec *r)
{
    settings_rec *cfg = ap_get_module_config( r->per_dir_config,
                                              &querystring2cookie_module );

    /* Do not run in subrequests, don't run if not enabled */
    if( !(cfg->enabled || r->main) ) {
        return DECLINED;
    }

    /* No query string? nothing to do here */
    if( !(r->args) || strlen( r->args ) < 1 ) {
        return DECLINED;
    }

    /* skip if dnt headers are present? */
    if( !(cfg->enabled_if_dnt) && apr_table_get( r->headers_in, "DNT" ) ) {
        _DEBUG && fprintf( stderr, "DNT header sent: declined\n" );
        return DECLINED;
    }

    _DEBUG && fprintf( stderr, "Query string: '%s'\n", r->args );

    // ***********************************
    // Calculate expiry time
    // ***********************************

    // The expiry time. We can't use max-age because IE6 - IE8 do not
    // support it :(
    char *expires = "";

    if( cfg->cookie_expires > 0 ) {

        apr_time_exp_t tms;
        apr_time_exp_gmt( &tms, r->request_time
                              + apr_time_from_sec( cfg->cookie_expires ) );

        expires = apr_psprintf( r->pool,
                            "expires=%s, %.2d-%s-%.2d %.2d:%.2d:%.2d GMT",
                            apr_day_snames[tms.tm_wday],
                            tms.tm_mday,
                            apr_month_snames[tms.tm_mon],
                            tms.tm_year % 100,
                            tms.tm_hour, tms.tm_min, tms.tm_sec
                        );
    }

    // ***********************************
    // Find key/value pairs
    // ***********************************

    // keep track of how much data we've been writing - there's a limit to how
    // much a browser will store per domain (usually 4k) so we want to make sure
    // it's not getting flooded.
    int total_pair_size = 0;

    // This holds the final cookie we'll send back - make sure to initialize
    // or it can point at garbage!
    char *cookie = "";

    // string to use as the cookie name (together with the prefix) - make sure to
    // initialize or it can point at garbage!
    char *cookie_name = "";

    // Iterate over the key/value pairs
    char *last_pair;
    char *pair = apr_strtok( apr_pstrdup( r->pool, r->args ), "&", &last_pair );

    _DEBUG && fprintf( stderr, "about to parse query string for pairs\n" );

    _DEBUG && fprintf( stderr, "looking for cookie name in %s\n", cfg->cookie_name_from );

    while( pair != NULL ) {

        // length of the substr before the = sign (or index of the = sign)
        int contains_equals_at = strcspn( pair, "=" );

        // Does not contains a =, or starts with a =, meaning it's garbage
        if( !strstr(pair, "=") || contains_equals_at < 1 ) {
            _DEBUG && fprintf( stderr, "invalid pair: %s\n", pair );

            // And get the next pair -- has to be done at every break
            pair = apr_strtok( NULL, "&", &last_pair );
            continue;
        }

        _DEBUG && fprintf( stderr, "pair looks valid: %s - = sign at pos: %i\n",
                            pair, contains_equals_at );

        // So this IS a key value pair. Let's get the key and the value.
        // first, get the key - everything up to the first =
        char *key   = apr_pstrndup( r->pool, pair, contains_equals_at );

        // now get the value, everything AFTER the = sign. We do that by
        // moving the pointer past the = sign.
        char *value = apr_pstrdup( r->pool, pair );
        value += contains_equals_at + 1;

        _DEBUG && fprintf( stderr, "pair=%s, key=%s, value=%s\n", pair, key, value );

        // you want us to use a name from the query string?
        // This might be that name.
        if( cfg->cookie_name_from && !(strlen(cookie_name)) &&
            strcasecmp( key, cfg->cookie_name_from ) == 0
        ) {
            // get everything after the = sign -- that's our name.
            cookie_name = apr_pstrcat( r->pool, cfg->cookie_prefix, value, NULL );

            _DEBUG && fprintf( stderr, "using %s as the cookie name\n", cookie_name );

            // And get the next pair -- has to be done at every break
            pair = apr_strtok( NULL, "&", &last_pair );
            continue;

        // may be on the ignore list
        } else {

            // may have to continue the outer loop, use this as a marker
            int do_continue = 0;

            // you might have blacklisted this key; let's check
            // Following tutorial code here again:
            // http://dev.ariel-networks.com/apr/apr-tutorial/html/apr-tutorial-19.html
            int i;
            for( i = 0; i < cfg->qs_ignore->nelts; i++ ) {

                char *ignore = ((char **)cfg->qs_ignore->elts)[i];

                _DEBUG && fprintf( stderr, "processing ignore %s against pair %s\n",
                                        ignore, pair );

                // it's indeed on the ignore list; move on
                // do this by comparing the string length first - if the length of
                // the ignore key and the key are identical AND the first N characters
                // of the string are the same
                if( strcasecmp( key, ignore ) == 0 ) {
                    _DEBUG && fprintf( stderr, "pair %s is on the ignore list: %s\n",
                                        pair, ignore );

                    // signal to continue the outer loop; we found an ignore match
                    do_continue = 1;
                    break;
                }
            }

            // ignore match found, move on
            if( do_continue ) {
                // And get the next pair -- has to be done at every break
                pair = apr_strtok( NULL, "&", &last_pair );
                continue;
            }
        }

        // looks like a valid key=value declaration
        _DEBUG && fprintf( stderr, "valid key/value pair: %s\n", pair );

        // Now, the key may contain URL unsafe characters, which are also
        // not allowed in Cookies. See here:
        // http://tools.ietf.org/html/rfc2068, section 2.2 on 'tspecials'
        //
        // So instead, we url encode the key. The size of the key is max
        // 3 times old key size (any char gets encoded into %xx), so allow
        // for that space. See the documentation here:
        // http://httpd.apache.org/apreq/docs/libapreq2/apreq__util_8h.html#785be2ceae273b0a7b2ffda223b2ebae
        char *escaped_key   = apreq_escape( r->pool, key, strlen(key) );
        char *escaped_value = apreq_escape( r->pool, value, strlen(value) );

        _DEBUG && fprintf( stderr, "Original key: %s - Escaped key: %s\n", key, escaped_key );
        _DEBUG && fprintf( stderr, "Original value: %s - Escaped value: %s\n", value, escaped_value );

        // Now, let's do some transposing: The '=' sign needs to be replaced
        // with whatever the separator is. It can't be a '=' sign, as that's
        // illegal in cookies. The string may be larger than a single char,
        // so split the string and do the magix.

        // This makes key[delim]value - redefining pair here is safe, we're
        // just using it for printing now.
        char *key_value = apr_pstrcat( r->pool,
                                       escaped_key,
                                       cfg->cookie_key_value_delimiter,
                                       escaped_value,
                                       NULL
                                    );

        int this_pair_size = strlen( key_value );

        // Make sure the individual pair, as well as the whole thing doesn't
        // get too long

        _DEBUG && fprintf( stderr,
                "this pair size: %i, total pair size: %i, max size: %i\n",
                this_pair_size, total_pair_size, cfg->cookie_max_size  );

        if( (this_pair_size <= cfg->cookie_max_size) &&
            (total_pair_size + this_pair_size <= cfg->cookie_max_size)
        ) {

            cookie = apr_pstrcat( r->pool,
                                  cookie,       // the cookie so far
                                  // If we already have pairs in here, we need the
                                  // delimiter, otherwise we don't.
                                  (strlen(cookie) ? cfg->cookie_pair_delimiter : ""),
                                  key_value,    // the next pair.
                                  NULL
                            );

            // update the book keeping - this is the new size including delims
            total_pair_size = strlen(cookie);

            _DEBUG && fprintf( stderr, "this pair size: %i, total pair size: %i\n",
                                    this_pair_size, total_pair_size );

        } else {
            _DEBUG && fprintf( stderr,
                "Pair size too long to add: %s (this: %i total: %i max: %i)\n",
                key_value, this_pair_size, total_pair_size, cfg->cookie_max_size );
        }

        // and move the pointer
        pair = apr_strtok( NULL, "&", &last_pair );
    }

     // So you told us we should use a cookie name from the query string,
     // but we never found it in there. That's a problem.
     if( cfg->cookie_name_from && !strlen(cookie_name) ) {

         // r->err_headers_out also honors non-2xx responses and
         // internal redirects. See the patch here:
         // http://svn.apache.org/viewvc?view=revision&revision=1154620
         apr_table_addn( r->err_headers_out,
             "X-QS2Cookie",
             apr_pstrcat( r->pool,
                 "ERROR: Did not detect cookie name - missing QS argument: ",
                 cfg->cookie_name_from,
                 NULL
             )
         );

     // Let's return the output
     } else {

         // we got here without a cookie name? We can use the default.
         if( !strlen(cookie_name) ) {
             _DEBUG && fprintf( stderr, "explicitly setting cookie name to: %s\n",
                                         cfg->cookie_name );

             cookie_name = apr_pstrcat( r->pool,
                                        cfg->cookie_prefix, cfg->cookie_name,
                                        NULL );
         }

         _DEBUG && fprintf( stderr, "cookie name: %s\n", cookie_name );

        // XXX use a sprintf format for more flexibility?
        if( cfg->encode_in_key ) {
            _DEBUG && fprintf( stderr, "%s: encoding in the key\n", cookie_name );

            cookie = apr_pstrcat( r->pool,
                            // cookie data
                            cookie_name, cfg->cookie_pair_delimiter, cookie, "=",
                            // The format is different on 32 (%ld) vs 64bit (%lld), so
                            // use the constant for it instead. You can find this in apr.h
                            apr_psprintf( r->pool, "%" APR_OFF_T_FMT, apr_time_sec(apr_time_now()) ),
                            NULL
                         );
        } else {
            _DEBUG && fprintf( stderr, "%s: encoding in the value\n", cookie_name );
            cookie = apr_pstrcat( r->pool, cookie_name, "=", cookie, NULL );

        }

        // And now add the meta data to the cookie
        cookie = apr_pstrcat( r->pool, cookie, "; ",
                                "path=/; ", cfg->cookie_domain, expires,
                                NULL );

        _DEBUG && fprintf( stderr, "cookie: %s\n", cookie );

        // r->err_headers_out also honors non-2xx responses and
        // internal redirects. See the patch here:
        // http://svn.apache.org/viewvc?view=revision&revision=1154620
        apr_table_addn( r->err_headers_out, "Set-Cookie", cookie );
    }

    return OK;
}
int main (int argc, const char * const argv[])
{
    char buf[BUFSIZE];
    apr_size_t nRead, nWrite;
    apr_file_t *f_stdin;
    apr_file_t *f_stdout;
    apr_getopt_t *opt;
    apr_status_t rv;
    char c;
    const char *opt_arg;
    const char *err = NULL;
#if APR_FILES_AS_SOCKETS
    apr_pollfd_t pollfd = { 0 };
    apr_status_t pollret = APR_SUCCESS;
    int polltimeout;
#endif

    apr_app_initialize(&argc, &argv, NULL);
    atexit(apr_terminate);

    memset(&config, 0, sizeof config);
    memset(&status, 0, sizeof status);
    status.rotateReason = ROTATE_NONE;

    apr_pool_create(&status.pool, NULL);
    apr_getopt_init(&opt, status.pool, argc, argv);
#if APR_FILES_AS_SOCKETS
    while ((rv = apr_getopt(opt, "lL:p:ftvecn:", &c, &opt_arg)) == APR_SUCCESS) {
#else
    while ((rv = apr_getopt(opt, "lL:p:ftven:", &c, &opt_arg)) == APR_SUCCESS) {
#endif
        switch (c) {
        case 'l':
            config.use_localtime = 1;
            break;
        case 'L':
            config.linkfile = opt_arg;
            break;
        case 'p':
            config.postrotate_prog = opt_arg;
            break;
        case 'f':
            config.force_open = 1;
            break;
        case 't':
            config.truncate = 1;
            break;
        case 'v':
            config.verbose = 1;
            break;
        case 'e':
            config.echo = 1;
            break;
#if APR_FILES_AS_SOCKETS
        case 'c':
            config.create_empty = 1;
            break;
#endif
        case 'n':
            config.num_files = atoi(opt_arg);
            status.fileNum = -1;
            break;
        }
    }

    if (rv != APR_EOF) {
        usage(argv[0], NULL /* specific error message already issued */ );
    }

    /*
     * After the initial flags we need 2 to 4 arguments,
     * the file name, either the rotation interval time or size
     * or both of them, and optionally the UTC offset.
     */
    if ((argc - opt->ind < 2) || (argc - opt->ind > 4) ) {
        usage(argv[0], "Incorrect number of arguments");
    }

    config.szLogRoot = argv[opt->ind++];

    /* Read in the remaining flags, namely time, size and UTC offset. */
    for(; opt->ind < argc; opt->ind++) {
        if ((err = get_time_or_size(&config, argv[opt->ind],
                                    opt->ind < argc - 1 ? 0 : 1)) != NULL) {
            usage(argv[0], err);
        }
    }

    config.use_strftime = (strchr(config.szLogRoot, '%') != NULL);

    if (config.use_strftime && config.num_files > 0) { 
        fprintf(stderr, "Cannot use -n with %% in filename\n");
        exit(1);
    }

    if (status.fileNum == -1 && config.num_files < 1) { 
        fprintf(stderr, "Invalid -n argument\n");
        exit(1);
    }

    if (apr_file_open_stdin(&f_stdin, status.pool) != APR_SUCCESS) {
        fprintf(stderr, "Unable to open stdin\n");
        exit(1);
    }

    if (apr_file_open_stdout(&f_stdout, status.pool) != APR_SUCCESS) {
        fprintf(stderr, "Unable to open stdout\n");
        exit(1);
    }

    /*
     * Write out result of config parsing if verbose is set.
     */
    if (config.verbose) {
        dumpConfig(&config);
    }

#if APR_FILES_AS_SOCKETS
    if (config.create_empty && config.tRotation) {
        pollfd.p = status.pool;
        pollfd.desc_type = APR_POLL_FILE;
        pollfd.reqevents = APR_POLLIN;
        pollfd.desc.f = f_stdin;
    }
#endif

    /*
     * Immediately open the logfile as we start, if we were forced
     * to do so via '-f'.
     */
    if (config.force_open) {
        doRotate(&config, &status);
    }

    for (;;) {
        nRead = sizeof(buf);
#if APR_FILES_AS_SOCKETS
        if (config.create_empty && config.tRotation) {
            polltimeout = status.tLogEnd ? status.tLogEnd - get_now(&config) : config.tRotation;
            if (polltimeout <= 0) {
                pollret = APR_TIMEUP;
            }
            else {
                pollret = apr_poll(&pollfd, 1, &pollret, apr_time_from_sec(polltimeout));
            }
        }
        if (pollret == APR_SUCCESS) {
            rv = apr_file_read(f_stdin, buf, &nRead);
            if (APR_STATUS_IS_EOF(rv)) {
                break;
            }
            else if (rv != APR_SUCCESS) {
                exit(3);
            }
        }
        else if (pollret == APR_TIMEUP) {
            *buf = 0;
            nRead = 0;
        }
        else {
            fprintf(stderr, "Unable to poll stdin\n");
            exit(5);
        }
#else /* APR_FILES_AS_SOCKETS */
        rv = apr_file_read(f_stdin, buf, &nRead);
        if (APR_STATUS_IS_EOF(rv)) {
            break;
        }
        else if (rv != APR_SUCCESS) {
            exit(3);
        }
#endif /* APR_FILES_AS_SOCKETS */
        checkRotate(&config, &status);
        if (status.rotateReason != ROTATE_NONE) {
            doRotate(&config, &status);
        }

        nWrite = nRead;
        rv = apr_file_write_full(status.current.fd, buf, nWrite, &nWrite);
        if (nWrite != nRead) {
            apr_off_t cur_offset;

            cur_offset = 0;
            if (apr_file_seek(status.current.fd, APR_CUR, &cur_offset) != APR_SUCCESS) {
                cur_offset = -1;
            }
            status.nMessCount++;
            apr_snprintf(status.errbuf, sizeof status.errbuf,
                         "Error %d writing to log file at offset %" APR_OFF_T_FMT ". "
                         "%10d messages lost (%pm)\n",
                         rv, cur_offset, status.nMessCount, &rv);

            truncate_and_write_error(&status);
        }
        else {
            status.nMessCount++;
        }
        if (config.echo) {
            if (apr_file_write_full(f_stdout, buf, nRead, &nWrite)) {
                fprintf(stderr, "Unable to write to stdout\n");
                exit(4);
            }
        }
    }

    return 0; /* reached only at stdin EOF. */
}
示例#19
0
/* Verify the OCSP status of given certificate.  Returns
 * V_OCSP_CERTSTATUS_* result code. */
static int verify_ocsp_status(X509 *cert, X509_STORE_CTX *ctx, conn_rec *c,
                              SSLSrvConfigRec *sc, server_rec *s,
                              apr_pool_t *pool)
{
    int rc = V_OCSP_CERTSTATUS_GOOD;
    OCSP_RESPONSE *response = NULL;
    OCSP_BASICRESP *basicResponse = NULL;
    OCSP_REQUEST *request = NULL;
    OCSP_CERTID *certID = NULL;
    apr_uri_t *ruri;

    ruri = determine_responder_uri(sc, cert, c, pool);
    if (!ruri) {
        return V_OCSP_CERTSTATUS_UNKNOWN;
    }

    request = create_request(ctx, cert, &certID, s, pool, sc);
    if (request) {
        apr_interval_time_t to = sc->server->ocsp_responder_timeout == UNSET ?
                                 apr_time_from_sec(DEFAULT_OCSP_TIMEOUT) :
                                 sc->server->ocsp_responder_timeout;
        response = modssl_dispatch_ocsp_request(ruri, to, request, c, pool);
    }

    if (!request || !response) {
        rc = V_OCSP_CERTSTATUS_UNKNOWN;
    }

    if (rc == V_OCSP_CERTSTATUS_GOOD) {
        int r = OCSP_response_status(response);

        if (r != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
            ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(01922)
                         "OCSP response not successful: %d", rc);
            rc = V_OCSP_CERTSTATUS_UNKNOWN;
        }
    }

    if (rc == V_OCSP_CERTSTATUS_GOOD) {
        basicResponse = OCSP_response_get1_basic(response);
        if (!basicResponse) {
            ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(01923)
                          "could not retrieve OCSP basic response");
            ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, s);
            rc = V_OCSP_CERTSTATUS_UNKNOWN;
        }
    }

    if (rc == V_OCSP_CERTSTATUS_GOOD &&
            sc->server->ocsp_use_request_nonce != FALSE &&
            OCSP_check_nonce(request, basicResponse) != 1) {
        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(01924)
                    "Bad OCSP responder answer (bad nonce)");
        rc = V_OCSP_CERTSTATUS_UNKNOWN;
    }

    if (rc == V_OCSP_CERTSTATUS_GOOD) {
        /* TODO: allow flags configuration. */
        if (OCSP_basic_verify(basicResponse, NULL, ctx->ctx, 0) != 1) {
            ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(01925)
                        "failed to verify the OCSP response");
            ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, s);
            rc = V_OCSP_CERTSTATUS_UNKNOWN;
        }
    }

    if (rc == V_OCSP_CERTSTATUS_GOOD) {
        int reason = -1, status;
        ASN1_GENERALIZEDTIME *thisup = NULL, *nextup = NULL;

        rc = OCSP_resp_find_status(basicResponse, certID, &status,
                                   &reason, NULL, &thisup, &nextup);
        if (rc != 1) {
            ssl_log_cxerror(SSLLOG_MARK, APLOG_ERR, 0, c, cert, APLOGNO(02272)
                            "failed to retrieve OCSP response status");
            ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, s);
            rc = V_OCSP_CERTSTATUS_UNKNOWN;
        }
        else {
            rc = status;
        }

        /* Check whether the response is inside the defined validity
         * period; otherwise fail.  */
        if (rc != V_OCSP_CERTSTATUS_UNKNOWN) {
            long resptime_skew = sc->server->ocsp_resptime_skew == UNSET ?
                                 DEFAULT_OCSP_MAX_SKEW : sc->server->ocsp_resptime_skew;
            /* oscp_resp_maxage can be passed verbatim - UNSET (-1) means
             * that responses can be of any age as long as nextup is in the
             * future. */
            int vrc  = OCSP_check_validity(thisup, nextup, resptime_skew,
                                           sc->server->ocsp_resp_maxage);
            if (vrc != 1) {
                ssl_log_cxerror(SSLLOG_MARK, APLOG_ERR, 0, c, cert, APLOGNO(02273)
                                "OCSP response outside validity period");
                ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, s);
                rc = V_OCSP_CERTSTATUS_UNKNOWN;
            }
        }

        {
            int level =
                (status == V_OCSP_CERTSTATUS_GOOD) ? APLOG_INFO : APLOG_ERR;
            const char *result =
                status == V_OCSP_CERTSTATUS_GOOD ? "good" :
                (status == V_OCSP_CERTSTATUS_REVOKED ? "revoked" : "unknown");

            ssl_log_cxerror(SSLLOG_MARK, level, 0, c, cert,
                            "OCSP validation completed, "
                            "certificate status: %s (%d, %d)",
                            result, status, reason);
        }
    }

    if (request) OCSP_REQUEST_free(request);
    if (response) OCSP_RESPONSE_free(response);
    if (basicResponse) OCSP_BASICRESP_free(basicResponse);
    /* certID is freed when the request is freed */

    return rc;
}
/*
 * Open a new log file, and if successful
 * also close the old one.
 *
 * The timestamp for the calculation of the file
 * name of the new log file will be the actual millisecond
 * timestamp, except when a regular rotation based on a time
 * interval is configured and the previous interval
 * is over. Then the timestamp is the starting time
 * of the actual interval.
 */
static void doRotate(rotate_config_t *config, rotate_status_t *status)
{

    int now = get_now(config);
    int tLogStart;
    apr_status_t rv;
    struct logfile newlog;
    int thisLogNum = -1;

    status->rotateReason = ROTATE_NONE;

    if (config->tRotation) {
        int tLogEnd;
        tLogStart = (now / config->tRotation) * config->tRotation;
        tLogEnd = tLogStart + config->tRotation;
        /*
         * Check if rotation was forced and the last rotation
         * interval is not yet over. Use the value of now instead
         * of the time interval boundary for the file name then.
         */
        if (tLogStart < status->tLogEnd) {
            tLogStart = now;
        }
        status->tLogEnd = tLogEnd;
    }
    else {
        tLogStart = now;
    }

    if (config->use_strftime) {
        apr_time_t tNow = apr_time_from_sec(tLogStart);
        apr_time_exp_t e;
        apr_size_t rs;

        apr_time_exp_gmt(&e, tNow);
        apr_strftime(newlog.name, &rs, sizeof(newlog.name), config->szLogRoot, &e);
    }
    else {
        if (config->truncate) {
            apr_snprintf(newlog.name, sizeof(newlog.name), "%s", config->szLogRoot);
        }
        else if (config->num_files > 0) { 
            if (status->fileNum == -1 || status->fileNum == (config->num_files - 1)) {
                thisLogNum = 0;
                apr_snprintf(newlog.name, sizeof(newlog.name), "%s", config->szLogRoot);
            }
            else { 
                thisLogNum = status->fileNum + 1;
                apr_snprintf(newlog.name, sizeof(newlog.name), "%s.%d", config->szLogRoot, thisLogNum);
            }
        }
        else {
            apr_snprintf(newlog.name, sizeof(newlog.name), "%s.%010d", config->szLogRoot,
                         tLogStart);
        }
    }
    apr_pool_create(&newlog.pool, status->pool);
    if (config->verbose) {
        fprintf(stderr, "Opening file %s\n", newlog.name);
    }
    rv = apr_file_open(&newlog.fd, newlog.name, APR_WRITE | APR_CREATE | APR_APPEND
                       | (config->truncate || (config->num_files > 0 && status->current.fd) ? APR_TRUNCATE : 0), 
                       APR_OS_DEFAULT, newlog.pool);
    if (rv == APR_SUCCESS) {
        /* Handle post-rotate processing. */
        post_rotate(newlog.pool, &newlog, config, status);

        status->fileNum = thisLogNum;
        /* Close out old (previously 'current') logfile, if any. */
        if (status->current.fd) {
            close_logfile(config, &status->current);
        }

        /* New log file is now 'current'. */
        status->current = newlog;
    }
    else {
        char error[120];

        apr_strerror(rv, error, sizeof error);

        /* Uh-oh. Failed to open the new log file. Try to clear
         * the previous log file, note the lost log entries,
         * and keep on truckin'. */
        if (status->current.fd == NULL) {
            fprintf(stderr, "Could not open log file '%s' (%s)\n", newlog.name, error);
            exit(2);
        }

        /* Throw away new state; it isn't going to be used. */
        apr_pool_destroy(newlog.pool);

        /* Try to keep this error message constant length
         * in case it occurs several times. */
        apr_snprintf(status->errbuf, sizeof status->errbuf,
                     "Resetting log file due to error opening "
                     "new log file, %10d messages lost: %-25.25s\n",
                     status->nMessCount, error);

        truncate_and_write_error(status);
    }

    status->nMessCount = 0;
}
示例#21
0
int mq_stream_read_wait(mq_stream_t *mqs)
{
    int err = 0;
    apr_interval_time_t dt;
    op_status_t status;

    //** If 1st time make all the variables
    if (mqs->mpool == NULL) {
        apr_pool_create(&mqs->mpool, NULL);
        apr_thread_mutex_create(&(mqs->lock), APR_THREAD_MUTEX_DEFAULT, mqs->mpool);
        apr_thread_cond_create(&(mqs->cond), mqs->mpool);
    }

    dt = apr_time_from_sec(1);


    //** Flag the just processed gop to clean up
    apr_thread_mutex_lock(mqs->lock);
    log_printf(5, "START msid=%d waiting=%d processed=%d gop_processed=%p\n", mqs->msid, mqs->waiting, mqs->processed, mqs->gop_processed);
    if (mqs->gop_processed != NULL) mqs->processed = 1;
    apr_thread_cond_broadcast(mqs->cond);

    if (mqs->data) {
        if (mqs->data[MQS_STATE_INDEX] != MQS_MORE) err = 1;
    }
    apr_thread_mutex_unlock(mqs->lock);

    if (mqs->gop_processed != NULL) {
        gop_waitany(mqs->gop_processed);
        gop_free(mqs->gop_processed, OP_DESTROY);
        mqs->gop_processed = NULL;
    }

    if (err != 0) {
        log_printf(2, "ERROR no more data available!\n");
        return(-1);
    }

    //** Now handle the waiting gop
    apr_thread_mutex_lock(mqs->lock);
    log_printf(5, "before loop msid=%d waiting=%d processed=%d\n", mqs->msid, mqs->waiting, mqs->processed);

    while (mqs->waiting == 1) {
        log_printf(5, "LOOP msid=%d waiting=%d processed=%d\n", mqs->msid, mqs->waiting, mqs->processed);
        if (gop_will_block(mqs->gop_waiting) == 0)  { //** Oops!  failed request
            status = gop_get_status(mqs->gop_waiting);
            log_printf(2, "msid=%d gid=%d status=%d\n", mqs->msid, gop_id(mqs->gop_waiting), status.op_status);
            if (status.op_status != OP_STATE_SUCCESS) {
                mqs->waiting = -3;
                err = 1;
            } else {
                apr_thread_cond_timedwait(mqs->cond, mqs->lock, dt);
            }
        } else {
            apr_thread_cond_timedwait(mqs->cond, mqs->lock, dt);
        }
    }

    if (mqs->waiting == 0) {  //** Flag the receiver to accept the data
        mqs->waiting = -1;
        apr_thread_cond_broadcast(mqs->cond);  //** Let the receiver know we're ready to accept the data

        //** Wait for the data to be accepted
        while (mqs->waiting != -2) {
            apr_thread_cond_wait(mqs->cond, mqs->lock);
        }
    } else if (mqs->waiting == -3) { //**error occured
        err = 1;
    }
    apr_thread_mutex_unlock(mqs->lock);

    //** Flip states
    mqs->gop_processed = mqs->gop_waiting;
    mqs->gop_waiting = NULL;

    //** This shouldn't get triggered but just in case lets throw an error.
    if ((mqs->gop_processed == NULL) && (mqs->data != NULL)) {
        if ((mqs->data[MQS_STATE_INDEX] == MQS_MORE) && (mqs->want_more == MQS_MORE)) {
            err = 3;
            log_printf(0, "ERROR: MQS gop processed=waiting=NULL  want_more set!!!!!! err=%d\n", err);
            fprintf(stderr, "ERROR: MQS gop processed=waiting=NULL want_more set!!!!!! err=%d\n", err);
        }
    }

    //** Check if we need to fire off the next request
    if (mqs->data != NULL) {
        if ((mqs->data[MQS_STATE_INDEX] == MQS_MORE) && (mqs->want_more == MQS_MORE)) {
            mq_stream_read_request(mqs);
        }
    }

    log_printf(5, "err=%d\n", err);
    return(err);
}
示例#22
0
int main(int argc, char **argv)
{
    int start_option, i, watch, summary, base;
    rs_mapping_notify_t notify, me;
    apr_time_t dt;
    char *config;

//printf("argc=%d\n", argc);

    if (argc < 2) {
        printf("\n");
        printf("lio_rs LIO_COMMON_OPTIONS [-w] [-b2 | -b10] [-s | -f]\n");
        lio_print_options(stdout);
        printf("    -w                 - Watch for RID configuration changes. Press ^C to exit\n");
        printf("    -b2                - Use powers of 2 for units(default)\n");
        printf("    -b10               - Use powers of 10 for units\n");
        printf("    -s                 - Print a RID space usage summary\n");
        printf("    -f                 - Print the full RID configuration\n");
        return(1);
    }

    lio_init(&argc, &argv);

    watch = 0;
    summary = 0;
    base = 1024;

    i=1;
    do {
        start_option = i;

        if (strcmp(argv[i], "-w") == 0) { //** Watch for any RID changes
            i++;
            watch = 1;
        } else if (strcmp(argv[i], "-s") == 0) {  //** Print space summary instead of full conifg
            i++;
            summary = 1;
        } else if (strcmp(argv[i], "-b2") == 0) {  //** base-2 units
            i++;
            base = 1024;
        } else if (strcmp(argv[i], "-b10") == 0) {  //** base-10 units
            i++;
            base = 1000;
        }
    } while ((start_option < i) && (i<argc));

    //** Make the APR stuff
    assert_result(apr_pool_create(&mpool, NULL), APR_SUCCESS);
    apr_thread_mutex_create(&lock, APR_THREAD_MUTEX_DEFAULT, mpool);
    apr_thread_cond_create(&cond, mpool);

//if (watch == 1) {
//  printf("Sleeping for 60s\n"); fflush(stdout);
//  sleep(60);
//  printf("Woken up\n"); fflush(stdout);
//}

    memset(&notify, 0, sizeof(notify));
    notify.lock = lock;
    notify.cond = cond;
    me = notify;
    me.map_version = 1; //** This triggers the initial load
    rs_register_mapping_updates(lio_gc->rs, &notify);
    dt = apr_time_from_sec(1);
    do {
        //** Check for an update
        apr_thread_mutex_lock(lock);
        if (watch == 1) apr_thread_cond_timedwait(notify.cond, notify.lock, dt);
        i = ((me.map_version != notify.map_version) || (me.status_version != notify.status_version)) ? 1 : 0;
        me = notify;
        apr_thread_mutex_unlock(lock);

        if (i != 0) {
            config = rs_get_rid_config(lio_gc->rs);

            printf("Map Version: %d  Status Version: %d\n", me.map_version, me.status_version);
            printf("--------------------------------------------------------------------------------------------------\n");

            if (config == NULL) {
                printf("ERROR NULL config!\n");
            } else if (summary == 1) {
                print_rid_summary(config, base);
            } else {
                printf("%s", config);
            }

            printf("--------------------------------------------------------------------------------------------------\n");

            if (config != NULL) free(config);
        }
    } while (watch == 1);

    info_printf(lio_ifd, 5, "BEFORE unregister\n");
    tbx_info_flush(lio_ifd);
    rs_unregister_mapping_updates(lio_gc->rs, &notify);
    info_printf(lio_ifd, 5, "AFTER unregister\n");
    tbx_info_flush(lio_ifd);

    //** Cleanup
    apr_pool_destroy(mpool);

//  info_printf(lio_ifd, 5, "AFTER shutdown\n"); tbx_info_flush(lio_ifd);
    lio_shutdown();

    return(0);
}
示例#23
0
文件: core.c 项目: MiniHero/mapcache
mapcache_http_response *mapcache_core_get_tile(mapcache_context *ctx, mapcache_request_get_tile *req_tile)
{
  int expires = 0;
  mapcache_http_response *response;
  int i,is_empty=1 /* response image is initially empty */;
  char *timestr;
  mapcache_image *base=NULL;
  mapcache_image_format *format = NULL;

#ifdef DEBUG
  if(req_tile->ntiles ==0) {
    ctx->set_error(ctx,500,"BUG: get_tile called with 0 tiles");
    return NULL;
  }
#endif
  response = mapcache_http_response_create(ctx->pool);


  mapcache_prefetch_tiles(ctx,req_tile->tiles,req_tile->ntiles);
  if(GC_HAS_ERROR(ctx))
    return NULL;

  /* loop through tiles, and eventually merge them vertically together */
  for(i=0; i<req_tile->ntiles; i++) {
    mapcache_tile *tile = req_tile->tiles[i]; /* shortcut */
    if(tile->mtime && (tile->mtime < response->mtime || response->mtime == 0))
      response->mtime = tile->mtime;
    if(tile->expires && (tile->expires < expires || expires == 0)) {
      expires = tile->expires;
    }
    
    if(tile->nodata) {
      /* treat the special case where the cache explicitely stated that the
       tile was empty, and we don't have any vertical merging to do */
      if(tile->encoded_data && req_tile->ntiles == 1) {
        response->data = tile->encoded_data;
        /* we don't touch is_empty, as we have access to the encoded empty image, but the
         resulting tile is empty */
      }
      continue;
    }
    
    /* treat the most common case: 
     - we have a single tile request (i.e. isempty is true)
     - the cache returned the encoded image
     */
    if(is_empty && tile->encoded_data) {
      response->data = tile->encoded_data;
      /* just in case we also have the raw image data available, keep a ref to it
       if we need to merge another tile ontop of it*/
      if(tile->raw_image) {
        base = tile->raw_image;
      }
      is_empty = 0; /* we now know we might need to do some vertical merging */
      continue;
    }

    /* if we're here, either
     * - we need to merge the current tile onto the previous one(s), or
     * - we only have the tile's raw data available
     */

    if(!is_empty) {
      /* we have an existing tile, so we know we need to merge the current one into it */
      if(!base) {
        /* the existing tile has not been decoded yet, but we need the access to the raw pixels*/
        base = mapcache_imageio_decode(ctx, response->data);
        if(!base) return NULL;
      }
      response->data = NULL; /* the encoded data is now obsolete, as we will be merging the current tile */

      /* we need to access the current tile's pixel data */
      if(!tile->raw_image) {
        tile->raw_image = mapcache_imageio_decode(ctx,tile->encoded_data);
        if(!tile->raw_image) return NULL;
      }
      mapcache_image_merge(ctx, base, tile->raw_image);
    } else {
      /* we don't need to merge onto an existing tile and don't have access to the tile's encoded data.
       * 
       * we don't encode the tile's raw image data just yet because we might need to merge another one on top
       * of it later.
       */
      base = tile->raw_image;
      is_empty = 0;
    }
  }

  if(!response->data) {
    /* we need to encode the raw image data*/
    if(base) {
      if(req_tile->format) {
        format = req_tile->format;
      } else {
        format = req_tile->tiles[0]->tileset->format;
        if(!format) {
          format = ctx->config->default_image_format; /* this one is always defined */
        }
      }
      response->data = format->write(ctx, base, format);
      if(GC_HAS_ERROR(ctx)) {
        return NULL;
      }
    } else {
#ifdef DEBUG
      if(!is_empty) {
        ctx->set_error(ctx,500,"BUG: no image data to encode, but tile not marked as empty");
        return NULL;
      }
#endif
      unsigned char empty[5] = {'#',0,0,0,0};
      response->data = mapcache_empty_png_decode(ctx,empty,&is_empty); /* is_empty is unchanged and left to 1 */
      format = mapcache_configuration_get_image_format(ctx->config,"PNG8");
    }
  }
  
  /* compute the content-type */
  mapcache_image_format_type t = mapcache_imageio_header_sniff(ctx,response->data);
  if(t == GC_PNG)
    apr_table_set(response->headers,"Content-Type","image/png");
  else if(t == GC_JPEG)
    apr_table_set(response->headers,"Content-Type","image/jpeg");

  /* compute expiry headers */
  if(expires) {
    apr_time_t now = apr_time_now();
    apr_time_t additional = apr_time_from_sec(expires);
    apr_time_t texpires = now + additional;
    apr_table_set(response->headers, "Cache-Control",apr_psprintf(ctx->pool, "max-age=%d", expires));
    timestr = apr_palloc(ctx->pool, APR_RFC822_DATE_LEN);
    apr_rfc822_date(timestr, texpires);
    apr_table_setn(response->headers, "Expires", timestr);
  }

  return response;
}
示例#24
0
void *ongoing_heartbeat_thread(apr_thread_t *th, void *data)
{
    mq_ongoing_t *on = (mq_ongoing_t *)data;
    apr_time_t timeout = apr_time_make(on->check_interval, 0);
    op_generic_t *gop;
    mq_msg_t *msg;
    ongoing_hb_t *oh;
    ongoing_table_t *table;
    apr_hash_index_t *hi, *hit;
    opque_t *q;
    char *id;
    mq_msg_hash_t *remote_hash;
    apr_time_t now;
    apr_ssize_t id_len;
    int n, k;
    char *remote_host_string;

    apr_thread_mutex_lock(on->lock);
    n = 0;
    do {
        now = apr_time_now() - apr_time_from_sec(5);  //** Give our selves a little buffer
        log_printf(5, "Loop Start now=" TT "\n", apr_time_now());
        q = new_opque();
//     opque_start_execution(q);
        for (hit = apr_hash_first(NULL, on->table); hit != NULL; hit = apr_hash_next(hit)) {
            apr_hash_this(hit, (const void **)&remote_hash, &id_len, (void **)&table);

            k = apr_hash_count(table->table);
            if (log_level() > 1) {
                remote_host_string = mq_address_to_string(table->remote_host);
                log_printf(1, "host=%s count=%d\n", remote_host_string, k);
                free(remote_host_string);
            }

            for (hi = apr_hash_first(NULL, table->table); hi != NULL; hi = apr_hash_next(hi)) {
                apr_hash_this(hi, (const void **)&id, &id_len, (void **)&oh);
                log_printf(1, "id=%s now=" TT " next_check=" TT "\n", oh->id, apr_time_sec(apr_time_now()), apr_time_sec(oh->next_check));
                if (now > oh->next_check) {
                    log_printf(1, "id=%s sending HEARTBEAT EXEC SUBMIT nows=" TT " hb=%d\n", oh->id, apr_time_sec(apr_time_now()), oh->heartbeat);
                    flush_log();
                    //** Form the message
                    msg = mq_make_exec_core_msg(table->remote_host, 1);
                    mq_msg_append_mem(msg, ONGOING_KEY, ONGOING_SIZE, MQF_MSG_KEEP_DATA);
                    mq_msg_append_mem(msg, oh->id, oh->id_len, MQF_MSG_KEEP_DATA);
                    mq_msg_append_mem(msg, NULL, 0, MQF_MSG_KEEP_DATA);

                    //** Make the gop
                    gop = new_mq_op(on->mqc, msg, ongoing_response_status, NULL, NULL, oh->heartbeat);
                    gop_set_private(gop, table);
                    opque_add(q, gop);

                    oh->in_progress = 1; //** Flag it as in progress so it doesn't get deleted behind the scenes
                }
            }

        }
        log_printf(5, "Loop end now=" TT "\n", apr_time_now());

        //** Wait for it to complete
        apr_thread_mutex_unlock(on->lock);
        opque_waitall(q);
        apr_thread_mutex_lock(on->lock);

        //** Dec the counters
        while ((gop = opque_waitany(q)) != NULL) {
            log_printf(0, "gid=%d gotone status=%d now=" TT "\n", gop_id(gop), (gop_get_status(gop)).op_status, apr_time_sec(apr_time_now()));
            table = gop_get_private(gop);
            table->count--;

            //** Update the next check
            for (hi = apr_hash_first(NULL, table->table); hi != NULL; hi = apr_hash_next(hi)) {
                apr_hash_this(hi, (const void **)&id, &id_len, (void **)&oh);
                oh->next_check = apr_time_now() + apr_time_from_sec(oh->heartbeat);

                //** Check if we get rid of it
                oh->in_progress = 0;
                if (oh->count <= 0) {  //** Need to delete it
                    apr_hash_set(table->table, id, id_len, NULL);
                    free(oh->id);
                    free(oh);
                }
            }

            gop_free(gop, OP_DESTROY);
        }
        opque_free(q, OP_DESTROY);

        now = apr_time_now();
        log_printf(2, "sleeping %d now=" TT "\n", on->check_interval, now);

        //** Sleep until time for the next heartbeat or time to exit
        if (on->shutdown == 0) apr_thread_cond_timedwait(on->cond, on->lock, timeout);
        n = on->shutdown;

        now = apr_time_now() - now;
        log_printf(2, "main loop bottom n=%d dt=" TT " sec=" TT "\n", n, now, apr_time_sec(now));
    } while (n == 0);

    log_printf(2, "CLEANUP\n");

    for (hit = apr_hash_first(NULL, on->table); hit != NULL; hit = apr_hash_next(hit)) {
        apr_hash_this(hit, (const void **)&remote_hash, &id_len, (void **)&table);

        for (hi = apr_hash_first(NULL, table->table); hi != NULL; hi = apr_hash_next(hi)) {
            apr_hash_this(hi, (const void **)&id, &id_len, (void **)&oh);
            apr_hash_set(table->table, id, id_len, NULL);
            free(oh->id);
            free(oh);
        }

        apr_hash_set(on->table, &(table->remote_host_hash), sizeof(mq_msg_hash_t), NULL);
        mq_msg_destroy(table->remote_host);
        free(table);
    }

    log_printf(2, "EXITING\n");

    apr_thread_mutex_unlock(on->lock);

    return(NULL);
}
示例#25
0
文件: core.c 项目: MiniHero/mapcache
mapcache_http_response *mapcache_core_get_map(mapcache_context *ctx, mapcache_request_get_map *req_map)
{
  mapcache_image_format *format = NULL;
  mapcache_http_response *response;
  mapcache_map *basemap = NULL;
  char *timestr;
#ifdef DEBUG
  if(req_map->nmaps ==0) {
    ctx->set_error(ctx,500,"BUG: get_map called with 0 maps");
    return NULL;
  }
#endif


  if(req_map->getmap_strategy == MAPCACHE_GETMAP_ERROR) {
    ctx->set_error(ctx, 404, "full wms support disabled");
    return NULL;
  }

  format = NULL;
  response = mapcache_http_response_create(ctx->pool);


  if(req_map->getmap_strategy == MAPCACHE_GETMAP_ASSEMBLE) {
    basemap = mapcache_assemble_maps(ctx, req_map->maps, req_map->nmaps, req_map->resample_mode);
    if(GC_HAS_ERROR(ctx)) return NULL;
  } else if(!ctx->config->non_blocking && req_map->getmap_strategy == MAPCACHE_GETMAP_FORWARD) {
    int i;
    basemap = req_map->maps[0];
    for(i=0; i<req_map->nmaps; i++) {
      if(!req_map->maps[i]->tileset->source) {
        ctx->set_error(ctx,404,"cannot forward request for tileset %s: no source configured",
                       req_map->maps[i]->tileset->name);
        return NULL;
      }
    }
    basemap->tileset->source->render_map(ctx, basemap);
    if(GC_HAS_ERROR(ctx)) return NULL;
    if(req_map->nmaps>1) {
      if(!basemap->raw_image) {
        basemap->raw_image = mapcache_imageio_decode(ctx,basemap->encoded_data);
        if(GC_HAS_ERROR(ctx)) return NULL;
      }
      for(i=1; i<req_map->nmaps; i++) {
        mapcache_map *overlaymap = req_map->maps[i];
        overlaymap->tileset->source->render_map(ctx, overlaymap);
        if(GC_HAS_ERROR(ctx)) return NULL;
        if(!overlaymap->raw_image) {
          overlaymap->raw_image = mapcache_imageio_decode(ctx,overlaymap->encoded_data);
          if(GC_HAS_ERROR(ctx)) return NULL;
        }
        if(GC_HAS_ERROR(ctx)) return NULL;
        mapcache_image_merge(ctx,basemap->raw_image,overlaymap->raw_image);
        if(GC_HAS_ERROR(ctx)) return NULL;
        if(!basemap->expires || overlaymap->expires<basemap->expires) basemap->expires = overlaymap->expires;
      }
    }
  } else {
    ctx->set_error(ctx,400,"failed getmap, readonly mode");
    return NULL;
  }

  if(basemap->raw_image) {
    format = req_map->getmap_format; /* always defined, defaults to JPEG */
    response->data = format->write(ctx,basemap->raw_image,format);
    if(GC_HAS_ERROR(ctx)) {
      return NULL;
    }
  } else {
    /* this case happens when we have a forward strategy for a single tileset */
#ifdef DEBUG
    if(!basemap->encoded_data) {
      ctx->set_error(ctx,500,"###BUG### core_get_map failed with null encoded_data");
      return NULL;
    }
#endif
    response->data = basemap->encoded_data;
  }

  /* compute the content-type */
  if(format && format->mime_type) {
    apr_table_set(response->headers,"Content-Type",format->mime_type);
  } else {
    mapcache_image_format_type t = mapcache_imageio_header_sniff(ctx,response->data);
    if(t == GC_PNG)
      apr_table_set(response->headers,"Content-Type","image/png");
    else if(t == GC_JPEG)
      apr_table_set(response->headers,"Content-Type","image/jpeg");
  }

  /* compute expiry headers */
  if(basemap->expires) {
    apr_time_t now = apr_time_now();
    apr_time_t additional = apr_time_from_sec(basemap->expires);
    apr_time_t texpires = now + additional;
    apr_table_set(response->headers, "Cache-Control",
                  apr_psprintf(ctx->pool, "max-age=%d", basemap->expires));
    timestr = apr_palloc(ctx->pool, APR_RFC822_DATE_LEN);
    apr_rfc822_date(timestr, texpires);
    apr_table_setn(response->headers, "Expires", timestr);
  }

  response->mtime = basemap->mtime;
  return response;
}
示例#26
0
/* Implements svn_config_enumerator2_t. */
static svn_boolean_t
add_memcache_server(const char *name,
                    const char *value,
                    void *baton,
                    apr_pool_t *pool)
{
  struct ams_baton *b = baton;
  char *host, *scope;
  apr_port_t port;
  apr_status_t apr_err;
  apr_memcache_server_t *server;

  apr_err = apr_parse_addr_port(&host, &scope, &port,
                                value, pool);
  if (apr_err != APR_SUCCESS)
    {
      b->err = svn_error_wrap_apr(apr_err,
                                  _("Error parsing memcache server '%s'"),
                                  name);
      return FALSE;
    }

  if (scope)
    {
      b->err = svn_error_createf(SVN_ERR_BAD_SERVER_SPECIFICATION, NULL,
                                  _("Scope not allowed in memcache server "
                                    "'%s'"),
                                  name);
      return FALSE;
    }
  if (!host || !port)
    {
      b->err = svn_error_createf(SVN_ERR_BAD_SERVER_SPECIFICATION, NULL,
                                  _("Must specify host and port for memcache "
                                    "server '%s'"),
                                  name);
      return FALSE;
    }

  /* Note: the four numbers here are only relevant when an
     apr_memcache_t is being shared by multiple threads. */
  apr_err = apr_memcache_server_create(b->memcache_pool,
                                       host,
                                       port,
                                       0,  /* min connections */
                                       5,  /* soft max connections */
                                       10, /* hard max connections */
                                       /*  time to live (in microseconds) */
                                       apr_time_from_sec(50),
                                       &server);
  if (apr_err != APR_SUCCESS)
    {
      b->err = svn_error_wrap_apr(apr_err,
                                  _("Unknown error creating memcache server"));
      return FALSE;
    }

  apr_err = apr_memcache_add_server(b->memcache, server);
  if (apr_err != APR_SUCCESS)
    {
      b->err = svn_error_wrap_apr(apr_err,
                                  _("Unknown error adding server to memcache"));
      return FALSE;
    }

  return TRUE;
}
示例#27
0
static apr_status_t rfc1413_connect(apr_socket_t **newsock, conn_rec *conn,
                                    server_rec *srv)
{
    apr_status_t rv;
    apr_sockaddr_t *localsa, *destsa;

    if ((rv = apr_sockaddr_info_get(&localsa, conn->local_ip, APR_UNSPEC, 
                              0, /* ephemeral port */
                              0, conn->pool)) != APR_SUCCESS) {
        /* This should not fail since we have a numeric address string
         * as the host. */
        ap_log_error(APLOG_MARK, APLOG_CRIT, rv, srv,
                     "rfc1413: apr_sockaddr_info_get(%s) failed",
                     conn->local_ip);
        return rv;
    }
    
    if ((rv = apr_sockaddr_info_get(&destsa, conn->remote_ip, 
                              localsa->family, /* has to match */
                              RFC1413_PORT, 0, conn->pool)) != APR_SUCCESS) {
        /* This should not fail since we have a numeric address string
         * as the host. */
        ap_log_error(APLOG_MARK, APLOG_CRIT, rv, srv,
                     "rfc1413: apr_sockaddr_info_get(%s) failed",
                     conn->remote_ip);
        return rv;
    }

    if ((rv = apr_socket_create(newsock, 
                                localsa->family, /* has to match */
                                SOCK_STREAM, conn->pool)) != APR_SUCCESS) {
	ap_log_error(APLOG_MARK, APLOG_CRIT, rv, srv,
                     "rfc1413: error creating query socket");
        return rv;
    }

    if ((rv = apr_socket_timeout_set(*newsock, apr_time_from_sec(ap_rfc1413_timeout)))
            != APR_SUCCESS) {
        ap_log_error(APLOG_MARK, APLOG_CRIT, rv, srv,
                     "rfc1413: error setting query socket timeout");
        apr_socket_close(*newsock);
        return rv;
    }

/*
 * Bind the local and remote ends of the query socket to the same
 * IP addresses as the connection under investigation. We go
 * through all this trouble because the local or remote system
 * might have more than one network address. The RFC1413 etc.
 * client sends only port numbers; the server takes the IP
 * addresses from the query socket.
 */

    if ((rv = apr_bind(*newsock, localsa)) != APR_SUCCESS) {
	ap_log_error(APLOG_MARK, APLOG_CRIT, rv, srv,
                     "rfc1413: Error binding query socket to local port");
        apr_socket_close(*newsock);
	return rv;
    }

/*
 * errors from connect usually imply the remote machine doesn't support
 * the service; don't log such an error
 */
    if ((rv = apr_connect(*newsock, destsa)) != APR_SUCCESS) {
        apr_socket_close(*newsock);
        return rv;
    }

    return APR_SUCCESS;
}
示例#28
0
/* This function connects to the server and sends enough data to
 * ensure the child wakes up and processes a new connection.  This
 * permits the MPM to skip the poll when there is only one listening
 * socket, because it provides a alternate way to unblock an accept()
 * when the pod is used.  */
static apr_status_t dummy_connection(ap_pod_t *pod)
{
    const char *data;
    apr_status_t rv;
    apr_socket_t *sock;
    apr_pool_t *p;
    apr_size_t len;
    ap_listen_rec *lp;

    /* create a temporary pool for the socket.  pconf stays around too long */
    rv = apr_pool_create(&p, pod->p);
    if (rv != APR_SUCCESS) {
        return rv;
    }

    /* If possible, find a listener which is configured for
     * plain-HTTP, not SSL; using an SSL port would either be
     * expensive to do correctly (performing a complete SSL handshake)
     * or cause log spam by doing incorrectly (simply sending EOF). */
    lp = ap_listeners;
    while (lp && lp->protocol && strcasecmp(lp->protocol, "http") != 0) {
        lp = lp->next;
    }
    if (!lp) {
        lp = ap_listeners;
    }

    rv = apr_socket_create(&sock, lp->bind_addr->family, SOCK_STREAM, 0, p);
    if (rv != APR_SUCCESS) {
        ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf, APLOGNO(00054)
                     "get socket to connect to listener");
        apr_pool_destroy(p);
        return rv;
    }

    /* on some platforms (e.g., FreeBSD), the kernel won't accept many
     * queued connections before it starts blocking local connects...
     * we need to keep from blocking too long and instead return an error,
     * because the MPM won't want to hold up a graceful restart for a
     * long time
     */
    rv = apr_socket_timeout_set(sock, apr_time_from_sec(3));
    if (rv != APR_SUCCESS) {
        ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf, APLOGNO(00055)
                     "set timeout on socket to connect to listener");
        apr_socket_close(sock);
        apr_pool_destroy(p);
        return rv;
    }

    rv = apr_socket_connect(sock, lp->bind_addr);
    if (rv != APR_SUCCESS) {
        int log_level = APLOG_WARNING;

        if (APR_STATUS_IS_TIMEUP(rv)) {
            /* probably some server processes bailed out already and there
             * is nobody around to call accept and clear out the kernel
             * connection queue; usually this is not worth logging
             */
            log_level = APLOG_DEBUG;
        }

        ap_log_error(APLOG_MARK, log_level, rv, ap_server_conf, APLOGNO(00056)
                     "connect to listener on %pI", lp->bind_addr);
        apr_pool_destroy(p);
        return rv;
    }

    if (lp->protocol && strcasecmp(lp->protocol, "https") == 0) {
        /* Send a TLS 1.0 close_notify alert.  This is perhaps the
         * "least wrong" way to open and cleanly terminate an SSL
         * connection.  It should "work" without noisy error logs if
         * the server actually expects SSLv3/TLSv1.  With
         * SSLv23_server_method() OpenSSL's SSL_accept() fails
         * ungracefully on receipt of this message, since it requires
         * an 11-byte ClientHello message and this is too short. */
        static const unsigned char tls10_close_notify[7] = {
            '\x15',         /* TLSPlainText.type = Alert (21) */
            '\x03', '\x01', /* TLSPlainText.version = {3, 1} */
            '\x00', '\x02', /* TLSPlainText.length = 2 */
            '\x01',         /* Alert.level = warning (1) */
            '\x00'          /* Alert.description = close_notify (0) */
        };
        data = (const char *)tls10_close_notify;
        len = sizeof(tls10_close_notify);
    }
    else /* ... XXX other request types here? */ {
        /* Create an HTTP request string.  We include a User-Agent so
         * that adminstrators can track down the cause of the
         * odd-looking requests in their logs.  A complete request is
         * used since kernel-level filtering may require that much
         * data before returning from accept(). */
        data = apr_pstrcat(p, "OPTIONS * HTTP/1.0\r\nUser-Agent: ",
                           ap_get_server_description(),
                           " (internal dummy connection)\r\n\r\n", NULL);
        len = strlen(data);
    }

    apr_socket_send(sock, data, &len);
    apr_socket_close(sock);
    apr_pool_destroy(p);

    return rv;
}
示例#29
0
int
main ( int argc, char *argv[] )
{
   int rc;
   struct stat struct_stat;
   pthread_t pid;
   pthread_attr_t attr;
   int i, num_sources;
   uid_t gmetad_uid;
   mode_t rrd_umask;
   char * gmetad_username;
   struct passwd *pw;
   gmetad_config_t *c = &gmetad_config;
   apr_interval_time_t sleep_time;
   apr_time_t last_metadata;
   double random_sleep_factor;
   unsigned int rand_seed;

   rc = apr_initialize();
   if (rc != APR_SUCCESS) {
      return -1;
   }

   /* create a memory pool. */
   apr_pool_create(&global_context, NULL);

   /* Ignore SIGPIPE */
   signal( SIGPIPE, SIG_IGN );

   initialize_scoreboard();

   /* Mark the time this gmetad started */
   started = apr_time_now();

   if (cmdline_parser(argc, argv, &args_info) != 0)
      err_quit("command-line parser error");

   num_sources = number_of_datasources( args_info.conf_arg );
   if(!num_sources)
      {
         err_quit("%s doesn't have any data sources specified", args_info.conf_arg);
      }

   memset(&root, 0, sizeof(root));
   root.id = ROOT_NODE;

   /* Get the real number of data sources later */
   sources = hash_create( num_sources + 10 );
   if (! sources )
      {
         err_quit("Unable to create sources hash\n");
      }

   root.authority = hash_create( num_sources + 10 );
   if (!root.authority)
      {
         err_quit("Unable to create root authority (our grids and clusters) hash\n");
      }

   root.metric_summary = hash_create (DEFAULT_METRICSIZE);
   if (!root.metric_summary)
      {
         err_quit("Unable to create root summary hash");
      }

   parse_config_file ( args_info.conf_arg );
    /* If given, use command line directives over config file ones. */
   if (args_info.debug_given)
      {
         c->debug_level = args_info.debug_arg;
      }
   debug_level = c->debug_level;
   set_debug_msg_level(debug_level);

   /* Setup our default authority pointer if the conf file hasnt yet.
    * Done in the style of hash node strings. */
   if (!root.stringslen)
      {
         gethostname(hostname, HOSTNAMESZ);
         root.authority_ptr = 0;
         sprintf(root.strings, "http://%s/ganglia/", hostname);
         root.stringslen += strlen(root.strings) + 1;
      }

   rand_seed = apr_time_now() * (int)pthread_self();
   for(i = 0; i < root.stringslen; rand_seed = rand_seed * root.strings[i++]);

   /* Debug level 1 is error output only, and no daemonizing. */
   if (!debug_level)
      {
         rrd_umask = c->umask;
         daemon_init (argv[0], 0, rrd_umask);
      }

   if (args_info.pid_file_given)
     {
       update_pidfile (args_info.pid_file_arg);
     }

   /* The rrd_rootdir must be writable by the gmetad process */
   if( c->should_setuid )
      {
         if(! (pw = getpwnam(c->setuid_username)))
            {
               err_sys("Getpwnam error");
            }
         gmetad_uid = pw->pw_uid;
         gmetad_username = c->setuid_username;
      }
   else
      {
         gmetad_uid = getuid();
         if(! (pw = getpwuid(gmetad_uid)))
            {
               err_sys("Getpwnam error");
            } 
         gmetad_username = strdup(pw->pw_name);
      }

   debug_msg("Going to run as user %s", gmetad_username);
   if( c->should_setuid )
      {
         become_a_nobody(c->setuid_username);
      }

   if( c->write_rrds )
      {
         if( stat( c->rrd_rootdir, &struct_stat ) )
            {
                err_sys("Please make sure that %s exists", c->rrd_rootdir);
            }
         if ( struct_stat.st_uid != gmetad_uid )
            {
                err_quit("Please make sure that %s is owned by %s", c->rrd_rootdir, gmetad_username);
            }
         if (! (struct_stat.st_mode & S_IWUSR) )
            {
                err_quit("Please make sure %s has WRITE permission for %s", gmetad_username, c->rrd_rootdir);
            }
      }

   if(debug_level)
      {
         fprintf(stderr,"Sources are ...\n");
         hash_foreach( sources, print_sources, NULL);
      }

#ifdef WITH_MEMCACHED
   if (c->memcached_parameters != NULL)
      {
         memcached_connection_pool = memcached_pool(c->memcached_parameters, strlen(c->memcached_parameters));
      }
#endif /* WITH_MEMCACHED */

   server_socket = g_tcp_socket_server_new( c->xml_port );
   if (server_socket == NULL)
      {
         err_quit("tcp_listen() on xml_port failed");
      }
   debug_msg("xml listening on port %d", c->xml_port);
   
   interactive_socket = g_tcp_socket_server_new( c->interactive_port );
   if (interactive_socket == NULL)
      {
         err_quit("tcp_listen() on interactive_port failed");
      }
   debug_msg("interactive xml listening on port %d", c->interactive_port);

    /* Forward metrics to Graphite using carbon protocol */
    if (c->carbon_server != NULL)
      {
         if (!strcmp(c->carbon_protocol, "udp"))
            {
               carbon_udp_socket = init_carbon_udp_socket (c->carbon_server, c->carbon_port);

               if (carbon_udp_socket == NULL)
                  err_quit("carbon %s socket failed for %s:%d", c->carbon_protocol, c->carbon_server, c->carbon_port);
            }
         debug_msg("carbon forwarding ready to send via %s to %s:%d", c->carbon_protocol, c->carbon_server, c->carbon_port);
      }

#ifdef WITH_RIEMANN
    if (c->riemann_server !=NULL)
      {
         if (!strcmp(c->riemann_protocol, "udp"))
            {
               riemann_udp_socket = init_riemann_udp_socket (c->riemann_server, c->riemann_port);

               if (riemann_udp_socket == NULL)
                  err_quit("[riemann] %s socket failed for %s:%d", c->riemann_protocol, c->riemann_server, c->riemann_port);
            } else {
               err_quit("[riemann] TCP transport not supported yet.");
            }
         debug_msg("[riemann] ready to forward metrics via %s to %s:%d", c->riemann_protocol, c->riemann_server, c->riemann_port);
      }
#endif /* WITH_RIEMANN */

   /* initialize summary mutex */
   root.sum_finished = (pthread_mutex_t *) 
                          malloc(sizeof(pthread_mutex_t));
   pthread_mutex_init(root.sum_finished, NULL);

   pthread_attr_init( &attr );
   pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_DETACHED );

   /* Spin off the non-interactive server threads. (Half as many as interactive). */
   for (i=0; i < c->server_threads/2; i++)
      pthread_create(&pid, &attr, server_thread, (void*) 0);

   /* Spin off the interactive server threads. */
   for (i=0; i < c->server_threads; i++)
      pthread_create(&pid, &attr, server_thread, (void*) 1);

   hash_foreach( sources, spin_off_the_data_threads, NULL );

   /* A thread to cleanup old metrics and hosts */
   pthread_create(&pid, &attr, cleanup_thread, (void *) NULL);
   debug_msg("cleanup thread has been started");

    /* Meta data */
   last_metadata = 0;
   for(;;)
      {
         /* Do at a random interval, between 
                 (shortest_step/2) +/- METADATA_SLEEP_RANDOMIZE percent */
         random_sleep_factor = (1 + (METADATA_SLEEP_RANDOMIZE / 50.0) * ((rand_r(&rand_seed) - RAND_MAX/2)/(float)RAND_MAX));
         sleep_time = random_sleep_factor * apr_time_from_sec(c->shortest_step) / 2;
         /* Make sure the sleep time is at least 1 second */
         if(apr_time_sec(apr_time_now() + sleep_time) < (METADATA_MINIMUM_SLEEP + apr_time_sec(apr_time_now())))
            sleep_time += apr_time_from_sec(METADATA_MINIMUM_SLEEP);
         apr_sleep(sleep_time);

         /* Need to be sure root is locked while doing summary */
         pthread_mutex_lock(root.sum_finished);

         /* Flush the old values */
         hash_foreach(root.metric_summary, zero_out_summary, NULL);
         root.hosts_up = 0;
         root.hosts_down = 0;

         /* Sum the new values */
         hash_foreach(root.authority, do_root_summary, NULL );

         /* summary completed */
         pthread_mutex_unlock(root.sum_finished);

         /* Save them to RRD */
         hash_foreach(root.metric_summary, write_root_summary, NULL);

         /* Remember our last run */
         last_metadata = apr_time_now();
      }

   apr_pool_destroy(global_context);

   apr_terminate();
   return 0;
}
// Generate the actual cookie
void make_cookie(request_rec *r, char uid[], char cur_uid[], int use_dnt_expires)
{   // configuration
    cookietrack_settings_rec *dcfg;
    dcfg = ap_get_module_config(r->per_dir_config, &cookietrack_module);

    /* 1024 == hardcoded constant */
    char cookiebuf[1024];
    char *new_cookie;
    const char *rname = ap_get_remote_host(r->connection, r->per_dir_config,
                                           REMOTE_NAME, NULL);

    /* XXX: hmm, this should really tie in with mod_unique_id */
    apr_snprintf(cookiebuf, sizeof(cookiebuf), "%s", uid );

    if (dcfg->expires) {

        /* Cookie with date; as strftime '%a, %d-%h-%y %H:%M:%S GMT' */
        new_cookie = apr_psprintf(r->pool, "%s=%s; path=/",
                                  dcfg->cookie_name, cookiebuf);

        if ((dcfg->style == CT_UNSET) || (dcfg->style == CT_NETSCAPE)) {
            apr_time_exp_t tms;
            apr_time_exp_gmt(&tms, r->request_time
                                 + apr_time_from_sec(dcfg->expires));

            // this sets a fixed expires in the future
            if( use_dnt_expires ) {
                new_cookie = apr_psprintf( r->pool,
                                "%s; expires=%s", new_cookie, dcfg->dnt_expires );

            // use the dynamic one
            } else {
                new_cookie = apr_psprintf( r->pool,
                                "%s; expires=%s, %.2d-%s-%.2d %.2d:%.2d:%.2d GMT",
                                new_cookie, apr_day_snames[tms.tm_wday],
                                tms.tm_mday,
                                apr_month_snames[tms.tm_mon],
                                tms.tm_year % 100,
                                tms.tm_hour, tms.tm_min, tms.tm_sec
                             );
            }
        } else {
            int expires = 0;

            // use a static expires date in the future
            if( use_dnt_expires ) {
                time_t t;
                time( &t );
                expires = dcfg->dnt_max_age - t;

            // use the dynamic one
            } else {
                expires = dcfg->expires;
            }

            _DEBUG && fprintf( stderr, "Expires = %d\n", expires );

            new_cookie = apr_psprintf( r->pool,
                                       "%s; max-age=%d",
                                       new_cookie,
                                       expires );
        }

    } else {
        new_cookie = apr_psprintf(r->pool, "%s=%s; path=/",
                                  dcfg->cookie_name, cookiebuf);
    }

    if (dcfg->cookie_domain != NULL) {
        new_cookie = apr_pstrcat(r->pool, new_cookie, "; domain=",
                                 dcfg->cookie_domain,
                                 (dcfg->style == CT_COOKIE2
                                  ? "; version=1"
                                  : ""),
                                 NULL);
    }

    // r->err_headers_out also honors non-2xx responses and
    // internal redirects. See the patch here:
    // http://svn.apache.org/viewvc?view=revision&revision=1154620
    apr_table_addn( r->err_headers_out,
                    (dcfg->style == CT_COOKIE2 ? "Set-Cookie2" : "Set-Cookie"),
                    new_cookie );

    // we also set it on the INCOMING cookie header, so the app can
    // Just Use It without worrying. Only do so if we don't already
    // have an incoming cookie value, or it will send 2 cookies with
    // the same name, with both the old and new value :(
    if( !cur_uid ) {
        apr_table_addn( r->headers_in, "Cookie",  new_cookie );
    }

    // Set headers? We set both incoming AND outgoing:
    if( dcfg->send_header ) {
        // incoming
        apr_table_addn( r->headers_in,
                        dcfg->header_name,
                        apr_pstrdup(r->pool, uid) );

        // outgoing
        apr_table_addn( r->err_headers_out,
                        dcfg->header_name,
                        apr_pstrdup(r->pool, uid) );
    }

    // set a note, so we can capture it in the logs
    // this expects chars, and apr_pstrdup will make sure any char stays
    // in scope for the function. If not, it ends up being empty.
    apr_table_setn( r->notes, dcfg->note_name, apr_pstrdup(r->pool, uid) );

}