Coverage Report

Created: 2023-05-19 06:16

/src/ntp-dev/libntp/socket.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * socket.c - low-level socket operations
3
 */
4
5
#ifdef HAVE_CONFIG_H
6
# include <config.h>
7
#endif
8
9
#include <stdio.h>
10
11
#include "ntp.h"
12
#include "ntp_io.h"
13
#include "ntp_net.h"
14
#include "ntp_debug.h"
15
16
/*
17
 * Windows C runtime ioctl() can't deal properly with sockets, 
18
 * map to ioctlsocket for this source file.
19
 */
20
#ifdef SYS_WINNT
21
#define ioctl(fd, opt, val)  ioctlsocket(fd, opt, (u_long *)(val))
22
#endif
23
24
/*
25
 * on Unix systems the stdio library typically
26
 * makes use of file descriptors in the lower
27
 * integer range.  stdio usually will make use
28
 * of the file descriptors in the range of
29
 * [0..FOPEN_MAX)
30
 * in order to keep this range clean, for socket
31
 * file descriptors we attempt to move them above
32
 * FOPEN_MAX. This is not as easy as it sounds as
33
 * FOPEN_MAX changes from implementation to implementation
34
 * and may exceed to current file decriptor limits.
35
 * We are using following strategy:
36
 * - keep a current socket fd boundary initialized with
37
 *   max(0, min(GETDTABLESIZE() - FD_CHUNK, FOPEN_MAX))
38
 * - attempt to move the descriptor to the boundary or
39
 *   above.
40
 *   - if that fails and boundary > 0 set boundary
41
 *     to min(0, socket_fd_boundary - FD_CHUNK)
42
 *     -> retry
43
 *     if failure and boundary == 0 return old fd
44
 *   - on success close old fd return new fd
45
 *
46
 * effects:
47
 *   - fds will be moved above the socket fd boundary
48
 *     if at all possible.
49
 *   - the socket boundary will be reduced until
50
 *     allocation is possible or 0 is reached - at this
51
 *     point the algrithm will be disabled
52
 */
53
SOCKET
54
move_fd(
55
  SOCKET fd
56
  )
57
5
{
58
5
#if !defined(SYS_WINNT) && defined(F_DUPFD)
59
5
#ifndef FD_CHUNK
60
5
#define FD_CHUNK  10
61
5
#endif
62
#ifndef FOPEN_MAX
63
#define FOPEN_MAX 20
64
#endif
65
/*
66
 * number of fds we would like to have for
67
 * stdio FILE* available.
68
 * we can pick a "low" number as our use of
69
 * FILE* is limited to log files and temporarily
70
 * to data and config files. Except for log files
71
 * we don't keep the other FILE* open beyond the
72
 * scope of the function that opened it.
73
 */
74
5
#ifndef FD_PREFERRED_SOCKBOUNDARY
75
5
#define FD_PREFERRED_SOCKBOUNDARY 48
76
5
#endif
77
78
5
  static SOCKET socket_boundary = -1;
79
5
  SOCKET newfd;
80
81
5
  REQUIRE((int)fd >= 0);
82
83
  /*
84
   * check whether boundary has be set up
85
   * already
86
   */
87
5
  if (socket_boundary == -1) {
88
1
    socket_boundary = max(0, min(GETDTABLESIZE() - FD_CHUNK,
89
1
               min(FOPEN_MAX, FD_PREFERRED_SOCKBOUNDARY)));
90
1
    TRACE(1, ("move_fd: estimated max descriptors: %d, "
91
1
        "initial socket boundary: %d\n",
92
1
        GETDTABLESIZE(), socket_boundary));
93
1
  }
94
95
  /*
96
   * Leave a space for stdio to work in. potentially moving the
97
   * socket_boundary lower until allocation succeeds.
98
   */
99
5
  do {
100
5
    if (fd >= 0 && fd < socket_boundary) {
101
      /* inside reserved range: attempt to move fd */
102
5
      newfd = fcntl(fd, F_DUPFD, socket_boundary);
103
104
5
      if (newfd != -1) {
105
        /* success: drop the old one - return the new one */
106
5
        close(fd);
107
5
        return newfd;
108
5
      }
109
5
    } else {
110
      /* outside reserved range: no work - return the original one */
111
0
      return fd;
112
0
    }
113
0
    socket_boundary = max(0, socket_boundary - FD_CHUNK);
114
0
    TRACE(1, ("move_fd: selecting new socket boundary: %d\n",
115
0
        socket_boundary));
116
0
  } while (socket_boundary > 0);
117
#else
118
  ENSURE((int)fd >= 0);
119
#endif /* !defined(SYS_WINNT) && defined(F_DUPFD) */
120
0
  return fd;
121
5
}
122
123
124
/*
125
 * make_socket_nonblocking() - set up descriptor to be non blocking
126
 */
