File: socket.h

package info (click to toggle)
rtpengine 13.5.1.3-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 13,676 kB
  • sloc: ansic: 86,764; perl: 59,422; python: 3,193; sh: 1,030; makefile: 693; asm: 211
file content (380 lines) | stat: -rw-r--r-- 11,569 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
#ifndef _SOCKET_H_
#define _SOCKET_H_


#include <arpa/inet.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <netinet/tcp.h>
#include <stdbool.h>
#include "containers.h"



enum socket_families {
	SF_IP4 = 0,
	SF_IP6,
	__SF_LAST
};



struct socket_address;
struct socket_type;
struct socket_family;
struct endpoint;
struct socket;
struct re_address;

typedef struct socket_address sockaddr_t;
typedef struct endpoint endpoint_t;
typedef struct socket socket_t;
typedef const struct socket_type socktype_t;
typedef const struct socket_family sockfamily_t;

TYPED_GQUEUE(socket, socket_t)


#include "str.h"



#define MAX_PACKET_HEADER_LEN 48 // 40 bytes IPv6 + 8 bytes UDP



struct local_intf;


struct socket_type {
	const char			*name; /* lower case */
	const char			*name_uc; /* upper case */
};
struct socket_family {
	int				idx;
	int				af;
	unsigned int			ethertype;
	size_t				sockaddr_size;
	const char			*name; /* "IPv4" */
	const char			*rfc_name; /* "IP4" */
	const char			*unspec_string; /* 0.0.0.0 or :: */
	unsigned int			(*hash)(const sockaddr_t *);
	bool				(*eq)(const sockaddr_t *, const sockaddr_t *);
	bool				(*addr_parse)(sockaddr_t *, const char *);
	bool				(*addr_print)(const sockaddr_t *, char *, size_t);
	bool				(*addr_print_p)(const sockaddr_t *, char *, size_t);
	bool				(*is_specified)(const sockaddr_t *);
	bool				(*sockaddr2endpoint)(endpoint_t *, const void *);
	bool				(*endpoint2sockaddr)(void *, const endpoint_t *);
	bool				(*addrport2sockaddr)(void *, const sockaddr_t *, unsigned int);
	bool				(*bind)(socket_t *, unsigned int, const sockaddr_t *);
	bool				(*connect)(socket_t *, const endpoint_t *);
	bool				(*listen)(socket_t *, int);
	bool				(*accept)(socket_t *, socket_t *);
	bool				(*getsockname)(socket_t *);
	bool				(*timestamping)(socket_t *);
	bool				(*pktinfo)(socket_t *);
	ssize_t				(*recvfrom)(socket_t *, void *, size_t, endpoint_t *);
	ssize_t				(*recvfrom_ts)(socket_t *, void *, size_t, endpoint_t *, int64_t *);
	ssize_t				(*recvfrom_to)(socket_t *, void *, size_t, endpoint_t *, sockaddr_t *);
	ssize_t				(*sendmsg)(socket_t *, struct msghdr *, const endpoint_t *);
	ssize_t				(*sendto)(socket_t *, const void *, size_t, const endpoint_t *);
	bool				(*tos)(socket_t *, unsigned int);
	void				(*pmtu_disc)(socket_t *, int);
	int				(*error)(socket_t *);
	void				(*endpoint2kernel)(struct re_address *, const endpoint_t *);
	void				(*kernel2endpoint)(endpoint_t *, const struct re_address *);
	unsigned int			(*packet_header)(unsigned char *, const endpoint_t *, const endpoint_t *,
						unsigned int);
	void				(*cmsg_pktinfo)(struct cmsghdr *, const sockaddr_t *);
};
struct socket_address {
	sockfamily_t			*family;
	union {
		struct in_addr			ipv4;
		struct in6_addr			ipv6;
	};
};
struct endpoint {
	sockaddr_t			address;
	unsigned int			port;
};
struct socket {
	int				fd;
	sockfamily_t			*family;
	endpoint_t			local;
	endpoint_t			remote;
};




extern socktype_t *socktype_udp;



#include "auxlib.h"


INLINE bool sockaddr_print(const sockaddr_t *a, char *buf, size_t len) {
	if (!a->family) {
		buf[0] = '\0';
		return true;
	}
	return a->family->addr_print(a, buf, len);
}
INLINE char *sockaddr_print_buf(const sockaddr_t *a) {
	char *buf = get_thread_buf();
	if (!a->family) {
		buf[0] = '\0';
		return buf;
	}
	sockaddr_print(a, buf, THREAD_BUF_SIZE);
	return buf;
}
INLINE bool sockaddr_print_gstring(GString *s, const sockaddr_t *a) {
	if (!a->family)
		return true;
	char buf[THREAD_BUF_SIZE];
	if (!sockaddr_print(a, buf, THREAD_BUF_SIZE))
		return false;
	g_string_append(s, buf);
	return true;
}
INLINE bool sockaddr_print_p(const sockaddr_t *a, char *buf, size_t len) {
	if (!a->family) {
		buf[0] = '\0';
		return true;
	}
	return a->family->addr_print_p(a, buf, len);
}
INLINE char *sockaddr_print_p_buf(const sockaddr_t *a) {
	char *buf = get_thread_buf();
	sockaddr_print_p(a, buf, THREAD_BUF_SIZE);
	return buf;
}
INLINE bool sockaddr_print_port(const sockaddr_t *a, unsigned int port, char *buf, size_t len) {
	if (!a->family) {
		buf[0] = '\0';
		return true;
	}
	if (!a->family->addr_print_p(a, buf, len-6))
		return false;
	sprintf(buf + strlen(buf), ":%u", port);
	return true;
}
INLINE char *sockaddr_print_port_buf(const sockaddr_t *a, unsigned int port) {
	char *buf = get_thread_buf();
	sockaddr_print_port(a, port, buf, THREAD_BUF_SIZE);
	return buf;
}
INLINE bool endpoint_print(const endpoint_t *ep, char *buf, size_t len) {
	return sockaddr_print_port(&ep->address, ep->port, buf, len);
}
INLINE char *endpoint_print_buf(const endpoint_t *ep) {
	return sockaddr_print_port_buf(&ep->address, ep->port);
}
INLINE bool is_addr_unspecified(const sockaddr_t *a) {
	if (!a || !a->family)
		return true;
	return !a->family->is_specified(a);
}
#define socket_recvfrom(s,a...) (s)->family->recvfrom((s), a)
#define socket_recvfrom_ts(s,a...) (s)->family->recvfrom_ts((s), a)
#define socket_recvfrom_to(s,a...) (s)->family->recvfrom_to((s), a)
#define socket_sendmsg(s,a...) (s)->family->sendmsg((s), a)
#define socket_sendto(s,a...) (s)->family->sendto((s), a)
#define socket_error(s) (s)->family->error((s))
#define socket_timestamping(s) (s)->family->timestamping((s))
#define socket_pktinfo(s) (s)->family->pktinfo((s))
#define socket_getsockname(s) (s)->family->getsockname((s))
INLINE ssize_t socket_sendiov(socket_t *s, const struct iovec *v, unsigned int len, const endpoint_t *dst,
		const sockaddr_t *src)
{
	struct msghdr mh = {0};
	char ctrl[64] = {0};

	mh.msg_iov = (void *) v;
	mh.msg_iovlen = len;

	if (src && src->family) {
		mh.msg_control = ctrl;
		mh.msg_controllen = sizeof(ctrl);

		struct cmsghdr *cm = CMSG_FIRSTHDR(&mh);

		s->family->cmsg_pktinfo(cm, src);
		cm = CMSG_NXTHDR(&mh, cm);
		assert(cm != NULL);

		mh.msg_controllen = (char *) cm - ctrl;
	}

	return socket_sendmsg(s, &mh, dst);
}
INLINE ssize_t socket_sendto_from(socket_t *s, const void *b, size_t l, const endpoint_t *dst, sockaddr_t *src) {
	return socket_sendiov(s, &(struct iovec) { .iov_base = (void *) b, .iov_len = l }, l, dst, src);
}

struct timeval32 {
	int32_t tv_sec;
	int32_t tv_usec;
};

#ifndef SO_TIMESTAMP_OLD
#define SO_TIMESTAMP_OLD SO_TIMESTAMP // pointless, compiler should remove it
#endif

#define socket_recvfrom_parse_cmsg(tv, to, parse_to, msgh, firsthdr, nexthdr) do { \
	if ((*tv) || (*to)) { \
		struct cmsghdr *cm; \
		for (cm = firsthdr; cm; cm = nexthdr) { \
			if ((*tv) && cm->cmsg_level == SOL_SOCKET) { \
				if (cm->cmsg_type == SO_TIMESTAMP) { \
					*(*tv) = timeval_us(*((struct timeval *) CMSG_DATA(cm))); \
					(*tv) = NULL; \
				} \
				else if (cm->cmsg_type == SO_TIMESTAMP_OLD) { \
					struct timeval32 *tc = (struct timeval32 *) CMSG_DATA(cm); \
					struct timeval tvv = { .tv_sec = tc->tv_sec, .tv_usec = tc->tv_usec }; \
					*(*tv) = timeval_us(tvv); \
					(*tv) = NULL; \
				} \
			} \
			if (parse && (*to) && parse_to(cm, (*to))) \
				(*to) = NULL; \
		} \
		if (G_UNLIKELY((*tv))) { \
			ilog(LOG_WARNING, "No receive timestamp received from kernel"); \
			ZERO(*(*tv)); \
		} \
		if (G_UNLIKELY((*to))) { \
			ilog(LOG_WARNING, "No local address received from kernel"); \
			ZERO(*(*to)); \
		} \
	} \
	if (G_UNLIKELY(((msgh)->msg_flags & MSG_TRUNC))) \
		ilog(LOG_WARNING, "Kernel indicates that data was truncated"); \
	if (G_UNLIKELY(((msgh)->msg_flags & MSG_CTRUNC))) \
		ilog(LOG_WARNING, "Kernel indicates that ancillary data was truncated"); \
} while (0)


