]> code.delx.au - pulseaudio/blob - src/iochannel.c
add dependency script
[pulseaudio] / src / iochannel.c
1 #include <stdlib.h>
2 #include <assert.h>
3 #include <fcntl.h>
4 #include <unistd.h>
5
6 #include "iochannel.h"
7 #include "util.h"
8 #include "socket-util.h"
9
10 struct pa_iochannel {
11 int ifd, ofd;
12 struct pa_mainloop_api* mainloop;
13
14 void (*callback)(struct pa_iochannel*io, void *userdata);
15 void*userdata;
16
17 int readable;
18 int writable;
19 int hungup;
20
21 int no_close;
22
23 void* input_source, *output_source;
24 };
25
26 static void enable_mainloop_sources(struct pa_iochannel *io) {
27 assert(io);
28
29 if (io->input_source == io->output_source) {
30 enum pa_mainloop_api_io_events e = PA_MAINLOOP_API_IO_EVENT_NULL;
31 assert(io->input_source);
32
33 if (!io->readable)
34 e |= PA_MAINLOOP_API_IO_EVENT_INPUT;
35 if (!io->writable)
36 e |= PA_MAINLOOP_API_IO_EVENT_OUTPUT;
37
38 io->mainloop->enable_io(io->mainloop, io->input_source, e);
39 } else {
40 if (io->input_source)
41 io->mainloop->enable_io(io->mainloop, io->input_source, io->readable ? PA_MAINLOOP_API_IO_EVENT_NULL : PA_MAINLOOP_API_IO_EVENT_INPUT);
42 if (io->output_source)
43 io->mainloop->enable_io(io->mainloop, io->output_source, io->writable ? PA_MAINLOOP_API_IO_EVENT_NULL : PA_MAINLOOP_API_IO_EVENT_OUTPUT);
44 }
45 }
46
47 static void callback(struct pa_mainloop_api* m, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata) {
48 struct pa_iochannel *io = userdata;
49 int changed = 0;
50 assert(m && fd >= 0 && events && userdata);
51
52 if ((events & PA_MAINLOOP_API_IO_EVENT_HUP) && !io->hungup) {
53 io->hungup = 1;
54 changed = 1;
55 }
56
57 if ((events & PA_MAINLOOP_API_IO_EVENT_INPUT) && !io->readable) {
58 io->readable = 1;
59 changed = 1;
60 assert(id == io->input_source);
61 }
62
63 if ((events & PA_MAINLOOP_API_IO_EVENT_OUTPUT) && !io->writable) {
64 io->writable = 1;
65 changed = 1;
66 assert(id == io->output_source);
67 }
68
69 if (changed) {
70 enable_mainloop_sources(io);
71
72 if (io->callback)
73 io->callback(io, io->userdata);
74 }
75 }
76
77 struct pa_iochannel* pa_iochannel_new(struct pa_mainloop_api*m, int ifd, int ofd) {
78 struct pa_iochannel *io;
79 assert(m && (ifd >= 0 || ofd >= 0));
80
81 io = malloc(sizeof(struct pa_iochannel));
82 io->ifd = ifd;
83 io->ofd = ofd;
84 io->mainloop = m;
85
86 io->userdata = NULL;
87 io->callback = NULL;
88 io->readable = 0;
89 io->writable = 0;
90 io->hungup = 0;
91 io->no_close = 0;
92
93 if (ifd == ofd) {
94 assert(ifd >= 0);
95 pa_make_nonblock_fd(io->ifd);
96 io->input_source = io->output_source = m->source_io(m, ifd, PA_MAINLOOP_API_IO_EVENT_BOTH, callback, io);
97 } else {
98
99 if (ifd >= 0) {
100 pa_make_nonblock_fd(io->ifd);
101 io->input_source = m->source_io(m, ifd, PA_MAINLOOP_API_IO_EVENT_INPUT, callback, io);
102 } else
103 io->input_source = NULL;
104
105 if (ofd >= 0) {
106 pa_make_nonblock_fd(io->ofd);
107 io->output_source = m->source_io(m, ofd, PA_MAINLOOP_API_IO_EVENT_OUTPUT, callback, io);
108 } else
109 io->output_source = NULL;
110 }
111
112 return io;
113 }
114
115 void pa_iochannel_free(struct pa_iochannel*io) {
116 assert(io);
117
118 if (!io->no_close) {
119 if (io->ifd >= 0)
120 close(io->ifd);
121 if (io->ofd >= 0 && io->ofd != io->ifd)
122 close(io->ofd);
123 }
124
125 if (io->input_source)
126 io->mainloop->cancel_io(io->mainloop, io->input_source);
127 if (io->output_source && (io->output_source != io->input_source))
128 io->mainloop->cancel_io(io->mainloop, io->output_source);
129
130 free(io);
131 }
132
133 int pa_iochannel_is_readable(struct pa_iochannel*io) {
134 assert(io);
135 return io->readable;
136 }
137
138 int pa_iochannel_is_writable(struct pa_iochannel*io) {
139 assert(io);
140 return io->writable;
141 }
142
143 int pa_iochannel_is_hungup(struct pa_iochannel*io) {
144 assert(io);
145 return io->hungup;
146 }
147
148 ssize_t pa_iochannel_write(struct pa_iochannel*io, const void*data, size_t l) {
149 ssize_t r;
150 assert(io && data && l && io->ofd >= 0);
151
152 if ((r = write(io->ofd, data, l)) >= 0) {
153 io->writable = 0;
154 enable_mainloop_sources(io);
155 }
156
157 return r;
158 }
159
160 ssize_t pa_iochannel_read(struct pa_iochannel*io, void*data, size_t l) {
161 ssize_t r;
162
163 assert(io && data && io->ifd >= 0);
164
165 if ((r = read(io->ifd, data, l)) >= 0) {
166 io->readable = 0;
167 enable_mainloop_sources(io);
168 }
169
170 return r;
171 }
172
173 void pa_iochannel_set_callback(struct pa_iochannel*io, void (*callback)(struct pa_iochannel*io, void *userdata), void *userdata) {
174 assert(io);
175 io->callback = callback;
176 io->userdata = userdata;
177 }
178
179 void pa_iochannel_set_noclose(struct pa_iochannel*io, int b) {
180 assert(io);
181 io->no_close = b;
182 }
183
184 void pa_iochannel_socket_peer_to_string(struct pa_iochannel*io, char*s, size_t l) {
185 assert(io && s && l);
186 pa_socket_peer_to_string(io->ifd, s, l);
187 }
188
189 int pa_iochannel_socket_set_rcvbuf(struct pa_iochannel *io, size_t l) {
190 assert(io);
191 return pa_socket_set_rcvbuf(io->ifd, l);
192 }
193
194 int pa_iochannel_socket_set_sndbuf(struct pa_iochannel *io, size_t l) {
195 assert(io);
196 return pa_socket_set_sndbuf(io->ofd, l);
197 }