📄 dialback_out.c
字号:
xmlnode x; spool errmsg = NULL; char *connect_results = NULL; char *bounce_reason = NULL; xhash_zap(c->d->out_connecting,jid_full(c->key)); /* get the results of connection attempts */ if (c->connect_results != NULL) { connect_results = spool_print(c->connect_results); } /* if there was never any ->m set but there's a queue yet, then we probably never got connected, just make a note of it */ if(c->m == NULL && c->q != NULL) { log_notice(c->d->i->id, "failed to establish connection to %s, %s: %s", c->key->server, dialback_out_connection_state_string(c->connection_state), connect_results); } /* if there's any packets in the queue, flush them! */ cur = c->q; if (cur != NULL) { /* generate bounce message, but only if there are queued messages */ errmsg = spool_new(c->p); spool_add(errmsg, "Failed to deliver stanza to other server while "); spool_add(errmsg, dialback_out_connection_state_string(c->connection_state)); spool_add(errmsg, ": "); spool_add(errmsg, connect_results); bounce_reason = spool_print(errmsg); } while(cur != NULL) { next = cur->next; deliver_fail(dpacket_new(cur->x), bounce_reason ? bounce_reason : "Could not send stanza to other server"); cur = next; } /* also kill any validations still waiting */ for(x = xmlnode_get_firstchild(c->verifies); x != NULL; x = xmlnode_get_nextsibling(x)) { jutil_tofrom(x); dialback_in_verify(c->d, xmlnode_dup(x)); /* it'll take these verifies and trash them */ } pool_free(c->p);}/** * handle packets we receive from our router for other hosts * * (packets to our instances address are not handled here, but in dialback_in_verify()) * * We have to: * - revert some magic we are using to talk to the dns resolver for db:verify packets * - check if there is already a connection and establish one else * - send or queue the packet (depending if we already authorized and if it's a db:verify) * * @param d the dialback instance * @param x the packet * @param ip where to connect to (if necessary) */void dialback_out_packet(db d, xmlnode x, char *ip){ jid to, from, key; miod md; int verify = 0; dboq q; dboc c; to = jid_new(xmlnode_pool(x),xmlnode_get_attrib(x,"to")); from = jid_new(xmlnode_pool(x),xmlnode_get_attrib(x,"from")); if(to == NULL || from == NULL) { log_warn(d->i->id, "dropping packet, invalid to or from: %s", xmlnode2str(x)); xmlnode_free(x); return; } log_debug2(ZONE, LOGT_IO, "dbout packet[%s]: %s",ip,xmlnode2str(x)); /* db:verify packets come in with us as the sender */ if(j_strcmp(from->server,d->i->id) == 0) { verify = 1; /* fix the headers, restore the real from */ /* (I think we wouldn't need to from/ofrom thing anymore because we have dnsqueryby, that we need for s2s clustering) */ xmlnode_put_attrib(x,"from",xmlnode_get_attrib(x,"ofrom")); xmlnode_hide_attrib(x,"ofrom"); xmlnode_hide_attrib(x,"dnsqueryby"); from = jid_new(xmlnode_pool(x),xmlnode_get_attrib(x,"from")); } /* build the standard key */ key = jid_new(xmlnode_pool(x),to->server); jid_set(key, from->server, JID_RESOURCE); /* try to get an active connection */ md = xhash_get(d->out_ok_db, jid_full(key)); log_debug2(ZONE, LOGT_IO, "outgoing packet with key %s and located existing %X",jid_full(key),md); /* yay! that was easy, just send the packet :) */ if(md != NULL) { /* if we've got an ip sent, and a connected host, we should be registered! */ if(ip != NULL) register_instance(md->d->i, key->server); dialback_miod_write(md, x); return; } /* get a connection to the other server */ c = dialback_out_connection(d, key, dialback_ip_get(d, key, ip), verify ? not_requested : want_request); log_debug2(ZONE, LOGT_IO, "got connection %x for request %s (%s)", c, jid_full(key), verify ? "not_requested" : "want_request"); /* verify requests can't be queued, they need to be sent outright */ if(verify) { if(c == NULL) { jutil_tofrom(x); /* pretend it bounced */ dialback_in_verify(d, x); /* no connection to send db:verify to, bounce back to in to send failure */ return; } /* if the server is already connected, just write it */ if(c->m != NULL) { mio_write(c->m, x, NULL, -1); }else{ /* queue it so that it's written after we're connected */ xmlnode_insert_tag_node(c->verifies,x); xmlnode_free(x); } return; } if(c == NULL) { log_warn(d->i->id,"dropping a packet that was missing an ip to connect to: %s",xmlnode2str(x)); xmlnode_free(x); return; } /* insert into the queue */ q = pmalloco(xmlnode_pool(x), sizeof(_dboq)); q->stamp = time(NULL); q->x = x; q->next = c->q; c->q = q;}/** * handle the events (incoming stanzas) on an outgoing dialback socket, which isn't much of a job * * The only packets we have to expect on an outgoing dialback socket are db:verify and maybe stream:error * * @param m the connection the packet has been received on * @param flags the mio action, we ignore anything but MIO_XML_NODE * @param arg the dialback instance * @param the packet that has been received */void dialback_out_read_db(mio m, int flags, void *arg, xmlnode x) { db d = (db)arg; if(flags != MIO_XML_NODE) return; /* it's either a valid verify response, or bust! */ if(j_strcmp(xmlnode_get_name(x),"db:verify") == 0) { dialback_in_verify(d, x); return; } if(j_strcmp(xmlnode_get_name(x),"stream:error") == 0) { spool s = spool_new(x->p); streamerr errstruct = pmalloco(x->p, sizeof(_streamerr)); char *errmsg = NULL; /* generate the error message */ xstream_parse_error(x->p, x, errstruct); xstream_format_error(s, errstruct); errmsg = spool_print(s); /* logging */ switch (errstruct->severity) { case normal: log_debug2(ZONE, LOGT_IO, "stream error on outgoing db conn to %s: %s", mio_ip(m), errmsg); break; case configuration: case feature_lack: case unknown: log_warn(d->i->id, "received stream error on outgoing db conn to %s: %s", mio_ip(m), errmsg); break; case error: default: log_error(d->i->id, "received stream error on outgoing db conn to %s: %s", mio_ip(m), errmsg); } } else { mio_write(m, NULL, "<stream:error><undefined-condition xmlns='urn:ietf:params:xml:ns:xmpp-streams'/><text xmlns='urn:ietf:params:xml:ns:xmpp-streams' xml:lang='en'>Received data on a send-only socket. You are not Allowed to send data on this socket!</text></stream:error>", -1); } mio_close(m); xmlnode_free(x);}/** * util to flush queue to mio * * Take elements from the queue and send it to a miod connection. * * @param md the miod connection * @param q the queue to flush */void dialback_out_qflush(miod md, dboq q){ dboq cur, next; cur = q; while(cur != NULL) { next = cur->next; dialback_miod_write(md, cur->x); cur = next; }}/** * handle the early connection process * * What to do: * - Send stream header after mio connected a socket for us * - Process the incoming stream header * - Check for incoming stream:features * - Generate db:result queries to start authorizing for a domain * - Process incoming db:verify queries * - Process incoming db:result responses (flush/send queue of waiting stanzas) */void dialback_out_read(mio m, int flags, void *arg, xmlnode x){ dboc c = (dboc)arg; xmlnode cur; miod md; int version = 0; char *dbns = NULL; log_debug2(ZONE, LOGT_IO, "dbout read: fd %d flag %d key %s",m->fd, flags, jid_full(c->key)); switch(flags) { case MIO_NEW: log_debug2(ZONE, LOGT_IO, "NEW outgoing server socket connected at %d",m->fd); /* add to the connect result messages */ if (c->connect_results != NULL) { spool_add(c->connect_results, "Connected"); } c->connection_state = connected; /* outgoing conneciton, write the header */ cur = xstream_header("jabber:server", c->key->server, NULL); xmlnode_hide_attrib(cur, "id"); /* no, we don't need the id on this stream */ xmlnode_put_attrib(cur,"xmlns:db","jabber:server:dialback"); /* flag ourselves as dialback capable */ if (c->xmpp_version == 1) { /* should we flag XMPP support? */ xmlnode_put_attrib(cur, "version", "1.0"); } mio_write(m, NULL, xstream_header_char(cur), -1); xmlnode_free(cur); return; case MIO_XML_ROOT: log_debug2(ZONE, LOGT_IO, "Incoming root %s",xmlnode2str(x)); c->connection_state = got_streamroot; /* validate namespace */ if(j_strcmp(xmlnode_get_attrib(x,"xmlns"),"jabber:server") != 0) { mio_write(m, NULL, "<stream:error><invalid-namespace xmlns='urn:ietf:params:xml:ns:xmpp-streams'/><text xmlns='urn:ietf:params:xml:ns:xmpp-streams' xml:lang='en'>Invalid Stream Header!</text></stream:error>", -1); mio_close(m); break; } /* remember the stream id the connected entity assigned ... required to do dialback */ c->stream_id = pstrdup(c->p, xmlnode_get_attrib(x,"id")); if (c->stream_id == NULL) { mio_write(m, NULL, "<stream:error><invalid-id xmlns='urn:ietf:params:xml:ns:xmpp-streams'/><text xmlns='urn:ietf:params:xml:ns:xmpp-streams' xml:lang='en'>You are missing the id attribute in your stream header!</text></stream:error>", -1); mio_close(m); break; } /* make sure we're not connecting to ourselves */ if(xhash_get(c->d->in_id,c->stream_id) != NULL) { log_alert(c->key->server,"hostname maps back to ourselves!- No service defined for this hostname, can not handle request. Check jabberd configuration."); mio_write(m, NULL, "<stream:error><internal-server-error xmlns='urn:ietf:params:xml:ns:xmpp-streams'/><text xmlns='urn:ietf:params:xml:ns:xmpp-streams' xml:lang='en'>Mirror Mirror on the wall (we connected to ourself)</text></stream:error>", -1); mio_close(m); break; } /* check version */ version = j_atoi(xmlnode_get_attrib(x, "version"), 0); dbns = xmlnode_get_attrib(x, "xmlns:db");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -