| 1244 | } |
| 1245 | |
| 1246 | int Socket::Connect(const timespec* abstime, |
| 1247 | int (*on_connect)(int, int, void*), void* data) { |
| 1248 | if (_ssl_ctx) { |
| 1249 | _ssl_state = SSL_CONNECTING; |
| 1250 | } else { |
| 1251 | _ssl_state = SSL_OFF; |
| 1252 | } |
| 1253 | struct sockaddr_storage serv_addr; |
| 1254 | socklen_t addr_size = 0; |
| 1255 | if (butil::endpoint2sockaddr(remote_side(), &serv_addr, &addr_size) != 0) { |
| 1256 | PLOG(ERROR) << "Fail to get sockaddr"; |
| 1257 | return -1; |
| 1258 | } |
| 1259 | butil::fd_guard sockfd(socket(serv_addr.ss_family, SOCK_STREAM, 0)); |
| 1260 | if (sockfd < 0) { |
| 1261 | PLOG(ERROR) << "Fail to create socket"; |
| 1262 | return -1; |
| 1263 | } |
| 1264 | CHECK_EQ(0, butil::make_close_on_exec(sockfd)); |
| 1265 | // We need to do async connect (to manage the timeout by ourselves). |
| 1266 | CHECK_EQ(0, butil::make_non_blocking(sockfd)); |
| 1267 | if (!_device_name.empty()) { |
| 1268 | if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, |
| 1269 | _device_name.c_str(), _device_name.size()) < 0) { |
| 1270 | PLOG(ERROR) << "Fail to set SO_BINDTODEVICE of fd=" << sockfd |
| 1271 | << " to device_name=" << _device_name; |
| 1272 | return -1; |
| 1273 | } |
| 1274 | } |
| 1275 | if (local_side().ip != butil::IP_ANY) { |
| 1276 | struct sockaddr_storage cli_addr; |
| 1277 | if (butil::endpoint2sockaddr(local_side(), &cli_addr, &addr_size) != 0) { |
| 1278 | PLOG(ERROR) << "Fail to get client sockaddr"; |
| 1279 | return -1; |
| 1280 | } |
| 1281 | if (::bind(sockfd, (struct sockaddr*)&cli_addr, addr_size) != 0) { |
| 1282 | PLOG(ERROR) << "Fail to bind client socket, errno=" << strerror(errno); |
| 1283 | return -1; |
| 1284 | } |
| 1285 | } |
| 1286 | const int rc = ::connect( |
| 1287 | sockfd, (struct sockaddr*)&serv_addr, addr_size); |
| 1288 | if (rc != 0 && errno != EINPROGRESS) { |
| 1289 | PLOG(WARNING) << "Fail to connect to " << remote_side(); |
| 1290 | return -1; |
| 1291 | } |
| 1292 | if (on_connect) { |
| 1293 | EpollOutRequest* req = new(std::nothrow) EpollOutRequest; |
| 1294 | if (req == NULL) { |
| 1295 | LOG(FATAL) << "Fail to new EpollOutRequest"; |
| 1296 | return -1; |
| 1297 | } |
| 1298 | req->fd = sockfd; |
| 1299 | req->timer_id = 0; |
| 1300 | req->on_epollout_event = on_connect; |
| 1301 | req->data = data; |
| 1302 | // A temporary Socket to hold `EpollOutRequest', which will |
| 1303 | // be added into epoll device soon |
no test coverage detected