CLI: Remove compatibility code.
[asterisk/asterisk.git] / main / alertpipe.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2017, Sean Bright
5  *
6  * Sean Bright <sean.bright@gmail.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief Alert Pipe API
22  *
23  * \author Sean Bright
24  */
25
26 #include "asterisk.h"
27
28 #include <unistd.h>
29 #include <fcntl.h>
30
31 #ifdef HAVE_EVENTFD
32 # include <sys/eventfd.h>
33 #endif
34
35 #include "asterisk/alertpipe.h"
36 #include "asterisk/logger.h"
37
38 int ast_alertpipe_init(int alert_pipe[2])
39 {
40 #ifdef HAVE_EVENTFD
41
42         int fd = eventfd(0, EFD_NONBLOCK | EFD_SEMAPHORE);
43         if (fd > -1) {
44                 alert_pipe[0] = alert_pipe[1] = fd;
45                 return 0;
46         }
47
48         ast_log(LOG_WARNING, "Failed to create alert pipe with eventfd(), falling back to pipe(): %s\n",
49                 strerror(errno));
50         ast_alertpipe_clear(alert_pipe);
51
52 #endif
53
54         if (pipe(alert_pipe)) {
55                 ast_log(LOG_WARNING, "Failed to create alert pipe: %s\n", strerror(errno));
56                 return -1;
57         } else {
58                 int flags = fcntl(alert_pipe[0], F_GETFL);
59                 if (fcntl(alert_pipe[0], F_SETFL, flags | O_NONBLOCK) < 0) {
60                         ast_log(LOG_WARNING, "Failed to set non-blocking mode on alert pipe: %s\n",
61                                 strerror(errno));
62                         ast_alertpipe_close(alert_pipe);
63                         return -1;
64                 }
65                 flags = fcntl(alert_pipe[1], F_GETFL);
66                 if (fcntl(alert_pipe[1], F_SETFL, flags | O_NONBLOCK) < 0) {
67                         ast_log(LOG_WARNING, "Failed to set non-blocking mode on alert pipe: %s\n",
68                                 strerror(errno));
69                         ast_alertpipe_close(alert_pipe);
70                         return -1;
71                 }
72         }
73
74         return 0;
75 }
76
77 void ast_alertpipe_close(int alert_pipe[2])
78 {
79 #ifdef HAVE_EVENTFD
80
81         if (alert_pipe[0] == alert_pipe[1]) {
82                 if (alert_pipe[0] > -1) {
83                         close(alert_pipe[0]);
84                         ast_alertpipe_clear(alert_pipe);
85                 }
86                 return;
87         }
88
89 #endif
90
91         if (alert_pipe[0] > -1) {
92                 close(alert_pipe[0]);
93         }
94         if (alert_pipe[1] > -1) {
95                 close(alert_pipe[1]);
96         }
97         ast_alertpipe_clear(alert_pipe);
98 }
99
100 ast_alert_status_t ast_alertpipe_read(int alert_pipe[2])
101 {
102         uint64_t tmp;
103
104         if (!ast_alertpipe_readable(alert_pipe)) {
105                 return AST_ALERT_NOT_READABLE;
106         }
107
108         if (read(alert_pipe[0], &tmp, sizeof(tmp)) < 0) {
109                 if (errno != EINTR && errno != EAGAIN) {
110                         ast_log(LOG_WARNING, "read() failed: %s\n", strerror(errno));
111                         return AST_ALERT_READ_FAIL;
112                 }
113         }
114
115         return AST_ALERT_READ_SUCCESS;
116 }
117
118 ssize_t ast_alertpipe_write(int alert_pipe[2])
119 {
120         uint64_t tmp = 1;
121
122         if (!ast_alertpipe_writable(alert_pipe)) {
123                 errno = EBADF;
124                 return 0;
125         }
126
127         /* preset errno in case returned size does not match */
128         errno = EPIPE;
129         return write(alert_pipe[1], &tmp, sizeof(tmp)) != sizeof(tmp);
130 }
131
132 ast_alert_status_t ast_alertpipe_flush(int alert_pipe[2])
133 {
134         int bytes_read;
135         uint64_t tmp[16];
136
137         if (!ast_alertpipe_readable(alert_pipe)) {
138                 return AST_ALERT_NOT_READABLE;
139         }
140
141         /* Read the alertpipe until it is exhausted. */
142         for (;;) {
143                 bytes_read = read(alert_pipe[0], tmp, sizeof(tmp));
144                 if (bytes_read < 0) {
145                         if (errno == EINTR) {
146                                 continue;
147                         }
148                         if (errno == EAGAIN || errno == EWOULDBLOCK) {
149                                 /*
150                                  * Would block so nothing left to read.
151                                  * This is the normal loop exit.
152                                  */
153                                 break;
154                         }
155                         ast_log(LOG_WARNING, "read() failed flushing alertpipe: %s\n",
156                                 strerror(errno));
157                         return AST_ALERT_READ_FAIL;
158                 }
159                 if (!bytes_read) {
160                         /* Read nothing so we are done */
161                         break;
162                 }
163         }
164
165         return AST_ALERT_READ_SUCCESS;
166 }