/** Connection is complete. */ int forwarder_connected(proxy_t *pr, su_wait_t *w, forwarder_t *f) { int events, error; forwarder_t *f_peer; events = su_wait_events(w, f->f_socket); error = su_soerror(f->f_socket); if (error) { SU_DEBUG_1(("connect: %s\n", su_strerror(error))); forwarder_destroy(f); return 0; } su_root_unregister(pr->pr_root, f->f_wait + 1, forwarder_connected, f); /* Wait for data, forward it to peer */ assert(f->f_peer); f_peer = f->f_peer; su_root_register(pr->pr_root, f->f_wait, forwarder_recv, f, 0); su_root_register(pr->pr_root, f_peer->f_wait, forwarder_recv, f_peer, 0); return 0; }
int forwarder_stream_peer(proxy_t *pr, forwarder_t *f_peer) { forwarder_t *f; su_addrinfo_t *ai; assert(f_peer); f = forwarder_create(pr); if (!f) { SU_DEBUG_1(("%s: cannot allocate peer\n", __func__)); goto error; } for (ai = pr->pr_addrinfo; ai; ai = ai->ai_next) { if (ai->ai_socktype == SOCK_STREAM) break; } if (!ai) { SU_DEBUG_1(("%s: no matching destination\n", __func__)); goto error; } f->f_socket = su_socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (f->f_socket == INVALID_SOCKET) { SU_DEBUG_1(("%s: socket: %s\n", __func__, su_strerror(su_errno()))); goto error; } if (su_wait_create(f->f_wait, f->f_socket, SU_WAIT_IN) || su_wait_create(f->f_wait + 1, f->f_socket, SU_WAIT_OUT)) { SU_DEBUG_1(("%s: cannot create wait objects\n", __func__)); goto error; } /* Asynchronous connect */ su_setblocking(f->f_socket, 0); su_seterrno(0); connect(f->f_socket, ai->ai_addr, ai->ai_addrlen); memcpy(f->f_dest, ai->ai_addr, ai->ai_addrlen); if (su_errno() != EINPROGRESS) { SU_DEBUG_1(("%s: connect: %s\n", __func__, su_strerror(su_errno()))); goto error; } if (su_root_register(pr->pr_root, f->f_wait + 1, forwarder_connected, f, 0) == -1) { SU_DEBUG_1(("%s: cannot register\n", __func__)); goto error; } f->f_peer = f_peer; f_peer->f_peer = f; return 0; error: forwarder_destroy(f); return SOCKET_ERROR; }
int forwarder_init_stream(forwarder_t *f) { if (listen(f->f_socket, SOMAXCONN) < 0) return SOCKET_ERROR; if (su_wait_create(f->f_wait, f->f_socket, SU_WAIT_ACCEPT) < 0) return SOCKET_ERROR; if (su_root_register(f->f_pr->pr_root, f->f_wait, forwarder_accept, f, 0) < 0) return SOCKET_ERROR; return 0; }
/** Receive data, forward it to peer */ int forwarder_recv(proxy_t *pr, su_wait_t *w, forwarder_t *f) { buffer_t b[1]; int n, events; events = su_wait_events(w, f->f_socket); n = recv(f->f_socket, b->b_data, sizeof(b->b_data), 0); if (n > 0) { b->b_sent = 0; b->b_used = n; if (f->f_peer->f_buf) { forwarder_append(f, b); return 0; } if (forwarder_send(pr, f->f_peer, b) >= 0) { if (b->b_sent < b->b_used) { su_root_unregister(pr->pr_root, w, forwarder_recv, f); su_root_register(pr->pr_root, f->f_peer->f_wait + 1, forwarder_empty, f->f_peer, 0); forwarder_append(f, b); } return 0; } else { /* Error when sending */ } } if (n < 0) { int error = su_errno(); SU_DEBUG_1(("recv: %s\n", su_strerror(error))); if (error == EINTR || error == EAGAIN || error == EWOULDBLOCK) { return 0; } /* XXX */ forwarder_destroy(f); } /* shutdown */ forwarder_shutdown(f); return 0; }
/** Empty forwarder buffers */ int forwarder_empty(proxy_t *pr, su_wait_t *w, forwarder_t *f) { buffer_t *b; int n, events; events = su_wait_events(w, f->f_socket); while ((b = f->f_buf)) { n = forwarder_send(f->f_pr, f, b); if (n == 0) { if ((f->f_buf = b->b_next)) b->b_next->b_prev = &f->f_buf; su_free(f->f_pr->pr_home, b); continue; } else if (n < 0) { /* XXX */ } break; } if (!f->f_buf) { forwarder_t *f_peer = f->f_peer; su_root_unregister(pr->pr_root, w, forwarder_empty, f); if (!f->f_shutdown) { /* Buffer is empty - start receiving */ su_root_register(pr->pr_root, f_peer->f_wait, forwarder_recv, f_peer, 0); } else { if (shutdown(f->f_socket, 1) < 0) { SU_DEBUG_1(("shutdown(1): %s\n", su_strerror(su_errno()))); } if (f_peer->f_shutdown) { forwarder_close(f); } } } return 0; }
int tls_connect(su_root_magic_t *magic, su_wait_t *w, tport_t *self) { tport_master_t *mr = self->tp_master; tport_tls_t *tlstp = (tport_tls_t *)self; tls_t *tls; int events = su_wait_events(w, self->tp_socket); int error; SU_DEBUG_7(("%s(%p): events%s%s%s%s\n", __func__, (void *)self, events & (SU_WAIT_CONNECT) ? " CONNECTING" : "", events & SU_WAIT_IN ? " NEGOTIATING" : "", events & SU_WAIT_ERR ? " ERROR" : "", events & SU_WAIT_HUP ? " HANGUP" : "")); #if HAVE_POLL assert(w->fd == self->tp_socket); #endif if (events & SU_WAIT_ERR) tport_error_event(self); if (events & SU_WAIT_HUP && !self->tp_closed) tport_hup_event(self); if (self->tp_closed) return 0; error = su_soerror(self->tp_socket); if (error) { tport_error_report(self, error, NULL); return 0; } if ((tls = tlstp->tlstp_context) == NULL) { SU_DEBUG_3(("%s(%p): Error: no TLS context data for connected socket.\n", __func__, (void *)tlstp)); tport_close(self); tport_set_secondary_timer(self); return 0; } if (self->tp_is_connected == 0) { int ret, status; ret = self->tp_accepted ? SSL_accept(tls->con) : SSL_connect(tls->con); status = SSL_get_error(tls->con, ret); switch (status) { case SSL_ERROR_WANT_READ: /* OpenSSL is waiting for the peer to send handshake data */ self->tp_events = SU_WAIT_IN | SU_WAIT_ERR | SU_WAIT_HUP; su_root_eventmask(mr->mr_root, self->tp_index, self->tp_socket, self->tp_events); return 0; case SSL_ERROR_WANT_WRITE: /* OpenSSL is waiting for the peer to receive handshake data */ self->tp_events = SU_WAIT_IN | SU_WAIT_ERR | SU_WAIT_HUP | SU_WAIT_OUT; su_root_eventmask(mr->mr_root, self->tp_index, self->tp_socket, self->tp_events); return 0; case SSL_ERROR_NONE: /* TLS Handshake complete */ status = tls_post_connection_check(self, tls); if ( status == X509_V_OK ) { su_wait_t wait[1] = {SU_WAIT_INIT}; tport_master_t *mr = self->tp_master; su_root_deregister(mr->mr_root, self->tp_index); self->tp_index = -1; self->tp_events = SU_WAIT_IN | SU_WAIT_ERR | SU_WAIT_HUP; if ((su_wait_create(wait, self->tp_socket, self->tp_events) == -1) || ((self->tp_index = su_root_register(mr->mr_root, wait, tport_wakeup, self, 0)) == -1)) { tport_close(self); tport_set_secondary_timer(self); return 0; } tls->read_events = SU_WAIT_IN; tls->write_events = 0; self->tp_is_connected = 1; self->tp_verified = tls->x509_verified; self->tp_subjects = tls->subjects; if (tport_has_queued(self)) tport_send_event(self); else tport_set_secondary_timer(self); return 0; } break; default: { char errbuf[64]; ERR_error_string_n(status, errbuf, 64); SU_DEBUG_3(("%s(%p): TLS setup failed (%s)\n", __func__, (void *)self, errbuf)); } break; } } /* TLS Handshake Failed or Peer Certificate did not Verify */ tport_close(self); tport_set_secondary_timer(self); return 0; }
/**Update registered socket. * * @retval 0 if success * @retval -1 upon failure */ static int sres_sofia_update(sres_sofia_t *srs, su_socket_t new_socket, su_socket_t old_socket) { char const *what = NULL; su_wait_t wait[1]; sres_sofia_register_t *reg = NULL; sres_sofia_register_t *old_reg = NULL; int i, index = -1, error = 0; int N = SRES_MAX_NAMESERVERS; SU_DEBUG_9(("sres_sofia_update(%p, %d, %d)\n", (void *)srs, (int)new_socket, (int)old_socket)); if (srs == NULL) return 0; if (srs->srs_root == NULL) return -1; if (old_socket == new_socket) { if (old_socket == INVALID_SOCKET) { sres_resolver_set_async(srs->srs_resolver, sres_sofia_update, NULL, 0); /* Destroy srs */ for (i = 0; i < N; i++) { if (!srs->srs_reg[i].reg_index) continue; su_root_deregister(srs->srs_root, srs->srs_reg[i].reg_index); memset(&srs->srs_reg[i], 0, sizeof(srs->srs_reg[i])); } su_timer_destroy(srs->srs_timer), srs->srs_timer = NULL; su_free(NULL, srs); } return 0; } if (old_socket != INVALID_SOCKET) for (i = 0; i < N; i++) if ((srs->srs_reg + i)->reg_socket == old_socket) { old_reg = srs->srs_reg + i; break; } if (new_socket != INVALID_SOCKET) { if (old_reg == NULL) { for (i = 0; i < N; i++) { if (!(srs->srs_reg + i)->reg_ptr) break; } if (i > N) return su_seterrno(ENOMEM); reg = srs->srs_reg + i; } else reg = old_reg; } if (reg) { if (su_wait_create(wait, new_socket, SU_WAIT_IN | SU_WAIT_ERR) == -1) { reg = NULL; what = "su_wait_create"; error = su_errno(); } if (reg) index = su_root_register(srs->srs_root, wait, sres_sofia_poll, reg, 0); if (index < 0) { reg = NULL; what = "su_root_register"; error = su_errno(); su_wait_destroy(wait); } } if (old_reg) { if (old_socket == srs->srs_socket) srs->srs_socket = INVALID_SOCKET; su_root_deregister(srs->srs_root, old_reg->reg_index); memset(old_reg, 0, sizeof *old_reg); } if (reg) { srs->srs_socket = new_socket; reg->reg_ptr = srs; reg->reg_socket = new_socket; reg->reg_index = index; } if (!what) return 0; /* success */ SU_DEBUG_3(("sres: %s: %s\n", what, su_strerror(error))); return su_seterrno(error); }
/** Add command line (standard input) to be waited. */ static int sofsip_init(cli_t *cli, int ac, char *av[]) { ssc_conf_t *conf = cli->cli_conf; int i; /* gboolean b = FALSE; */ /* long, short, flags, arg, arg_data, desc, arg_desc */ GOptionEntry options[] = { { "autoanswer", 'a', 0, G_OPTION_ARG_NONE, &conf->ssc_autoanswer, "Auto-answer to calls", NULL }, { "register", 'R', 0, G_OPTION_ARG_NONE, &conf->ssc_register, "Register at startup", NULL }, { "contact", 'c', 0, G_OPTION_ARG_STRING, &conf->ssc_contact, "SIP contact, local address to bind to (optional)", "SIP-URI" }, { "media-addr", 'm', 0, G_OPTION_ARG_STRING, &conf->ssc_media_addr, "media address (optional)", "address" }, { "media-impl", 'i', 0, G_OPTION_ARG_STRING, &conf->ssc_media_impl, "media implementation to use", "dummy,gstreamer" }, { "registrar", 'r', 0, G_OPTION_ARG_STRING, &conf->ssc_registrar, "SIP registrar/server (optional)", "SIP-URI" }, { "proxy", 'p', 0, G_OPTION_ARG_STRING, &conf->ssc_proxy, "outbound proxy (optional)", "SIP-URI" }, { "stun-server", 's', 0, G_OPTION_ARG_STRING, &conf->ssc_stun_server, "STUN server (optional)", "address" }, { NULL } }; GOptionContext *context; GError *error = NULL; /* step: process environment variables */ conf->ssc_aor = getenv("SOFSIP_ADDRESS"); conf->ssc_proxy = getenv("SOFSIP_PROXY"); conf->ssc_registrar = getenv("SOFSIP_REGISTRAR"); conf->ssc_certdir = getenv("SOFSIP_CERTDIR"); conf->ssc_stun_server = getenv("SOFSIP_STUN_SERVER"); /* step: process command line arguments */ context = g_option_context_new("- sofsip_cli usage"); g_option_context_add_main_entries(context, options, "sofsip_cli"); #if HAVE_GST g_option_context_add_group (context, gst_init_get_option_group ()); #endif if (!g_option_context_parse(context, &ac, &av, &error)) { g_print ("option parsing failed: %s\n", error->message); exit (1); } g_option_context_free(context); for (i = 1; i < ac; i++) { if (av[i] && av[i][0] != '-') { cli->cli_conf->ssc_aor = av[i]; break; } } // notice that in iOS we can't register STDIN; we get an error 'Invalid argument' // in su_root_register() below. Let's use a pipe instead for iOS core app <-> sofia sip communication su_wait_create(&cli->cli_input, cli->cli_input_fd, SU_WAIT_IN); if (su_root_register(cli->cli_root, &cli->cli_input, sofsip_handle_input, NULL, 0) == SOCKET_ERROR) { su_perror("su_root_register"); return -1; } cli->cli_init = 1; return 0; }
static int register_test(root_test_t *rt) { int i; int s; char msg[3] = "foo"; BEGIN(); TEST_1((s = su_socket(rt->rt_family, SOCK_DGRAM, 0)) != -1); for (i = 0; i < 5; i++) { rt->rt_ep[i]->registered = su_root_register(rt->rt_root, rt->rt_ep[i]->wait, wakeups[i], rt->rt_ep[i], 0); TEST(rt->rt_ep[i]->registered, i + 1 + SU_HAVE_PTHREADS); } for (i = 0; i < 5; i++) { test_ep_t *ep = rt->rt_ep[i]; TEST(su_sendto(s, msg, sizeof(msg), 0, ep->addr, ep->addrlen), sizeof(msg)); test_run(rt); TEST(rt->rt_received, i); TEST(rt->rt_wakeup, i); } for (i = 0; i < 5; i++) { TEST(su_root_unregister(rt->rt_root, rt->rt_ep[i]->wait, wakeups[i], rt->rt_ep[i]), rt->rt_ep[i]->registered); } for (i = 0; i < 5; i++) { rt->rt_ep[i]->registered = su_root_register(rt->rt_root, rt->rt_ep[i]->wait, wakeups[i], rt->rt_ep[i], 1); TEST_1(rt->rt_ep[i]->registered > 0); } for (i = 0; i < 5; i++) { test_ep_t *ep = rt->rt_ep[i]; TEST(su_sendto(s, msg, sizeof(msg), 0, ep->addr, ep->addrlen), sizeof(msg)); test_run(rt); TEST(rt->rt_received, i); TEST(rt->rt_wakeup, i); } for (i = 0; i < 5; i++) { TEST(su_root_deregister(rt->rt_root, rt->rt_ep[i]->registered), rt->rt_ep[i]->registered); } for (i = 0; i < 5; i++) { test_ep_t *ep = rt->rt_ep[i]; TEST_1(su_wait_create(ep->wait, ep->s, SU_WAIT_IN|SU_WAIT_ERR) != -1); ep->registered = su_root_register(rt->rt_root, ep->wait, wakeups[i], ep, 1); TEST_1(ep->registered > 0); } for (i = 0; i < 5; i++) { test_ep_t *ep = rt->rt_ep[i]; TEST(su_sendto(s, msg, sizeof(msg), 0, ep->addr, ep->addrlen), sizeof(msg)); test_run(rt); TEST(rt->rt_received, i); TEST(rt->rt_wakeup, i); } for (i = 0; i < 5; i++) { TEST(su_root_unregister(rt->rt_root, rt->rt_ep[i]->wait, wakeups[i], rt->rt_ep[i]), rt->rt_ep[i]->registered); } END(); }