3232#endif
3333#include <sys/un.h>
3434
35+ #if defined(__linux__ )
36+ #include <linux/errqueue.h>
37+ #endif
38+
3539#if defined(IPV6_JOIN_GROUP ) && !defined(IPV6_ADD_MEMBERSHIP )
3640# define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
3741#endif
4145#endif
4246
4347static void uv__udp_run_completed (uv_udp_t * handle );
44- static void uv__udp_recvmsg (uv_udp_t * handle );
48+ static void uv__udp_recvmsg (uv_udp_t * handle , int flag );
4549static void uv__udp_sendmsg (uv_udp_t * handle );
4650static int uv__udp_maybe_deferred_bind (uv_udp_t * handle ,
4751 int domain ,
@@ -135,22 +139,61 @@ static void uv__udp_run_completed(uv_udp_t* handle) {
135139}
136140
137141
142+ #if defined(__linux__ )
143+ static int uv__udp_recvmsg_errqueue (uv_udp_t * handle ,
144+ struct msghdr * h ,
145+ uv_buf_t * buf ,
146+ const struct sockaddr * peer ,
147+ int flags ) {
148+ struct cmsghdr * cmsg ;
149+ struct sock_extended_err * serr ;
150+ struct sockaddr * offender ;
151+
152+ if (!(h -> msg_flags & MSG_ERRQUEUE ))
153+ return 0 ;
154+
155+ flags |= UV_UDP_LINUX_RECVERR ;
156+ for (cmsg = CMSG_FIRSTHDR (h ); cmsg != NULL ; cmsg = CMSG_NXTHDR (h , cmsg )) {
157+ if ((cmsg -> cmsg_level == SOL_IP && cmsg -> cmsg_type == IP_RECVERR ) ||
158+ (cmsg -> cmsg_level == SOL_IPV6 && cmsg -> cmsg_type == IPV6_RECVERR )) {
159+ serr = (struct sock_extended_err * ) CMSG_DATA (cmsg );
160+
161+ offender = SO_EE_OFFENDER (serr );
162+ handle -> recv_cb (handle ,
163+ UV__ERR (serr -> ee_errno ),
164+ buf ,
165+ offender ,
166+ flags );
167+ return 1 ; /* handled */
168+ }
169+ }
170+ return 0 ;
171+ }
172+ #endif
173+
174+
138175void uv__udp_io (uv_loop_t * loop , uv__io_t * w , unsigned int revents ) {
139176 uv_udp_t * handle ;
140177
141178 handle = container_of (w , uv_udp_t , io_watcher );
142179 assert (handle -> type == UV_UDP );
143180
144181 if (revents & POLLIN )
145- uv__udp_recvmsg (handle );
182+ uv__udp_recvmsg (handle , 0 );
183+
184+ /* Just Linux support for now. */
185+ #if defined(__linux__ )
186+ if (revents & POLLERR )
187+ uv__udp_recvmsg (handle , MSG_ERRQUEUE );
188+ #endif
146189
147190 if (revents & POLLOUT && !uv__is_closing (handle )) {
148191 uv__udp_sendmsg (handle );
149192 uv__udp_run_completed (handle );
150193 }
151194}
152195
153- static int uv__udp_recvmmsg (uv_udp_t * handle , uv_buf_t * buf ) {
196+ static int uv__udp_recvmmsg (uv_udp_t * handle , uv_buf_t * buf , int flag ) {
154197#if defined(__linux__ ) || defined(__FreeBSD__ ) || defined(__APPLE__ )
155198 struct sockaddr_in6 peers [20 ];
156199 struct iovec iov [ARRAY_SIZE (peers )];
@@ -160,6 +203,9 @@ static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf) {
160203 size_t chunks ;
161204 int flags ;
162205 size_t k ;
206+ #if defined(__linux__ )
207+ char control [ARRAY_SIZE (peers )][64 ];
208+ #endif
163209
164210 /* prepare structures for recvmmsg */
165211 chunks = buf -> len / UV__UDP_DGRAM_MAXSIZE ;
@@ -177,6 +223,12 @@ static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf) {
177223 msgs [k ].msg_hdr .msg_controllen = 0 ;
178224 msgs [k ].msg_hdr .msg_flags = 0 ;
179225 msgs [k ].msg_len = 0 ;
226+ #if defined(__linux__ )
227+ if (flag & MSG_ERRQUEUE ) {
228+ msgs [k ].msg_hdr .msg_control = control [k ];
229+ msgs [k ].msg_hdr .msg_controllen = sizeof (control [k ]);
230+ }
231+ #endif
180232 }
181233
182234#if defined(__APPLE__ )
@@ -185,7 +237,7 @@ static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf) {
185237 while (nread == -1 && errno == EINTR );
186238#else
187239 do
188- nread = recvmmsg (handle -> io_watcher .fd , msgs , chunks , 0 , NULL );
240+ nread = recvmmsg (handle -> io_watcher .fd , msgs , chunks , flag , NULL );
189241 while (nread == -1 && errno == EINTR );
190242#endif
191243
@@ -202,6 +254,13 @@ static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf) {
202254 flags |= UV_UDP_PARTIAL ;
203255
204256 chunk_buf = uv_buf_init (iov [k ].iov_base , iov [k ].iov_len );
257+ #if defined(__linux__ )
258+ if ((flag & MSG_ERRQUEUE ) &&
259+ uv__udp_recvmsg_errqueue (handle , & msgs [k ].msg_hdr , & chunk_buf ,
260+ (const struct sockaddr * ) & peers [k ], flags )) {
261+ continue ;
262+ }
263+ #endif
205264 handle -> recv_cb (handle ,
206265 msgs [k ].msg_len ,
207266 & chunk_buf ,
@@ -219,13 +278,16 @@ static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf) {
219278#endif /* __linux__ || ____FreeBSD__ || __APPLE__ */
220279}
221280
222- static void uv__udp_recvmsg (uv_udp_t * handle ) {
281+ static void uv__udp_recvmsg (uv_udp_t * handle , int flag ) {
223282 struct sockaddr_storage peer ;
224283 struct msghdr h ;
225284 ssize_t nread ;
226285 uv_buf_t buf ;
227286 int flags ;
228287 int count ;
288+ #if defined(__linux__ )
289+ char control [256 ];
290+ #endif
229291
230292 assert (handle -> recv_cb != NULL );
231293 assert (handle -> alloc_cb != NULL );
@@ -245,7 +307,7 @@ static void uv__udp_recvmsg(uv_udp_t* handle) {
245307 assert (buf .base != NULL );
246308
247309 if (uv_udp_using_recvmmsg (handle )) {
248- nread = uv__udp_recvmmsg (handle , & buf );
310+ nread = uv__udp_recvmmsg (handle , & buf , flag );
249311 if (nread > 0 )
250312 count -= nread ;
251313 continue ;
@@ -257,13 +319,26 @@ static void uv__udp_recvmsg(uv_udp_t* handle) {
257319 h .msg_namelen = sizeof (peer );
258320 h .msg_iov = (void * ) & buf ;
259321 h .msg_iovlen = 1 ;
322+ #if defined(__linux__ )
323+ if (flag & MSG_ERRQUEUE ) {
324+ h .msg_control = control ;
325+ h .msg_controllen = sizeof (control );
326+ }
327+ #endif
260328
261329 do {
262- nread = recvmsg (handle -> io_watcher .fd , & h , 0 );
330+ nread = recvmsg (handle -> io_watcher .fd , & h , flag );
263331 }
264332 while (nread == -1 && errno == EINTR );
265333
266334 if (nread == -1 ) {
335+ #if defined(__linux__ )
336+ if ((flag & MSG_ERRQUEUE ) &&
337+ uv__udp_recvmsg_errqueue (handle , & h , & buf ,
338+ (const struct sockaddr * ) & peer , flags )) {
339+ goto out ;
340+ }
341+ #endif
267342 if (errno == EAGAIN || errno == EWOULDBLOCK )
268343 handle -> recv_cb (handle , 0 , & buf , NULL , 0 );
269344 else
@@ -274,8 +349,16 @@ static void uv__udp_recvmsg(uv_udp_t* handle) {
274349 if (h .msg_flags & MSG_TRUNC )
275350 flags |= UV_UDP_PARTIAL ;
276351
352+ #if defined(__linux__ )
353+ if ((flag & MSG_ERRQUEUE ) &&
354+ uv__udp_recvmsg_errqueue (handle , & h , & buf ,
355+ (const struct sockaddr * ) & peer , flags )) {
356+ goto out ;
357+ }
358+ #endif
277359 handle -> recv_cb (handle , nread , & buf , (const struct sockaddr * ) & peer , flags );
278360 }
361+ out :
279362 count -- ;
280363 }
281364 /* recv_cb callback may decide to pause or close the handle */
0 commit comments