127
void
128
make_socket_nonblocking(
129
  SOCKET fd
130
  )
131
5
{
132
  /*
133
   * set non-blocking,
134
   */
135
136
#ifdef USE_FIONBIO
137
  /* in vxWorks we use FIONBIO, but the others are defined for old
138
   * systems, so all hell breaks loose if we leave them defined
139
   */
140
#undef O_NONBLOCK
141
#undef FNDELAY
142
#undef O_NDELAY
143
#endif
144
145
5
#if defined(O_NONBLOCK) /* POSIX */
146
5
  if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
147
0
    msyslog(LOG_ERR,
148
0
      "fcntl(O_NONBLOCK) fails on fd #%d: %m", fd);
149
0
    exit(1);
150
0
  }
151
#elif defined(FNDELAY)
152
  if (fcntl(fd, F_SETFL, FNDELAY) < 0) {
153
    msyslog(LOG_ERR, "fcntl(FNDELAY) fails on fd #%d: %m",
154
      fd);
155
    exit(1);
156
  }
157
#elif defined(O_NDELAY) /* generally the same as FNDELAY */
158
  if (fcntl(fd, F_SETFL, O_NDELAY) < 0) {
159
    msyslog(LOG_ERR, "fcntl(O_NDELAY) fails on fd #%d: %m",
160
      fd);
161
    exit(1);
162
  }
163
#elif defined(FIONBIO)
164
  {
165
    int on = 1;
166
167
    if (ioctl(fd, FIONBIO, &on) < 0) {
168
      msyslog(LOG_ERR,
169
        "ioctl(FIONBIO) fails on fd #%d: %m",
170
        fd);
171
      exit(1);
172
    }
173
  }
174
#elif defined(FIOSNBIO)
175
  if (ioctl(fd, FIOSNBIO, &on) < 0) {
176
    msyslog(LOG_ERR,
177
      "ioctl(FIOSNBIO) fails on fd #%d: %m", fd);
178
    exit(1);
179
  }
180
#else
181
# include "Bletch: Need non-blocking I/O!"
182
#endif
183
5
}
184
185
#if 0
186
187
/* The following subroutines should probably be moved here */
188
189
static SOCKET
190
open_socket(
191
  sockaddr_u *  addr,
192
  int   bcast,
193
  int   turn_off_reuse,
194
  endpt *   interf
195
  )
196
void
197
sendpkt(
198
  sockaddr_u *    dest,
199
  struct interface *  ep,
200
  int     ttl,
201
  struct pkt *    pkt,
202
  int     len
203
  )
204
205
static inline int
206
read_refclock_packet(SOCKET fd, struct refclockio *rp, l_fp ts)
207
208
static inline int
209
read_network_packet(
210
  SOCKET      fd,
211
  struct interface *  itf,
212
  l_fp      ts
213
  )
214
215
void
216
kill_asyncio(int startfd)
217
218
#endif /* 0 */