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-2024 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 api_posix_htons(uint16_t host16)
67 #else
68 unsigned short int api_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 api_posix_htonl(uint32_t host32)
76 #else
77 unsigned long int api_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 api_posix_ntohs(uint16_t net16)
85 #else
86 unsigned short int api_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 api_posix_ntohl(uint32_t net32)
94 #else
95 unsigned long int api_posix_ntohl(unsigned long int net32)
96 #endif /* CFG_HDR_INTTYPES_H */
97 {
98  return(ntohl(net32));
99 }
100 
101 
102 /* Implementation is incomplete, but sufficient for 'api_posix_inet_pton()' */
103 api_posix_in_addr_t api_posix_inet_addr(const char* cp)
104 {
105  api_posix_in_addr_t res = (api_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 = (api_posix_in_addr_t)
117  api_posix_htonl(a << 24 | b << 16 | c << 8 | d);
118  }
119  }
120  }
121 
122  return(res);
123 }
124 
125 
126 api_posix_struct_servent* api_posix_getservbyname(const char* name,
127  const char* proto)
128 {
129  static api_posix_struct_servent se;
130  struct servent* tmp;
131 
132  tmp = getservbyname(name, proto);
133  if(NULL == tmp) { return(NULL); }
134  else
135  {
136  se.s_name = tmp->s_name;
137  se.s_aliases = tmp->s_aliases;
138  se.s_port = tmp->s_port;
139  se.s_proto = tmp->s_proto;
140  }
141 
142  return(&se);
143 }
144 
145 
146 api_posix_struct_hostent* api_posix_gethostbyname(const char* name)
147 {
148  static api_posix_struct_hostent he;
149  struct hostent* tmp;
150 
151  tmp = gethostbyname(name);
152  if(NULL == tmp) { return(NULL); }
153  else
154  {
155  he.h_name = tmp->h_name;
156  he.h_aliases = tmp->h_aliases;
157  he.h_addrtype = API_POSIX_AF_INET;
158  he.h_length = tmp->h_length;
159  he.h_addr_list = tmp->h_addr_list;
160  }
161 
162  return(&he);
163 }
164 
165 
166 /* ========================================================================== */
167 /* Create socket */
168 
169 #include <sys/socket.h>
170 
171 int api_posix_socket(int domain, int type, int protocol)
172 {
173  switch(domain)
174  {
175  case API_POSIX_AF_INET:
176  {
177  domain = AF_INET;
178  break;
179  }
180  default:
181  {
182  errno = EAFNOSUPPORT;
183  return(-1);
184  }
185  }
186 
187  switch(type)
188  {
189  case API_POSIX_SOCK_STREAM:
190  {
191  type = SOCK_STREAM;
192  break;
193  }
194  default:
195  {
196  errno = EPROTOTYPE;
197  return(-1);
198  }
199  }
200 
201  return(socket(domain, type, protocol));
202 }
203 
204 
205 /* ========================================================================== */
206 /* Connect socket */
207 
208 #include <sys/socket.h>
209 
210 int api_posix_connect(int sd, const api_posix_struct_sockaddr* address,
211  api_posix_socklen_t address_len)
212 {
213  struct sockaddr_in sai;
214  struct sockaddr_in* sap = &sai;
215 
216  switch(address->sa_family)
217  {
218  case API_POSIX_AF_INET:
219  {
220  sap->sin_family = AF_INET;
221  memcpy(&sap->sin_port,
222  &((api_posix_struct_sockaddr_in*) address)->sin_port, 2);
223  memcpy(&sap->sin_addr,
224  &((api_posix_struct_sockaddr_in*) address)->sin_addr, 4);
225  break;
226  }
227  default:
228  {
229  errno = EAFNOSUPPORT;
230  return(-1);
231  }
232  }
233 
234  return(connect(sd, (struct sockaddr*) sap,
235  (socklen_t) sizeof(struct sockaddr)));
236 }
237 
238 
239 /* ========================================================================== */
240 /* Get socket options */
241 
242 #include <sys/socket.h>
243 
244 int api_posix_getsockopt(int sd, int level, int optname,
245  void* optval, api_posix_socklen_t* optlen)
246 {
247  int res;
248 #if defined(_AIX) || defined(__hpux)
249  size_t bsd_optlen = (size_t) *optlen;
250 #else /* defined(_AIX) || defined(__hpux) */
251  /* This is the genuine BSD socket API */
252  int bsd_optlen = (int) *optlen;
253 #endif /* defined(_AIX) || defined(__hpux) */
254 
255  /* Check buffer size */
256  if((api_posix_socklen_t) INT_MAX < *optlen || 0 > bsd_optlen)
257  {
258  PRINT_ERROR("Invalid parameter value for optlen in getsockopt()");
259  return(-1);
260  }
261 
262  switch(level)
263  {
264  case API_POSIX_SOL_SOCKET:
265  {
266  level = SOL_SOCKET;
267  break;
268  }
269  default:
270  {
271  errno = EINVAL;
272  return(-1);
273  }
274  }
275 
276  switch(optname)
277  {
278  case API_POSIX_SO_ERROR:
279  {
280  optname = SO_ERROR;
281  break;
282  }
283  default:
284  {
285  errno = ENOPROTOOPT;
286  return(-1);
287  }
288  }
289 
290  /*
291  * The original BSD API used a pointer of type 'int' for parameter 'optlen'
292  * The initial value must be positive and the system never return a larger
293  * value. This limits the required range to 0..INT_MAX as checked above.
294  *
295  * It looks like some implementations (even more recent real BSDs) today
296  * intentionally typedef 'socklen_t' to 'unsigned int' because this doesn't
297  * break the BSD ABI and is backward compatible for the required value range
298  * (at least on all systems that use 2's complement arithmetic).
299  * Therefore check again carefully your warning/error messages
300  * => If you get a warning about wrong signedness here, ignore it
301  * => If you get a warning about incompatible pointer type:
302  * Most likely your system does support the POSIX 'socklen_t' type and
303  * provides no BSD compatibility. Try to enable forced usage of XSI
304  * extension in the configuration file. If it doesn't work this way,
305  * send a bug report and an OS specific workaround must be implemented.
306  */
307  res = getsockopt(sd, level, optname, optval, &bsd_optlen);
308  if(!res) { *optlen = (api_posix_socklen_t) bsd_optlen; }
309 
310  return(res);
311 }
312 
313 
314 /* ========================================================================== */
315 /* Set socket options */
316 
317 #include <sys/socket.h>
318 
319 int api_posix_setsockopt(int sd, int level, int optname,
320  const void* optval, api_posix_socklen_t optlen)
321 {
322  switch(level)
323  {
324  case API_POSIX_SOL_SOCKET:
325  {
326  level = SOL_SOCKET;
327  break;
328  }
329  default:
330  {
331  errno = EINVAL;
332  return(-1);
333  }
334  }
335 
336  errno = ENOPROTOOPT;
337  return(-1);
338 }
339 
340 
341 /* ========================================================================== */
342 /* Synchronous I/O multiplexing */
343 
344 #if CFG_HDR_SYS_SELECT_H
345 # include <sys/select.h>
346 #endif /* CFG_HDR_SYS_SELECT_H */
347 #include <sys/time.h>
348 #include <limits.h>
349 
350 #include <stdio.h>
351 #include <stdlib.h>
352 int api_posix_poll(api_posix_struct_pollfd fds[], api_posix_nfds_t nfds,
353  int timeout)
354 {
355  int res;
356  api_posix_nfds_t i;
357  int fdmax = 0;
358  fd_set readfds;
359  fd_set writefds;
360  fd_set errorfds;
361  struct timeval to;
362  struct timeval* top = &to;
363 
364  /* Prepare FD structures */
365  FD_ZERO(&readfds);
366  FD_ZERO(&writefds);
367  FD_ZERO(&errorfds);
368  for(i = 0; i < nfds; ++i)
369  {
370  if(fdmax < fds[i].fd) { fdmax = fds[i].fd; }
371  fds[i].revents = 0;
372  if (0 < fds[i].fd)
373  {
374  /* Set bit for read */
375  if (API_POSIX_POLLIN & fds[i].events)
376  {
377  FD_SET(fds[i].fd, &readfds);
378  }
379  /* Set bit for write */
380  if (API_POSIX_POLLOUT & fds[i].events)
381  {
382  FD_SET(fds[i].fd, &writefds);
383  }
384  /* Set bit for write */
385  FD_SET(fds[i].fd, &errorfds);
386  }
387  }
388 
389  /* Convert timeout */
390  if(0 < timeout)
391  {
392  to.tv_sec = (timeout / 1000);
393  to.tv_usec = (long int) (timeout % 1000) * (long int) 1000;
394  }
395  else
396  {
397  to.tv_sec = 0;
398  to.tv_usec = 0;
399  }
400  if(0 > timeout) { top = NULL; }
401 
402  /* Check fd range */
403  if (INT_MAX == fdmax)
404  {
405  PRINT_ERROR("Number of fd too large in poll()");
406  errno = EINVAL;
407  res = -1;
408  }
409  else
410  {
411  /* Use 'select()' to emulate 'poll()' */
412  res = select(++fdmax, &readfds, &writefds, NULL, top);
413  }
414 
415  /* Prepare results */
416  if (-1 == res)
417  {
418  /* Error */
419  switch(errno)
420  {
421  case EINTR:
422  {
423  /* Interrupted by signal is valid for 'poll()' too */
424  break;
425  }
426  default:
427  {
428  /* Map other errors to EINVAL */
429  errno = EINVAL;
430  break;
431  }
432  }
433  }
434  if (0 < res)
435  {
436  for(i = 0; i < nfds; ++i)
437  {
438  if (FD_ISSET(fds[i].fd, &readfds))
439  {
440  fds[i].revents |= API_POSIX_POLLIN;
441  }
442  if (FD_ISSET(fds[i].fd, &writefds))
443  {
444  fds[i].revents |= API_POSIX_POLLOUT;
445  }
446  if (FD_ISSET(fds[i].fd, &errorfds))
447  {
448  /* Set all error bits because we do not know which one it is */
449  fds[i].revents |= API_POSIX_POLLERR | API_POSIX_POLLHUP
450  | API_POSIX_POLLNVAL;
451  }
452  }
453  }
454 
455  return(res);
456 }
457 
458 
459 /* ========================================================================== */
460 /* Socket I/O */
461 
462 #include <sys/socket.h>
463 #include <sys/types.h>
464 
465 ssize_t api_posix_send(int sd, const void* buf, size_t len, int flags)
466 {
467  return(send(sd, buf, len, flags));
468 }
469 
470 ssize_t api_posix_recv(int sd, void* buf, size_t len, int flags)
471 {
472  return(recv(sd, buf, len, flags));
473 }
474 
475 
476 #else /* CFG_USE_POSIX_API < 200112 && !CFG_USE_XSI && !CFG_USE_IP6 */
477 
478 
479 /* Dummy variable to avoid warnings like "empty translation unit" */
480 extern int api_posix_bsd_dummy;
481 int api_posix_bsd_dummy = 0;
482 
483 
484 #endif /* CFG_USE_POSIX_API < 200112 && !CFG_USE_XSI && !CFG_USE_IP6 */
485 
486 
487 /* EOF */
PRINT_ERROR
#define PRINT_ERROR(s)
Prepend module prefix and print error message.
Definition: main.h:19

Generated at 2026-01-27 using  doxygen