INLINE void usertimeout(socket_t *s, unsigned int val) {
	// coverity[check_return : FALSE]
	setsockopt(s->fd, IPPROTO_TCP, TCP_USER_TIMEOUT, &val, sizeof(val));
}
INLINE void nonblock(int fd) {
	// coverity[check_return : FALSE]
	fcntl(fd, F_SETFL, O_NONBLOCK);
}
INLINE void socket_rcvtimeout(socket_t *s, int64_t us) {
	struct timeval tv = timeval_from_us(us);
	// coverity[check_return : FALSE]
	setsockopt(s->fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
}
INLINE int socket_cpu_affinity(socket_t *s, int cpu) {
#ifndef SO_INCOMING_CPU
	errno = ENOTSUP;
	return -1;
#else
	return setsockopt(s->fd, SOL_SOCKET, SO_INCOMING_CPU, &cpu, sizeof(cpu));
#endif
}



void socket_init(void);

bool open_socket(socket_t *r, int type, unsigned int port, const sockaddr_t *);
bool open_v46_socket(socket_t *r, int type);
bool connect_socket(socket_t *r, int type, const endpoint_t *ep);
int connect_socket_nb(socket_t *r, int type, const endpoint_t *ep); // 1 == in progress
int connect_socket_retry(socket_t *r); // retries connect() while in progress
bool close_socket(socket_t *r);
bool reset_socket(socket_t *r);
void move_socket(socket_t *dst, socket_t *src);
void dummy_socket(socket_t *r, const sockaddr_t *);

sockfamily_t *get_socket_family_rfc(const str *s);
sockfamily_t *__get_socket_family_enum(enum socket_families);
bool sockaddr_parse_any(sockaddr_t *dst, const char *src);
bool sockaddr_parse_any_str(sockaddr_t *dst, const str *src);
bool sockaddr_parse_str(sockaddr_t *dst, sockfamily_t *fam, const str *src);
bool endpoint_parse_any(endpoint_t *, const char *); // address (ip) optional
bool sockaddr_getaddrinfo_alt(sockaddr_t *a, sockaddr_t *a2, const char *s);
bool endpoint_parse_any_getaddrinfo_alt(endpoint_t *d, endpoint_t *d2, const char *s); // address (ip or hostname) optional
INLINE bool endpoint_parse_any_getaddrinfo(endpoint_t *d, const char *s);
void endpoint_parse_sockaddr_storage(endpoint_t *, struct sockaddr_storage *);
void kernel2endpoint(endpoint_t *ep, const struct re_address *ra);

unsigned int sockaddr_hash(const sockaddr_t *);
bool sockaddr_eq(const sockaddr_t *, const sockaddr_t *);
guint sockaddr_t_hash(gconstpointer); // for glib
gint sockaddr_t_eq(gconstpointer, gconstpointer); // true/false, for glib

unsigned int endpoint_hash(const endpoint_t *);
gboolean endpoint_eq(const endpoint_t *, const endpoint_t *); /* true/false */

INLINE sockfamily_t *get_socket_family_enum(enum socket_families i) {
	if (i >= __SF_LAST)
		return NULL;
	return __get_socket_family_enum(i);
}
INLINE bool endpoint_parse_port_any(endpoint_t *e, const char *p, unsigned int port) {
	if (port > 0xffff)
		return false;
	e->port = port;
	return sockaddr_parse_any(&e->address, p);
}
// address (ip or hostname) required
INLINE bool endpoint_parse_any_getaddrinfo_full(endpoint_t *d, const char *s) {
	bool ret;
	ret = endpoint_parse_any_getaddrinfo(d, s);
	if (!ret)
		return ret;
	if (is_addr_unspecified(&d->address))
		return false;
	return true;
}
INLINE bool sockaddr_getaddrinfo(sockaddr_t *a, const char *s) {
	return sockaddr_getaddrinfo_alt(a, NULL, s);
}
INLINE bool endpoint_parse_any_getaddrinfo(endpoint_t *d, const char *s) {
	return endpoint_parse_any_getaddrinfo_alt(d, NULL, s);
}
INLINE bool ipv46_any_convert(endpoint_t *ep) {
	if (ep->address.family->af != AF_INET)
		return false;
	if (!is_addr_unspecified(&ep->address))
		return false;
	ep->address.family = __get_socket_family_enum(SF_IP6);
	ZERO(ep->address.ipv6);
	return true;
}
// needs a writeable str
INLINE bool endpoint_parse_any_str(endpoint_t *d, str *s) {
	char tmp = s->s[s->len];
	s->s[s->len] = '\0';
	bool ret = endpoint_parse_any(d, s->s);
	s->s[s->len] = tmp;
	return ret;
}

#define endpoint_packet_header(o, src, dst, len) (dst)->address.family->packet_header(o, src, dst, len)

INLINE void set_tos(socket_t *s, unsigned int tos) {
	s->family->tos(s, tos);
}
INLINE void set_pmtu_disc(socket_t *s, int opt) {
	if (s->family->pmtu_disc)
		s->family->pmtu_disc(s, opt);
}

socktype_t *get_socket_type(const str *s);
socktype_t *get_socket_type_c(const char *s);


#endif