-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathcommon.c
More file actions
157 lines (125 loc) · 3.02 KB
/
common.c
File metadata and controls
157 lines (125 loc) · 3.02 KB
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
// Test for poll() and select() system calls
//
// Copyright (C) 2018 Ricardo Biehl Pasquali
//
// License: See LICENSE file at the root of this repository.
// 2017-11-19
//
// polling for send timestamp on socket's error queue
//
// do_poll(), do_recv, do_send(), open_socket()
#include <arpa/inet.h> // hton*()
#include <poll.h> // poll()
#include <string.h> // memset()
#include <sys/types.h> // socket(), recv()
#include <sys/select.h> // select()
#include <sys/socket.h> // socket(), recv()
#include <unistd.h> // close()
#include <linux/net_tstamp.h> // timestamp stuff
#include "common.h"
int
do_select(int sfd, short request_mask)
{
fd_set rfds, wfds, efds;
FD_ZERO(&rfds);
FD_ZERO(&wfds);
FD_ZERO(&efds);
if (request_mask & POLLIN)
FD_SET(sfd, &rfds);
if (request_mask & POLLOUT)
FD_SET(sfd, &wfds);
if (request_mask & POLLPRI)
FD_SET(sfd, &efds);
return select(sfd + 1, &rfds, &wfds, &efds, NULL);
}
int
do_poll(int sfd, short request_mask)
{
struct pollfd pfd;
// prepare
memset(&pfd, 0, sizeof(pfd));
pfd.fd = sfd;
pfd.events = request_mask;
// poll
return poll(&pfd, 1, -1);
}
void
do_recv(int sfd)
{
char tmp;
while (recv(sfd, &tmp, sizeof(tmp), 0) == sizeof(tmp));
while (recv(sfd, &tmp, sizeof(tmp), MSG_ERRQUEUE) == sizeof(tmp));
}
void
do_send(int sfd)
{
struct sockaddr_in saddr;
char tmp = 'a';
// prepare
saddr.sin_family = AF_INET;
saddr.sin_port = htons(PORT);
saddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
sendto(sfd, &tmp, sizeof(tmp), 0, (struct sockaddr*) &saddr,
sizeof(saddr));
}
// SO_SELECT_ERR_QUEUE: wake the socket with POLLPRI |
// POLLERR if it is in the error list, which would enable
// software to wait on error queue packets without waking
// up for regular data on the socket
static int
set_pollpri_on_errqueue(int sfd)
{
int on = 1;
int tmp;
tmp = setsockopt(sfd, SOL_SOCKET, SO_SELECT_ERR_QUEUE, &on, sizeof(on));
if (tmp == -1)
return -1;
return 0;
}
// SO_TIMESTAMPING: timestamp packets
static int
set_ts_opt(int sfd)
{
unsigned int opt;
// set timestamp option
opt = SOF_TIMESTAMPING_SOFTWARE | SOF_TIMESTAMPING_TX_SCHED |
SOF_TIMESTAMPING_OPT_CMSG;
if (setsockopt(sfd, SOL_SOCKET, SO_TIMESTAMPING, (char*) &opt,
sizeof(opt)) == -1)
return -1;
return 0;
}
int
open_socket(int flags)
{
int sfd;
int tmp;
// open socket in non-blocking mode
sfd = socket(AF_INET, SOCK_DGRAM|SOCK_NONBLOCK, 0);
if (sfd == -1)
return -1;
if (flags & BIND_SOCKET) {
struct sockaddr_in saddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(PORT);
saddr.sin_addr.s_addr = htonl(INADDR_ANY);
tmp = bind(sfd, (const struct sockaddr*) &saddr,
sizeof(saddr));
if (tmp == -1)
goto _go_close_socket;
}
if (flags & POLLPRI_WAKEUP_ON_ERROR_QUEUE) {
tmp = set_pollpri_on_errqueue(sfd);
if (tmp == -1)
goto _go_close_socket;
}
if (flags & ENABLE_TX_TIMESTAMP) {
tmp = set_ts_opt(sfd);
if (tmp == -1)
goto _go_close_socket;
}
return sfd;
_go_close_socket:
close(sfd);
return -1;
}