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