/* * This file is part of the Sofia-SIP package * * Copyright (C) 2005 Nokia Corporation. * * Contact: Pekka Pessi * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * */ /**@ingroup su_wait * @CFILE su_socket_port.c * * OS-Independent Syncronization Interface with socket mailbox * * This implements wakeup using sockets by su_port_send(). * * @author Pekka Pessi * @author Kai Vehmanen * * @date Created: Tue Sep 14 15:51:04 1999 ppessi */ #include "config.h" #include #include #include #include #include #include #include #define su_socket_port_s su_port_s #define SU_CLONE_T su_msg_t #include "sofia-sip/su.h" #include "su_port.h" #include "sofia-sip/su_alloc.h" #if HAVE_SOCKETPAIR #define SU_MBOX_SEND 1 #else #define SU_MBOX_SEND 0 #endif /** @internal Message box wakeup function. */ static int su_mbox_port_wakeup(su_root_magic_t *magic, /* NULL */ su_wait_t *w, su_wakeup_arg_t *arg) { char buf[32]; su_socket_t socket = *(su_socket_t*)arg; su_wait_events(w, socket); recv(socket, buf, sizeof(buf), 0); return 0; } /**@internal * * Initializes a message port. It creates a mailbox used to wake up the * thread waiting on the port if needed. Currently, the mailbox is a * socketpair or an UDP socket connected to itself. */ int su_socket_port_init(su_port_t *self, su_port_vtable_t const *vtable) { int retval = -1; int af; su_socket_t mb = INVALID_SOCKET; su_wait_t wait[1] = { SU_WAIT_INIT }; char const *why; SU_DEBUG_9(("su_socket_port_init(%p, %p) called\n", (void *)self, (void *)vtable)); if (su_pthread_port_init(self, vtable) != 0) return -1; #if HAVE_SOCKETPAIR #if defined(AF_LOCAL) af = AF_LOCAL; #else af = AF_UNIX; #endif if (socketpair(af, SOCK_STREAM, 0, self->sup_mbox) == -1) { why = "socketpair"; goto error; } mb = self->sup_mbox[0]; su_setblocking(self->sup_mbox[1], 0); #else { struct sockaddr_in sin = { sizeof(struct sockaddr_in), 0 }; socklen_t sinsize = sizeof sin; struct sockaddr *sa = (struct sockaddr *)&sin; af = PF_INET; self->sup_mbox[0] = mb = su_socket(af, SOCK_DGRAM, IPPROTO_UDP); if (mb == INVALID_SOCKET) { why = "socket"; goto error; } sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); /* 127.1 */ /* Get a port for us */ if (bind(mb, sa, sizeof sin) == -1) { why = "bind"; goto error; } if (getsockname(mb, sa, &sinsize) == -1) { why = "getsockname"; goto error; } if (connect(mb, sa, sinsize) == -1) { why = "connect"; goto error; } } #endif if (su_wait_create(wait, mb, SU_WAIT_IN) == -1) { why = "su_wait_create"; goto error; } self->sup_mbox_index = su_port_register(self, NULL, wait, su_mbox_port_wakeup, (void *)self->sup_mbox, 0); if (self->sup_mbox_index <= 0) { why = "su_port_register"; su_wait_destroy(wait); goto error; } return 0; error: su_log("%s: %s: %s\n", "su_socket_port_init", why, su_strerror(su_errno())); return retval; } /** @internal Deinit a base implementation of port. */ void su_socket_port_deinit(su_port_t *self) { assert(self); if (self->sup_mbox_index > 0) su_port_deregister(self, self->sup_mbox_index); self->sup_mbox_index = 0; if (self->sup_mbox[0] && self->sup_mbox[0] != INVALID_SOCKET) su_close(self->sup_mbox[0]); self->sup_mbox[0] = INVALID_SOCKET; #if HAVE_SOCKETPAIR if (self->sup_mbox[1] && self->sup_mbox[1] != INVALID_SOCKET) su_close(self->sup_mbox[1]); self->sup_mbox[1] = INVALID_SOCKET; #endif su_pthread_port_deinit(self); } /** @internal Send a message to the port. */ int su_socket_port_send(su_port_t *self, su_msg_r rmsg) { int wakeup = su_base_port_send(self, rmsg); if (wakeup < 0) return -1; if (wakeup) { assert(self->sup_mbox[SU_MBOX_SEND] != INVALID_SOCKET); if (send(self->sup_mbox[SU_MBOX_SEND], "X", 1, 0) == -1) { #if HAVE_SOCKETPAIR if (su_errno() != EWOULDBLOCK) #endif su_perror("su_msg_send: send()"); } } return 0; }