⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mio.c

📁 jabber server jabber server jabber server jabber server
💻 C
📖 第 1 页 / 共 3 页
字号:
/* -------------------------------------------------------------------------- * * 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 mio.c * @brief MIO -- Managed Input/Output * * The purpose of this file, is mainly to provide support, to any component * of jabberd, for abstraced I/O functions.  This works much like tstreams, * and will incorporate the functionality of io_select initially, but will be * expanded to support any socket handling model, such as polld, SIGIO, etc * * This works to abstract the socket work, and hide it from the component, * this way, the component does not have to deal with any complexeties of * socket functions. */#define MIO#include <jabberd.h>#include <errno.h>/******************************************************** *************  Internal MIO Functions  ***************** ********************************************************//** * @brief structure that holds the global mio data */typedef struct mio_main_st{    pool p;             /**< (memory-)pool to hold this data */    mio master__list;   /**< a list of all the sockets */    pth_t t;            /**< a pointer to thread for signaling */    int shutdown;	/**< flag that the select loop can be left (if value is 1) */    int zzz[2];		/**< pipe used to send signals to the select loop */    int zzz_active;	/**< if set to something else then 1, there has been sent a signal already, that is not yet processed */    struct karma *k;	/**< default karma */    int rate_t, rate_p; /**< default rate, if any */} _ios,*ios;/** * @brief internal structure holding data of the destination where we connect to */typedef struct mio_connect_st{    pool p;		/**< (memory-)pool to hold this data */    char *ip;		/**< IP address where to connect to */    int port;		/**< port where to connect to */    void *cb;		/**< callback function that should be notified on the new connection */    void *cb_arg;	/**< argument that should be passed to the callback function */    mio_connect_func cf;    mio_handlers mh;    pth_t t;		/**< thread for this connection */    int connected;	/**< flag if the socket is connected */} _connect_data,  *connect_data;/* global object */int mio__errno = 0;	/**< mio_ssl.c passes EAGAIN on this variable, if a read/write would have blocked  */int mio__ssl_reread = 0;/**< mio_ssl.c tells us on this variable, that there might be more to read */ios mio__data = NULL;	/**< global data for mio */char *mio__bounce_uri = NULL; /**< where to bounce HTTP requests to */extern xmlnode greymatter__;#ifdef WITH_IPV6/** * compare two IPv6 or IPv4 addresses if they are in the same network * * @param addr1 the first address * @param addr2 the second address * @param netsize how many bits are in the network address * @return 1 if both addresses are in the same network, 0 if not */int _mio_compare_ipv6(const struct in6_addr *addr1, const struct in6_addr *addr2, int netsize){    int i;    u_int8_t mask;    if(netsize > 128)	netsize = 128;    for(i = 0; i < netsize/8; i++)    {	if(addr1->s6_addr[i] != addr2->s6_addr[i])	    return 0;    }    if (netsize%8 == 0)	return 1;    mask = 0xff << (8 - netsize%8);    return ((addr1->s6_addr[i]&mask) == (addr2->s6_addr[i]&mask));}/** * convert a netmask to an IPv6 network size * * If the netmask is NULL, 128 is returned. * * E.g. 255.255.255.0 is converted to 120 (the network is ::ffff:a.b.c.0 in this case) * * @param netmask string containing the netmask in traditional IPv4 notation * @return number of bits in the network part of the address (range 96...128, because the argument is IPv4) */int _mio_netmask_to_ipv6(const char *netmask){    struct in_addr addr;    if (netmask == NULL)    {	return 128;    }    if (inet_pton(AF_INET, netmask, &addr))    {	uint32_t temp = ntohl(addr.s_addr);	int netmask = 128;	while (netmask>96 && temp%2==0)	{	    netmask--;	    temp /= 2;	}	return netmask;    }    return atoi(netmask);}#endif/** * check if an IP address (IPv4 or IPv6) is allowed to connect * * @param address the address that should be checked * @return 1 if allowed by default, or IP inside an allowed network, 2 if explicitly allowed IP address, 0 if not allowed */int _mio_allow_check(const char *address){#ifdef WITH_IPV6    char temp_address[INET6_ADDRSTRLEN];    char temp_ip[INET6_ADDRSTRLEN];    static struct in_addr tmpa;#endif        xmlnode io = xmlnode_get_tag(greymatter__, "io");    xmlnode cur;#ifdef WITH_IPV6    if (inet_pton(AF_INET, address, &tmpa)) {	strcpy(temp_address, "::ffff:");	strcat(temp_address, address);	address = temp_address;    }#endif    if(xmlnode_get_tag(io, "allow") == NULL)        return 1; /* if there is no allow section, allow all */    for(cur = xmlnode_get_firstchild(io); cur != NULL; cur = xmlnode_get_nextsibling(cur))    {        char *ip, *netmask;#ifdef WITH_IPV6	struct in6_addr in_address, in_ip;	int in_netmask;#else        struct in_addr in_address, in_ip, in_netmask;#endif        if(xmlnode_get_type(cur) != NTYPE_TAG)            continue;        if(j_strcmp(xmlnode_get_name(cur), "allow") != 0)             continue;        ip = xmlnode_get_tag_data(cur, "ip");        netmask = xmlnode_get_tag_data(cur, "mask");        if(ip == NULL)            continue;#ifdef WITH_IPV6	if (inet_pton(AF_INET, ip, &tmpa))	{	    strcpy(temp_ip, "::ffff:");	    strcat(temp_ip, ip);	    ip = temp_ip;	}	inet_pton(AF_INET6, address, &in_address);#else        inet_aton(address, &in_address);#endif        if(ip != NULL)#ifdef WITH_IPV6	    inet_pton(AF_INET6, ip, &in_ip);#else            inet_aton(ip, &in_ip);#endif        if(netmask != NULL)        {#ifdef WITH_IPV6	    in_netmask = _mio_netmask_to_ipv6(netmask);	    if(_mio_compare_ipv6(&in_address, &in_ip, in_netmask))#else            inet_aton(netmask, &in_netmask);            if((in_address.s_addr & in_netmask.s_addr) == (in_ip.s_addr & in_netmask.s_addr))#endif            { /* this ip is in the allow network */                return 1;            }        }        else        {#ifdef WITH_IPV6	    if(_mio_compare_ipv6(&in_ip, &in_address, 128))#else            if(in_ip.s_addr == in_address.s_addr)#endif                return 2; /* exact matches hold greater weight */        }    }    /* deny the rest */    return 0;}/** * check if an IP address (IPv4 or IPv6) is forbitten to connect * * @param address the address that should be checked * @return 1 if forbidden by default, or IP inside an forbidden network, 2 if explicitly forbidden IP address, 0 if not allowed */int _mio_deny_check(const char *address){#ifdef WITH_IPV6    char temp_address[INET6_ADDRSTRLEN];    char temp_ip[INET6_ADDRSTRLEN];    static struct in_addr tmpa;#endif    xmlnode io = xmlnode_get_tag(greymatter__, "io");    xmlnode cur;#ifdef WITH_IPV6    if (inet_pton(AF_INET, address, &tmpa)) {	strcpy(temp_address, "::ffff:");	strcat(temp_address, address);	address = temp_address;    }#endif    if(xmlnode_get_tag(io, "deny") == NULL)        return 0; /* if there is no deny section, allow all */    for(cur = xmlnode_get_firstchild(io); cur != NULL; cur = xmlnode_get_nextsibling(cur))    {        char *ip, *netmask;#ifdef WITH_IPV6	struct in6_addr in_address, in_ip;	int in_netmask;#else        struct in_addr in_address, in_ip, in_netmask;#endif        if(xmlnode_get_type(cur) != NTYPE_TAG)            continue;        if(j_strcmp(xmlnode_get_name(cur), "deny") != 0)             continue;        ip = xmlnode_get_tag_data(cur, "ip");        netmask = xmlnode_get_tag_data(cur, "mask");        if(ip == NULL)            continue;#ifdef WITH_IPV6	if (inet_pton(AF_INET, ip, &tmpa))	{	    strcpy(temp_ip, ":ffff:");	    strcat(temp_ip, ip);	    ip = temp_ip;	}	inet_pton(AF_INET6, address, &in_address);#else        inet_aton(address, &in_address);#endif        if(ip != NULL)#ifdef WITH_IPV6	    inet_pton(AF_INET6, ip, &in_ip);#else            inet_aton(ip, &in_ip);#endif        if(netmask != NULL)        {#ifdef WITH_IPV6	    in_netmask = _mio_netmask_to_ipv6(netmask);	    if (_mio_compare_ipv6(&in_address, &in_ip, in_netmask))#else            inet_aton(netmask, &in_netmask);            if((in_address.s_addr & in_netmask.s_addr) == (in_ip.s_addr & in_netmask.s_addr))#endif            { /* this ip is in the deny network */                return 1;            }        }        else        {#ifdef WITH_IPV6	    if(_mio_compare_ipv6(&in_ip, &in_address, 128))#else            if(in_ip.s_addr == in_address.s_addr)#endif                return 2; /* must be an exact match, if no netmask */        }    }    return 0;}/** * callback for Heartbeat, increments karma, and signals the * select loop, whenever a socket's punishment is over * * @param arg unused/ignored * @return always r_DONE */result _karma_heartbeat(void*arg){    mio cur;    /* if there is nothing to do, just return */    if(mio__data == NULL || mio__data->master__list == NULL)         return r_DONE;    /* loop through the list, and add karma where appropriate */    for(cur = mio__data->master__list; cur != NULL; cur = cur->next)    {        if(cur->k.dec != 0)        { /* Karma is enabled for this connection */            int was_negative = 0;            /* don't update if we are closing, or pre-initilized */            if(cur->state == state_CLOSE || cur->k.init == 0)                 continue;                 /* if we are being punished, set the flag */            if(cur->k.val < 0) was_negative = 1;                  /* possibly increment the karma */            karma_increment( &cur->k );                 /* punishment is over */            if(was_negative && cur->k.val >= 0)  {               log_debug2(ZONE, LOGT_IO, "Punishment Over for socket %d: ", cur->fd);	       /* we don't have to signal again, if a signal is pending */	       if (mio__data->zzz_active <= 0) {		   mio__data->zzz_active++;		   pth_write(mio__data->zzz[1]," ",1);	       }            }        }    }    /* always return r_DONE, to keep getting heartbeats */    return r_DONE;}/**  * unlinks a socket from the master list  * * @param m socket that should be unlinked from mio__data->master__list */void _mio_unlink(mio m){    if(mio__data == NULL)         return;    if(mio__data->master__list == m)       mio__data->master__list = mio__data->master__list->next;    if(m->prev != NULL)         m->prev->next = m->next;    if(m->next != NULL)         m->next->prev = m->prev;}/**  * links a socket to the master list * * The new socket is inserted as the first list element, but you must not rely on this. * * @param m socket that should be linked to mio__data->master__list */void _mio_link(mio m){    if(mio__data == NULL)         return;    m->next = mio__data->master__list;    m->prev = NULL;    if(mio__data->master__list != NULL)         mio__data->master__list->prev = m;    mio__data->master__list = m;}/**  * Dump this socket's write queue. * * Tries to write * as much of the write queue as it can, before the * write call would block the server * * @param m the connection that should get it's write queue dumped * @return -1 on error, 0 on success, and 1 if more data to write */int _mio_write_dump(mio m){    int len;    mio_wbq cur;    /* try to write as much as we can */    while(m->queue != NULL)    {        cur = m->queue;        log_debug2(ZONE, LOGT_IO, "write_dump writing data: %.*s", cur->len, cur->cur);        /* write a bit from the current buffer */        len = (*m->mh->write)(m, cur->cur, cur->len);        /* we had an error on the write */        if(len == 0)        {            if(m->cb != NULL)                (*(mio_std_cb)m->cb)(m, MIO_ERROR, m->cb_arg);            return -1;        }        if(len < 0)        {             /* if we have an error, that isn't a blocking issue */             if(errno != EWOULDBLOCK && errno != EINTR && errno != EAGAIN &&               mio__errno != EAGAIN)            {                 /* bounce the queue */                if(m->cb != NULL)                    (*(mio_std_cb)m->cb)(m, MIO_ERROR, m->cb_arg);                return -1;            }            return 1;        }        /* we didnt' write it all, move the current buffer up */        else if(len < cur->len)        {             cur->cur += len;            cur->len -= len;            return 1;        }         /* we wrote the entire node, kill it and move on */        else        {              m->queue = m->queue->next;            if(m->queue == NULL)                m->tail = NULL;            pool_free(cur->p);        }    }     return 0;}/**  * internal close function  *  * does a final write of the queue, bouncing and freeing all memory * * @param m the connection that gets closed */void _mio_close(mio m){    int ret = 0;    xmlnode cur;    /* ensure that the state is set to CLOSED */    m->state = state_CLOSE;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -