bsd.c
Go to the documentation of this file.
1 /* ========================================================================== */
2 /*! \file
3  * \brief This is a wrapper to map BSD functionality of OS into POSIX subsystem
4  *
5  * Copyright (c) 2012-2021 by the developers. See the LICENSE file for details.
6  *
7  * BSD functions not defined in POSIX.1-1990 or XSI extension should be called
8  * from here.
9  *
10  * Why do it this way:
11  * The POSIX subsystem defines '_POSIX_C_SOURCE' because otherwise some systems
12  * by default expose functions that are not POSIX conformant (for preserving
13  * compatibility to historical versions). Indeed in many cases they have
14  * conformant versions too, and with the definition they get exposed instead of
15  * the default ones so we can use them. That is in general the desired
16  * behaviour. But as a side effect we can't access all non-POSIX functions any
17  * more. We have asked for POSIX and we got POSIX. This wrapper pulls in the
18  * historical BSD stuff that can't be avoided. And because using it this way is
19  * a pain in the ass, the programmer is forced to use it only if POSIX offers no
20  * other option.
21  */
22 
23 
24 /* ========================================================================== */
25 /* Configuration (must be 1st) */
26 
27 #include "config.h"
28 
29 
30 /* ========================================================================== */
31 /* The socket API is included in POSIX.1g, POSIX.1-2001 and XSI extension */
32 
33 #if CFG_USE_POSIX_API < 200112 && !CFG_USE_XSI && !CFG_USE_IP6
34 
35 
36 /* ========================================================================== */
37 /* BSD declarations (must be 2nd) */
38 
39 #define BSD_FOR_POSIX
40 #include "bsd.h"
41 
42 
43 /* ========================================================================== */
44 /* Include headers */
45 
46 #include <limits.h>
47 
48 #include "main.h"
49 
50 
51 /* ========================================================================== */
52 /* Constants */
53 
54 /* Message prefix for POSIX module */
55 #define MAIN_ERR_PREFIX "POSIX: "
56 
57 
58 /* ========================================================================== */
59 /* ARPA internet stuff */
60 
61 #include <arpa/inet.h>
62 #include <netdb.h>
63 #include <stdio.h>
64 
65 #if CFG_HDR_INTTYPES_H
66 uint16_t posix_htons(uint16_t host16)
67 #else
68 unsigned short int posix_htons(unsigned short int host16)
69 #endif /* CFG_HDR_INTTYPES_H */
70 {
71  return(htons(host16));
72 }
73 
74 #if CFG_HDR_INTTYPES_H
75 uint32_t posix_htonl(uint32_t host32)
76 #else
77 unsigned long int posix_htonl(unsigned long int host32)
78 #endif /* CFG_HDR_INTTYPES_H */
79 {
80  return(htonl(host32));
81 }
82 
83 #if CFG_HDR_INTTYPES_H
84 uint16_t posix_ntohs(uint16_t net16)
85 #else
86 unsigned short int posix_ntohs(unsigned short int net16)
87 #endif /* CFG_HDR_INTTYPES_H */
88 {
89  return(ntohs(net16));
90 }
91 
92 #if CFG_HDR_INTTYPES_H
93 uint32_t posix_ntohl(uint32_t net32)
94 #else
95 unsigned long int posix_ntohl(unsigned long int net32)
96 #endif /* CFG_HDR_INTTYPES_H */
97 {
98  return(ntohl(net32));
99 }
100 
101 
102 /* This implementation is incomplete, but sufficient for 'posix_inet_pton()' */
103 posix_in_addr_t posix_inet_addr(const char* cp)
104 {
105  posix_in_addr_t res = (posix_in_addr_t) -1;
106  unsigned long int a, b, c, d;
107  int rv;
108 
109  if(NULL != cp)
110  {
111  rv = sscanf(cp, "%lu.%lu.%lu.%lu", &a, &b, &c, &d);
112  if(4 == rv)
113  {
114  if(256L > a && 256L > b && 256L > c && 256L > d)
115  {
116  res = (posix_in_addr_t) posix_htonl(a << 24 | b << 16 | c << 8 | d);
117  }
118  }
119  }
120 
121  return(res);
122 }
123 
124 
125 struct_posix_servent* posix_getservbyname(const char* name,
126  const char* proto)
127 {
128  static struct_posix_servent se;
129  struct servent* tmp;
130 
131  tmp = getservbyname(name, proto);
132  if(NULL == tmp) { return(NULL); }
133  else
134  {
135  se.s_name = tmp->s_name;
136  se.s_aliases = tmp->s_aliases;
137  se.s_port = tmp->s_port;
138  se.s_proto = tmp->s_proto;
139  }
140 
141  return(&se);
142 }
143 
144 
145 struct_posix_hostent* posix_gethostbyname(const char* name)
146 {
147  static struct_posix_hostent he;
148  struct hostent* tmp;
149 
150  tmp = gethostbyname(name);
151  if(NULL == tmp) { return(NULL); }
152  else
153  {
154  he.h_name = tmp->h_name;
155  he.h_aliases = tmp->h_aliases;
156  he.h_addrtype = POSIX_AF_INET;
157  he.h_length = tmp->h_length;
158  he.h_addr_list = tmp->h_addr_list;
159  }
160 
161  return(&he);
162 }
163 
164 
165 /* ========================================================================== */
166 /* Create socket */
167 
168 #include <sys/socket.h>
169 
170 int posix_socket(int domain, int type, int protocol)
171 {
172  switch(domain)
173  {
174  case POSIX_AF_INET:
175  {
176  domain = AF_INET;
177  break;
178  }
179  default:
180  {
181  errno = EAFNOSUPPORT;
182  return(-1);
183  }
184  }
185 
186  switch(type)
187  {
188  case POSIX_SOCK_STREAM:
189  {
190  type = SOCK_STREAM;
191  break;
192  }
193  default:
194  {
195  errno = EPROTOTYPE;
196  return(-1);
197  }
198  }
199 
200  return(socket(domain, type, protocol));
201 }
202 
203 
204 /* ========================================================================== */
205 /* Connect socket */
206 
207 #include <sys/socket.h>
208 
209 int posix_connect(int sd, const struct_posix_sockaddr* address,
210  posix_socklen_t address_len)
211 {
212  struct sockaddr_in sai;
213  struct sockaddr_in* sap = &sai;
214 
215  switch(address->sa_family)
216  {
217  case POSIX_AF_INET:
218  {
219  sap->sin_family = AF_INET;
220  memcpy(&sap->sin_port,
221  &((struct_posix_sockaddr_in*) address)->sin_port, 2);
222  memcpy(&sap->sin_addr,
223  &((struct_posix_sockaddr_in*) address)->sin_addr, 4);
224  break;
225  }
226  default:
227  {
228  errno = EAFNOSUPPORT;
229  return(-1);
230  }
231  }
232 
233  return(connect(sd, (struct sockaddr*) sap,
234  (socklen_t) sizeof(struct sockaddr)));
235 }
236 
237 
238 /* ========================================================================== */
239 /* Get socket options */
240 
241 #include <sys/socket.h>
242 
243 int posix_getsockopt(int sd, int level, int optname,
244  void* optval, posix_socklen_t* optlen)
245 {
246  int res;
247 #if defined(_AIX) || defined(__hpux)
248  size_t bsd_optlen = (size_t) *optlen;
249 #else /* defined(_AIX) || defined(__hpux) */
250  /* This is the genuine BSD socket API */
251  int bsd_optlen = (int) *optlen;
252 #endif /* defined(_AIX) || defined(__hpux) */
253 
254  /* Check buffer size */
255  if((posix_socklen_t) INT_MAX < *optlen || 0 > bsd_optlen)
256  {
257  PRINT_ERROR("Invalid parameter value for optlen in getsockopt()");
258  return(-1);
259  }
260 
261  switch(level)
262  {
263  case POSIX_SOL_SOCKET:
264  {
265  level = SOL_SOCKET;
266  break;
267  }
268  default:
269  {
270  errno = EINVAL;
271  return(-1);
272  }
273  }
274 
275  switch(optname)
276  {
277  case POSIX_SO_ERROR:
278  {
279  optname = SO_ERROR;
280  break;
281  }
282  default:
283  {
284  errno = ENOPROTOOPT;
285  return(-1);
286  }
287  }
288 
289  /*
290  * The original BSD API used a pointer of type 'int' for parameter 'optlen'
291  * The initial value must be positive and the system never return a larger
292  * value. This limits the required range to 0..INT_MAX as checked above.
293  *
294  * It looks like some implementations (even more recent real BSDs) today
295  * intentionally typedef 'socklen_t' to 'unsigned int' because this doesn't
296  * break the BSD ABI and is backward compatible for the required value range
297  * (at least on all systems that use 2's complement arithmetic).
298  * Therefore check again carefully your warning/error messages
299  * => If you get a warning about wrong signedness here, ignore it
300  * => If you get a warning about incompatible pointer type:
301  * Most likely your system does support the POSIX 'socklen_t' type and
302  * provides no BSD compatibility. Try to enable forced usage of XSI
303  * extension in the configuration file. If it doesn't work this way,
304  * send a bug report and an OS specific workaround must be implemented.
305  */
306  res = getsockopt(sd, level, optname, optval, &bsd_optlen);
307  if(!res) { *optlen = (posix_socklen_t) bsd_optlen; }
308 
309  return(res);
310 }
311 
312 
313 /* ========================================================================== */
314 /* Set socket options */
315 
316 #include <sys/socket.h>
317 
318 int posix_setsockopt(int sd, int level, int optname,
319  const void* optval, posix_socklen_t optlen)
320 {
321  switch(level)
322  {
323  case POSIX_SOL_SOCKET:
324  {
325  level = SOL_SOCKET;
326  break;
327  }
328  default:
329  {
330  errno = EINVAL;
331  return(-1);
332  }
333  }
334 
335  errno = ENOPROTOOPT;
336  return(-1);
337 }
338 
339 
340 /* ========================================================================== */
341 /* Synchronous I/O multiplexing */
342 
343 #if CFG_HDR_SYS_SELECT_H
344 # include <sys/select.h>
345 #endif /* CFG_HDR_SYS_SELECT_H */
346 #include <sys/time.h>
347 #include <limits.h>
348 
349 #include <stdio.h>
350 #include <stdlib.h>
351 int posix_poll(struct_posix_pollfd fds[], posix_nfds_t nfds, int timeout)
352 {
353  int res;
354  posix_nfds_t i;
355  int fdmax = 0;
356  fd_set readfds;
357  fd_set writefds;
358  fd_set errorfds;
359  struct timeval to;
360  struct timeval* top = &to;
361 
362  /* Prepare FD structures */
363  FD_ZERO(&readfds);
364  FD_ZERO(&writefds);
365  FD_ZERO(&errorfds);
366  for(i = 0; i < nfds; ++i)
367  {
368  if(fdmax < fds[i].fd) { fdmax = fds[i].fd; }
369  fds[i].revents = 0;
370  if (0 < fds[i].fd)
371  {
372  /* Set bit for read */
373  if (POSIX_POLLIN & fds[i].events)
374  {
375  FD_SET(fds[i].fd, &readfds);
376  }
377  /* Set bit for write */
378  if (POSIX_POLLOUT & fds[i].events)
379  {
380  FD_SET(fds[i].fd, &writefds);
381  }
382  /* Set bit for write */
383  FD_SET(fds[i].fd, &errorfds);
384  }
385  }
386 
387  /* Convert timeout */
388  if(0 < timeout)
389  {
390  to.tv_sec = (timeout / 1000);
391  to.tv_usec = (long int) (timeout % 1000) * (long int) 1000;
392  }
393  else
394  {
395  to.tv_sec = 0;
396  to.tv_usec = 0;
397  }
398  if(0 > timeout) { top = NULL; }
399 
400  /* Check fd range */
401  if (INT_MAX == fdmax)
402  {
403  PRINT_ERROR("Number of fd too large in poll()");
404  errno = EINVAL;
405  res = -1;
406  }
407  else
408  {
409  /* Use 'select()' to emulate 'poll()' */
410  res = select(++fdmax, &readfds, &writefds, NULL, top);
411  }
412 
413  /* Prepare results */
414  if (-1 == res)
415  {
416  /* Error */
417  switch(errno)
418  {
419  case EINTR:
420  {
421  /* Interrupted by signal is valid for 'poll()' too */
422  break;
423  }
424  default:
425  {
426  /* Map other errors to EINVAL */
427  errno = EINVAL;
428  break;
429  }
430  }
431  }
432  if (0 < res)
433  {
434  for(i = 0; i < nfds; ++i)
435  {
436  if (FD_ISSET(fds[i].fd, &readfds))
437  {
438  fds[i].revents |= POSIX_POLLIN;
439  }
440  if (FD_ISSET(fds[i].fd, &writefds))
441  {
442  fds[i].revents |= POSIX_POLLOUT;
443  }
444  if (FD_ISSET(fds[i].fd, &errorfds))
445  {
446  /* Set all error bits because we do not know which one it is */
447  fds[i].revents |= POSIX_POLLERR | POSIX_POLLHUP | POSIX_POLLNVAL;
448  }
449  }
450  }
451 
452  return(res);
453 }
454 
455 
456 /* ========================================================================== */
457 /* Socket I/O */
458 
459 #include <sys/socket.h>
460 #include <sys/types.h>
461 
462 ssize_t posix_send(int sd, const void* buf, size_t len, int flags)
463 {
464  return(send(sd, buf, len, flags));
465 }
466 
467 ssize_t posix_recv(int sd, void* buf, size_t len, int flags)
468 {
469  return(recv(sd, buf, len, flags));
470 }
471 
472 
473 #else /* CFG_USE_POSIX_API < 200112 && !CFG_USE_XSI && !CFG_USE_IP6 */
474 
475 
476 /* Dummy variable to avoid warnings like "empty translation unit" */
477 extern int posix_bsd_dummy;
478 int posix_bsd_dummy = 0;
479 
480 
481 #endif /* CFG_USE_POSIX_API < 200112 && !CFG_USE_XSI && !CFG_USE_IP6 */
482 
483 
484 /* EOF */
PRINT_ERROR
#define PRINT_ERROR(s)
Prepend module prefix and print error message.
Definition: main.h:19

Generated at 2024-04-27 using  doxygen