• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* MIT License
2  *
3  * Copyright (c) 2024 Brad House
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy
6  * of this software and associated documentation files (the "Software"), to deal
7  * in the Software without restriction, including without limitation the rights
8  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9  * copies of the Software, and to permit persons to whom the Software is
10  * furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  *
24  * SPDX-License-Identifier: MIT
25  */
26 #include "ares_setup.h"
27 #include "ares.h"
28 #include "ares_private.h"
29 #include "ares_event.h"
30 #ifdef HAVE_UNISTD_H
31 #  include <unistd.h>
32 #endif
33 #ifdef HAVE_FCNTL_H
34 #  include <fcntl.h>
35 #endif
36 
37 #ifdef HAVE_PIPE
38 typedef struct {
39   int filedes[2];
40 } ares_pipeevent_t;
41 
ares_pipeevent_destroy(ares_pipeevent_t * p)42 static void ares_pipeevent_destroy(ares_pipeevent_t *p)
43 {
44   if (p->filedes[0] != -1) {
45     close(p->filedes[0]);
46   }
47   if (p->filedes[1] != -1) {
48     close(p->filedes[1]);
49   }
50 
51   ares_free(p);
52 }
53 
ares_pipeevent_destroy_cb(void * arg)54 static void ares_pipeevent_destroy_cb(void *arg)
55 {
56   ares_pipeevent_destroy(arg);
57 }
58 
ares_pipeevent_init(void)59 static ares_pipeevent_t *ares_pipeevent_init(void)
60 {
61   ares_pipeevent_t *p = ares_malloc_zero(sizeof(*p));
62   if (p == NULL) {
63     return NULL;
64   }
65 
66   p->filedes[0] = -1;
67   p->filedes[1] = -1;
68 
69 #  ifdef HAVE_PIPE2
70   if (pipe2(p->filedes, O_NONBLOCK | O_CLOEXEC) != 0) {
71     ares_pipeevent_destroy(p);
72     return NULL;
73   }
74 #  else
75   if (pipe(p->filedes) != 0) {
76     ares_pipeevent_destroy(p);
77     return NULL;
78   }
79 
80 #    ifdef O_NONBLOCK
81   {
82     int val;
83     val = fcntl(p->filedes[0], F_GETFL, 0);
84     if (val >= 0) {
85       val |= O_NONBLOCK;
86     }
87     fcntl(p->filedes[0], F_SETFL, val);
88 
89     val = fcntl(p->filedes[1], F_GETFL, 0);
90     if (val >= 0) {
91       val |= O_NONBLOCK;
92     }
93     fcntl(p->filedes[1], F_SETFL, val);
94   }
95 #    endif
96 
97 #    ifdef O_CLOEXEC
98   fcntl(p->filedes[0], F_SETFD, O_CLOEXEC);
99   fcntl(p->filedes[1], F_SETFD, O_CLOEXEC);
100 #    endif
101 #  endif
102 
103 #  ifdef F_SETNOSIGPIPE
104   fcntl(p->filedes[0], F_SETNOSIGPIPE, 1);
105   fcntl(p->filedes[1], F_SETNOSIGPIPE, 1);
106 #  endif
107 
108   return p;
109 }
110 
ares_pipeevent_signal(const ares_event_t * e)111 static void ares_pipeevent_signal(const ares_event_t *e)
112 {
113   const ares_pipeevent_t *p;
114 
115   if (e == NULL || e->data == NULL) {
116     return;
117   }
118 
119   p = e->data;
120   (void)write(p->filedes[1], "1", 1);
121 }
122 
ares_pipeevent_cb(ares_event_thread_t * e,ares_socket_t fd,void * data,ares_event_flags_t flags)123 static void ares_pipeevent_cb(ares_event_thread_t *e, ares_socket_t fd,
124                               void *data, ares_event_flags_t flags)
125 {
126   unsigned char           buf[32];
127   const ares_pipeevent_t *p = NULL;
128 
129   (void)e;
130   (void)fd;
131   (void)flags;
132 
133   if (data == NULL) {
134     return;
135   }
136 
137   p = data;
138 
139   while (read(p->filedes[0], buf, sizeof(buf)) == sizeof(buf)) {
140     /* Do nothing */
141   }
142 }
143 
ares_pipeevent_create(ares_event_thread_t * e)144 ares_event_t *ares_pipeevent_create(ares_event_thread_t *e)
145 {
146   ares_event_t     *event = NULL;
147   ares_pipeevent_t *p     = NULL;
148   ares_status_t     status;
149 
150   p = ares_pipeevent_init();
151   if (p == NULL) {
152     return NULL;
153   }
154 
155   status = ares_event_update(&event, e, ARES_EVENT_FLAG_READ, ares_pipeevent_cb,
156                              p->filedes[0], p, ares_pipeevent_destroy_cb,
157                              ares_pipeevent_signal);
158   if (status != ARES_SUCCESS) {
159     ares_pipeevent_destroy(p);
160     return NULL;
161   }
162 
163   return event;
164 }
165 
166 #endif
167