📄 dialback_out.c
字号:
/* -------------------------------------------------------------------------- * * License * * The contents of this file are subject to the Jabber Open Source License * Version 1.0 (the "JOSL"). You may not copy or use this file, in either * source code or executable form, except in compliance with the JOSL. You * may obtain a copy of the JOSL at http://www.jabber.org/ or at * http://www.opensource.org/. * * Software distributed under the JOSL is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the JOSL * for the specific language governing rights and limitations under the * JOSL. * * Copyrights * * Portions created by or assigned to Jabber.com, Inc. are * Copyright (c) 1999-2002 Jabber.com, Inc. All Rights Reserved. Contact * information for Jabber.com, Inc. is available at http://www.jabber.com/. * * Portions Copyright (c) 1998-1999 Jeremie Miller. * * Acknowledgements * * Special thanks to the Jabber Open Source Contributors for their * suggestions and support of Jabber. * * Alternatively, the contents of this file may be used under the terms of the * GNU General Public License Version 2 or later (the "GPL"), in which case * the provisions of the GPL are applicable instead of those above. If you * wish to allow use of your version of this file only under the terms of the * GPL and not to allow others to use your version of this file under the JOSL, * indicate your decision by deleting the provisions above and replace them * with the notice and other provisions required by the GPL. If you do not * delete the provisions above, a recipient may use your version of this file * under either the JOSL or the GPL. * * * --------------------------------------------------------------------------*//** * @file dialback_out.c * @brief handle outgoing server to server connections * * This is where the server to server connection manager handles outgoing connections. * * There might be two types of outgoing connections: * - We want to send stanzas to the user of an other server, we then have to * convince the peer, that we are who we claim to be (using dialback) * - We want to verify the identity of a peer that connected to us, using the * dialback protocol. (We might reuse an outgoing connection of the other type * if there is already one.) * * On outgoing connections, we need to send: * - An initial db:result element to tell the peer, that we want to authorize for * the use of a domain, that the peer should verify that we are allowed to use * this sending domain - and watch for the results to this * - db:verify elements to verify if a peer is allowed to use a domain as * sender - and watch for the results * - After we are authorized by the peer to send stanzas from a domain, we send them. * - The starttls command, if the peer and we are supporting TLS. */#include "dialback.h"/** simple queue for out_queue */typedef struct dboq_struct{ int stamp; xmlnode x; struct dboq_struct *next;} *dboq, _dboq;/** * enumeration of dialback request states an outgoing connection can have */typedef enum { not_requested, /**< there was no packet yet, for that we want to request doing dialback (just sending db:verifys), and we could not yet send them */ could_request, /**< there was no packet yet, that requested doing dialback, but we could send out dialback requests */ want_request, /**< we want to send a dialback request */ sent_request /**< we did sent a dialback request */} db_request;/** * enumeration of connection establishment states an outgoing connection can have * * used for more detailed logging of failed connections */typedef enum { created, /**< outgoing connection request created, but not yet started to connect */ connecting, /**< we started to connect, but have no connection yet */ connected, /**< we have connected to the other host */ got_streamroot, /**< we got the stream root of the other server */ waiting_features, /**< we are waiting for the stream features on a XMPP1.0 connection */ got_features, /**< we got the stream features on a XMPP1.0 connection */ sent_db_request, /**< we sent out a dialback request */ db_succeeded, /**< we had success with our dialback request */ db_failed, /**< dialback failed */} db_connection_state;/* for connecting db sockets *//** * structure holding information about an outgoing connection */typedef struct { char *ip; /**< where to connect to (list of comma separated addresses of the format [ip]:port, [ip], ip:port, or ip) */ int stamp; /**< when we started to connect to this peer */ db d; /**< our dialback instance */ jid key; /**< destination and source for this connection, format: dest/src */ xmlnode verifies; /**< waiting db:verify elements we have to send to the peer */ pool p; /**< memory pool we are using for this connections data */ dboq q; /**< pending stanzas, that need to be sent to the peer */ mio m; /**< the mio connection this outgoing stream is using */ /* original comment: for that short time when we're connected and open, but haven't auth'd ourselves yet */ int xmpp_version; /**< 0 if no version should be advertized, 1 if XMPP 1.0 should be advertized */ int xmpp_no_tls; /**< 0 if starting TLS is allowed, 1 if TLS should not be established */ char *stream_id; /**< the stream id the connected entity assigned */ db_request db_state; /**< if we want to send a <db:result/> and if we already did */ db_connection_state connection_state; /**< how far did we proceed in connecting to the other host */ spool connect_results; /**< result messages for the connection attempts */} *dboc, _dboc;/* forward declaration */void dialback_out_read(mio m, int flags, void *arg, xmlnode x);/** * try to start a connection based upon a given connect object * * Tell mio to connect to the peer and make dialback_out_read() the first mio handler * * @param c the connect object */void dialback_out_connect(dboc c){ char *ip, *col; int port = 5269; if(c->ip == NULL) return; ip = c->ip; c->ip = strchr(ip,','); if(c->ip != NULL) { /* chop off this ip if there is another, track the other */ *c->ip = '\0'; c->ip++; } log_debug2(ZONE, LOGT_IO, "Attempting to connect to %s at %s",jid_full(c->key),ip); /* to which IP we connect, for logging */ if (c->connect_results != NULL) { spool_add(c->connect_results, ip); spool_add(c->connect_results, ": "); } /* get the ip/port for io_select */#ifdef WITH_IPV6 if(ip[0] == '[') { /* format "[ipaddr]:port" or "[ipaddr]" */ ip++; col=strchr(ip,']'); if(col != NULL) { *col = '\0'; if(col[1]==':') { col++; } } } else { /* format "ipaddr" or "ipaddr:port" */ col = strchr(ip, ':'); /* if it has at least two colons it is an IPv6 address */ if(col!=NULL && strchr(col+1,':')) { col = NULL; } }#else col = strchr(ip,':');#endif if(col != NULL) { *col = '\0'; col++; port = atoi(col); } /* we are now in the state of connecting */ c->connection_state = connecting; mio_connect(ip, port, dialback_out_read, (void *)c, 20, MIO_CONNECT_XML);}/** * make a new outgoing connect(ion) object, and start to connect to the peer * * @param d the dialback instance * @param key destination and source for this connection * @param ip where to connect to (format see description to the _dboc structure) * @param db_state if sending a <db:result/> is requested * @return the newly created object */dboc dialback_out_connection(db d, jid key, char *ip, db_request db_state) { dboc c; pool p; if((c = xhash_get(d->out_connecting, jid_full(key))) != NULL) { /* db:request now wanted? */ if (db_state == want_request) { if (c->db_state == not_requested) { log_debug2(ZONE, LOGT_IO, "packet for existing connection: state change not_requested -> want_request"); c->db_state = want_request; } else if (c->db_state == could_request) { /* send <db:result/> to request dialback */ xmlnode db_result = xmlnode_new_tag("db:result"); xmlnode_put_attrib(db_result, "to", c->key->server); xmlnode_put_attrib(db_result, "from", c->key->resource); xmlnode_insert_cdata(db_result, dialback_merlin(xmlnode_pool(db_result), c->d->secret, c->key->server, c->stream_id), -1); mio_write(c->m,db_result, NULL, 0); c->db_state = sent_request; log_debug2(ZONE, LOGT_IO, "packet for existing connection: state change could_request -> sent_request"); } } return c; } if(ip == NULL) return NULL; /* none, make a new one */ p = pool_heap(2*1024); c = pmalloco(p, sizeof(_dboc)); c->p = p; c->d = d; c->key = jid_new(p,jid_full(key)); c->stamp = time(NULL); c->verifies = xmlnode_new_tag_pool(p,"v"); c->ip = pstrdup(p,ip); c->xmpp_version = j_strcmp(xhash_get(d->hosts_xmpp, c->key->server), "no")==0 ? 0 : 1; if (c->xmpp_version == 0) { log_debug2(ZONE, LOGT_IO, "disabled XMPP due to configuration for host %s", c->key->server); } c->xmpp_no_tls = j_strcmp(xhash_get(d->hosts_tls, c->key->server), "no")==0 ? 1 : 0; if (c->xmpp_no_tls != 0) { log_debug2(ZONE, LOGT_IO, "disabled STARTTLS due to configuration for host %s", c->key->server); } c->db_state = db_state; c->connection_state = created; c->connect_results = spool_new(p); /* insert in the hash */ xhash_put(d->out_connecting, jid_full(c->key), (void *)c); /* start the conneciton process */ dialback_out_connect(c); return c;}/** * get the textual representation of a db_connection_state * * @param state the state * @return the textual representation */char *dialback_out_connection_state_string(db_connection_state state) { switch (state) { case created: return "connection object just created"; case connecting: return "connecting to other host"; case connected: return "connected to other host"; case got_streamroot: return "got the stream root"; case waiting_features: return "waiting for stream features on XMPP stream"; case got_features: return "got stream features on XMPP stream"; case sent_db_request: return "sent out dialback request"; case db_succeeded: return "dialback succeeded"; case db_failed: return "dialback failed"; } return "unknown connection state";}/** * handle failed connection attempts, bounce pending stanzas and db:verify elements * * either we're connected, or failed, or something like that, but the connection process is kaput * * @param c the outgoing connect that failed */void dialback_out_connection_cleanup(dboc c){ dboq cur, next;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -