struct bufferevent* red_connect_relay(struct sockaddr_in *addr, evbuffercb writecb, everrorcb errorcb, void *cbarg) { struct bufferevent *retval = NULL; int relay_fd = -1; int error; relay_fd = socket(AF_INET, SOCK_STREAM, 0); if (relay_fd == -1) { log_errno(LOG_ERR, "socket"); goto fail; } error = fcntl_nonblock(relay_fd); if (error) { log_errno(LOG_ERR, "fcntl"); goto fail; } if (apply_tcp_keepalive(relay_fd)) goto fail; error = connect(relay_fd, (struct sockaddr*)addr, sizeof(*addr)); if (error && errno != EINPROGRESS) { log_errno(LOG_NOTICE, "connect"); goto fail; } retval = bufferevent_new(relay_fd, NULL, writecb, errorcb, cbarg); if (!retval) { log_errno(LOG_ERR, "bufferevent_new"); goto fail; } error = bufferevent_enable(retval, EV_WRITE); // we wait for connection... if (error) { log_errno(LOG_ERR, "bufferevent_enable"); goto fail; } return retval; fail: if (relay_fd != -1) redsocks_close(relay_fd); if (retval) bufferevent_free(retval); return NULL; }
struct bufferevent* red_prepare_relay(const char *ifname, bufferevent_data_cb readcb, bufferevent_data_cb writecb, bufferevent_event_cb errorcb, void *cbarg) { struct bufferevent *retval = NULL; int relay_fd = -1; int error; relay_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (relay_fd == -1) { log_errno(LOG_ERR, "socket"); goto fail; } if (ifname && strlen(ifname)) { #ifdef USE_PF // BSD error = setsockopt(relay_fd, SOL_SOCKET, IP_RECVIF, ifname, strlen(ifname)); #else // Linux error = setsockopt(relay_fd, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen(ifname)); #endif if (error) { log_errno(LOG_ERR, "setsockopt"); goto fail; } } error = evutil_make_socket_nonblocking(relay_fd); if (error) { log_errno(LOG_ERR, "evutil_make_socket_nonblocking"); goto fail; } retval = bufferevent_socket_new(get_event_base(), relay_fd, 0); if (!retval) { log_errno(LOG_ERR, "bufferevent_socket_new"); goto fail; } bufferevent_setcb(retval, readcb, writecb, errorcb, cbarg); if (writecb) { error = bufferevent_enable(retval, EV_WRITE); // we wait for connection... if (error) { log_errno(LOG_ERR, "bufferevent_enable"); goto fail; } } if (apply_tcp_keepalive(relay_fd)) goto fail; return retval; fail: if (retval){ bufferevent_disable(retval, EV_READ|EV_WRITE); bufferevent_free(retval); } if (relay_fd != -1) redsocks_close(relay_fd); return NULL; }