1 /* Copyright (C) 2002 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, write to the Free
16 Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 Boston, MA 0211-1301 USA */
24 #include <sys/socket.h>
25 #include <sys/fcntl.h>
34 # define __socket(d, t, p) socket ((d), (t), (p))
35 # define __close(f) close ((f))
38 int getservport(u_long number, const char *proto)
40 char rpcdata[1024], servdata[1024];
41 struct rpcent rpcbuf, *rpcp;
42 struct servent servbuf, *servp = NULL;
45 ret = getrpcbynumber_r(number, &rpcbuf, rpcdata, sizeof rpcdata,
47 if (ret == 0 && rpcp != NULL) {
49 ret = getservbyname_r(rpcp->r_name, proto, &servbuf, servdata,
50 sizeof servdata, &servp);
51 if ((ret != 0 || servp == NULL) && rpcp->r_aliases) {
54 /* Then we try aliases. */
55 for (a = (const char **) rpcp->r_aliases; *a != NULL; a++) {
56 ret = getservbyname_r(*a, proto, &servbuf, servdata,
57 sizeof servdata, &servp);
58 if (ret == 0 && servp != NULL)
64 if (ret == 0 && servp != NULL)
65 return ntohs(servp->s_port);
71 svc_socket (u_long number, int type, int protocol, int reuse)
73 struct sockaddr_in addr;
74 socklen_t len = sizeof (struct sockaddr_in);
76 const char *proto = protocol == IPPROTO_TCP ? "tcp" : "udp";
78 if ((sock = __socket (AF_INET, type, protocol)) < 0)
80 perror (_("svc_socket: socket creation problem"));
87 ret = setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &ret,
91 perror (_("svc_socket: socket reuse problem"));
96 memset (&addr, 0, sizeof (addr));
97 addr.sin_family = AF_INET;
98 addr.sin_port = htons(getservport(number, proto));
100 if (bind(sock, (struct sockaddr *) &addr, len) < 0)
102 perror (_("svc_socket: bind problem"));
103 (void) __close(sock);
109 /* This socket might be shared among multiple processes
110 * if mountd is run multi-threaded. So it is safest to
111 * make it non-blocking, else all threads might wake
112 * one will get the data, and the others will block
114 * In all cases, transaction on this socket are atomic
115 * (accept for TCP, packet-read and packet-write for UDP)
116 * so O_NONBLOCK will not confuse unprepared code causing
117 * it to corrupt messages.
118 * It generally safest to have O_NONBLOCK when doing an accept
119 * as if we get a RST after the SYN and before accept runs,
120 * we can block despite being told there was an acceptable
124 if ((flags = fcntl(sock, F_GETFL)) < 0)
126 perror (_("svc_socket: can't get socket flags"));
127 (void) __close (sock);
130 else if (fcntl(sock, F_SETFL, flags|O_NONBLOCK) < 0)
132 perror (_("svc_socket: can't set socket flags"));
133 (void) __close (sock);
142 * Create and bind a TCP socket based on program number
145 svctcp_socket (u_long number, int reuse)
147 return svc_socket (number, SOCK_STREAM, IPPROTO_TCP, reuse);
151 * Create and bind a UDP socket based on program number
154 svcudp_socket (u_long number)
156 return svc_socket (number, SOCK_DGRAM, IPPROTO_UDP, FALSE);
161 check (u_long number, u_short port, int protocol, int reuse)
165 struct sockaddr_in addr;
166 socklen_t len = sizeof (struct sockaddr_in);
168 if (protocol == IPPROTO_TCP)
169 socket = svctcp_socket (number, reuse);
171 socket = svcudp_socket (number);
176 result = getsockname (socket, (struct sockaddr *) &addr, &len);
179 if (port != 0 && ntohs (addr.sin_port) != port)
180 printf ("Program: %ld, expect port: %d, got: %d\n",
181 number, port, ntohs (addr.sin_port));
183 printf ("Program: %ld, port: %d\n",
184 number, ntohs (addr.sin_port));
196 result += check (100001, 0, IPPROTO_TCP, 0);
197 result += check (100001, 0, IPPROTO_UDP, 0);
198 result += check (100003, 2049, IPPROTO_TCP, 1);
199 result += check (100003, 2049, IPPROTO_UDP, 1);