/* Coprocess functionality */ void dnsrv_child_process_xstream_io(int type, xmlnode x, void* args) { dns_io di = (dns_io)args; char* hostname; char* str = NULL; dns_resend_list iternode = NULL; if (type == XSTREAM_NODE) { /* Get the hostname out... */ hostname = xmlnode_get_data(x); log_debug(ZONE, "dnsrv: Recv'd lookup request for %s", hostname); if (hostname != NULL) { /* For each entry in the svclist, try and resolve using the specified service and resend it to the specified host */ iternode = di->svclist; while (iternode != NULL) { str = srv_lookup(x->p, iternode->service, hostname); if (str != NULL) { log_debug(ZONE, "Resolved %s(%s): %s\tresend to:%s", hostname, iternode->service, str, iternode->host); xmlnode_put_attrib(x, "ip", str); xmlnode_put_attrib(x, "to", iternode->host); break; } iternode = iternode->next; } str = xmlnode2str(x); write(di->out, str, strlen(str)); } } xmlnode_free(x); }
static void srv_handler(int err, const struct dnshdr *hdr, struct list *ansl, struct list *authl, struct list *addl, void *arg) { struct sip_request *req = arg; (void)hdr; (void)authl; dns_rrlist_sort(ansl, DNS_TYPE_SRV); dns_rrlist_apply(ansl, NULL, DNS_TYPE_SRV, DNS_CLASS_IN, false, rr_append_handler, &req->srvl); if (!req->srvl.head) { if (!req->tp_selected) { if (transp_next(req->sip, &req->tp)) { err = srv_lookup(req, req->host); if (err) goto fail; return; } req->tp = SIP_TRANSP_NONE; if (!transp_next(req->sip, &req->tp)) { err = EPROTONOSUPPORT; goto fail; } } req->port = sip_transp_port(req->tp, 0); err = addr_lookup(req, req->host); if (err) goto fail; return; } dns_rrlist_apply(addl, NULL, DNS_QTYPE_ANY, DNS_CLASS_IN, false, rr_cache_handler, req); err = request_next(req); if (err) goto fail; if (!req->stateful) { req->resph = NULL; terminate(req, 0, NULL); mem_deref(req); } return; fail: terminate(req, err, NULL); mem_deref(req); }
static void naptr_handler(int err, const struct dnshdr *hdr, struct list *ansl, struct list *authl, struct list *addl, void *arg) { struct sip_request *req = arg; struct dnsrr *rr; (void)hdr; (void)authl; dns_rrlist_sort(ansl, DNS_TYPE_NAPTR); rr = dns_rrlist_apply(ansl, NULL, DNS_TYPE_NAPTR, DNS_CLASS_IN, false, rr_naptr_handler, req); if (!rr) { err = srv_lookup(req, req->host); if (err) goto fail; return; } dns_rrlist_sort(addl, DNS_TYPE_SRV); dns_rrlist_apply(addl, rr->rdata.naptr.replace, DNS_TYPE_SRV, DNS_CLASS_IN, true, rr_append_handler, &req->srvl); if (!req->srvl.head) { err = dnsc_query(&req->dnsq, req->sip->dnsc, rr->rdata.naptr.replace, DNS_TYPE_SRV, DNS_CLASS_IN, true, srv_handler, req); if (err) goto fail; return; } dns_rrlist_apply(addl, NULL, DNS_QTYPE_ANY, DNS_CLASS_IN, false, rr_cache_handler, req); err = request_next(req); if (err) goto fail; if (!req->stateful) { req->resph = NULL; terminate(req, 0, NULL); mem_deref(req); } return; fail: terminate(req, err, NULL); mem_deref(req); }
/** * Send a SIP request * * @param reqp Pointer to allocated SIP request object * @param sip SIP Stack * @param stateful Stateful client transaction * @param met SIP Method string * @param metl Length of SIP Method string * @param uri Request URI * @param uril Length of Request URI string * @param route Next hop route URI * @param mb Buffer containing SIP request * @param sendh Send handler * @param resph Response handler * @param arg Handler argument * * @return 0 if success, otherwise errorcode */ int sip_request(struct sip_request **reqp, struct sip *sip, bool stateful, const char *met, int metl, const char *uri, int uril, const struct uri *route, struct mbuf *mb, sip_send_h *sendh, sip_resp_h *resph, void *arg) { struct sip_request *req; struct sa dst; struct pl pl; int err; if (!sip || !met || !uri || !route || !mb) return EINVAL; if (pl_strcasecmp(&route->scheme, "sip")) return ENOSYS; req = mem_zalloc(sizeof(*req), destructor); if (!req) return ENOMEM; list_append(&sip->reql, &req->le, req); err = str_ldup(&req->met, met, metl); if (err) goto out; err = str_ldup(&req->uri, uri, uril); if (err) goto out; if (sip_param_decode(&route->params, "maddr", &pl)) pl = route->host; err = pl_strdup(&req->host, &pl); if (err) goto out; req->stateful = stateful; req->mb = mem_ref(mb); req->sip = sip; req->sendh = sendh; req->resph = resph; req->arg = arg; if (!sip_param_decode(&route->params, "transport", &pl)) { if (!pl_strcasecmp(&pl, "udp")) req->tp = SIP_TRANSP_UDP; else if (!pl_strcasecmp(&pl, "tcp")) req->tp = SIP_TRANSP_TCP; else if (!pl_strcasecmp(&pl, "tls")) req->tp = SIP_TRANSP_TLS; else { err = EPROTONOSUPPORT; goto out; } if (!sip_transp_supported(sip, req->tp, AF_UNSPEC)) { err = EPROTONOSUPPORT; goto out; } req->tp_selected = true; } else { req->tp = SIP_TRANSP_NONE; if (!transp_next(sip, &req->tp)) { err = EPROTONOSUPPORT; goto out; } req->tp_selected = false; } if (!sa_set_str(&dst, req->host, sip_transp_port(req->tp, route->port))) { err = request(req, req->tp, &dst); if (!req->stateful) { mem_deref(req); return err; } } else if (route->port) { req->port = sip_transp_port(req->tp, route->port); err = addr_lookup(req, req->host); } else if (req->tp_selected) { err = srv_lookup(req, req->host); } else { err = dnsc_query(&req->dnsq, sip->dnsc, req->host, DNS_TYPE_NAPTR, DNS_CLASS_IN, true, naptr_handler, req); } out: if (err) mem_deref(req); else if (reqp) { req->reqp = reqp; *reqp = req; } return err; }
/* Separate this from jabber_login() so we can do OAuth first if necessary. Putting this in io.c would probably be more correct. */ void jabber_connect( struct im_connection *ic ) { account_t *acc = ic->acc; struct jabber_data *jd = ic->proto_data; int i; char *connect_to; struct ns_srv_reply **srvl = NULL, *srv = NULL; /* Figure out the hostname to connect to. */ if( acc->server && *acc->server ) connect_to = acc->server; else if( ( srvl = srv_lookup( "xmpp-client", "tcp", jd->server ) ) || ( srvl = srv_lookup( "jabber-client", "tcp", jd->server ) ) ) { /* Find the lowest-priority one. These usually come back in random/shuffled order. Not looking at weights etc for now. */ srv = *srvl; for( i = 1; srvl[i]; i ++ ) if( srvl[i]->prio < srv->prio ) srv = srvl[i]; connect_to = srv->name; } else connect_to = jd->server; imcb_log( ic, "Connecting" ); for( i = 0; jabber_port_list[i] > 0; i ++ ) if( set_getint( &acc->set, "port" ) == jabber_port_list[i] ) break; if( jabber_port_list[i] == 0 ) { imcb_log( ic, "Illegal port number" ); imc_logout( ic, FALSE ); return; } /* For non-SSL connections we can try to use the port # from the SRV reply, but let's not do that when using SSL, SSL usually runs on non-standard ports... */ if( set_getbool( &acc->set, "ssl" ) ) { jd->ssl = ssl_connect( connect_to, set_getint( &acc->set, "port" ), FALSE, jabber_connected_ssl, ic ); jd->fd = jd->ssl ? ssl_getfd( jd->ssl ) : -1; } else { jd->fd = proxy_connect( connect_to, srv ? srv->port : set_getint( &acc->set, "port" ), jabber_connected_plain, ic ); } srv_free( srvl ); if( jd->fd == -1 ) { imcb_error( ic, "Could not connect to server" ); imc_logout( ic, TRUE ); return; } if( set_getbool( &acc->set, "xmlconsole" ) ) { jd->flags |= JFLAG_XMLCONSOLE; /* Shouldn't really do this at this stage already, maybe. But I think this shouldn't break anything. */ imcb_add_buddy( ic, JABBER_XMLCONSOLE_HANDLE, NULL ); } jabber_generate_id_hash( jd ); }
/* Separate this from jabber_login() so we can do OAuth first if necessary. Putting this in io.c would probably be more correct. */ void jabber_connect(struct im_connection *ic) { account_t *acc = ic->acc; struct jabber_data *jd = ic->proto_data; int i; char *connect_to; struct ns_srv_reply **srvl = NULL, *srv = NULL; /* Figure out the hostname to connect to. */ if (acc->server && *acc->server) { connect_to = acc->server; } else if ((srvl = srv_lookup("xmpp-client", "tcp", jd->server)) || (srvl = srv_lookup("jabber-client", "tcp", jd->server))) { /* Find the lowest-priority one. These usually come back in random/shuffled order. Not looking at weights etc for now. */ srv = *srvl; for (i = 1; srvl[i]; i++) { if (srvl[i]->prio < srv->prio) { srv = srvl[i]; } } connect_to = srv->name; } else { connect_to = jd->server; } imcb_log(ic, "Connecting"); for (i = 0; jabber_port_list[i] > 0; i++) { if (set_getint(&acc->set, "port") == jabber_port_list[i]) { break; } } if (jabber_port_list[i] == 0) { imcb_log(ic, "Illegal port number"); imc_logout(ic, FALSE); return; } /* For non-SSL connections we can try to use the port # from the SRV reply, but let's not do that when using SSL, SSL usually runs on non-standard ports... */ if (set_getbool(&acc->set, "ssl")) { jd->ssl = ssl_connect(connect_to, set_getint(&acc->set, "port"), set_getbool(&acc->set, "tls_verify"), jabber_connected_ssl, ic); jd->fd = jd->ssl ? ssl_getfd(jd->ssl) : -1; } else { jd->fd = proxy_connect(connect_to, srv ? srv->port : set_getint(&acc->set, "port"), jabber_connected_plain, ic); } srv_free(srvl); if (jd->fd == -1) { imcb_error(ic, "Could not connect to server"); imc_logout(ic, TRUE); return; } if (set_getbool(&acc->set, "xmlconsole")) { jabber_xmlconsole_enable(ic); } if (set_getbool(&acc->set, "mail_notifications")) { /* It's gmail specific, but it checks for server support before enabling it */ jd->flags |= JFLAG_GMAILNOTIFY; if (set_getstr(&acc->set, "mail_notifications_handle")) { imcb_add_buddy(ic, set_getstr(&acc->set, "mail_notifications_handle"), NULL); } } jabber_generate_id_hash(jd); }