1 /*
2 
3 Copyright (C) 2019 Olaf Till <i7tiol@t-online.de>
4 
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; If not, see <http://www.gnu.org/licenses/>.
17 
18 */
19 
20 #define EXTERNAL_BINARY
21 #include "config.h"
22 
23 #include <fcntl.h>
24 #include <unistd.h>
25 #include <sys/socket.h>
26 #include <netdb.h>
27 #include <poll.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <sys/select.h>
31 #include <sys/stat.h>
32 #include <errno.h>
33 #include <signal.h>
34 #include <math.h>
35 #include <string.h>
36 #include <stdint.h>
37 
gnulib_close(int fd)38 int gnulib_close (int fd)
39 {
40   return close (fd);
41 }
42 
gnulib_socket_pfinet_sockstream(int protocol)43 int gnulib_socket_pfinet_sockstream (int protocol)
44 {
45   return socket (PF_INET, SOCK_STREAM, protocol);
46 }
47 
gnulib_recv(int sockfd,void * buf,size_t len,int flags)48 ssize_t gnulib_recv (int sockfd, void *buf, size_t len, int flags)
49 {
50   return recv (sockfd, buf, len, flags);
51 }
52 
gnulib_send(int sockfd,const void * buf,size_t len,int flags)53 ssize_t gnulib_send (int sockfd, const void *buf, size_t len, int flags)
54 {
55   return send (sockfd, buf, len, flags);
56 }
57 
gnulib_malloc(size_t size)58 void *gnulib_malloc (size_t size)
59 {
60   return malloc (size);
61 }
62 
63 static
get_canonname_hints(void)64 const struct addrinfo *get_canonname_hints (void)
65 {
66   static struct addrinfo hints;
67 
68   if (! hints.ai_socktype) // ai_socktype == 0 means "any type", so it
69                            // should be distinct from SOCK_STREAM
70     {
71       hints.ai_family = AF_INET;
72       hints.ai_socktype = SOCK_STREAM;
73       hints.ai_protocol = 0;
74       hints.ai_flags = AI_CANONNAME;
75     }
76 
77   return &hints;
78 }
79 
80 static
get_set_port_hints(void)81 const struct addrinfo *get_set_port_hints (void)
82 {
83   static struct addrinfo hints;
84 
85   if (! hints.ai_socktype) // ai_socktype == 0 means "any type", so it
86                            // should be distinct from SOCK_STREAM
87     {
88       hints.ai_family = AF_INET;
89       hints.ai_socktype = SOCK_STREAM;
90       hints.ai_protocol = 0;
91       hints.ai_flags = 0;
92     }
93 
94   return &hints;
95 }
96 
97 inline static
get_ai(void)98 struct addrinfo **get_ai (void)
99 {
100   static struct addrinfo *ai;
101 
102   return &ai;
103 }
104 
gnulib_freeaddrinfo(void)105 void gnulib_freeaddrinfo (void)
106 {
107   freeaddrinfo (*get_ai ());
108 }
109 
gnulib_get_canonname(const char * hostname)110 const char *gnulib_get_canonname (const char *hostname)
111 {
112   struct addrinfo **ai_p = get_ai ();
113 
114   if (getaddrinfo (hostname, NULL, get_canonname_hints (), ai_p))
115     return "";
116   else
117     return (*ai_p)->ai_canonname;
118 }
119 
gnulib_set_port(const char * hostname,const char * port)120 int gnulib_set_port (const char *hostname, const char *port)
121 {
122   struct addrinfo **ai_p = get_ai ();
123 
124   if (getaddrinfo (hostname, port, get_set_port_hints (), ai_p))
125     return 1;
126   else
127     return 0;
128 }
129 
gnulib_connect(int sockfd)130 int gnulib_connect (int sockfd)
131 {
132   struct addrinfo **ai_p = get_ai ();
133 
134   return connect (sockfd, (*ai_p)->ai_addr, (*ai_p)->ai_addrlen);
135 }
136 
137 // 'poll'-related stuff
138 
gnulib_alloc_pollfds(int n)139 void *gnulib_alloc_pollfds (int n)
140 {
141   return calloc (n, sizeof (struct pollfd));
142 }
143 
gnulib_poll_in_wrapper(int * in_out,void * pfds_arg,int nfds,int timeout)144 int gnulib_poll_in_wrapper (int *in_out, void *pfds_arg, int nfds, int timeout)
145 {
146   struct pollfd *pfds = pfds_arg;
147 
148   for (int id = 0; id < nfds; id++)
149     {
150       pfds[id].fd = in_out[id];
151 
152       pfds[id].events = POLLIN;
153 
154       pfds[id].revents = 0;
155     }
156 
157   int ret;
158 
159   ret = poll (pfds, nfds, timeout);
160 
161   for (int id = 0; id < nfds; id++)
162     {
163       in_out[id] = pfds[id].revents;
164     }
165 
166   return ret;
167 }
168 
gnulib_pollin_1_noblock(int fd)169 int gnulib_pollin_1_noblock (int fd)
170 {
171   struct pollfd pfd;
172 
173   pfd.fd = fd;
174   pfd.events = POLLIN;
175   pfd.revents = 0;
176 
177   return poll (&pfd, 1, 0);
178 }
179 
gnulib_pollin_2_block(int fd1,int fd2,int * rev1,int * rev2)180 int gnulib_pollin_2_block (int fd1, int fd2, int *rev1, int *rev2)
181 {
182   struct pollfd pfd[2];
183 
184   pfd[0].fd = fd1;
185   pfd[0].events = POLLIN;
186   pfd[0].revents = 0;
187 
188   pfd[1].fd = fd2;
189   pfd[1].events = POLLIN;
190   pfd[1].revents = 0;
191 
192   int ret;
193 
194   ret = poll (pfd, 2, -1);
195 
196   *rev1 = pfd[0].revents;
197 
198   *rev2 = pfd[1].revents;
199 
200   return ret;
201 }
202 
203 // 'select'-related stuff
204 
gnulib_get_fd_setsize(void)205 int gnulib_get_fd_setsize (void)
206 {
207   return FD_SETSIZE;
208 }
209 
210 static
gnulib_select_wrapper(int nfds,void * rfds,void * wfds,void * efds,double dtimeout,char ** err_msg)211 int gnulib_select_wrapper (int nfds, void *rfds, void *wfds, void *efds,
212                            double dtimeout, char **err_msg)
213 {
214   // make a pointer already here for convenience (so it can be set to
215   // NULL)
216   struct timeval timeout;
217   struct timeval *timeout_p = &timeout;
218 
219   if (dtimeout < 0)
220     timeout_p = NULL;
221   else
222     {
223       double ipart, fpart;
224       fpart = modf (dtimeout, &ipart);
225       timeout.tv_sec = lrint (ipart);
226       timeout.tv_usec = lrint (fpart * 1000);
227     }
228 
229   int ret = select (nfds,
230                     (fd_set *) rfds,
231                     (fd_set *) wfds,
232                     (fd_set *) efds,
233                     timeout_p);
234 
235   if (ret == -1)
236     switch (errno)
237       {
238       case EBADF:
239         *err_msg = "EBADF";
240         break;
241       case EINTR:
242         *err_msg = "EINTR";
243         break;
244       case EINVAL:
245         *err_msg = "EINVAL";
246         break;
247       default:
248         *err_msg = "unknown error";
249       }
250 
251   return ret;
252 }
253 
254 inline static
get_rfds(void)255 fd_set *get_rfds (void)
256 {
257   static fd_set rfds;
258 
259   return &rfds;
260 }
261 
262 inline static
get_wfds(void)263 fd_set *get_wfds (void)
264 {
265   static fd_set wfds;
266 
267   return &wfds;
268 }
269 
270 inline static
get_efds(void)271 fd_set *get_efds (void)
272 {
273   static fd_set efds;
274 
275   return &efds;
276 }
277 
gnulib_fd_zero_all(void)278 void gnulib_fd_zero_all (void)
279 {
280   FD_ZERO (get_rfds ());
281   FD_ZERO (get_wfds ());
282   FD_ZERO (get_efds ());
283 }
284 
gnulib_add_to_rfds(int fd)285 void gnulib_add_to_rfds (int fd)
286 {
287   FD_SET (fd, get_rfds ());
288 }
289 
gnulib_add_to_wfds(int fd)290 void gnulib_add_to_wfds (int fd)
291 {
292   FD_SET (fd, get_wfds ());
293 }
294 
gnulib_add_to_efds(int fd)295 void gnulib_add_to_efds (int fd)
296 {
297   FD_SET (fd, get_efds ());
298 }
299 
gnulib_select(int nfds,double dtimeout,char ** err_msg)300 int gnulib_select (int nfds, double dtimeout, char **err_msg)
301 {
302 
303   return gnulib_select_wrapper (nfds, get_rfds (), get_wfds (), get_efds (),
304                                 dtimeout, err_msg);
305 }
306 
gnulib_fd_isset_rfds(int fd)307 int gnulib_fd_isset_rfds (int fd)
308 {
309   return FD_ISSET (fd, get_rfds ());
310 }
311 
gnulib_fd_isset_wfds(int fd)312 int gnulib_fd_isset_wfds (int fd)
313 {
314   return FD_ISSET (fd, get_wfds ());
315 }
316 
gnulib_fd_isset_efds(int fd)317 int gnulib_fd_isset_efds (int fd)
318 {
319   return FD_ISSET (fd, get_efds ());
320 }
321 
322 // end of 'select'-related stuff
323 
gnulib_fstat_reg_exec_nonsuid(int fd)324 int gnulib_fstat_reg_exec_nonsuid (int fd)
325 {
326   struct stat statbuf;
327 
328   return (fstat (fd, &statbuf)
329           || ! S_ISREG (statbuf.st_mode)
330           || ! (statbuf.st_mode & S_IXUSR)
331           || statbuf.st_mode & S_ISUID);
332 }
333 
gnulib_perror(const char * s)334 void gnulib_perror (const char *s)
335 {
336   perror (s);
337 }
338 
339 // 'sigset'-related stuff
340 
gnulib_alloc_sigset(void)341 void *gnulib_alloc_sigset (void)
342 {
343   return gnulib_malloc (sizeof (sigset_t));
344 }
345 
gnulib_get_sigmask(void * dest)346 int gnulib_get_sigmask (void *dest)
347 {
348   return pthread_sigmask (SIG_SETMASK, NULL, (sigset_t *)dest);
349 }
350 
gnulib_set_sigmask(void * src)351 int gnulib_set_sigmask (void *src)
352 {
353   return pthread_sigmask (SIG_SETMASK, (sigset_t *)src, NULL);
354 }
355 
gnulib_sigismember(const void * sig_set,int signum)356 int gnulib_sigismember (const void *sig_set, int signum)
357 {
358   return sigismember ((sigset_t *)sig_set, signum);
359 }
360 
gnulib_set_newset_one_signal(void * sig_set,int signum)361 void gnulib_set_newset_one_signal (void *sig_set, int signum)
362 {
363   sigemptyset ((sigset_t *)sig_set);
364 
365   sigaddset ((sigset_t *)sig_set, signum);
366 }
367 
gnulib_unblock(void * sig_set)368 int gnulib_unblock (void *sig_set)
369 {
370   return pthread_sigmask (SIG_UNBLOCK, (sigset_t *)sig_set, NULL);
371 }
372 
373 // 'sigaction'-related stuff
374 
gnulib_alloc_sigaction(void)375 void *gnulib_alloc_sigaction (void)
376 {
377   return gnulib_malloc (sizeof (struct sigaction));
378 }
379 
gnulib_getsigaction(int signum,void * dest)380 int gnulib_getsigaction (int signum, void *dest)
381 {
382   return sigaction (signum, NULL, (struct sigaction *)dest);
383 }
384 
gnulib_setsigaction(int signum,void * src)385 int gnulib_setsigaction (int signum, void *src)
386 {
387   return sigaction (signum, (struct sigaction *)src, NULL);
388 }
389 
gnulib_copy_sigaction(void * dest,const void * src)390 void gnulib_copy_sigaction (void *dest, const void *src)
391 {
392   memcpy (dest, src, sizeof (struct sigaction));
393 }
394 
gnulib_remove_sa_restart(void * sig_action)395 void gnulib_remove_sa_restart (void *sig_action)
396 {
397   ((struct sigaction *)sig_action)->sa_flags &= ~ SA_RESTART;
398 }
399 
gnulib_install_sighandler(int signum,void (* handler)(int))400 int gnulib_install_sighandler (int signum, void (*handler) (int))
401 {
402   struct sigaction sa;
403 
404   sa.sa_handler = handler;
405 
406   sa.sa_flags = 0;
407 
408   if (sigemptyset (&sa.sa_mask)
409       || sigaction (signum, &sa, NULL))
410     return -1;
411   else
412     return 0;
413 }
414 
415 // end of 'sigaction'-related stuff
416 
417 // these are probably defined at Windows as macros in winsock.h or
418 // winsock2.h
gnulib_htonl(uint32_t hostlong)419 uint32_t gnulib_htonl (uint32_t hostlong)
420 {
421   return htonl (hostlong);
422 }
gnulib_ntohl(uint32_t netlong)423 uint32_t gnulib_ntohl (uint32_t netlong)
424 {
425   return ntohl (netlong);
426 }
427 
gnulib_mkdir_mode_0700(const char * pathname)428 int gnulib_mkdir_mode_0700 (const char *pathname)
429 {
430   mkdir (pathname, 0700);
431 }
432 
gnulib_getpass(const char * prompt)433 char* gnulib_getpass (const char *prompt)
434 {
435   return getpass (prompt);
436 }
437