void on_accept(int fd, short ev, void *arg) { int client_fd; struct sockaddr_in client_addr; socklen_t client_len = sizeof(client_addr); workqueue_t *workqueue = (workqueue_t *)arg; client_t *client; job_t *job; client_fd = accept(fd, (struct sockaddr *)&client_addr, &client_len); if (client_fd < 0) { warn("accept failed"); return; } if (setnonblock(client_fd) < 0) { warn("failed to set client socket to non-blocking"); close(client_fd); return; } if ((client = malloc(sizeof(*client))) == NULL) { warn("failed to allocate memory for client state"); close(client_fd); return; } memset(client, 0, sizeof(*client)); client->fd = client_fd; if ((client->output_buffer = evbuffer_new()) == NULL) { warn("client output buffer allocation failed"); closeAndFreeClient(client); return; } if ((client->evbase = event_base_new()) == NULL) { warn("client event_base creation failed"); closeAndFreeClient(client); return; } if ((client->buf_ev = bufferevent_new(client_fd, buffered_on_read, buffered_on_write, buffered_on_error, client)) == NULL) { warn("client bufferevent creation failed"); closeAndFreeClient(client); return; } bufferevent_base_set(client->evbase, client->buf_ev); bufferevent_enable(client->buf_ev, EV_READ); if ((job = malloc(sizeof(*job))) == NULL) { warn("failed to allocate memory for job state"); closeAndFreeClient(client); return; } job->job_function = server_job_function; job->user_data = client; workqueue_add_job(workqueue, job); }
static void maxconns_handler(const int fd, const short which, void *arg) { struct timeval t = {.tv_sec = 0, .tv_usec = 10000}; if (fd == -42 || allow_new_conns == false) { /* reschedule in 10ms if we need to keep polling */ evtimer_set(&maxconnsevent, maxconns_handler, 0); event_base_set(main_base, &maxconnsevent); evtimer_add(&maxconnsevent, &t); } else { evtimer_del(&maxconnsevent); accept_new_conns(true); } } static bool update_event(conn *c, const int new_flags) { assert(c != NULL); if (c->ev_flags == new_flags) return true; pthread_t tid = pthread_self(); if (tid == dispatcher_thread.thread_id) { struct event_base *base = c->event.ev_base; if (event_del(&c->event) == -1) return false; event_set(&c->event, c->sfd, new_flags, master_event_handler, (void *)c); event_base_set(base, &c->event); c->ev_flags = new_flags; if (event_add(&c->event, 0) == -1) return false; return true; }else{ struct event_base *base = bufferevent_get_base(c->buf_ev); bufferevent_free(c->buf_ev); c->buf_ev = bufferevent_new(c->sfd, event_handler, buf_write_callback, buf_error_callback, (void * )c); bufferevent_base_set(base, c->buf_ev); c->ev_flags = new_flags; if (bufferevent_enable(c->buf_ev, new_flags) == -1) return false; return true; } //这个也得改成bufferevent的形式 /* event_set(&c->event, c->sfd, new_flags, event_handler, (void *)c); event_base_set(base, &c->event); event_add(&c->event, 0); c->buf_ev = bufferevent_new(c->sfd, event_handler, event_handler, NULL, (void * )c); bufferevent_base_set(base, c->buf_ev); bufferevent_enable(c->buf_ev, new_flags); c->ev_flags = new_flags; if (event_add(&c->event, 0) == -1) return false; return true; */ }
conn *conn_new(const int sfd, enum conn_states init_state, const int event_flags, const int read_buffer_size, enum network_transport transport, struct event_base *base) { /*此函数需要做的事情 1.新建一个conn结构,加入到connQ 2.为此链接(文件描述符),注册一个event_handler 3.event_handler进行状态的处理,不同状态不同的处理方式,master,slave共用此方法。 */ conn * new_c; new_c = conns[sfd]; if (NULL == new_c) { if ( !(new_c = (conn *)calloc(1, sizeof(conn))) ) { perror("alloc conn fail"); exit(1); } new_c->sfd = sfd; conns[sfd] = new_c; } new_c->state = init_state; //以上是连接的初始化,接下来是连接的事件注册 pthread_t tid = pthread_self(); if (tid == dispatcher_thread.thread_id) { event_set(&new_c->event, sfd, event_flags, master_event_handler, (void*)new_c); event_base_set(base, &new_c->event); event_add(&new_c->event, 0); }else{ new_c->buf_ev = bufferevent_new(sfd, event_handler, event_handler, buf_error_callback, (void *)new_c); bufferevent_base_set(base, new_c->buf_ev); bufferevent_enable(new_c->buf_ev, event_flags); } /* 想着想着还是决定改成用bufferevent。 因为master线程与slave用的是同一个函数来做处理event_handler -> drive_machine, 所以master线程的accept也需要改为用bufferevent,而且event_handler以及drive_machine也得改 还有struct conn的event也得改呀,得改成bufferevent类型呢 */ /* new_c->buf_ev = bufferevent_new(sfd, event_handler, event_handler, buf_error_callback, (void *)new_c); bufferevent_base_set(base, new_c->buf_ev); bufferevent_enable(new_c->buf_ev, event_flags); */ return new_c; }
static void http_base_test(void) { struct bufferevent *bev; int fd; const char *http_request; short port = -1; test_ok = 0; fprintf(stdout, "Testing HTTP Server Event Base: "); base = event_init(); /* * create another bogus base - which is being used by all subsequen * tests - yuck! */ event_init(); http = http_setup(&port, base); fd = http_connect("127.0.0.1", port); /* Stupid thing to send a request */ bev = bufferevent_new(fd, http_readcb, http_writecb, http_errorcb, NULL); bufferevent_base_set(base, bev); http_request = "GET /test HTTP/1.1\r\n" "Host: somehost\r\n" "Connection: close\r\n" "\r\n"; bufferevent_write(bev, http_request, strlen(http_request)); event_base_dispatch(base); bufferevent_free(bev); EVUTIL_CLOSESOCKET(fd); evhttp_free(http); event_base_free(base); base = NULL; if (test_ok != 2) { fprintf(stdout, "FAILED\n"); exit(1); } fprintf(stdout, "OK\n"); }
/* * Create a new bufferevent for a socket and register it with the provided * base. Note that options is always ignored, so programs using this backward * compatibility layer cannot rely on it. */ struct bufferevent * bufferevent_socket_new(struct event_base *base, evutil_socket_t fd, int options UNUSED) { struct bufferevent *bev; bev = bufferevent_new(fd, NULL, NULL, NULL, NULL); if (bufferevent_base_set(base, bev) < 0) { bufferevent_free(bev); return NULL; } return bev; }
Client *client_new(SocksLink *sl, int fd, struct sockaddr_storage *addr, socklen_t addrlen) { Client *cl = calloc(sizeof (*cl), 1); struct bufferevent *bev; INIT_LIST_HEAD(&cl->next); INIT_LIST_HEAD(&cl->next_auth); if (!cl) return NULL; bev = bufferevent_new(fd, NULL, NULL, NULL, NULL); if (!bev) { free(cl); return NULL; } bufferevent_base_set(sl->base, bev); cl->client_method = AUTH_METHOD_INVALID; cl->server_method = AUTH_METHOD_INVALID; cl->parent = sl; cl->client.bufev = bev; cl->client.fd = fd; cl->client.addr = *addr; cl->client.addrlen = addrlen; cl->server.fd = -1; list_add(&cl->next, &sl->clients); if (sl->pipe) { client_connect_server(cl); } else { bufferevent_setcb(bev, on_client_read_init, on_client_write, on_client_event, cl); bufferevent_settimeout(bev, SOCKS5_AUTH_TIMEOUT, SOCKS5_AUTH_TIMEOUT); bufferevent_enable(bev, EV_READ|EV_WRITE); } return cl; }
void SocketListen::OnAccept(int fd) { struct sockaddr_in sin; socklen_t len = sizeof(sin); int socket_fd = accept(fd, (struct sockaddr*)&sin, &len); string ip = inet_ntoa(sin.sin_addr); //std::cout << __func__ <<" "<<ip<<" "<<"port: "<<sin.sin_port <<" socket_fd = "<<socket_fd<< std::endl; if (socket_fd == INVALID_SOCKET || socket_fd == SOCKET_ERROR) { std::cout << __func__<< " listen error errno = "<< errno << std::endl; return ; } evutil_make_socket_nonblocking(socket_fd); SocketStream* ss = SocketStreamMgr::Instance().Add(sin.sin_addr.s_addr, queue_); if (!ss) return ; ss->SetIsShortConnect(is_short_connnect_); ss->SetSocketFd(socket_fd); ss->buffer_event_ = bufferevent_new(socket_fd, SocketStream::OnReadCb, SocketStream::OnWriteCb, SocketStream::OnErrorCb,ss); bufferevent_base_set(base_, ss->buffer_event_); bufferevent_enable(ss->buffer_event_, EV_READ | EV_WRITE); ss->Connected(); }
/** * This function will be called by libevent when there is a connection * ready to be accepted. */ void on_accept(int fd, short ev, void *arg) { int client_fd; struct sockaddr_in client_addr; socklen_t client_len = sizeof(client_addr); workqueue_t *workqueue = (workqueue_t *)arg; client_t *client; job_t *job; client_fd = accept(fd, (struct sockaddr *)&client_addr, &client_len); if (client_fd < 0) { warn("accept failed"); return; } printf("Run accept fd:%d\n", fd); /* Set the client socket to non-blocking mode. */ if (setnonblock(client_fd) < 0) { ; warn("failed to set client socket to non-blocking"); close(client_fd); return; } /* Create a client object. */ if ((client = (client_t *)malloc(sizeof(*client))) == NULL) { warn("failed to allocate memory for client state"); close(client_fd); return; } memset(client, 0, sizeof(*client)); client->fd = client_fd; /* Add any custom code anywhere from here to the end of this function * to initialize your application-specific attributes in the client struct. */ if ((client->output_buffer = evbuffer_new()) == NULL) { warn("client output buffer allocation failed"); closeAndFreeClient(client); return; } if ((client->evbase = event_base_new()) == NULL) { warn("client event_base creation failed"); closeAndFreeClient(client); return; } /* Create the buffered event. * * The first argument is the file descriptor that will trigger * the events, in this case the clients socket. * * The second argument is the callback that will be called * when data has been read from the socket and is available to * the application. * * The third argument is a callback to a function that will be * called when the write buffer has reached a low watermark. * That usually means that when the write buffer is 0 length, * this callback will be called. It must be defined, but you * don't actually have to do anything in this callback. * * The fourth argument is a callback that will be called when * there is a socket error. This is where you will detect * that the client disconnected or other socket errors. * * The fifth and final argument is to store an argument in * that will be passed to the callbacks. We store the client * object here. */ if ((client->buf_ev = bufferevent_new(client_fd, buffered_on_read, buffered_on_write, buffered_on_error, client)) == NULL) { warn("client bufferevent creation failed"); closeAndFreeClient(client); return; } bufferevent_base_set(client->evbase, client->buf_ev); bufferevent_settimeout(client->buf_ev, SOCKET_READ_TIMEOUT_SECONDS, SOCKET_WRITE_TIMEOUT_SECONDS); /* We have to enable it before our callbacks will be * called. */ bufferevent_enable(client->buf_ev, EV_READ); /* Create a job object and add it to the work queue. */ if ((job = (job_t *)malloc(sizeof(*job))) == NULL) { warn("failed to allocate memory for job state"); closeAndFreeClient(client); return; } job->job_function = server_job_function; job->user_data = client; workqueue_add_job(workqueue, job); }