]>
git.ipfire.org Git - thirdparty/bash.git/blob - examples/loadables/accept.c
1 /* accept - listen for and accept a remote network connection on a given port */
4 Copyright (C) 2020 Free Software Foundation, Inc.
6 This file is part of GNU Bash.
7 Bash is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 Bash is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with Bash. If not, see <http://www.gnu.org/licenses/>.
23 #if defined (HAVE_UNISTD_H)
30 #include "bashtypes.h"
36 #include <sys/socket.h>
37 #include <arpa/inet.h>
38 #include <netinet/in.h>
40 #include "loadables.h"
42 static int accept_bind_variable (char *, int);
51 char *tmoutarg
, *fdvar
, *rhostvar
, *rhost
, *bindaddr
;
53 int servsock
, clisock
;
54 struct sockaddr_in server
, client
;
56 struct timeval timeval
;
57 struct linger linger
= { 0, 0 };
59 rhostvar
= tmoutarg
= fdvar
= rhost
= bindaddr
= (char *)NULL
;
61 reset_internal_getopt ();
62 while ((opt
= internal_getopt (list
, "b:r:t:v:")) != -1)
67 bindaddr
= list_optarg
;
70 rhostvar
= list_optarg
;
73 tmoutarg
= list_optarg
;
87 /* Validate input and variables */
91 opt
= uconvert (tmoutarg
, &ival
, &uval
, (char **)0);
92 if (opt
== 0 || ival
< 0 || uval
< 0)
94 builtin_error ("%s: invalid timeout specification", tmoutarg
);
95 return (EXECUTION_FAILURE
);
97 timeval
.tv_sec
= ival
;
98 timeval
.tv_usec
= uval
;
99 /* XXX - should we warn if ival == uval == 0 ? */
108 if (legal_number (list
->word
->word
, &iport
) == 0 || iport
< 0 || iport
> TYPE_MAXIMUM (unsigned short))
110 builtin_error ("%s: invalid port number", list
->word
->word
);
111 return (EXECUTION_FAILURE
);
113 uport
= (unsigned short)iport
;
118 unbind_variable (fdvar
);
120 unbind_variable (rhostvar
);
122 if ((servsock
= socket (AF_INET
, SOCK_STREAM
, IPPROTO_IP
)) < 0)
124 builtin_error ("cannot create socket: %s", strerror (errno
));
125 return (EXECUTION_FAILURE
);
128 memset ((char *)&server
, 0, sizeof (server
));
129 server
.sin_family
= AF_INET
;
130 server
.sin_port
= htons(uport
);
131 server
.sin_addr
.s_addr
= bindaddr
? inet_addr (bindaddr
) : htonl(INADDR_ANY
);
133 if (server
.sin_addr
.s_addr
== INADDR_NONE
)
135 builtin_error ("invalid address: %s", strerror (errno
));
136 return (EXECUTION_FAILURE
);
140 setsockopt (servsock
, SOL_SOCKET
, SO_REUSEADDR
, (void *)&opt
, sizeof (opt
));
141 setsockopt (servsock
, SOL_SOCKET
, SO_LINGER
, (void *)&linger
, sizeof (linger
));
143 if (bind (servsock
, (struct sockaddr
*)&server
, sizeof (server
)) < 0)
145 builtin_error ("socket bind failure: %s", strerror (errno
));
147 return (EXECUTION_FAILURE
);
150 if (listen (servsock
, 1) < 0)
152 builtin_error ("listen failure: %s", strerror (errno
));
154 return (EXECUTION_FAILURE
);
162 FD_SET(servsock
, &iofds
);
164 opt
= select (servsock
+1, &iofds
, 0, 0, &timeval
);
166 builtin_error ("select failure: %s", strerror (errno
));
170 return (EXECUTION_FAILURE
);
174 clientlen
= sizeof (client
);
175 if ((clisock
= accept (servsock
, (struct sockaddr
*)&client
, &clientlen
)) < 0)
177 builtin_error ("client accept failure: %s", strerror (errno
));
179 return (EXECUTION_FAILURE
);
184 accept_bind_variable (fdvar
, clisock
);
187 rhost
= inet_ntoa (client
.sin_addr
);
188 v
= builtin_bind_variable (rhostvar
, rhost
, 0);
189 if (v
== 0 || readonly_p (v
) || noassign_p (v
))
190 builtin_error ("%s: cannot set variable", rhostvar
);
193 return (EXECUTION_SUCCESS
);
197 accept_bind_variable (varname
, intval
)
202 char ibuf
[INT_STRLEN_BOUND (int) + 1], *p
;
204 p
= fmtulong (intval
, 10, ibuf
, sizeof (ibuf
), 0);
205 v
= builtin_bind_variable (varname
, p
, 0); /* XXX */
206 if (v
== 0 || readonly_p (v
) || noassign_p (v
))
207 builtin_error ("%s: cannot set variable", varname
);
211 char *accept_doc
[] = {
212 "Accept a network connection on a specified port.",
214 "This builtin allows a bash script to act as a TCP/IP server.",
216 "Options, if supplied, have the following meanings:",
217 " -b address use ADDRESS as the IP address to listen on; the",
218 " default is INADDR_ANY",
219 " -t timeout wait TIMEOUT seconds for a connection. TIMEOUT may",
220 " be a decimal number including a fractional portion",
221 " -v varname store the numeric file descriptor of the connected",
222 " socket into VARNAME. The default VARNAME is ACCEPT_FD",
223 " -r rhost store the IP address of the remote host into the shell",
224 " variable RHOST, in dotted-decimal notation",
226 "If successful, the shell variable ACCEPT_FD, or the variable named by the",
227 "-v option, will be set to the fd of the connected socket, suitable for",
228 "use as 'read -u$ACCEPT_FD'. RHOST, if supplied, will hold the IP address",
229 "of the remote client. The return status is 0.",
231 "On failure, the return status is 1 and ACCEPT_FD (or VARNAME) and RHOST,",
232 "if supplied, will be unset.",
234 "The server socket fd will be closed before accept returns.",
238 struct builtin accept_struct
= {
239 "accept", /* builtin name */
240 accept_builtin
, /* function implementing the builtin */
241 BUILTIN_ENABLED
, /* initial flags for builtin */
242 accept_doc
, /* array of long documentation strings. */
243 "accept [-b address] [-t timeout] [-v varname] [-r addrvar ] port", /* usage synopsis; becomes short_doc */
244 0 /* reserved for internal use */