Quake II RTX doxygen  1.0 dev
unix.h
Go to the documentation of this file.
1 /*
2 Copyright (C) 2012 Andrey Nazarov
3 
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13 
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18 
19 //
20 // net_unix.h -- BSD sockets wrapper
21 //
22 
23 static const char *os_error_string(int err)
24 {
25  return strerror(err);
26 }
27 
28 // returns true if failed socket operation should be retried.
29 static qboolean process_error_queue(qsocket_t sock, const netadr_t *to)
30 {
31 #ifdef IP_RECVERR
32  byte buffer[1024];
33  struct sockaddr_storage from_addr;
34  struct msghdr msg;
35  struct cmsghdr *cmsg;
36  struct sock_extended_err *ee;
37  netadr_t from;
38  int tries;
39  qboolean found = qfalse;
40 
41  for (tries = 0; tries < MAX_ERROR_RETRIES; tries++) {
42  memset(&from_addr, 0, sizeof(from_addr));
43 
44  memset(&msg, 0, sizeof(msg));
45  msg.msg_name = &from_addr;
46  msg.msg_namelen = sizeof(from_addr);
47  msg.msg_control = buffer;
48  msg.msg_controllen = sizeof(buffer);
49 
50  if (recvmsg(sock, &msg, MSG_ERRQUEUE) == -1) {
51  if (errno != EWOULDBLOCK)
52  Com_DPrintf("%s: %s\n", __func__, strerror(errno));
53  break;
54  }
55 
56  if (!(msg.msg_flags & MSG_ERRQUEUE)) {
57  Com_DPrintf("%s: no extended error received\n", __func__);
58  break;
59  }
60 
61  // find an ICMP error message
62  for (cmsg = CMSG_FIRSTHDR(&msg);
63  cmsg != NULL;
64  cmsg = CMSG_NXTHDR(&msg, cmsg)) {
65  if (cmsg->cmsg_level != IPPROTO_IP &&
66  cmsg->cmsg_level != IPPROTO_IPV6) {
67  continue;
68  }
69  if (cmsg->cmsg_type != IP_RECVERR &&
70  cmsg->cmsg_type != IPV6_RECVERR) {
71  continue;
72  }
73  ee = (struct sock_extended_err *)CMSG_DATA(cmsg);
74  if (ee->ee_origin == SO_EE_ORIGIN_ICMP ||
75  ee->ee_origin == SO_EE_ORIGIN_ICMP6) {
76  break;
77  }
78  }
79 
80  if (!cmsg) {
81  Com_DPrintf("%s: no ICMP error found\n", __func__);
82  break;
83  }
84 
85  NET_SockadrToNetadr(&from_addr, &from);
86 
87  // check for offender address being current packet destination
88  if (to != NULL && NET_IsEqualBaseAdr(&from, to) &&
89  (from.port == 0 || from.port == to->port)) {
90  Com_DPrintf("%s: found offending address: %s\n", __func__,
91  NET_AdrToString(&from));
92  found = qtrue;
93  }
94 
95  // handle ICMP error
96  NET_ErrorEvent(sock, &from, ee->ee_errno, ee->ee_info);
97  }
98 
99  return !!tries && !found;
100 #else
101  return qfalse;
102 #endif
103 }
104 
105 static ssize_t os_udp_recv(qsocket_t sock, void *data,
106  size_t len, netadr_t *from)
107 {
108  struct sockaddr_storage addr;
109  socklen_t addrlen;
110  ssize_t ret;
111  int tries;
112 
113  for (tries = 0; tries < MAX_ERROR_RETRIES; tries++) {
114  memset(&addr, 0, sizeof(addr));
115  addrlen = sizeof(addr);
116  ret = recvfrom(sock, data, len, 0,
117  (struct sockaddr *)&addr, &addrlen);
118 
119  NET_SockadrToNetadr(&addr, from);
120 
121  if (ret >= 0)
122  return ret;
123 
124  net_error = errno;
125 
126  // wouldblock is silent
127  if (net_error == EWOULDBLOCK)
128  return NET_AGAIN;
129 
130  if (!process_error_queue(sock, NULL))
131  break;
132  }
133 
134  return NET_ERROR;
135 }
136 
137 static ssize_t os_udp_send(qsocket_t sock, const void *data,
138  size_t len, const netadr_t *to)
139 {
140  struct sockaddr_storage addr;
141  socklen_t addrlen;
142  ssize_t ret;
143  int tries;
144 
145  addrlen = NET_NetadrToSockadr(to, &addr);
146 
147  for (tries = 0; tries < MAX_ERROR_RETRIES; tries++) {
148  ret = sendto(sock, data, len, 0,
149  (struct sockaddr *)&addr, addrlen);
150  if (ret >= 0)
151  return ret;
152 
153  net_error = errno;
154 
155  // wouldblock is silent
156  if (net_error == EWOULDBLOCK)
157  return NET_AGAIN;
158 
159  if (!process_error_queue(sock, to))
160  break;
161  }
162 
163  return NET_ERROR;
164 }
165 
166 static neterr_t os_get_error(void)
167 {
168  net_error = errno;
169  if (net_error == EWOULDBLOCK)
170  return NET_AGAIN;
171 
172  return NET_ERROR;
173 }
174 
175 static ssize_t os_recv(qsocket_t sock, void *data, size_t len, int flags)
176 {
177  ssize_t ret = recv(sock, data, len, flags);
178 
179  if (ret == -1)
180  return os_get_error();
181 
182  return ret;
183 }
184 
185 static ssize_t os_send(qsocket_t sock, const void *data, size_t len, int flags)
186 {
187  ssize_t ret = send(sock, data, len, flags);
188 
189  if (ret == -1)
190  return os_get_error();
191 
192  return ret;
193 }
194 
195 static neterr_t os_listen(qsocket_t sock, int backlog)
196 {
197  if (listen(sock, backlog) == -1) {
198  net_error = errno;
199  return NET_ERROR;
200  }
201 
202  return NET_OK;
203 }
204 
205 static neterr_t os_accept(qsocket_t sock, qsocket_t *newsock, netadr_t *from)
206 {
207  struct sockaddr_storage addr;
208  socklen_t addrlen;
209  int s;
210 
211  memset(&addr, 0, sizeof(addr));
212  addrlen = sizeof(addr);
213  s = accept(sock, (struct sockaddr *)&addr, &addrlen);
214 
215  NET_SockadrToNetadr(&addr, from);
216 
217  if (s == -1) {
218  *newsock = -1;
219  return os_get_error();
220  }
221 
222  *newsock = s;
223  return NET_OK;
224 }
225 
226 static neterr_t os_connect(qsocket_t sock, const netadr_t *to)
227 {
228  struct sockaddr_storage addr;
229  socklen_t addrlen;
230 
231  addrlen = NET_NetadrToSockadr(to, &addr);
232 
233  if (connect(sock, (struct sockaddr *)&addr, addrlen) == -1) {
234  net_error = errno;
235  if (net_error == EINPROGRESS)
236  return NET_OK;
237 
238  return NET_ERROR;
239  }
240 
241  return NET_OK;
242 }
243 
244 static neterr_t os_make_nonblock(qsocket_t sock, int val)
245 {
246  if (ioctl(sock, FIONBIO, &val) == -1) {
247  net_error = errno;
248  return NET_ERROR;
249  }
250 
251  return NET_OK;
252 }
253 
254 static neterr_t os_setsockopt(qsocket_t sock, int level, int name, int val)
255 {
256  if (setsockopt(sock, level, name, &val, sizeof(val)) == -1) {
257  net_error = errno;
258  return NET_ERROR;
259  }
260 
261  return NET_OK;
262 }
263 
264 static neterr_t os_getsockopt(qsocket_t sock, int level, int name, int *val)
265 {
266  socklen_t _optlen = sizeof(*val);
267 
268  if (getsockopt(sock, level, name, val, &_optlen) == -1) {
269  net_error = errno;
270  return NET_ERROR;
271  }
272 
273  return NET_OK;
274 }
275 
276 static neterr_t os_bind(qsocket_t sock, const struct sockaddr *addr, size_t addrlen)
277 {
278  if (bind(sock, addr, addrlen) == -1) {
279  net_error = errno;
280  return NET_ERROR;
281  }
282 
283  return NET_OK;
284 }
285 
286 static neterr_t os_getsockname(qsocket_t sock, netadr_t *name)
287 {
288  struct sockaddr_storage addr;
289  socklen_t addrlen;
290 
291  memset(&addr, 0, sizeof(addr));
292  addrlen = sizeof(addr);
293  if (getsockname(sock, (struct sockaddr *)&addr, &addrlen) == -1) {
294  net_error = errno;
295  return NET_ERROR;
296  }
297 
298  NET_SockadrToNetadr(&addr, name);
299  return NET_OK;
300 }
301 
302 static void os_closesocket(qsocket_t sock)
303 {
304  close(sock);
305 }
306 
307 static qsocket_t os_socket(int domain, int type, int protocol)
308 {
309  int s = socket(domain, type, protocol);
310 
311  if (s == -1) {
312  net_error = errno;
313  return -1;
314  }
315 
316  return s;
317 }
318 
319 static ioentry_t *_os_get_io(qsocket_t fd, const char *func)
320 {
321  if (fd < 0 || fd >= FD_SETSIZE)
322  Com_Error(ERR_FATAL, "%s: fd out of range: %d", func, fd);
323 
324  return &io_entries[fd];
325 }
326 
327 static ioentry_t *os_add_io(qsocket_t fd)
328 {
329  if (fd >= io_numfds) {
330  io_numfds = fd + 1;
331  }
332 
333  return _os_get_io(fd, __func__);
334 }
335 
336 static ioentry_t *os_get_io(qsocket_t fd)
337 {
338  return _os_get_io(fd, __func__);
339 }
340 
341 static qsocket_t os_get_fd(ioentry_t *e)
342 {
343  return e - io_entries;
344 }
345 
346 static int os_select(int nfds, fd_set *rfds, fd_set *wfds,
347  fd_set *efds, struct timeval *tv)
348 {
349  int ret = select(nfds, rfds, wfds, efds, tv);
350 
351  if (ret == -1) {
352  net_error = errno;
353  if (net_error == EINTR)
354  return 0;
355  }
356 
357  return ret;
358 }
359 
360 static void os_net_init(void)
361 {
362 }
363 
364 static void os_net_shutdown(void)
365 {
366 }
367 
os_get_fd
static qsocket_t os_get_fd(ioentry_t *e)
Definition: unix.h:341
os_recv
static ssize_t os_recv(qsocket_t sock, void *data, size_t len, int flags)
Definition: unix.h:175
os_bind
static neterr_t os_bind(qsocket_t sock, const struct sockaddr *addr, size_t addrlen)
Definition: unix.h:276
MAX_ERROR_RETRIES
#define MAX_ERROR_RETRIES
Definition: net.c:65
NET_AdrToString
char * NET_AdrToString(const netadr_t *a)
Definition: net.c:257
os_getsockname
static neterr_t os_getsockname(qsocket_t sock, netadr_t *name)
Definition: unix.h:286
net_error
static int net_error
Definition: net.c:110
os_connect
static neterr_t os_connect(qsocket_t sock, const netadr_t *to)
Definition: unix.h:226
os_udp_recv
static ssize_t os_udp_recv(qsocket_t sock, void *data, size_t len, netadr_t *from)
Definition: unix.h:105
os_accept
static neterr_t os_accept(qsocket_t sock, qsocket_t *newsock, netadr_t *from)
Definition: unix.h:205
os_closesocket
static void os_closesocket(qsocket_t sock)
Definition: unix.h:302
os_get_io
static ioentry_t * os_get_io(qsocket_t fd)
Definition: unix.h:336
tv
float * tv(float x, float y, float z)
Definition: g_utils.c:248
os_add_io
static ioentry_t * os_add_io(qsocket_t fd)
Definition: unix.h:327
os_error_string
static const char * os_error_string(int err)
Definition: unix.h:23
Com_Error
void Com_Error(error_type_t type, const char *fmt,...)
Definition: g_main.c:258
io_numfds
static int io_numfds
Definition: net.c:123
os_socket
static qsocket_t os_socket(int domain, int type, int protocol)
Definition: unix.h:307
NET_SockadrToNetadr
static void NET_SockadrToNetadr(const struct sockaddr_storage *s, netadr_t *a)
Definition: net.c:176
NET_NetadrToSockadr
static size_t NET_NetadrToSockadr(const netadr_t *a, struct sockaddr_storage *s)
Definition: net.c:145
os_getsockopt
static neterr_t os_getsockopt(qsocket_t sock, int level, int name, int *val)
Definition: unix.h:264
_os_get_io
static ioentry_t * _os_get_io(qsocket_t fd, const char *func)
Definition: unix.h:319
os_send
static ssize_t os_send(qsocket_t sock, const void *data, size_t len, int flags)
Definition: unix.h:185
os_make_nonblock
static neterr_t os_make_nonblock(qsocket_t sock, int val)
Definition: unix.h:244
os_net_shutdown
static void os_net_shutdown(void)
Definition: unix.h:364
io_entries
static ioentry_t io_entries[FD_SETSIZE]
Definition: net.c:122
os_listen
static neterr_t os_listen(qsocket_t sock, int backlog)
Definition: unix.h:195
os_get_error
static neterr_t os_get_error(void)
Definition: unix.h:166
os_select
static int os_select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *tv)
Definition: unix.h:346
os_setsockopt
static neterr_t os_setsockopt(qsocket_t sock, int level, int name, int val)
Definition: unix.h:254
process_error_queue
static qboolean process_error_queue(qsocket_t sock, const netadr_t *to)
Definition: unix.h:29
level
level_locals_t level
Definition: g_main.c:22
os_net_init
static void os_net_init(void)
Definition: unix.h:360
err
int err
Definition: win.h:24
os_udp_send
static ssize_t os_udp_send(qsocket_t sock, const void *data, size_t len, const netadr_t *to)
Definition: unix.h:137
msg
const char * msg
Definition: win.h:25