Connect server

Other than server’s socket, client’s socket works in non-block mode:

  1. if ((s = socket(res->ai_family, res->ai_socktype |
  2. SOCK_NONBLOCK, res->ai_protocol)) < 0)

timeout_connect() function is used by client to connect server:

  1. int
  2. timeout_connect(int s, const struct sockaddr *name, socklen_t namelen)
  3. {
  4. struct pollfd pfd;
  5. socklen_t optlen;
  6. int optval;
  7. int ret;
  8. if ((ret = connect(s, name, namelen)) != 0 && errno == EINPROGRESS) {
  9. pfd.fd = s;
  10. pfd.events = POLLOUT;
  11. if ((ret = poll(&pfd, 1, timeout)) == 1) {
  12. optlen = sizeof(optval);
  13. if ((ret = getsockopt(s, SOL_SOCKET, SO_ERROR,
  14. &optval, &optlen)) == 0) {
  15. errno = optval;
  16. ret = optval == 0 ? 0 : -1;
  17. }
  18. } else if (ret == 0) {
  19. errno = ETIMEDOUT;
  20. ret = -1;
  21. } else
  22. err(1, "poll failed");
  23. }
  24. return ret;
  25. }

We will analyze it step by step:

(1) There is a timeout variable that can be specified by -w option (default value is -1, means no timeout), and denotes how long connect() function can wait (the unit is seconds):

  1. int timeout = -1;
  2. ......
  3. while ((ch = getopt(argc, argv, ...))) {
  4. ......
  5. switch (ch) {
  6. ......
  7. case 'w':
  8. timeout = strtonum(optarg, 0, INT_MAX / 1000, &errstr);
  9. if (errstr)
  10. errx(1, "timeout %s: %s", errstr, optarg);
  11. timeout *= 1000;
  12. break;
  13. ......
  14. }
  15. }

(2) Check connect()‘s return value: if return value is 0, it means connection is established successfully; if errno is EINPROGRESS, we can use timeout to control how long to wait; otherwise the connection can’t be built:

  1. if ((ret = connect(s, name, namelen)) != 0 && errno == EINPROGRESS) {
  2. ......
  3. }

(3) Use poll() to monitor whether the connection is successful or not. The POLLOUT event means socket become writable. Even return value of poll is 1, the getsockopt() can be used to check whether there is indeed no error.

P.S., generally speaking, because UDP is connection-less protocol, there is no need to call connect() for UDP client.