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; }
/** Test root initialization */ int init_test(root_test_t *rt) { su_sockaddr_t su[1] = {{ 0 }}; int i; BEGIN(); su_init(); su->su_family = rt->rt_family; TEST_1(rt->rt_root = su_root_osx_runloop_create(rt)); for (i = 0; i < 5; i++) { test_ep_t *ep = rt->rt_ep[i]; ep->i = i; ep->addrlen = su_sockaddr_size(su); TEST_1((ep->s = su_socket(su->su_family, SOCK_DGRAM, 0)) != -1); TEST_1(bind(ep->s, &su->su_sa, ep->addrlen) != -1); TEST_1(su_wait_create(ep->wait, ep->s, SU_WAIT_IN|SU_WAIT_ERR) != -1); TEST_1(getsockname(ep->s, &ep->addr->su_sa, &ep->addrlen) != -1); if (SU_HAS_INADDR_ANY(ep->addr)) { su_inet_pton(su->su_family, su->su_family == AF_INET ? "127.0.0.1" : "::1", SU_ADDR(ep->addr)); } } END(); }
int main(int argc, char *argv[]) { su_socket_t s; su_sockaddr_t su = { 0 }; char *host = argv[1]; char *port = host ? argv[2] : NULL; su_addrinfo_t *ai = NULL, hints[1] = {{ 0 }}; int error; if (argv[1] && (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)) usage(argv[0]); if (!port) port = "echo"; if ((error = su_getaddrinfo(host, port, hints, &ai))) { fprintf(stderr, "poll_test: su_getaddrinfo(): %s\n", su_gai_strerror(error)); exit(1); } memcpy(SU_ADDR(&su), ai->ai_addr, ai->ai_addrlen); s = su_socket(ai->ai_family, SOCK_STREAM, 0); if (s == INVALID_SOCKET) { su_perror("socket"); exit(1); } su_freeaddrinfo(ai); su_setblocking(s, 0); /* Don't block */ if (connect(s, &su.su_sa, su_sockaddr_size(&su)) == -1) { if (errno != EINPROGRESS) { su_perror("connect"); exit(1); } } { su_wait_t w; int n, err; su_wait_create(&w, s, SU_WAIT_OUT); n = su_wait(&w, 1, SU_WAIT_FOREVER); printf("su_wait returned %d\n", n); err = su_soerror(s); printf("connect: %s\n", su_strerror(err)); } exit(0); }
/** Accept a connection. */ int forwarder_accept(proxy_t *pr, su_wait_t *w, forwarder_t *f0) { forwarder_t *f; su_sockaddr_t *su; socklen_t sulen; int events; events = su_wait_events(w, f0->f_socket); f = forwarder_create(pr); if (f) { su = f->f_dest; sulen = sizeof(f->f_dest); f->f_socket = accept(f0->f_socket, &su->su_sa, &sulen); f->f_upstream = 1; if (f->f_socket != INVALID_SOCKET) { char buf[SU_ADDRSIZE]; SU_DEBUG_3(("accept: connection from %s:%u\n", su_inet_ntop(su->su_family, SU_ADDR(su), buf, sizeof(buf)), ntohs(su->su_port))); 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)) { if (forwarder_stream_peer(pr, f) != SOCKET_ERROR) { /* success */ return 0; } } else { SU_DEBUG_1(("%s: cannot create wait objects\n", __func__)); } } } forwarder_destroy(f); return 0; }
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; }
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; }
int test_sendrecv(void) { su_socket_t s, l, a; ssize_t n; su_sockaddr_t su, csu; socklen_t sulen = sizeof su.su_sin, csulen = sizeof csu.su_sin; char b1[8], b2[8], b3[8]; su_iovec_t sv[3], rv[3]; sv[0].siv_base = "one!one!", sv[0].siv_len = 8; sv[1].siv_base = "two!two!", sv[1].siv_len = 8; sv[2].siv_base = "third!", sv[2].siv_len = 6; rv[0].siv_base = b1, rv[0].siv_len = 8; rv[1].siv_base = b2, rv[1].siv_len = 8; rv[2].siv_base = b3, rv[2].siv_len = 8; BEGIN(); s = su_socket(AF_INET, SOCK_DGRAM, 0); TEST_1(s != -1); su_setblocking(s, 1); memset(&su, 0, sulen); su.su_len = sulen; su.su_family = AF_INET; TEST(su_inet_pton(AF_INET, "127.0.0.1", &su.su_sin.sin_addr), 1); TEST(bind(s, &su.su_sa, sulen), 0); TEST(getsockname(s, &su.su_sa, &sulen), 0); n = su_vsend(s, sv, 3, 0, &su, sulen); TEST(n, 8 + 8 + 6); n = su_vrecv(s, rv, 3, 0, &su, &sulen); TEST(n, 8 + 8 + 6); TEST_M(rv[0].siv_base, sv[0].siv_base, sv[0].siv_len); TEST_M(rv[1].siv_base, sv[1].siv_base, sv[1].siv_len); TEST_M(rv[2].siv_base, sv[2].siv_base, sv[2].siv_len); su_close(s); l = su_socket(AF_INET, SOCK_STREAM, 0); TEST_1(l != -1); s = su_socket(AF_INET, SOCK_STREAM, 0); TEST_1(s != -1); memset(&su, 0, sulen); su.su_len = sulen; su.su_family = AF_INET; TEST(su_inet_pton(AF_INET, "127.0.0.1", &su.su_sin.sin_addr), 1); TEST(bind(l, &su.su_sa, sulen), 0); TEST(bind(s, &su.su_sa, sulen), 0); TEST(getsockname(l, &su.su_sa, &sulen), 0); TEST(listen(l, 5), 0); TEST(su_setblocking(s, 1), 0); TEST(connect(s, &su.su_sa, sulen), 0); a = accept(l, &csu.su_sa, &csulen); TEST_1(a != -1); TEST(su_setblocking(a, 1), 0); n = su_vsend(s, sv, 3, 0, NULL, 0); TEST(n, 8 + 8 + 6); n = su_vrecv(a, rv, 3, 0, NULL, NULL); TEST(n, 8 + 8 + 6); TEST_M(rv[0].siv_base, sv[0].siv_base, sv[0].siv_len); TEST_M(rv[1].siv_base, sv[1].siv_base, sv[1].siv_len); TEST_M(rv[2].siv_base, sv[2].siv_base, sv[2].siv_len); n = send(a, "", 0, 0); TEST(n, 0); n = su_vsend(a, sv, 3, 0, NULL, 0); TEST(n, 8 + 8 + 6); { su_wait_t w[1] = { SU_WAIT_INIT }; TEST(su_wait_create(w, s, SU_WAIT_IN | SU_WAIT_HUP), 0); TEST(su_wait(w, 0, 500), SU_WAIT_TIMEOUT); TEST(su_wait(w, 1, 500), 0); TEST(su_wait_events(w, s), SU_WAIT_IN); TEST_SIZE(su_getmsgsize(s), 8 + 8 + 6); n = su_vrecv(s, rv, 3, 0, NULL, NULL); TEST(n, 8 + 8 + 6); TEST(su_wait(w, 1, 100), SU_WAIT_TIMEOUT); shutdown(a, 2); TEST(su_wait(w, 1, 100), 0); #if SU_HAVE_WINSOCK TEST_1(su_wait_events(w, s) & SU_WAIT_HUP); #else TEST_1(su_wait_events(w, s)); n = su_vrecv(s, rv, 3, 0, NULL, NULL); TEST(n, 0); #endif su_wait_destroy(w); } su_close(a); su_close(l); su_close(s); END(); }
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(); }