1/*** 2 This file is part of PulseAudio. 3 4 Copyright 2004-2006 Lennart Poettering 5 Copyright 2006-2007 Pierre Ossman <ossman@cendio.se> for Cendio AB 6 7 PulseAudio is free software; you can redistribute it and/or modify 8 it under the terms of the GNU Lesser General Public License as 9 published by the Free Software Foundation; either version 2.1 of the 10 License, or (at your option) any later version. 11 12 PulseAudio is distributed in the hope that it will be useful, but 13 WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 Lesser General Public License for more details. 16 17 You should have received a copy of the GNU Lesser General Public 18 License along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 19***/ 20 21#ifdef HAVE_CONFIG_H 22#include <config.h> 23#endif 24 25#include <stdlib.h> 26#include <unistd.h> 27#include <errno.h> 28 29#ifdef HAVE_SYS_UN_H 30#include <sys/un.h> 31#endif 32 33#include <pulse/xmalloc.h> 34 35#include <pulsecore/core-error.h> 36#include <pulsecore/core-util.h> 37#include <pulsecore/socket.h> 38#include <pulsecore/socket-util.h> 39#include <pulsecore/log.h> 40#include <pulsecore/macro.h> 41 42#include "iochannel.h" 43 44struct pa_iochannel { 45 int ifd, ofd; 46 int ifd_type, ofd_type; 47 pa_mainloop_api* mainloop; 48 49 pa_iochannel_cb_t callback; 50 void*userdata; 51 52 bool readable:1; 53 bool writable:1; 54 bool hungup:1; 55 bool no_close:1; 56 57 pa_io_event* input_event, *output_event; 58}; 59 60static void callback(pa_mainloop_api* m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata); 61 62static void delete_events(pa_iochannel *io) { 63 pa_assert(io); 64 65 if (io->input_event) 66 io->mainloop->io_free(io->input_event); 67 68 if (io->output_event && io->output_event != io->input_event) 69 io->mainloop->io_free(io->output_event); 70 71 io->input_event = io->output_event = NULL; 72} 73 74static void enable_events(pa_iochannel *io) { 75 pa_assert(io); 76 77 if (io->hungup) { 78 delete_events(io); 79 return; 80 } 81 82 if (io->ifd == io->ofd && io->ifd >= 0) { 83 pa_io_event_flags_t f = PA_IO_EVENT_NULL; 84 85 if (!io->readable) 86 f |= PA_IO_EVENT_INPUT; 87 if (!io->writable) 88 f |= PA_IO_EVENT_OUTPUT; 89 90 pa_assert(io->input_event == io->output_event); 91 92 if (f != PA_IO_EVENT_NULL) { 93 if (io->input_event) 94 io->mainloop->io_enable(io->input_event, f); 95 else 96 io->input_event = io->output_event = io->mainloop->io_new(io->mainloop, io->ifd, f, callback, io); 97 } else 98 delete_events(io); 99 100 } else { 101 102 if (io->ifd >= 0) { 103 if (!io->readable) { 104 if (io->input_event) 105 io->mainloop->io_enable(io->input_event, PA_IO_EVENT_INPUT); 106 else 107 io->input_event = io->mainloop->io_new(io->mainloop, io->ifd, PA_IO_EVENT_INPUT, callback, io); 108 } else if (io->input_event) { 109 io->mainloop->io_free(io->input_event); 110 io->input_event = NULL; 111 } 112 } 113 114 if (io->ofd >= 0) { 115 if (!io->writable) { 116 if (io->output_event) 117 io->mainloop->io_enable(io->output_event, PA_IO_EVENT_OUTPUT); 118 else 119 io->output_event = io->mainloop->io_new(io->mainloop, io->ofd, PA_IO_EVENT_OUTPUT, callback, io); 120 } else if (io->output_event) { 121 io->mainloop->io_free(io->output_event); 122 io->output_event = NULL; 123 } 124 } 125 } 126} 127 128static void callback(pa_mainloop_api* m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) { 129 pa_iochannel *io = userdata; 130 bool changed = false; 131 132 pa_assert(m); 133 pa_assert(e); 134 pa_assert(fd >= 0); 135 pa_assert(userdata); 136 137 if ((f & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) && !io->hungup) { 138 io->hungup = true; 139 changed = true; 140 } 141 142 if ((f & PA_IO_EVENT_INPUT) && !io->readable) { 143 io->readable = true; 144 changed = true; 145 pa_assert(e == io->input_event); 146 } 147 148 if ((f & PA_IO_EVENT_OUTPUT) && !io->writable) { 149 io->writable = true; 150 changed = true; 151 pa_assert(e == io->output_event); 152 } 153 154 if (changed) { 155 enable_events(io); 156 157 if (io->callback) 158 io->callback(io, io->userdata); 159 } 160} 161 162pa_iochannel* pa_iochannel_new(pa_mainloop_api*m, int ifd, int ofd) { 163 pa_iochannel *io; 164 165 pa_assert(m); 166 pa_assert(ifd >= 0 || ofd >= 0); 167 168 io = pa_xnew0(pa_iochannel, 1); 169 io->ifd = ifd; 170 io->ofd = ofd; 171 io->mainloop = m; 172 173 if (io->ifd >= 0) 174 pa_make_fd_nonblock(io->ifd); 175 176 if (io->ofd >= 0 && io->ofd != io->ifd) 177 pa_make_fd_nonblock(io->ofd); 178 179 enable_events(io); 180 return io; 181} 182 183void pa_iochannel_free(pa_iochannel*io) { 184 pa_assert(io); 185 186 delete_events(io); 187 188 if (!io->no_close) { 189 if (io->ifd >= 0) 190 pa_close(io->ifd); 191 if (io->ofd >= 0 && io->ofd != io->ifd) 192 pa_close(io->ofd); 193 } 194 195 pa_xfree(io); 196} 197 198bool pa_iochannel_is_readable(pa_iochannel*io) { 199 pa_assert(io); 200 201 return io->readable || io->hungup; 202} 203 204bool pa_iochannel_is_writable(pa_iochannel*io) { 205 pa_assert(io); 206 207 return io->writable && !io->hungup; 208} 209 210bool pa_iochannel_is_hungup(pa_iochannel*io) { 211 pa_assert(io); 212 213 return io->hungup; 214} 215 216ssize_t pa_iochannel_write(pa_iochannel*io, const void*data, size_t l) { 217 ssize_t r; 218 219 pa_assert(io); 220 pa_assert(data); 221 pa_assert(l); 222 pa_assert(io->ofd >= 0); 223 224 r = pa_write(io->ofd, data, l, &io->ofd_type); 225 226 if ((size_t) r == l) 227 return r; /* Fast path - we almost always successfully write everything */ 228 229 if (r < 0) { 230 if (errno == EAGAIN) 231 r = 0; 232 else 233 return r; 234 } 235 236 /* Partial write - let's get a notification when we can write more */ 237 io->writable = io->hungup = false; 238 enable_events(io); 239 240 return r; 241} 242 243ssize_t pa_iochannel_read(pa_iochannel*io, void*data, size_t l) { 244 ssize_t r; 245 246 pa_assert(io); 247 pa_assert(data); 248 pa_assert(io->ifd >= 0); 249 250 if ((r = pa_read(io->ifd, data, l, &io->ifd_type)) >= 0) { 251 252 /* We also reset the hangup flag here to ensure that another 253 * IO callback is triggered so that we will again call into 254 * user code */ 255 io->readable = io->hungup = false; 256 enable_events(io); 257 } 258 259 return r; 260} 261 262#ifdef HAVE_CREDS 263 264#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__GNU__) 265typedef struct cmsgcred pa_ucred_t; 266#define SCM_CREDENTIALS SCM_CREDS 267#else 268typedef struct ucred pa_ucred_t; 269#endif 270 271bool pa_iochannel_creds_supported(pa_iochannel *io) { 272 struct { 273 struct sockaddr sa; 274#ifdef HAVE_SYS_UN_H 275 struct sockaddr_un un; 276#endif 277 struct sockaddr_storage storage; 278 } sa; 279 280 socklen_t l; 281 282 pa_assert(io); 283 pa_assert(io->ifd >= 0); 284 pa_assert(io->ofd == io->ifd); 285 286 l = sizeof(sa); 287 if (getsockname(io->ifd, &sa.sa, &l) < 0) 288 return false; 289 290 return sa.sa.sa_family == AF_UNIX; 291} 292 293int pa_iochannel_creds_enable(pa_iochannel *io) { 294#if !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__) && !defined(__GNU__) 295 int t = 1; 296#endif 297 298 pa_assert(io); 299 pa_assert(io->ifd >= 0); 300 301#if !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__) && !defined(__GNU__) 302 if (setsockopt(io->ifd, SOL_SOCKET, SO_PASSCRED, &t, sizeof(t)) < 0) { 303 pa_log_error("setsockopt(SOL_SOCKET, SO_PASSCRED): %s", pa_cstrerror(errno)); 304 return -1; 305 } 306#endif 307 308 return 0; 309} 310 311ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l, const pa_creds *ucred) { 312 ssize_t r; 313 struct msghdr mh; 314 struct iovec iov; 315 union { 316 struct cmsghdr hdr; 317 uint8_t data[CMSG_SPACE(sizeof(pa_ucred_t))]; 318 } cmsg; 319 pa_ucred_t *u; 320 321 pa_assert(io); 322 pa_assert(data); 323 pa_assert(l); 324 pa_assert(io->ofd >= 0); 325 326 pa_zero(iov); 327 iov.iov_base = (void*) data; 328 iov.iov_len = l; 329 330 pa_zero(cmsg); 331 cmsg.hdr.cmsg_len = CMSG_LEN(sizeof(pa_ucred_t)); 332 cmsg.hdr.cmsg_level = SOL_SOCKET; 333 cmsg.hdr.cmsg_type = SCM_CREDENTIALS; 334 335 u = (pa_ucred_t*) CMSG_DATA(&cmsg.hdr); 336 337#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__GNU__) 338 // the kernel fills everything 339#else 340 u->pid = getpid(); 341 if (ucred) { 342 u->uid = ucred->uid; 343 u->gid = ucred->gid; 344 } else { 345 u->uid = getuid(); 346 u->gid = getgid(); 347 } 348#endif 349 350 pa_zero(mh); 351 mh.msg_iov = &iov; 352 mh.msg_iovlen = 1; 353 mh.msg_control = &cmsg; 354 mh.msg_controllen = sizeof(cmsg); 355 356 if ((r = sendmsg(io->ofd, &mh, MSG_NOSIGNAL)) >= 0) { 357 io->writable = io->hungup = false; 358 enable_events(io); 359 } 360 361 return r; 362} 363 364/* For more details on FD passing, check the cmsg(3) manpage 365 * and IETF RFC #2292: "Advanced Sockets API for IPv6" */ 366ssize_t pa_iochannel_write_with_fds(pa_iochannel*io, const void*data, size_t l, int nfd, const int *fds) { 367 ssize_t r; 368 int *msgdata; 369 struct msghdr mh; 370 struct iovec iov; 371 union { 372 struct cmsghdr hdr; 373 uint8_t data[CMSG_SPACE(sizeof(int) * MAX_ANCIL_DATA_FDS)]; 374 } cmsg; 375 376 pa_assert(io); 377 pa_assert(data); 378 pa_assert(l); 379 pa_assert(io->ofd >= 0); 380 pa_assert(fds); 381 pa_assert(nfd > 0); 382 pa_assert(nfd <= MAX_ANCIL_DATA_FDS); 383 384 pa_zero(iov); 385 iov.iov_base = (void*) data; 386 iov.iov_len = l; 387 388 pa_zero(cmsg); 389 cmsg.hdr.cmsg_level = SOL_SOCKET; 390 cmsg.hdr.cmsg_type = SCM_RIGHTS; 391 392 msgdata = (int*) CMSG_DATA(&cmsg.hdr); 393 memcpy(msgdata, fds, nfd * sizeof(int)); 394 cmsg.hdr.cmsg_len = CMSG_LEN(sizeof(int) * nfd); 395 396 pa_zero(mh); 397 mh.msg_iov = &iov; 398 mh.msg_iovlen = 1; 399 mh.msg_control = &cmsg; 400 401 /* If we followed the example on the cmsg man page, we'd use 402 * sizeof(cmsg.data) here, but if nfd < MAX_ANCIL_DATA_FDS, then the data 403 * buffer is larger than needed, and the kernel doesn't like it if we set 404 * msg_controllen to a larger than necessary value. The commit message for 405 * commit 451d1d6762 contains a longer explanation. */ 406 mh.msg_controllen = CMSG_SPACE(sizeof(int) * nfd); 407 408 if ((r = sendmsg(io->ofd, &mh, MSG_NOSIGNAL)) >= 0) { 409 io->writable = io->hungup = false; 410 enable_events(io); 411 } 412 return r; 413} 414 415ssize_t pa_iochannel_read_with_ancil_data(pa_iochannel*io, void*data, size_t l, pa_cmsg_ancil_data *ancil_data) { 416 ssize_t r; 417 struct msghdr mh; 418 struct iovec iov; 419 union { 420 struct cmsghdr hdr; 421 uint8_t data[CMSG_SPACE(sizeof(pa_ucred_t)) + CMSG_SPACE(sizeof(int) * MAX_ANCIL_DATA_FDS)]; 422 } cmsg; 423 424 pa_assert(io); 425 pa_assert(data); 426 pa_assert(l); 427 pa_assert(io->ifd >= 0); 428 pa_assert(ancil_data); 429 430 if (io->ifd_type > 0) { 431 ancil_data->creds_valid = false; 432 ancil_data->nfd = 0; 433 return pa_iochannel_read(io, data, l); 434 } 435 436 iov.iov_base = data; 437 iov.iov_len = l; 438 439 pa_zero(mh); 440 mh.msg_iov = &iov; 441 mh.msg_iovlen = 1; 442 mh.msg_control = &cmsg; 443 mh.msg_controllen = sizeof(cmsg); 444 445 if ((r = recvmsg(io->ifd, &mh, 0)) >= 0) { 446 struct cmsghdr *cmh; 447 448 ancil_data->creds_valid = false; 449 ancil_data->nfd = 0; 450 451 for (cmh = CMSG_FIRSTHDR(&mh); cmh; cmh = CMSG_NXTHDR(&mh, cmh)) { 452 453 if (cmh->cmsg_level != SOL_SOCKET) 454 continue; 455 456 if (cmh->cmsg_type == SCM_CREDENTIALS) { 457 pa_ucred_t u; 458 pa_assert(cmh->cmsg_len == CMSG_LEN(sizeof(pa_ucred_t))); 459 memcpy(&u, CMSG_DATA(cmh), sizeof(pa_ucred_t)); 460#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__GNU__) 461 ancil_data->creds.gid = u.cmcred_gid; 462 ancil_data->creds.uid = u.cmcred_uid; 463#else 464 ancil_data->creds.gid = u.gid; 465 ancil_data->creds.uid = u.uid; 466#endif 467 ancil_data->creds_valid = true; 468 } 469 else if (cmh->cmsg_type == SCM_RIGHTS) { 470 int nfd = (cmh->cmsg_len - CMSG_LEN(0)) / sizeof(int); 471 if (nfd > MAX_ANCIL_DATA_FDS) { 472 int i; 473 pa_log("Trying to receive too many file descriptors!"); 474 for (i = 0; i < nfd; i++) 475 pa_close(((int*) CMSG_DATA(cmh))[i]); 476 continue; 477 } 478 memcpy(ancil_data->fds, CMSG_DATA(cmh), nfd * sizeof(int)); 479 ancil_data->nfd = nfd; 480 ancil_data->close_fds_on_cleanup = true; 481 } 482 } 483 484 io->readable = io->hungup = false; 485 enable_events(io); 486 } 487 488 if (r == -1 && errno == ENOTSOCK) { 489 io->ifd_type = 1; 490 return pa_iochannel_read_with_ancil_data(io, data, l, ancil_data); 491 } 492 493 return r; 494} 495 496#endif /* HAVE_CREDS */ 497 498void pa_iochannel_set_callback(pa_iochannel*io, pa_iochannel_cb_t _callback, void *userdata) { 499 pa_assert(io); 500 501 io->callback = _callback; 502 io->userdata = userdata; 503} 504 505void pa_iochannel_set_noclose(pa_iochannel*io, bool b) { 506 pa_assert(io); 507 508 io->no_close = b; 509} 510 511void pa_iochannel_socket_peer_to_string(pa_iochannel*io, char*s, size_t l) { 512 pa_assert(io); 513 pa_assert(s); 514 pa_assert(l); 515 516 pa_socket_peer_to_string(io->ifd, s, l); 517} 518 519int pa_iochannel_socket_set_rcvbuf(pa_iochannel *io, size_t l) { 520 pa_assert(io); 521 522 return pa_socket_set_rcvbuf(io->ifd, l); 523} 524 525int pa_iochannel_socket_set_sndbuf(pa_iochannel *io, size_t l) { 526 pa_assert(io); 527 528 return pa_socket_set_sndbuf(io->ofd, l); 529} 530 531pa_mainloop_api* pa_iochannel_get_mainloop_api(pa_iochannel *io) { 532 pa_assert(io); 533 534 return io->mainloop; 535} 536 537int pa_iochannel_get_recv_fd(pa_iochannel *io) { 538 pa_assert(io); 539 540 return io->ifd; 541} 542 543int pa_iochannel_get_send_fd(pa_iochannel *io) { 544 pa_assert(io); 545 546 return io->ofd; 547} 548 549bool pa_iochannel_socket_is_local(pa_iochannel *io) { 550 pa_assert(io); 551 552 if (pa_socket_is_local(io->ifd)) 553 return true; 554 555 if (io->ifd != io->ofd) 556 if (pa_socket_is_local(io->ofd)) 557 return true; 558 559 return false; 560} 561