int bufferevent_socket_connect(struct bufferevent *bev, struct sockaddr *sa, int socklen) { struct bufferevent_private *bufev_p = EVUTIL_UPCAST(bev, struct bufferevent_private, bev); evutil_socket_t fd; int r = 0; int result=-1; int ownfd = 0; bufferevent_incref_and_lock_(bev); if (!bufev_p) goto done; fd = bufferevent_getfd(bev); if (fd < 0) { if (!sa) goto done; fd = evutil_socket_(sa->sa_family, SOCK_STREAM|EVUTIL_SOCK_NONBLOCK, 0); if (fd < 0) goto done; ownfd = 1; } if (sa) { #ifdef _WIN32 if (bufferevent_async_can_connect_(bev)) { bufferevent_setfd(bev, fd); r = bufferevent_async_connect_(bev, fd, sa, socklen); if (r < 0) goto freesock; bufev_p->connecting = 1; result = 0; goto done; } else #endif r = evutil_socket_connect_(&fd, sa, socklen); if (r < 0) goto freesock; } #ifdef _WIN32 /* ConnectEx() isn't always around, even when IOCP is enabled. * Here, we borrow the socket object's write handler to fall back * on a non-blocking connect() when ConnectEx() is unavailable. */ if (BEV_IS_ASYNC(bev)) { event_assign(&bev->ev_write, bev->ev_base, fd, EV_WRITE|EV_PERSIST, bufferevent_writecb, bev); } #endif bufferevent_setfd(bev, fd); if (r == 0) { if (! be_socket_enable(bev, EV_WRITE)) { bufev_p->connecting = 1; result = 0; goto done; } } else if (r == 1) { /* The connect succeeded already. How very BSD of it. */ result = 0; bufev_p->connecting = 1; event_active(&bev->ev_write, EV_WRITE, 1); } else { /* The connect failed already. How very BSD of it. */ bufev_p->connection_refused = 1; bufev_p->connecting = 1; result = 0; event_active(&bev->ev_write, EV_WRITE, 1); } goto done; freesock: bufferevent_run_eventcb_(bev, BEV_EVENT_ERROR); if (ownfd) evutil_closesocket(fd); /* do something about the error? */ done: bufferevent_decref_and_unlock_(bev); return result; }
static void regress_pick_a_port(void *arg) { struct basic_test_data *data = arg; struct event_base *base = data->base; struct evconnlistener *listener1 = NULL, *listener2 = NULL; struct sockaddr_in sin; int count1 = 2, count2 = 1; struct sockaddr_storage ss1, ss2; struct sockaddr_in *sin1, *sin2; ev_socklen_t slen1 = sizeof(ss1), slen2 = sizeof(ss2); unsigned int flags = LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_EXEC; evutil_socket_t fd1 = -1, fd2 = -1, fd3 = -1; if (data->setup_data && strstr((char*)data->setup_data, "ts")) { flags |= LEV_OPT_THREADSAFE; } 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; /* "You pick!" */ listener1 = evconnlistener_new_bind(base, acceptcb, &count1, flags, -1, (struct sockaddr *)&sin, sizeof(sin)); tt_assert(listener1); listener2 = evconnlistener_new_bind(base, acceptcb, &count2, flags, -1, (struct sockaddr *)&sin, sizeof(sin)); tt_assert(listener2); tt_int_op(evconnlistener_get_fd(listener1), >=, 0); tt_int_op(evconnlistener_get_fd(listener2), >=, 0); tt_assert(getsockname(evconnlistener_get_fd(listener1), (struct sockaddr*)&ss1, &slen1) == 0); tt_assert(getsockname(evconnlistener_get_fd(listener2), (struct sockaddr*)&ss2, &slen2) == 0); tt_int_op(ss1.ss_family, ==, AF_INET); tt_int_op(ss2.ss_family, ==, AF_INET); sin1 = (struct sockaddr_in*)&ss1; sin2 = (struct sockaddr_in*)&ss2; tt_int_op(ntohl(sin1->sin_addr.s_addr), ==, 0x7f000001); tt_int_op(ntohl(sin2->sin_addr.s_addr), ==, 0x7f000001); tt_int_op(sin1->sin_port, !=, sin2->sin_port); tt_ptr_op(evconnlistener_get_base(listener1), ==, base); tt_ptr_op(evconnlistener_get_base(listener2), ==, base); fd1 = fd2 = fd3 = -1; evutil_socket_connect_(&fd1, (struct sockaddr*)&ss1, slen1); evutil_socket_connect_(&fd2, (struct sockaddr*)&ss1, slen1); evutil_socket_connect_(&fd3, (struct sockaddr*)&ss2, slen2); #ifdef _WIN32 Sleep(100); /* XXXX this is a stupid stopgap. */ #endif event_base_dispatch(base); tt_int_op(count1, ==, 0); tt_int_op(count2, ==, 0); end: if (fd1>=0) EVUTIL_CLOSESOCKET(fd1); if (fd2>=0) EVUTIL_CLOSESOCKET(fd2); if (fd3>=0) EVUTIL_CLOSESOCKET(fd3); if (listener1) evconnlistener_free(listener1); if (listener2) evconnlistener_free(listener2); }