/** Initialize the common timeout that we'll use to refill the buckets every * time a tick elapses. */ static void tor_libevent_set_tick_timeout(int msec_per_tick) { struct event_base *base = tor_libevent_get_base(); struct timeval tv; tor_assert(! one_tick); tv.tv_sec = msec_per_tick / 1000; tv.tv_usec = (msec_per_tick % 1000) * 1000; one_tick = event_base_init_common_timeout(base, &tv); }
int main( int argc, char *argv[] ) { size_t i; int ret, opt, longIndex = 0; struct event *evsig_int; #ifdef _WIN32 WSADATA WSAData; #endif pthread_t tcp_thread, *job_threads; if ( evutil_secure_rng_init() < 0 ) { ED2KD_LOGERR("failed to seed random number generator"); return EXIT_FAILURE; } /* parse command line arguments */ opt = getopt_long( argc, argv, optString, longOpts, &longIndex ); while( opt != -1 ) { switch( opt ) { case 'v': display_version(); return EXIT_SUCCESS; case 'g': { unsigned char hash[ED2K_HASH_SIZE]; char hex_hash[sizeof(hash)*2+1]; get_random_user_hash(hash); bin2hex(hash, hex_hash, sizeof(hex_hash)); puts(hex_hash); return EXIT_SUCCESS; } case 'h': display_usage(); return EXIT_SUCCESS; default: return EXIT_FAILURE; } opt = getopt_long( argc, argv, optString, longOpts, &longIndex ); } #ifdef _WIN32 if ( 0 != WSAStartup(0x0201, &WSAData) ) { ED2KD_LOGERR("WSAStartup failed!"); return EXIT_FAILURE; } #endif if ( !server_load_config(NULL) ) { ED2KD_LOGERR("failed to load configuration file"); return EXIT_FAILURE; } display_libevent_info(); #ifdef EVTHREAD_USE_WINDOWS_THREADS_IMPLEMENTED ret = evthread_use_windows_threads(); #elif EVTHREAD_USE_PTHREADS_IMPLEMENTED ret = evthread_use_pthreads(); #else #error "unable to determine threading model" #endif if ( ret < 0 ) { ED2KD_LOGERR("failed to init libevent threading model"); return EXIT_FAILURE; } g_srv.evbase_main = event_base_new(); if ( NULL == g_srv.evbase_main ) { ED2KD_LOGERR("failed to create main event loop"); return EXIT_FAILURE; } g_srv.evbase_tcp = event_base_new(); if ( NULL == g_srv.evbase_tcp ) { ED2KD_LOGERR("failed to create tcp event loop"); return EXIT_FAILURE; } evsig_int = evsignal_new(g_srv.evbase_main, SIGINT, sigint_cb, NULL); evsignal_add(evsig_int, NULL); // common timers timevals g_srv.portcheck_timeout_tv = event_base_init_common_timeout(g_srv.evbase_tcp, &g_srv.cfg->portcheck_timeout_tv); g_srv.status_notify_tv = event_base_init_common_timeout(g_srv.evbase_tcp, &g_srv.cfg->status_notify_tv); if ( !db_create() ) { ED2KD_LOGERR("failed to create database"); return EXIT_FAILURE; } g_srv.thread_count = omp_get_num_procs() + 1; pthread_cond_init(&g_srv.job_cond, NULL); pthread_mutex_init(&g_srv.job_mutex, NULL); TAILQ_INIT(&g_srv.jqueue); job_threads = (pthread_t *)malloc(g_srv.thread_count * sizeof(*job_threads)); // start tcp worker threads for ( i=0; i<g_srv.thread_count; ++i ) { pthread_create(&job_threads[i], NULL, server_job_worker, NULL); } // start tcp dispatch thread pthread_create(&tcp_thread, NULL, server_base_worker, g_srv.evbase_tcp); // start tcp listen loop if ( !server_listen() ) { ED2KD_LOGERR("failed to start server listener"); server_stop(); } pthread_join(tcp_thread, NULL); while ( EBUSY == pthread_cond_destroy(&g_srv.job_cond) ) { pthread_cond_broadcast(&g_srv.job_cond); //pthread_yield(); } pthread_mutex_destroy(&g_srv.job_mutex); for ( i=0; i<g_srv.thread_count; ++i ) { pthread_join(job_threads[i], NULL); } free(job_threads); // todo: free job queue items evconnlistener_free(g_srv.tcp_listener); event_free(evsig_int); event_base_free(g_srv.evbase_tcp); event_base_free(g_srv.evbase_main); if ( db_destroy() < 0 ) { ED2KD_LOGERR("failed to destroy database"); } server_free_config(); return EXIT_SUCCESS; }
static int test_ratelimiting(void) { struct event_base *base; struct sockaddr_in sin; struct evconnlistener *listener; struct sockaddr_storage ss; ev_socklen_t slen; int i; struct timeval tv; ev_uint64_t total_received; double total_sq_persec, total_persec; double variance; double expected_total_persec = -1.0, expected_avg_persec = -1.0; int ok = 1; struct event_config *base_cfg; struct event *periodic_level_check; struct event *group_drain_event=NULL; memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl(0x7f000001); /* 127.0.0.1 */ sin.sin_port = 0; /* unspecified port */ if (0) event_enable_debug_mode(); base_cfg = event_config_new(); #ifdef _WIN32 if (cfg_enable_iocp) { evthread_use_windows_threads(); event_config_set_flag(base_cfg, EVENT_BASE_FLAG_STARTUP_IOCP); } #endif base = event_base_new_with_config(base_cfg); event_config_free(base_cfg); if (! base) { fprintf(stderr, "Couldn't create event_base"); return 1; } listener = evconnlistener_new_bind(base, echo_listenercb, base, LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE, -1, (struct sockaddr *)&sin, sizeof(sin)); if (! listener) { fprintf(stderr, "Couldn't create listener"); return 1; } slen = sizeof(ss); if (getsockname(evconnlistener_get_fd(listener), (struct sockaddr *)&ss, &slen) < 0) { perror("getsockname"); return 1; } if (cfg_connlimit > 0) { conn_bucket_cfg = ev_token_bucket_cfg_new( cfg_connlimit, cfg_connlimit * 4, cfg_connlimit, cfg_connlimit * 4, &cfg_tick); assert(conn_bucket_cfg); } if (cfg_grouplimit > 0) { group_bucket_cfg = ev_token_bucket_cfg_new( cfg_grouplimit, cfg_grouplimit * 4, cfg_grouplimit, cfg_grouplimit * 4, &cfg_tick); group = ratelim_group = bufferevent_rate_limit_group_new( base, group_bucket_cfg); expected_total_persec = cfg_grouplimit - (cfg_group_drain / seconds_per_tick); expected_avg_persec = cfg_grouplimit / cfg_n_connections; if (cfg_connlimit > 0 && expected_avg_persec > cfg_connlimit) expected_avg_persec = cfg_connlimit; if (cfg_min_share >= 0) bufferevent_rate_limit_group_set_min_share( ratelim_group, cfg_min_share); } if (expected_avg_persec < 0 && cfg_connlimit > 0) expected_avg_persec = cfg_connlimit; if (expected_avg_persec > 0) expected_avg_persec /= seconds_per_tick; if (expected_total_persec > 0) expected_total_persec /= seconds_per_tick; bevs = calloc(cfg_n_connections, sizeof(struct bufferevent *)); states = calloc(cfg_n_connections, sizeof(struct client_state)); if (bevs == NULL || states == NULL) { printf("Unable to allocate memory...\n"); return 1; } for (i = 0; i < cfg_n_connections; ++i) { bevs[i] = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE|BEV_OPT_THREADSAFE); assert(bevs[i]); bufferevent_setcb(bevs[i], discard_readcb, loud_writecb, write_on_connectedcb, &states[i]); bufferevent_enable(bevs[i], EV_READ|EV_WRITE); bufferevent_socket_connect(bevs[i], (struct sockaddr *)&ss, slen); } tv.tv_sec = cfg_duration - 1; tv.tv_usec = 995000; event_base_loopexit(base, &tv); tv.tv_sec = 0; tv.tv_usec = 100*1000; ms100_common = event_base_init_common_timeout(base, &tv); periodic_level_check = event_new(base, -1, EV_PERSIST, check_group_bucket_levels_cb, NULL); event_add(periodic_level_check, ms100_common); if (cfg_group_drain && ratelim_group) { group_drain_event = event_new(base, -1, EV_PERSIST, group_drain_cb, NULL); event_add(group_drain_event, &cfg_tick); } event_base_dispatch(base); ratelim_group = NULL; /* So no more responders get added */ event_free(periodic_level_check); if (group_drain_event) event_del(group_drain_event); for (i = 0; i < cfg_n_connections; ++i) { bufferevent_free(bevs[i]); } evconnlistener_free(listener); /* Make sure no new echo_conns get added to the group. */ ratelim_group = NULL; /* This should get _everybody_ freed */ while (n_echo_conns_open) { printf("waiting for %d conns\n", n_echo_conns_open); tv.tv_sec = 0; tv.tv_usec = 300000; event_base_loopexit(base, &tv); event_base_dispatch(base); } if (group) bufferevent_rate_limit_group_free(group); if (total_n_bev_checks) { printf("Average read bucket level: %f\n", (double)total_rbucket_level/total_n_bev_checks); printf("Average write bucket level: %f\n", (double)total_wbucket_level/total_n_bev_checks); printf("Highest read bucket level: %f\n", (double)max_bucket_level); printf("Highest write bucket level: %f\n", (double)min_bucket_level); printf("Average max-to-read: %f\n", ((double)total_max_to_read)/total_n_bev_checks); printf("Average max-to-write: %f\n", ((double)total_max_to_write)/total_n_bev_checks); } if (total_n_group_bev_checks) { printf("Average group read bucket level: %f\n", ((double)total_group_rbucket_level)/total_n_group_bev_checks); printf("Average group write bucket level: %f\n", ((double)total_group_wbucket_level)/total_n_group_bev_checks); } total_received = 0; total_persec = 0.0; total_sq_persec = 0.0; for (i=0; i < cfg_n_connections; ++i) { double persec = states[i].received; persec /= cfg_duration; total_received += states[i].received; total_persec += persec; total_sq_persec += persec*persec; printf("%d: %f per second\n", i+1, persec); } printf(" total: %f per second\n", ((double)total_received)/cfg_duration); if (expected_total_persec > 0) { double diff = expected_total_persec - ((double)total_received/cfg_duration); printf(" [Off by %lf]\n", diff); if (cfg_grouplimit_tolerance > 0 && fabs(diff) > cfg_grouplimit_tolerance) { fprintf(stderr, "Group bandwidth out of bounds\n"); ok = 0; } } printf(" average: %f per second\n", (((double)total_received)/cfg_duration)/cfg_n_connections); if (expected_avg_persec > 0) { double diff = expected_avg_persec - (((double)total_received)/cfg_duration)/cfg_n_connections; printf(" [Off by %lf]\n", diff); if (cfg_connlimit_tolerance > 0 && fabs(diff) > cfg_connlimit_tolerance) { fprintf(stderr, "Connection bandwidth out of bounds\n"); ok = 0; } } variance = total_sq_persec/cfg_n_connections - total_persec*total_persec/(cfg_n_connections*cfg_n_connections); printf(" stddev: %f per second\n", sqrt(variance)); if (cfg_stddev_tolerance > 0 && sqrt(variance) > cfg_stddev_tolerance) { fprintf(stderr, "Connection variance out of bounds\n"); ok = 0; } event_base_free(base); free(bevs); free(states); return ok ? 0 : 1; }
/* Testing code for event_base_dump_events(). Notes that just because we have code to exercise this function, doesn't mean that *ANYTHING* about the output format is guaranteed to remain in the future. */ int main(int argc, char **argv) { #define N_EVENTS 13 int i; struct event *ev[N_EVENTS]; evutil_socket_t pair1[2]; evutil_socket_t pair2[2]; struct timeval tv_onesec = {1,0}; struct timeval tv_two5sec = {2,500*1000}; const struct timeval *tv_onesec_common; const struct timeval *tv_two5sec_common; struct event_base *base; struct timeval now; #ifdef _WIN32 WORD wVersionRequested; WSADATA wsaData; wVersionRequested = MAKEWORD(2, 2); WSAStartup(wVersionRequested, &wsaData); #endif #ifdef _WIN32 #define LOCAL_SOCKETPAIR_AF AF_INET #else #define LOCAL_SOCKETPAIR_AF AF_UNIX #endif if (evutil_make_internal_pipe_(pair1) < 0 || evutil_make_internal_pipe_(pair2) < 0) { sock_perror("evutil_make_internal_pipe_"); return 1; } if (!(base = event_base_new())) { fprintf(stderr,"Couldn't make event_base\n"); return 2; } tv_onesec_common = event_base_init_common_timeout(base, &tv_onesec); tv_two5sec_common = event_base_init_common_timeout(base, &tv_two5sec); ev[0] = event_new(base, pair1[0], EV_WRITE, callback1, NULL); ev[1] = event_new(base, pair1[1], EV_READ|EV_PERSIST, callback1, NULL); ev[2] = event_new(base, pair2[0], EV_WRITE|EV_PERSIST, callback2, NULL); ev[3] = event_new(base, pair2[1], EV_READ, callback2, NULL); /* For timers */ ev[4] = evtimer_new(base, callback1, NULL); ev[5] = evtimer_new(base, callback1, NULL); ev[6] = evtimer_new(base, callback1, NULL); ev[7] = event_new(base, -1, EV_PERSIST, callback2, NULL); ev[8] = event_new(base, -1, EV_PERSIST, callback2, NULL); ev[9] = event_new(base, -1, EV_PERSIST, callback2, NULL); /* To activate */ ev[10] = event_new(base, -1, 0, callback1, NULL); ev[11] = event_new(base, -1, 0, callback2, NULL); /* Signals */ ev[12] = evsignal_new(base, SIGINT, callback2, NULL); event_add(ev[0], NULL); event_add(ev[1], &tv_onesec); event_add(ev[2], tv_onesec_common); event_add(ev[3], tv_two5sec_common); event_add(ev[4], tv_onesec_common); event_add(ev[5], tv_onesec_common); event_add(ev[6], &tv_onesec); event_add(ev[7], tv_two5sec_common); event_add(ev[8], tv_onesec_common); event_add(ev[9], &tv_two5sec); event_active(ev[10], EV_READ, 1); event_active(ev[11], EV_READ|EV_WRITE|EV_TIMEOUT, 1); event_active(ev[1], EV_READ, 1); event_add(ev[12], NULL); evutil_gettimeofday(&now,NULL); puts("=====expected"); printf("Now= %ld.%06d\n",(long)now.tv_sec,(int)now.tv_usec); puts("Inserted:"); printf(" %p [fd %ld] Write\n",ev[0],(long)pair1[0]); printf(" %p [fd %ld] Read Persist Timeout=T+1\n",ev[1],(long)pair1[1]); printf(" %p [fd %ld] Write Persist Timeout=T+1\n",ev[2],(long)pair2[0]); printf(" %p [fd %ld] Read Timeout=T+2.5\n",ev[3],(long)pair2[1]); printf(" %p [fd -1] Timeout=T+1\n",ev[4]); printf(" %p [fd -1] Timeout=T+1\n",ev[5]); printf(" %p [fd -1] Timeout=T+1\n",ev[6]); printf(" %p [fd -1] Persist Timeout=T+2.5\n",ev[7]); printf(" %p [fd -1] Persist Timeout=T+1\n",ev[8]); printf(" %p [fd -1] Persist Timeout=T+2.5\n",ev[9]); printf(" %p [sig %d] Signal Persist\n", ev[12], (int)SIGINT); puts("Active:"); printf(" %p [fd -1, priority=0] Read active\n", ev[10]); printf(" %p [fd -1, priority=0] Read Write Timeout active\n", ev[11]); printf(" %p [fd %ld, priority=0] Read active\n", ev[1], (long)pair1[1]); puts("======received"); event_base_dump_events(base, stdout); for (i = 0; i < N_EVENTS; ++i) { event_free(ev[i]); } event_base_free(base); return 0; }