/* ARISA - (de)Allocation and (de)Initialization Functions * Copyright (C) 2003, 2004 Carl Ritson * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "arisa.h" #include "script-eng.h" #include /** xalloc * Homogenised linkage to malloc, perhaps other system memory allocation * functions. * NOTE: This function is also intended handle allocation tracking and * an allocation cache at some point in the future if they are * deemed useful, hence xalloc'd memory must be xfree'd. */ inline void *xalloc(size_t size) { void *ptr = NULL; if(size > 0) { ptr = malloc(size); assert(ptr != NULL); //memset(ptr,0xAD,size); //memset(ptr,0,size); //fprintf(stderr,"xalloc(%d) = %p\n",size,ptr); } return ptr; } inline void *xalloc_zero(size_t size) { void *ptr = xalloc(size); if(ptr != NULL) memset(ptr,0,size); return ptr; } /** xreloc * Companion to xalloc, should be used in place of realloc when memory * has been xalloc'd. */ inline void *xreloc(void *ptr, size_t size) { return realloc(ptr,size); } /** xfree * All xalloc'd and xreloc'd memory should by freed with xfree not free. * See notes in xalloc for more information. */ inline void xfree(void *ptr) { assert(ptr != NULL); //fprintf(stderr,"xfree(%p)\n",ptr); free(ptr); } /** xstrdup * Companion to xalloc, for use with string duplication. */ inline char *xstrdup(const char *s) { char *ptr; assert(s != NULL); ptr = strdup(s); //fprintf(stderr,"xstrdup(%s) = %p\n",s,ptr); return ptr; } /*************************************************************************** * Allocation Functions * * Every core structure bar user_t has a allocator and de-allocator here. * * These take the form: * alloc_ * and free_ * * alloc_ functions allocate and correctly initialise a structure of the * type and return a pointer to it, some take one or more arguments used to * determine the sub type of a structure to initialise. * * free_ functions do the opposite of alloc_ functions and correctly * de-initialise and free a structure. They return nothing. * ****************************************************************************/ settings_t *alloc_settings(void) { settings_t *s = xalloc(sizeof(settings_t)); LOCK_INIT(&(s->lock)); s->config = NULL; s->pid = NULL; s->log = NULL; s->admin_socket = NULL; s->hash_packs = 1; s->list_frequency = 300; s->log_interval = 30; s->autosave_interval = 15 * 60; s->tick_interval = 5 * 60; s->hashing_io_usage = 50; s->scripts = NULL; s->no_scripts = 0; return s; } void free_settings(settings_t *s) { int i; LOCK_FREE(&(s->lock)); if(s->config != NULL) xfree(s->config); if(s->pid != NULL) xfree(s->pid); if(s->log != NULL) xfree(s->log); if(s->admin_socket != NULL) xfree(s->admin_socket); if(s->scripts != NULL) { for(i = 0; i < s->no_scripts; ++i) xfree(s->scripts[i]); xfree(s->scripts); } xfree(s); } netset_t *alloc_netset(void) { netset_t *n = xalloc(sizeof(netset_t)); n->nick = NULL; n->loginname = NULL; n->realname = NULL; n->message_rate = 0.5; n->message_rate_max = 2; n->recv_per_sec = 100; n->average_window = 30; n->max_target = 1; n->irc_timeout = 300; n->on_connect_delay = 5; n->join_delay = 5; n->reconnect_delay = 90; n->no_autoconnect = 0; n->nick_tracking = 1; n->bind_ip = NULL; n->info_line = NULL; n->taglines = NULL; n->no_taglines = 0; return n; } void free_netset(netset_t *n) { int i; if(n->nick != NULL) xfree(n->nick); if(n->loginname != NULL) xfree(n->loginname); if(n->realname != NULL) xfree(n->realname); if(n->bind_ip != NULL) xfree(n->bind_ip); if(n->info_line != NULL) xfree(n->info_line); if(n->taglines != NULL) { for(i = 0; i < n->no_taglines; ++i) xfree(n->taglines[i]); xfree(n->taglines); } xfree(n); } global_t *alloc_global(void) { global_t *g = xalloc(sizeof(global_t)); int tmp[2] = { -1, -1 }; LOCK_INIT(&(g->lock)); pipe(tmp); g->end = 0; g->end_time = 0; g->signal_in = tmp[1]; g->signal_out = tmp[0]; thread_init(&(g->hash_thread)); thread_init(&(g->log_thread)); g->networks = NULL; g->no_networks = 0; g->interfaces = NULL; g->no_interfaces= 0; g->queues = NULL; g->no_queues = 0; g->packlists = NULL; g->no_packlists = 0; g->users = NULL; g->no_users = 0; g->admins = NULL; g->no_admins = 0; LOCK_INIT(&(g->log_subs.lock)); g->log_subs.subs = NULL; g->log_subs.no_subs = 0; g->log_subs.fd = -1; LOCK_INIT(&(g->hashing.lock)); g->hashing.reqs = NULL; LOCK_INIT(&(g->party_line.lock)); g->party_line.subs = NULL; g->party_line.no_subs = 0; LOCK_INIT(&(g->se.lock)); g->se.interpreters = NULL; g->se.no_interpreters = 0; g->aresolver = aresolv_init(); g->ignore_list = alloc_ignore_list(); g->ignore_list->log = 1; g->ignore_list->trigger = 10; g->ignore_list->period = 300; g->pack_cache = pack_cache_init(); g->settings = alloc_settings(); g->network_settings = alloc_netset(); return g; } void free_global(global_t *g) { int i; LOCK_FREE(&(g->lock)); LOCK_FREE(&(g->log_subs.lock)); LOCK_FREE(&(g->hashing.lock)); LOCK_FREE(&(g->party_line.lock)); LOCK_FREE(&(g->se.lock)); thread_free(&(g->hash_thread)); thread_free(&(g->log_thread)); if(g->signal_in != -1) close(g->signal_in); if(g->signal_out != -1) close(g->signal_out); for(i = 0; i < g->no_networks; ++i) free_network(g->networks[i]); if(g->networks != NULL) xfree(g->networks); for(i = 0; i < g->no_interfaces; ++i) free_interface(g->interfaces[i]); if(g->interfaces != NULL) xfree(g->interfaces); for(i = 0; i < g->no_queues; ++i) free_queue(g->queues[i]); if(g->queues != NULL) xfree(g->queues); for(i = 0; i < g->no_packlists; ++i) free_packlist(g->packlists[i]); if(g->packlists != NULL) xfree(g->packlists); for(i = 0; i < g->no_admins; ++i) free_chat(g->admins[i]); if(g->admins != NULL) xfree(g->admins); if(g->log_subs.subs != NULL) xfree(g->log_subs.subs); if(g->party_line.subs != NULL) xfree(g->party_line.subs); if(g->se.interpreters != NULL) { for(i = 0; i < g->se.no_interpreters; ++i) free_interpreter(g->se.interpreters[i]); xfree(g->se.interpreters); } aresolv_free(g->aresolver); free_ignore_list(g->ignore_list); pack_cache_free(g->pack_cache); free_settings(g->settings); free_netset(g->network_settings); xfree(g); } netinfo_t *alloc_netinfo(void) { netinfo_t *n = xalloc(sizeof(netinfo_t)); LOCK_INIT(&(n->lock)); n->nick = NULL; n->server = NULL; n->password = NULL; n->self_ip = 0; n->port = 0; n->connected = 0; pqueue_init(&n->p_squeue,1); pqueue_init(&n->j_squeue,1); pqueue_init(&n->d_squeue,1); pqueue_init(&n->r_squeue,1); n->nick_tracker = nickhash_init(); return n; } void free_netinfo(netinfo_t *n) { LOCK_FREE(&(n->lock)); if(n->nick != NULL) xfree(n->nick); if(n->server != NULL) xfree(n->server); pqueue_deinit(&n->p_squeue,xfree,1); pqueue_deinit(&n->j_squeue,xfree,1); pqueue_deinit(&n->d_squeue,xfree,1); pqueue_deinit(&n->r_squeue,xfree,1); nickhash_free(n->nick_tracker); xfree(n); } /** alloc_network * Allocates a network structure and nested netset_t structure, the * netset_t structure is duplicated from the argument is not NULL. */ network_t *alloc_network(netset_t *master_settings) { network_t *n = xalloc(sizeof(network_t)); LOCK_INIT(&(n->lock)); n->deleted = 0; thread_init(&(n->thread)); n->name = NULL; n->info = NULL; n->state = NETWORK_OFFLINE; if(master_settings != NULL) { n->settings = alloc_netset(); memcpy(n->settings,master_settings,sizeof(netset_t)); n->settings->nick = xstrdup(master_settings->nick); n->settings->loginname = xstrdup(master_settings->loginname); n->settings->realname = xstrdup(master_settings->realname); if(master_settings->bind_ip != NULL) n->settings->bind_ip = xstrdup(master_settings->bind_ip); if(master_settings->info_line != NULL) n->settings->info_line = xstrdup(master_settings->info_line); } else { n->settings = NULL; } n->servers = NULL; n->no_servers = 0; n->channels = NULL; n->no_channels = 0; n->on_connects = NULL; n->no_on_connects = 0; n->listeners = NULL; n->no_listeners = 0; return n; } void free_network(network_t *n) { int i; LOCK_FREE(&(n->lock)); thread_free(&(n->thread)); if(n->name != NULL) xfree(n->name); if(n->info != NULL) free_netinfo(n->info); if(n->settings != NULL) free_netset(n->settings); for(i = 0; i < n->no_servers; ++i) xfree(n->servers[i]); if(n->servers != NULL) xfree(n->servers); for(i = 0; i < n->no_channels; ++i) free_channel(n->channels[i]); if(n->channels != NULL) xfree(n->channels); for(i = 0; i < n->no_on_connects; ++i) xfree(n->on_connects[i]); if(n->on_connects != NULL) xfree(n->on_connects); if(n->listeners != NULL) xfree(n->listeners); xfree(n); } channel_t *alloc_channel(void) { channel_t *c = xalloc(sizeof(channel_t)); LOCK_INIT(&(c->lock)); c->deleted = 0; c->name = NULL; c->key = NULL; c->joined = 0; c->nolist = 0; c->plist = 0; c->track_key = 1; c->pformat = PFORMAT_SUMMARY; c->last_plist = 0; c->taglines = NULL; c->no_taglines = 0; c->listeners = NULL; c->no_listeners = 0; c->mode = NULL; c->topic = NULL; c->limit = 0; c->bans = NULL; c->no_bans = 0; return c; } void free_channel(channel_t *c) { int i; LOCK_FREE(&(c->lock)); if(c->name != NULL) xfree(c->name); if(c->key != NULL) xfree(c->key); for(i = 0; i < c->no_taglines; ++i) xfree(c->taglines[i]); if(c->taglines != NULL) xfree(c->taglines); if(c->listeners != NULL) xfree(c->listeners); if(c->mode != NULL) xfree(c->mode); if(c->topic != NULL) xfree(c->topic); for(i = 0; i < c->no_bans; ++i) xfree(c->bans[i]); if(c->bans != NULL) xfree(c->bans); xfree(c); } send_t *alloc_send(void) { send_t *s = xalloc(sizeof(send_t)); int i; LOCK_INIT(&(s->lock)); s->pack = NULL; s->host = NULL; s->nick = NULL; s->network = NULL; s->state = STATE_UNKNOWN; s->pool = NULL; s->queue = NULL; s->retries = 0; s->started = 0; s->connected = 0; s->last_contact = 0; for(i = 0; i < AVGSPEED; ++i) s->avgspeed[i] = 0; s->pos = 0; s->bytes_sent = 0; s->reason = NULL; s->aux = NULL; return s; } void free_send(send_t *s) { LOCK_FREE(&(s->lock)); if(s->pack != NULL) free_pack(s->pack); if(s->host != NULL) xfree(s->host); if(s->nick != NULL) xfree(s->nick); if(s->reason != NULL) xfree(s->reason); xfree(s); } /** alloc_interface * Allocates and initialises an interface_t structure of the type * specified by the argument. Types: * INTERFACE_SEND, INTERFACE_RECV, INTERFACE_CHAT */ interface_t *alloc_interface(const interfacetype_t type) { interface_t *i = xalloc(sizeof(interface_t)); int j; LOCK_INIT(&(i->lock)); thread_init(&(i->thread)); i->name = NULL; i->deleted = 0; i->type = type; i->mode = IMODE_NORMAL; i->def = 0; i->bandwidth = 0; i->advertise_ip = NULL; i->bind_ip = NULL; i->accept_per_sec = 1; i->secure_mode = 0; i->dcc_port = 0; i->no_ports = 0; i->dccserver_port = 0; i->dcc_timeout = 180; i->dcc_packet = 4096; i->record_rate = 0; i->stat_mib = 0; i->stat_carry = 0; for(j = 0; j < AVGSPEED; ++j) i->avgspeed[j] = 0; if(type == INTERFACE_SEND) { i->send.pools = NULL; i->send.no_pools = 0; } else if(type == INTERFACE_RECV) { i->recv.dir = NULL; i->recv.access = alloc_access(); i->recv.access->flags = ACCESS_DENY; i->recv.uploads = NULL; i->recv.no_uploads = 0; i->recv.max_no_uploads = 1; i->recv.max_size = 0; } else if(type == INTERFACE_CHAT) { i->dcc_packet = 512; i->chat.max_no = 5; i->chat.chats = NULL; i->chat.no_chats = 0; } return i; } void free_interface(interface_t *i) { int j; LOCK_FREE(&(i->lock)); thread_free(&(i->thread)); if(i->name != NULL) xfree(i->name); if(i->advertise_ip != NULL) xfree(i->advertise_ip); if(i->bind_ip != NULL) xfree(i->bind_ip); if(i->type == INTERFACE_SEND) { for(j = 0; j < i->send.no_pools; ++j) free_pool(i->send.pools[j]); if(i->send.pools != NULL) xfree(i->send.pools); } else if(i->type == INTERFACE_RECV) { if(i->recv.dir != NULL) xfree(i->recv.dir); free_access(i->recv.access); for(j = 0; j < i->recv.no_uploads; ++j) free_send(i->recv.uploads[j]); if(i->recv.uploads != NULL) xfree(i->recv.uploads); } else if(i->type == INTERFACE_CHAT) { for(j = 0; j < i->chat.no_chats; ++j) free_chat(i->chat.chats[j]); if(i->chat.chats != NULL) xfree(i->chat.chats); } xfree(i); } pool_t *alloc_pool(void) { pool_t *p = xalloc(sizeof(pool_t)); int i; LOCK_INIT(&(p->lock)); p->name = NULL; p->deleted = 0; p->state = STATE_UNKNOWN; p->csends = NULL; p->no_csends = 0; p->sends = 1; p->bandwidth = 0; p->send_max_bandwidth = 0; p->send_min_bandwidth = 0; p->sends_per_user = 1; p->dequeue_algorithm = 2; p->record_send = 0; p->record_rate = 0; p->stat_mib = 0; p->stat_carry = 0; for(i = 0; i < AVGSPEED; ++i) p->avgspeed[i] = 0; return p; } void free_pool(pool_t *p) { int i; LOCK_FREE(&(p->lock)); if(p->name != NULL) xfree(p->name); for(i = 0; i < p->no_csends; ++i) free_send(p->csends[i]); if(p->csends != NULL) xfree(p->csends); xfree(p); } queue_t *alloc_queue(void) { queue_t *q = xalloc(sizeof(queue_t)); LOCK_INIT(&(q->lock)); q->name = NULL; q->deleted = 0; q->pool = NULL; q->qsends = NULL; q->no_qsends = 0; q->notify = 0; q->length = 0; q->queues_per_user = 0; q->overflow_requeue = 0; q->priority = 1; q->priority_queues = 0; q->combined_queue_limit = 0; q->bypass_size = 0; q->last_notify = 0; q->last_dequeue = 0; q->last_checked = 0; return q; } void free_queue(queue_t *q) { int i; LOCK_FREE(&(q->lock)); if(q->name != NULL) xfree(q->name); for(i = 0; i < q->no_qsends; ++i) free_send(q->qsends[i]); if(q->qsends != NULL) xfree(q->qsends); xfree(q); } packlist_t *alloc_packlist(void) { packlist_t *p = xalloc(sizeof(packlist_t)); LOCK_INIT(&(p->lock)); p->name = NULL; p->deleted = 0; p->type = LIST_NORMAL; p->response = RESPONSE_NOTICE; p->chat_interface = NULL; p->queue = NULL; p->packs = NULL; p->no_packs = 0; p->dirs = NULL; p->no_dirs = 0; p->access = alloc_access(); p->nolist = 0; p->nolist_reason= NULL; p->nosend = 0; p->nosend_reason= NULL; p->taglines = NULL; p->no_taglines = 0; p->ignore_list = alloc_ignore_list(); p->time_limit = 300; p->command_limit = 10; p->retries = 0; p->auto_sort = 0; p->dir_scan_interval = 0; p->scan_depth = 1; p->last_scan = 0; p->hash_display = HASH_CRC_AND_MD5; p->ignore_list->trigger = 1; if(global != NULL) { // can be NULL during init LOCK(global->settings); p->ignore_list->period = global->settings->list_frequency; UNLOCK(global->settings); } else { // no global means this should be overwritten by loadsave code p->ignore_list->period = 300; } p->filters = NULL; p->no_filters = 0; return p; } void free_packlist(packlist_t *p) { int i; LOCK_FREE(&(p->lock)); if(p->name != NULL) xfree(p->name); if(p->packs != NULL) { for(i = 0; i < p->no_packs; ++i) free_pack(p->packs[i]); xfree(p->packs); } if(p->dirs != NULL) { for(i = 0; i < p->no_dirs; ++i) xfree(p->dirs[i]); xfree(p->dirs); } free_access(p->access); if(p->nolist_reason != NULL) xfree(p->nolist_reason); if(p->nosend_reason != NULL) xfree(p->nosend_reason); if(p->taglines != NULL) { for(i = 0; i < p->no_taglines; ++i) xfree(p->taglines[i]); xfree(p->taglines); } free_ignore_list(p->ignore_list); if(p->filters != NULL) { for(i = 0; i < p->no_filters; ++i) xfree(p->filters[i]); xfree(p->filters); } xfree(p); } pack_t *alloc_pack(void) { pack_t *p = xalloc(sizeof(pack_t)); LOCK_RW_INIT(&(p->lock)); p->ref_count = 1; p->size = 0; p->file = NULL; p->label = NULL; p->md5 = NULL; p->crc = NULL; p->hashed = 0; p->no_gets = 0; // Pack Cache Fields p->next = NULL; p->prev = NULL; p->hash = 0; return p; } void free_pack(pack_t *p) { pack_deref(p); } void free_pack_real(pack_t *p) { assert(p->ref_count == 0); LOCK_RW_FREE(&(p->lock)); if(p->file != NULL) xfree(p->file); if(p->label != NULL) xfree(p->label); if(p->md5 != NULL) xfree(p->md5); if(p->crc != NULL) xfree(p->crc); xfree(p); } /** alloc_chat * Allocates and initialises a chat_t structure of the type specified by * the argument, CHAT_ADMIN or CHAT_LIST. */ chat_t *alloc_chat(chattype_t type) { chat_t *c = xalloc(sizeof(chat_t)); LOCK_INIT(&(c->lock)); c->type = type; c->colour = COLOUR_NONE; c->state = STATE_UNKNOWN; c->nick = NULL; c->network = NULL; c->host = NULL; c->hostmask = NULL; pqueue_init(&(c->msgqueue),1); c->started = 0; c->connected = 0; c->last_contact = 0; c->reason = NULL; c->aux = NULL; if(type == CHAT_LIST) { c->list.commands = 0; c->list.packlist = NULL; } else if(type == CHAT_ADMIN) { thread_init(&(c->admin.thread)); c->admin.user = NULL; } return c; } void free_chat(chat_t *c) { LOCK_FREE(&(c->lock)); if(c->nick != NULL) xfree(c->nick); if(c->host != NULL) xfree(c->host); if(c->type == CHAT_ADMIN) thread_free(&(c->admin.thread)); if(c->reason != NULL) xfree(c->reason); pqueue_deinit(&c->msgqueue,xfree,1); } interpreter_t *alloc_interpreter(void) { interpreter_t *i = xalloc(sizeof(interpreter_t)); LOCK_INIT(&(i->lock)); thread_init(&(i->thread)); i->name = NULL; i->func = NULL; i->flags = 0; pqueue_init(&i->msgqueue,1); i->loaded = NULL; i->no_loaded = 0; i->types = NULL; i->no_types = 0; return i; } void free_interpreter(interpreter_t *i) { LOCK_FREE(&(i->lock)); thread_free(&(i->thread)); if(i->name != NULL) xfree(i->name); if(i->loaded != NULL) strarr_free(&(i->loaded),&(i->no_loaded)); if(i->types != NULL) strarr_free(&(i->types),&(i->no_types)); pqueue_deinit(&(i->msgqueue),(void (*)(void *))free_msg,1); xfree(i); } access_entry_t *alloc_access_entry(void) { access_entry_t *ent = xalloc_zero(sizeof(access_entry_t)); ent->flags = ACCESS_SMART; ent->mode = MODE_REG; ent->network = NULL; ent->channel = NULL; ent->host = NULL; return ent; } void free_access_entry(access_entry_t *ent) { if(ent->host != NULL) xfree(ent->host); xfree(ent); } access_t *alloc_access(void) { access_t *a = xalloc_zero(sizeof(access_t)); LOCK_INIT(&(a->lock)); a->flags = ACCESS_SMART; a->entries = NULL; a->no_entries = 0; return a; } void free_access(access_t *a) { LOCK_FREE(&(a->lock)); if(a->entries != NULL) { int i; for(i = 0; i < a->no_entries; ++i) free_access_entry(a->entries[i]); xfree(a->entries); } xfree(a); }