servopen.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  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. servopen(char *host, char *port)
  12. {
  13. int fd, newfd, i, on, pid;
  14. const char *protocol;
  15. struct in_addr inaddr;
  16. struct servent *sp;
  17. protocol = udp ? "udp" : "tcp";
  18. /* Initialize the socket address structure */
  19. bzero(&servaddr, sizeof(servaddr));
  20. servaddr.sin_family = AF_INET;
  21. /* Caller normally wildcards the local Internet address, meaning
  22. a connection will be accepted on any connected interface.
  23. We only allow an IP address for the "host", not a name. */
  24. if (host == NULL)
  25. servaddr.sin_addr.s_addr = htonl(INADDR_ANY); /* wildcard */
  26. else {
  27. if (inet_aton(host, &inaddr) == 0)
  28. err_quit("invalid host name for server: %s", host);
  29. servaddr.sin_addr = inaddr;
  30. }
  31. /* See if "port" is a service name or number */
  32. if ( (i = atoi(port)) == 0) {
  33. if ( (sp = getservbyname(port, protocol)) == NULL)
  34. err_ret("getservbyname() error for: %s/%s", port, protocol);
  35. servaddr.sin_port = sp->s_port;
  36. } else
  37. servaddr.sin_port = htons(i);
  38. if ( (fd = socket(AF_INET, udp ? SOCK_DGRAM : SOCK_STREAM, 0)) < 0)
  39. err_sys("socket() error");
  40. if (reuseaddr) {
  41. on = 1;
  42. if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
  43. err_sys("setsockopt of SO_REUSEADDR error");
  44. }
  45. #ifdef SO_REUSEPORT
  46. if (reuseport) {
  47. on = 1;
  48. if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on)) < 0)
  49. err_sys("setsockopt of SO_REUSEPORT error");
  50. }
  51. #endif
  52. /* Bind our well-known port so the client can connect to us. */
  53. if (bind(fd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0)
  54. err_sys("can't bind local address");
  55. join_mcast(fd, &servaddr);
  56. if (udp) {
  57. buffers(fd);
  58. if (foreignip[0] != 0) { /* connect to foreignip/port# */
  59. bzero(&cliaddr, sizeof(cliaddr));
  60. if (inet_aton(foreignip, &cliaddr.sin_addr) == 0)
  61. err_quit("invalid IP address: %s", foreignip);
  62. cliaddr.sin_family = AF_INET;
  63. cliaddr.sin_port = htons(foreignport);
  64. /* connect() for datagram socket doesn't appear to allow
  65. wildcarding of either IP address or port number */
  66. if (connect(fd, (struct sockaddr *) &cliaddr, sizeof(cliaddr))
  67. < 0)
  68. err_sys("connect() error");
  69. }
  70. sockopts(fd, 1);
  71. return(fd); /* nothing else to do */
  72. }
  73. buffers(fd); /* may set receive buffer size; must do here to get
  74. correct window advertised on SYN */
  75. sockopts(fd, 0); /* only set some socket options for fd */
  76. listen(fd, listenq);
  77. if (pauselisten)
  78. sleep_us(pauselisten*1000); /* lets connection queue build up */
  79. if (dofork)
  80. TELL_WAIT(); /* initialize synchronization primitives */
  81. for ( ; ; ) {
  82. i = sizeof(cliaddr);
  83. if ( (newfd = accept(fd, (struct sockaddr *) &cliaddr, &i)) < 0)
  84. err_sys("accept() error");
  85. if (dofork) {
  86. if ( (pid = fork()) < 0)
  87. err_sys("fork error");
  88. if (pid > 0) {
  89. close(newfd); /* parent closes connected socket */
  90. WAIT_CHILD(); /* wait for child to output to terminal */
  91. continue; /* and back to for(;;) for another accept() */
  92. } else {
  93. close(fd); /* child closes listening socket */
  94. }
  95. }
  96. /* child (or iterative server) continues here */
  97. if (verbose) {
  98. /* Call getsockname() to find local address bound to socket:
  99. local internet address is now determined (if multihomed). */
  100. i = sizeof(servaddr);
  101. if (getsockname(newfd, (struct sockaddr *) &servaddr, &i) < 0)
  102. err_sys("getsockname() error");
  103. /* Can't do one fprintf() since inet_ntoa() stores
  104. the result in a static location. */
  105. fprintf(stderr, "connection on %s.%d ",
  106. INET_NTOA(servaddr.sin_addr), ntohs(servaddr.sin_port));
  107. fprintf(stderr, "from %s.%d\n",
  108. INET_NTOA(cliaddr.sin_addr), ntohs(cliaddr.sin_port));
  109. }
  110. buffers(newfd); /* setsockopt() again, in case it didn't propagate
  111. from listening socket to connected socket */
  112. sockopts(newfd, 1); /* can set all socket options for this socket */
  113. if (dofork)
  114. TELL_PARENT(getppid()); /* tell parent we're done with terminal */
  115. return(newfd);
  116. }
  117. }