cliopen.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. /*
  2. * Copyright (c) 1993 W. Richard Stevens. All rights reserved.
  3. * Permission to use or modify this software and its documentation only for
  4. * educational purposes and without fee is hereby granted, provided that
  5. * the above copyright notice appear in all copies. The author makes no
  6. * representations about the suitability of this software for any purpose.
  7. * It is provided "as is" without express or implied warranty.
  8. */
  9. #include "sock.h"
  10. int
  11. cliopen(char *host, char *port)
  12. {
  13. int fd, i, on;
  14. const char *protocol;
  15. struct in_addr inaddr;
  16. struct servent *sp;
  17. struct hostent *hp;
  18. protocol = udp ? "udp" : "tcp";
  19. /* initialize socket address structure */
  20. bzero(&servaddr, sizeof(servaddr));
  21. servaddr.sin_family = AF_INET;
  22. /* see if "port" is a service name or number */
  23. if ( (i = atoi(port)) == 0) {
  24. if ( (sp = getservbyname(port, protocol)) == NULL)
  25. err_quit("getservbyname() error for: %s/%s", port, protocol);
  26. servaddr.sin_port = sp->s_port;
  27. } else
  28. servaddr.sin_port = htons(i);
  29. /*
  30. * First try to convert the host name as a dotted-decimal number.
  31. * Only if that fails do we call gethostbyname().
  32. */
  33. if (inet_aton(host, &inaddr) == 1)
  34. servaddr.sin_addr = inaddr; /* it's dotted-decimal */
  35. else if ( (hp = gethostbyname(host)) != NULL)
  36. memcpy(&servaddr.sin_addr, hp->h_addr, hp->h_length);
  37. else
  38. err_quit("invalid hostname: %s", host);
  39. if ( (fd = socket(AF_INET, udp ? SOCK_DGRAM : SOCK_STREAM, 0)) < 0)
  40. err_sys("socket() error");
  41. if (reuseaddr) {
  42. on = 1;
  43. if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) < 0)
  44. err_sys("setsockopt of SO_REUSEADDR error");
  45. }
  46. #ifdef SO_REUSEPORT
  47. if (reuseport) {
  48. on = 1;
  49. if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof (on)) < 0)
  50. err_sys("setsockopt of SO_REUSEPORT error");
  51. }
  52. #endif
  53. /*
  54. * User can specify port number for client to bind. Only real use
  55. * is to see a TCP connection initiated by both ends at the same time.
  56. * Also, if UDP is being used, we specifically call bind() to assign
  57. * an ephemeral port to the socket.
  58. * Also, for experimentation, client can also set local IP address
  59. * (and port) using -l option. Allow localip[] to be set but bindport
  60. * to be 0.
  61. */
  62. if (bindport != 0 || localip[0] != 0 || udp) {
  63. bzero(&cliaddr, sizeof(cliaddr));
  64. cliaddr.sin_family = AF_INET;
  65. cliaddr.sin_port = htons(bindport); /* can be 0 */
  66. if (localip[0] != 0) {
  67. if (inet_aton(localip, &cliaddr.sin_addr) == 0)
  68. err_quit("invalid IP address: %s", localip);
  69. } else
  70. cliaddr.sin_addr.s_addr = htonl(INADDR_ANY); /* wildcard */
  71. if (bind(fd, (struct sockaddr *) &cliaddr, sizeof(cliaddr)) < 0)
  72. err_sys("bind() error");
  73. }
  74. /* Need to allocate buffers before connect(), since they can affect
  75. * TCP options (window scale, etc.).
  76. */
  77. buffers(fd);
  78. sockopts(fd, 0); /* may also want to set SO_DEBUG */
  79. /*
  80. * Connect to the server. Required for TCP, optional for UDP.
  81. */
  82. if (udp == 0 || connectudp) {
  83. for ( ; ; ) {
  84. if (connect(fd, (struct sockaddr *) &servaddr, sizeof(servaddr))
  85. == 0)
  86. break; /* all OK */
  87. if (errno == EINTR) /* can happen with SIGIO */
  88. continue;
  89. if (errno == EISCONN) /* can happen with SIGIO */
  90. break;
  91. err_sys("connect() error");
  92. }
  93. }
  94. if (verbose) {
  95. /* Call getsockname() to find local address bound to socket:
  96. TCP ephemeral port was assigned by connect() or bind();
  97. UDP ephemeral port was assigned by bind(). */
  98. i = sizeof(cliaddr);
  99. if (getsockname(fd, (struct sockaddr *) &cliaddr, &i) < 0)
  100. err_sys("getsockname() error");
  101. /* Can't do one fprintf() since inet_ntoa() stores
  102. the result in a static location. */
  103. fprintf(stderr, "connected on %s.%d ",
  104. INET_NTOA(cliaddr.sin_addr), ntohs(cliaddr.sin_port));
  105. fprintf(stderr, "to %s.%d\n",
  106. INET_NTOA(servaddr.sin_addr), ntohs(servaddr.sin_port));
  107. }
  108. sockopts(fd, 1); /* some options get set after connect() */
  109. return(fd);
  110. }