예제 #1
0
파일: wrapper.c 프로젝트: liwcezar/atrinik
/**
 * Get absolute path to the specified relative path. This path will typically
 * point to the to client data directory (which is usually located in the user's
 * home/appdata directory), but depending on the specified mode, extra actions
 * may be performed. These ensure that if you're trying to access a file that
 * does not yet exist in the client data directory, it will be read from the
 * client installation directory instead (unless it's being appended to, in
 * which case it will be copied to the client data directory first).
 *
 * Generally, you should almost always use this when you need to construct a
 * path, or use one of the many @ref file_wrapper_functions.
 * @param fname
 * The file path.
 * @param mode
 * File mode.
 * @return
 * The absolute path. Must be freed.
 */
char *file_path(const char *path, const char *mode)
{
    bool is_write, is_append;
    StringBuffer *sb;
    char version[MAX_BUF], client_path[HUGE_BUF], *new_path;

    HARD_ASSERT(path != NULL);
    HARD_ASSERT(mode != NULL);

    SOFT_ASSERT_RC(path[0] != '/', estrdup(path),
            "Path is already absolute: %s", path);

    sb = stringbuffer_new();
    stringbuffer_append_printf(sb, "%s/.atrinik/%s/%s", get_config_dir(),
            package_get_version_partial(VS(version)), path);
    new_path = stringbuffer_sub(sb, 0, 0);

    is_write = is_append = false;

    if (strchr(mode, 'w') != NULL) {
        is_write = true;
    } else if (strchr(mode, '+') != NULL || strchr(mode, 'a') != NULL) {
        is_append = true;
    }

    if (is_write || is_append) {
        if (access(new_path, W_OK) != 0) {
            char *dirname;

            /* Ensure directories exist if we're going to use this path for
             * writing/appending. */
            dirname = path_dirname(new_path);
            mkdir_recurse(dirname);
            efree(dirname);

            if (is_append) {
                get_data_dir_file(VS(client_path), path);
                copy_file(client_path, new_path);
            }
        }
    } else {
        if (access(new_path, R_OK) != 0) {
            get_data_dir_file(VS(client_path), path);
            stringbuffer_seek(sb, 0);
            stringbuffer_append_string(sb, client_path);
        }
    }

    efree(new_path);

    return stringbuffer_finish(sb);
}
예제 #2
0
파일: item.c 프로젝트: atrinik/atrinik
void object_redraw(object *op)
{
    object *env;

    HARD_ASSERT(op != NULL);

    if (op->env == NULL) {
        return;
    }

    env = op->env;

    if (env == cpl.sack) {
        env = cpl.sack->env;
    }

    if (env == cpl.interface) {
        interface_redraw();
    } else if (env == cpl.below) {
        widget_redraw_type_id(INVENTORY_ID, "below");
    } else {
        widget_redraw_type_id(INVENTORY_ID, "main");
        /* TODO: This could be more sophisticated... */
        WIDGET_REDRAW_ALL(QUICKSLOT_ID);
    }
}
예제 #3
0
파일: wrapper.c 프로젝트: liwcezar/atrinik
/**
 * Removes all the files in the specified directory.
 *
 * @param dir
 * The directory.
 * @param path
 * Path to the directory.
 */
static void
_rmrf (DIR *dir, const char *path)
{
    HARD_ASSERT(dir != NULL);

    struct dirent *file;
    while ((file = readdir(dir)) != NULL) {
        if (strcmp(file->d_name, ".") == 0 ||
            strcmp(file->d_name, "..") == 0) {
            continue;
        }

        char buf[HUGE_BUF];
        snprintf(VS(buf), "%s/%s", path, file->d_name);

        DIR *dir2 = opendir(buf);
        if (dir2 != NULL) {
            _rmrf(dir2, buf);
            closedir(dir2);
            rmdir(buf);
        } else {
            unlink(buf);
        }
    }
}
예제 #4
0
/**
 * Free the specified server certificate information structure.
 *
 * @param info
 * What to free.
 */
static void
metaserver_cert_free (server_cert_info_t *info)
{
    HARD_ASSERT(info != NULL);

    if (info->name != NULL) {
        efree(info->name);
    }

    if (info->hostname != NULL) {
        efree(info->hostname);
    }

    if (info->ipv4_address != NULL) {
        efree(info->ipv4_address);
    }

    if (info->ipv6_address != NULL) {
        efree(info->ipv6_address);
    }

    if (info->pubkey != NULL) {
        efree(info->pubkey);
    }

    efree(info);
}
예제 #5
0
파일: sprite.c 프로젝트: liwcezar/atrinik
/**
 * Free the specified sprite cache entry.
 * @param cache
 */
static void
sprite_cache_free (sprite_cache_t *cache)
{
    HARD_ASSERT(cache != NULL);

    efree(cache->name);
    SDL_FreeSurface(cache->surface);
    efree(cache);
}
예제 #6
0
/**
 * Updates all network graph widgets with new data.
 * @param type
 * The network graph type.
 * @param traffic
 * The traffic type (tx/rx).
 * @param bytes
 * Bytes.
 * @note This function is thread-safe.
 */
void network_graph_update(int type, int traffic, size_t bytes)
{
    HARD_ASSERT(type >= 0 && type < NETWORK_GRAPH_TYPE_MAX);
    HARD_ASSERT(traffic >= 0 && traffic < NETWORK_GRAPH_TRAFFIC_MAX);

    if (network_graph_mutex == NULL) {
        return;
    }

    network_graph_work_t *work = ecalloc(1, sizeof(*work));
    work->type = type;
    work->traffic = traffic;
    work->bytes = bytes;

    SDL_LockMutex(network_graph_mutex);
    LL_PREPEND(work_queue, work);
    SDL_UnlockMutex(network_graph_mutex);
}
예제 #7
0
파일: mempool.c 프로젝트: atrinik/atrinik
/**
 * Construct debug information about leaked chunks in the specified pool.
 *
 * @param pool
 * Memory pool.
 * @param sb
 * StringBuffer instance to store the information in.
 */
static void
mempool_leak_info(mempool_struct *pool, StringBuffer *sb)
{
    size_t chunksize_real, nrof_arrays, i, j;
    char buf[HUGE_BUF];
    mempool_puddle_struct *puddle;
    mempool_chunk_struct *chunk;
    void *data;

    HARD_ASSERT(pool != NULL);
    HARD_ASSERT(sb != NULL);

#ifndef NDEBUG
    if (pool->debugger == NULL) {
#else
    {
#endif
        snprintf(VS(buf), "no debug information available");
    }
예제 #8
0
파일: sprite.c 프로젝트: liwcezar/atrinik
/**
 * Create a new sprite cache entry.
 *
 * @param name
 * Name of the cache entry.
 * @return
 * Created sprite entry.
 */
static sprite_cache_t *
sprite_cache_create (const char *name)
{
    HARD_ASSERT(name != NULL);

    sprite_cache_t *cache = ecalloc(1, sizeof(*cache));
    cache->name = estrdup(name);
    cache->last_used = time(NULL);
    return cache;
}
예제 #9
0
파일: wrapper.c 프로젝트: liwcezar/atrinik
/**
 * Create a path to the per-server settings directory.
 * @param path
 * Path inside the per-server settings directory.
 * @return
 * New path. Must be freed.
 */
char *file_path_server(const char *path)
{
    StringBuffer *sb;

    HARD_ASSERT(path != NULL);

    sb = file_path_server_internal();
    stringbuffer_append_printf(sb, ".common/%s", path);

    return stringbuffer_finish(sb);
}
예제 #10
0
/**
 * Verify resolved address of a server against the server's metaserver
 * certificate.
 *
 * @param server
 * Server to verify.
 * @param host
 * Host address.
 * @return
 * True if the resolved address is equal to the one in the certificate,
 * false otherwise.
 */
bool
metaserver_cert_verify_host (server_struct *server, const char *host)
{
    HARD_ASSERT(server != NULL);
    HARD_ASSERT(host != NULL);

    /* No certificate, nothing to verify. */
    if (server->cert_info == NULL) {
        return true;
    }

    struct sockaddr_storage addr;
    SOFT_ASSERT_RC(socket_host2addr(host, &addr), false,
                   "Failed to convert host to IP address");

    switch (addr.ss_family) {
    case AF_INET:
        if (strcmp(host, server->cert_info->ipv4_address) != 0) {
            LOG(ERROR, "!!! Certificate IPv4 address error: %s != %s !!!",
                host, server->cert_info->ipv4_address);
            return false;
        }

        break;

    case AF_INET6:
        if (strcmp(host, server->cert_info->ipv6_address) != 0) {
            LOG(ERROR, "!!! Certificate IPv6 address error: %s != %s !!!",
                host, server->cert_info->ipv6_address);
            return false;
        }

        break;

    default:
        LOG(ERROR, "!!! Unknown address family %u !!!", addr.ss_family);
        return false;
    }

    return true;
}
예제 #11
0
파일: labels_ref.c 프로젝트: Julow/Corewar
void			labels_ref_solve(t_dstr *bcode, t_asm_bytecode const *b)
{
	t_label_ref const	*ref;
	uint32_t const		*loc;

	ref = VECTOR_IT(b->labels_ref);
	while (VECTOR_NEXT(b->labels_ref, ref))
	{
		loc = ft_hmapget(b->labels_loc, ref->name).value;
		HARD_ASSERT(loc != NULL);
		put_loc(bcode, ref->offset, *loc - ref->instr_begin, ref->short_value);
	}
}
예제 #12
0
파일: wrapper.c 프로젝트: liwcezar/atrinik
/**
 * Recursively remove a directory and its contents.
 *
 * Effectively same as 'rf -rf path'.
 *
 * @param path
 * What to remove.
 */
void rmrf(const char *path)
{
    HARD_ASSERT(path != NULL);

    DIR *dir = opendir(path);
    if (dir == NULL) {
        return;
    }

    _rmrf(dir, path);
    closedir(dir);
    rmdir(path);
}
예제 #13
0
파일: socket.c 프로젝트: liwcezar/atrinik
/**
 * Open a new socket.
 * @param csock
 * Socket to open.
 * @param host
 * Host to connect to.
 * @param port
 * Port to connect to.
 * @param secure
 * Whether the port is the secure port.
 * @return
 * True on success, false on failure.
 */
bool
client_socket_open (client_socket_t *csock,
                    const char      *host,
                    int              port,
                    bool             secure)
{
    HARD_ASSERT(csock != NULL);
    HARD_ASSERT(host != NULL);

    csock->sc = socket_create(host, port, secure, SOCKET_ROLE_CLIENT, false);
    if (csock->sc == NULL) {
        return false;
    }

    if (!socket_connect(csock->sc)) {
        goto error;
    }

    if (!socket_opt_linger(csock->sc, true, 5)) {
        goto error;
    }

    if (setting_get_int(OPT_CAT_CLIENT, OPT_MINIMIZE_LATENCY)) {
        if (!socket_opt_ndelay(csock->sc, true)) {
            goto error;
        }
    }

    if (!socket_opt_recv_buffer(csock->sc, 65535)) {
        goto error;
    }

    return true;

error:
    socket_destroy(csock->sc);
    csock->sc = NULL;
    return false;
}
예제 #14
0
파일: sprite.c 프로젝트: liwcezar/atrinik
/**
 * Find a sprite in the sprite cache.
 *
 * @param name
 * Name of the sprite to find.
 * @return
 * Sprite if found, NULL otherwise.
 */
static sprite_cache_t *
sprite_cache_find (const char *name)
{
    HARD_ASSERT(name != NULL);

    sprite_cache_t *cache;
    HASH_FIND_STR(sprites_cache, name, cache);

    if (cache != NULL) {
        cache->last_used = time(NULL);
    }

    return cache;
}
예제 #15
0
파일: wrapper.c 프로젝트: liwcezar/atrinik
/**
 * Create a path to the per-player settings directory.
 * @param path
 * Path inside the per-player settings directory.
 * @return
 * New path. Must be freed.
 */
char *file_path_player(const char *path)
{
    StringBuffer *sb;

    HARD_ASSERT(path != NULL);

    sb = file_path_server_internal();

    SOFT_ASSERT_LABEL(*cpl.account != '\0', done, "Account name is empty.");
    SOFT_ASSERT_LABEL(*cpl.name != '\0', done, "Player name is empty.");

    stringbuffer_append_printf(sb, "%s/%s/%s", cpl.account, cpl.name, path);

done:
    return stringbuffer_finish(sb);
}
예제 #16
0
파일: socket.c 프로젝트: liwcezar/atrinik
/**
 * Close a client socket.
 * @param csock
 * Socket to close.
 */
void client_socket_close(client_socket_t *csock)
{
    HARD_ASSERT(csock != NULL);

    SDL_LockMutex(socket_mutex);

    if (csock->sc != NULL) {
        socket_destroy(csock->sc);
        csock->sc = NULL;
    }

    abort_thread = 1;

    /* Poke anyone waiting at a cond */
    SDL_CondSignal(input_buffer_cond);
    SDL_CondSignal(output_buffer_cond);

    SDL_UnlockMutex(socket_mutex);
}
예제 #17
0
bool			parse_opt_ui(t_parse_argv *argv)
{
	t_sub			val;

	if (!ARGV_HAS_VALUE(&argv->args))
		argv->ui_type = UI_NCURSES;
	else
	{
		if (!ft_argv_arg(&argv->args, &val))
			HARD_ASSERT(false);
		if (SUB_EQU(val, SUBC("ncurses")))
			argv->ui_type = UI_NCURSES;
		else if (SUB_EQU(val, SUBC("debug")))
			argv->ui_type = UI_DEBUG;
		else
		{
			PARSE_ARGV_ERR("Invalid ui mode '%ts'", val);
			return (false);
		}
	}
	return (true);
}
예제 #18
0
/**
 * Free the specified metaserver server node.
 *
 * @param server
 * Node to free.
 */
static void
metaserver_free (server_struct *server)
{
    HARD_ASSERT(server != NULL);

    if (server->hostname != NULL) {
        efree(server->hostname);
    }

    if (server->name != NULL) {
        efree(server->name);
    }

    if (server->version != NULL) {
        efree(server->version);
    }

    if (server->desc != NULL) {
        efree(server->desc);
    }

    if (server->cert_pubkey != NULL) {
        efree(server->cert_pubkey);
    }

    if (server->cert != NULL) {
        efree(server->cert);
    }

    if (server->cert_sig != NULL) {
        efree(server->cert_sig);
    }

    if (server->cert_info != NULL) {
        metaserver_cert_free(server->cert_info);
    }

    efree(server);
}
예제 #19
0
파일: socket.c 프로젝트: liwcezar/atrinik
void socket_send_packet(struct packet_struct *packet)
{
    HARD_ASSERT(packet != NULL);

    if (csocket.sc == NULL) {
        packet_free(packet);
        return;
    }

    packet_struct *packet_meta = packet_new(0, 4, 0);
    if (socket_is_secure(csocket.sc)) {
        bool checksum_only = !socket_crypto_client_should_encrypt(packet->type);
        packet = socket_crypto_encrypt(csocket.sc,
                                       packet,
                                       packet_meta,
                                       checksum_only);
        if (packet == NULL) {
            /* Logging already done. */
            cpl.state = ST_START;
            return;
        }
    } else {
        packet_append_uint16(packet_meta, packet->len + 1);
        packet_append_uint8(packet_meta, packet->type);
    }

    command_buffer *buf1 = command_buffer_new(packet_meta->len,
                                              packet_meta->data);
    packet_free(packet_meta);
    command_buffer *buf2 = command_buffer_new(packet->len,
                                              packet->data);
    packet_free(packet);

    SDL_LockMutex(output_buffer_mutex);
    command_buffer_enqueue(buf1, &output_queue_start, &output_queue_end);
    command_buffer_enqueue(buf2, &output_queue_start, &output_queue_end);
    SDL_CondSignal(output_buffer_cond);
    SDL_UnlockMutex(output_buffer_mutex);
}
예제 #20
0
/**
 * Parse metaserver 'server' node.
 *
 * @param node
 * Node to parse.
 */
static void
parse_metaserver_node (xmlNodePtr node)
{
    HARD_ASSERT(node != NULL);

    server_struct *server = ecalloc(1, sizeof(*server));
    server->port_crypto = -1;
    server->is_meta = true;

    for (xmlNodePtr tmp = node->children; tmp != NULL; tmp = tmp->next) {
        if (!parse_metaserver_data_node(tmp, server)) {
            goto error;
        }
    }

    if (server->hostname == NULL ||
        server->port == 0 ||
        server->name == NULL ||
        server->version == NULL ||
        server->desc == NULL) {
        LOG(ERROR, "Incomplete data from metaserver");
        goto error;
    }

    if (!parse_metaserver_cert(server)) {
        /* Logging already done */
        goto error;
    }

    SDL_LockMutex(server_head_mutex);
    DL_PREPEND(server_head, server);
    server_count++;
    SDL_UnlockMutex(server_head_mutex);
    return;

error:
    metaserver_free(server);
}
예제 #21
0
파일: mempool.c 프로젝트: atrinik/atrinik
/**
 * Go through the freelists and free puddles with no used chunks.
 *
 * @return
 * Number of freed puddles.
 */
static size_t
mempool_free_puddles (mempool_struct *pool)
{
    size_t chunksize_real, nrof_arrays, i, j, freed;
    mempool_chunk_struct *last_free, *chunk;
    mempool_puddle_struct *puddle, *next_puddle;

    HARD_ASSERT(pool != NULL);

    if (pool->flags & MEMPOOL_BYPASS_POOLS) {
        return 0;
    }

    freed = 0;

    for (i = 0; i < MEMPOOL_NROF_FREELISTS; i++) {
        chunksize_real = sizeof(mempool_chunk_struct) + (pool->chunksize << i);
        nrof_arrays = pool->expand_size >> i;

        /* Free empty puddles and setup puddle-local freelists */
        for (puddle = pool->puddlelist[i], pool->puddlelist[i] = NULL;
                puddle != NULL; puddle = next_puddle) {
            next_puddle = puddle->next;

            /* Count free chunks in puddle, and set up a local freelist */
            puddle->first_free = puddle->last_free = NULL;
            puddle->nrof_free = 0;

            for (j = 0; j < nrof_arrays; j++) {
                chunk = (mempool_chunk_struct *)
                        (((char *) puddle->first_chunk) + chunksize_real * j);

                /* Find free chunks. */
                if (CHUNK_FREE(MEM_USERDATA(chunk))) {
                    if (puddle->nrof_free == 0) {
                        puddle->first_free = chunk;
                        puddle->last_free = chunk;
                        chunk->next = NULL;
                    } else {
                        chunk->next = puddle->first_free;
                        puddle->first_free = chunk;
                    }

                    puddle->nrof_free++;
                }
            }

            /* Can we actually free this puddle? */
            if (puddle->nrof_free == nrof_arrays ||
                    (deiniting && pool == pool_puddle)) {
                /* Yup. Forget about it. */
                efree(puddle->first_chunk);

                if (!deiniting || pool != pool_puddle) {
                    mempool_return(pool_puddle, puddle);
                }

                pool->nrof_free[i] -= nrof_arrays;
                pool->nrof_allocated[i] -= nrof_arrays;
                freed++;
            } else {
                /* Nope, keep this puddle: put it back into the tracking list */
                puddle->next = pool->puddlelist[i];
                pool->puddlelist[i] = puddle;
            }
        }

        /* Sort the puddles by amount of free chunks. It will let us set up the
         * freelist so that the chunks from the fullest puddles are used first.
         * This should (hopefully) help us free some of the lesser-used puddles
         * earlier. */
        pool->puddlelist[i] = sort_linked_list(pool->puddlelist[i], 0,
                sort_puddle_by_nrof_free, NULL, NULL, NULL);

        /* Finally: restore the global freelist */
        pool->freelist[i] = &end_marker;
        last_free = &end_marker;

        for (puddle = pool->puddlelist[i]; puddle != NULL;
                puddle = puddle->next) {
            if (puddle->nrof_free > 0) {
                if (pool->freelist[i] == &end_marker) {
                    pool->freelist[i] = puddle->first_free;
                } else {
                    last_free->next = puddle->first_free;
                }

                puddle->last_free->next = &end_marker;
                last_free = puddle->last_free;
            }
        }
    }

    return freed;
}
예제 #22
0
/**
 * Parse the metaserver certificate information.
 *
 * @param server
 * Metaserver entry.
 * @return
 * True on success, false on failure.
 */
static bool
parse_metaserver_cert (server_struct *server)
{
    HARD_ASSERT(server != NULL);

    if (server->cert == NULL || server->cert_sig == NULL) {
        /* No certificate. */
        return true;
    }

    /* Generate a SHA512 hash of the certificate's contents. */
    unsigned char cert_digest[SHA512_DIGEST_LENGTH];
    if (SHA512((unsigned char *) server->cert,
               strlen(server->cert),
               cert_digest) == NULL) {
        LOG(ERROR, "SHA512() failed: %s",
            ERR_error_string(ERR_get_error(), NULL));
        return false;
    }

    char cert_hash[SHA512_DIGEST_LENGTH * 2 + 1];
    SOFT_ASSERT_RC(string_tohex(VS(cert_digest),
                                VS(cert_hash),
                                false) == sizeof(cert_hash) - 1,
                   false,
                   "string_tohex failed");
    string_tolower(cert_hash);

    /* Verify the signature. */
    if (!curl_verify(CURL_PKEY_TRUST_ULTIMATE,
                     cert_hash,
                     strlen(cert_hash),
                     server->cert_sig,
                     server->cert_sig_len)) {
        LOG(ERROR, "Failed to verify signature");
        return false;
    }

    server_cert_info_t *info = ecalloc(1, sizeof(*info));

    char buf[MAX_BUF];
    size_t pos = 0;
    bool in_info = false;
    while (string_get_word(server->cert, &pos, '\n', VS(buf), 0)) {
        char *cp = buf;
        string_skip_whitespace(cp);
        string_strip_newline(cp);

        if (*cp == '\0') {
            continue;
        }

        if (strcmp(cp, cert_begin_str) == 0) {
            in_info = true;
            continue;
        } else if (!in_info) {
            continue;
        } else if (strcmp(cp, cert_end_str) == 0) {
            break;
        }

        char *cps[2];
        if (string_split(cp, cps, arraysize(cps), ':') != arraysize(cps)) {
            LOG(ERROR, "Parsing error");
            continue;
        }

        string_tolower(cps[0]);
        string_skip_whitespace(cps[1]);
        const char *key = cps[0];
        const char *value = cps[1];
        char **content = NULL;
        if (strcmp(key, "name") == 0) {
            content = &info->name;
        } else if (strcmp(key, "hostname") == 0) {
            content = &info->hostname;
        } else if (strcmp(key, "ipv4 address") == 0) {
            content = &info->ipv4_address;
        } else if (strcmp(key, "ipv6 address") == 0) {
            content = &info->ipv6_address;
        } else if (strcmp(key, "public key") == 0) {
            content = &info->pubkey;
        } else if (strcmp(key, "port") == 0) {
            info->port = atoi(value);
        } else if (strcmp(key, "crypto port") == 0) {
            info->port_crypto = atoi(value);
        } else {
            LOG(DEVEL, "Unrecognized key: %s", key);
            continue;
        }

        if (content != NULL) {
            StringBuffer *sb = stringbuffer_new();

            if (*content != NULL) {
                stringbuffer_append_string(sb, *content);
                stringbuffer_append_char(sb, '\n');
                efree(*content);
            }

            stringbuffer_append_string(sb, value);
            *content = stringbuffer_finish(sb);
        }
    }

    /* Ensure we got the data we need. */
    if (info->name == NULL ||
        info->hostname == NULL ||
        info->pubkey == NULL ||
        info->port_crypto <= 0 ||
        (info->ipv4_address == NULL) != (info->ipv6_address == NULL)) {
        LOG(ERROR,
            "Certificate is missing required data.");
        goto error;
    }

    /* Ensure certificate attributes match the advertised ones. */
    if (strcmp(info->hostname, server->hostname) != 0) {
        LOG(ERROR,
            "Certificate hostname does not match advertised hostname.");
        goto error;
    }

    if (strcmp(info->name, server->name) != 0) {
        LOG(ERROR,
            "Certificate name does not match advertised name.");
        goto error;
    }

    if (info->port != server->port) {
        LOG(ERROR,
            "Certificate port does not match advertised port.");
        goto error;
    }

    if (info->port_crypto != server->port_crypto) {
        LOG(ERROR,
            "Certificate crypto port does not match advertised crypto port.");
        goto error;
    }

    server->cert_info = info;
    return true;

error:
    metaserver_cert_free(info);
    return false;
}
예제 #23
0
/**
 * Parse a single metaserver data node within a 'server' node.
 *
 * @param node
 * The data node.
 * @param server
 * Allocated server structure.
 * @return
 * True on success, false on failure.
 */
static bool
parse_metaserver_data_node (xmlNodePtr node, server_struct *server)
{
    HARD_ASSERT(node != NULL);
    HARD_ASSERT(server != NULL);

    xmlChar *content = xmlNodeGetContent(node);
    SOFT_ASSERT_LABEL(content != NULL && *content != '\0',
                      error,
                      "Parsing error");

    if (XML_STR_EQUAL(node->name, "Hostname")) {
        SOFT_ASSERT_LABEL(server->hostname == NULL, error, "Parsing error");
        server->hostname = estrdup((const char *) content);
    } else if (XML_STR_EQUAL(node->name, "Port")) {
        SOFT_ASSERT_LABEL(server->port == 0, error, "Parsing error");
        server->port = atoi((const char *) content);
    } else if (XML_STR_EQUAL(node->name, "PortCrypto")) {
        SOFT_ASSERT_LABEL(server->port_crypto == -1, error, "Parsing error");
        server->port_crypto = atoi((const char *) content);
    } else if (XML_STR_EQUAL(node->name, "Name")) {
        SOFT_ASSERT_LABEL(server->name == NULL, error, "Parsing error");
        server->name = estrdup((const char *) content);
    } else if (XML_STR_EQUAL(node->name, "PlayersCount")) {
        SOFT_ASSERT_LABEL(server->player == 0, error, "Parsing error");
        server->player = atoi((const char *) content);
    } else if (XML_STR_EQUAL(node->name, "Version")) {
        SOFT_ASSERT_LABEL(server->version == NULL, error, "Parsing error");
        server->version = estrdup((const char *) content);
    } else if (XML_STR_EQUAL(node->name, "TextComment")) {
        SOFT_ASSERT_LABEL(server->desc == NULL, error, "Parsing error");
        server->desc = estrdup((const char *) content);
    } else if (XML_STR_EQUAL(node->name, "CertificatePublicKey")) {
        SOFT_ASSERT_LABEL(server->cert_pubkey == NULL, error, "Parsing error");
        server->cert_pubkey = estrdup((const char *) content);
    } else if (XML_STR_EQUAL(node->name, "Certificate")) {
        SOFT_ASSERT_LABEL(server->cert == NULL, error, "Parsing error");
        server->cert = estrdup((const char *) content);
    } else if (XML_STR_EQUAL(node->name, "CertificateSignature")) {
        SOFT_ASSERT_LABEL(server->cert_sig == NULL, error, "Parsing error");
        unsigned char *sig;
        size_t sig_len;
        if (!math_base64_decode((const char *) content, &sig, &sig_len)) {
            LOG(ERROR, "Error decoding BASE64 certificate signature");
            goto error;
        }

        server->cert_sig = sig;
        server->cert_sig_len = sig_len;
    } else {
        LOG(DEVEL, "Unrecognized node: %s", (const char *) node->name);
    }

    bool ret = true;
    goto out;

error:
    ret = false;

out:
    if (content != NULL) {
        xmlFree(content);
    }

    return ret;
}
예제 #24
0
/**
 * Parse data returned from HTTP metaserver and add it to the list of servers.
 *
 * @param body
 * The data to parse.
 * @param body_size
 * Length of the body.
 */
static void
parse_metaserver_data (const char *body, size_t body_size)
{
    HARD_ASSERT(body != NULL);

    xmlSchemaParserCtxtPtr parser_ctx = NULL;
    xmlSchemaPtr schema = NULL;
    xmlSchemaValidCtxtPtr valid_ctx = NULL;

    xmlDocPtr doc = xmlReadMemory(body, body_size, "noname.xml", NULL, 0);
    if (doc == NULL) {
        LOG(ERROR, "Failed to parse data from metaserver");
        goto out;
    }

    parser_ctx = xmlSchemaNewParserCtxt("schemas/Atrinik-ADS-7.xsd");
    if (parser_ctx == NULL) {
        LOG(ERROR, "Failed to create a schema parser context");
        goto out;
    }

    schema = xmlSchemaParse(parser_ctx);
    if (schema == NULL) {
        LOG(ERROR, "Failed to parse schema file");
        goto out;
    }

    valid_ctx = xmlSchemaNewValidCtxt(schema);
    if (valid_ctx == NULL) {
        LOG(ERROR, "Failed to create a validation context");
        goto out;
    }

    xmlSetStructuredErrorFunc(NULL, NULL);
    xmlSetGenericErrorFunc(NULL, parse_metaserver_data_error);
    xmlThrDefSetStructuredErrorFunc(NULL, NULL);
    xmlThrDefSetGenericErrorFunc(NULL, parse_metaserver_data_error);

    if (xmlSchemaValidateDoc(valid_ctx, doc) != 0) {
        LOG(ERROR, "XML verification failed.");
        goto out;
    }

    xmlNodePtr root = xmlDocGetRootElement(doc);
    if (root == NULL || !XML_STR_EQUAL(root->name, "Servers")) {
        LOG(ERROR, "No servers element found in metaserver XML");
        goto out;
    }

    xmlNodePtr last = NULL;
    for (xmlNodePtr node = root->children; node != NULL; node = node->next) {
        last = node;
    }

    for (xmlNodePtr node = last; node != NULL; node = node->prev) {
        if (!XML_STR_EQUAL(node->name, "Server")) {
            continue;
        }

        parse_metaserver_node(node);
    }

out:
    if (doc != NULL) {
            xmlFreeDoc(doc);
    }

    if (parser_ctx != NULL) {
        xmlSchemaFreeParserCtxt(parser_ctx);
    }

    if (schema != NULL) {
        xmlSchemaFree(schema);
    }

    if (valid_ctx != NULL) {
        xmlSchemaFreeValidCtxt(valid_ctx);
    }
}
예제 #25
0
/**
 * Actually performs updating for the specified network graph widget.
 * @param widget
 * The widget.
 * @param type
 * The network graph type.
 * @param traffic
 * The traffic type (tx/rx).
 * @param bytes
 * Bytes.
 */
static void widget_network_graph_update(widgetdata *widget, int type,
        int traffic, size_t bytes)
{
    HARD_ASSERT(widget != NULL);

    if (!widget->show) {
        return;
    }

    network_graph_widget_t *network_graph = widget->subwidget;
    network_graph_data_t *data = &network_graph->data[type];

    if (data->data == NULL || data->width != widget->w) {
        if (data->data == NULL) {
            data->ticks = LastTick;
        }

        data->data = ereallocz(data->data,
                sizeof(*data->data) * NETWORK_GRAPH_TRAFFIC_MAX * data->width,
                sizeof(*data->data) * NETWORK_GRAPH_TRAFFIC_MAX * widget->w);
        data->width = widget->w;
    }

    if (data->width == 0) {
        return;
    }

    if (LastTick - data->ticks > 1000) {
        data->pos++;
        data->ticks = LastTick;
    }

    if (data->pos == data->width) {
        data->pos--;

        bool recalc_max = false;
        for (int i = 0; i < NETWORK_GRAPH_TRAFFIC_MAX; i++) {
            if (data->data[i] >= data->max) {
                recalc_max = true;
            }
        }

        memmove(data->data, data->data + NETWORK_GRAPH_TRAFFIC_MAX,
                sizeof(*data->data) * (NETWORK_GRAPH_TRAFFIC_MAX *
                (data->width - 1)));

        if (recalc_max) {
            data->max = 0;
        }

        for (int i = 0; i < NETWORK_GRAPH_TRAFFIC_MAX; i++) {
            data->data[data->pos * NETWORK_GRAPH_TRAFFIC_MAX + i] = 0;

            if (recalc_max) {
                for (int x = 0; x < data->pos; x++) {
                    size_t bytes2 = data->data[x * NETWORK_GRAPH_TRAFFIC_MAX +
                            i];
                    if (bytes2 > data->max) {
                        data->max = bytes2;
                    }
                }
            }
        }
    }

    size_t *dst = &data->data[data->pos * NETWORK_GRAPH_TRAFFIC_MAX + traffic];
    *dst += bytes;

    if (*dst > data->max) {
        data->max = *dst;
    }

    widget->redraw = 1;
}
예제 #26
0
파일: sprite.c 프로젝트: liwcezar/atrinik
/**
 * Remove a sprite entry from the sprite cache.
 *
 * @param cache
 * Cache entry to remove.
 */
static void
sprite_cache_remove (sprite_cache_t *cache)
{
    HARD_ASSERT(cache != NULL);
    HASH_DEL(sprites_cache, cache);
}
예제 #27
0
파일: sprite.c 프로젝트: liwcezar/atrinik
/**
 * Add a sprite cache entry to the sprite cache.
 *
 * @param cache
 * Cache entry to add.
 */
static void
sprite_cache_add (sprite_cache_t *cache)
{
    HARD_ASSERT(cache != NULL);
    HASH_ADD_KEYPTR(hh, sprites_cache, cache->name, strlen(cache->name), cache);
}
예제 #28
0
파일: item.c 프로젝트: atrinik/atrinik
/**
 * Draw the object, centering it. Animation offsets are taken into
 * account for perfect centering, even with different image sizes in
 * animation.
 *
 * @param surface
 * Surface to render on.
 * @param tmp
 * Object to show.
 * @param x
 * X position.
 * @param y
 * Y position.
 * @param w
 * Maximum width.
 * @param h
 * Maximum height.
 * @param fit
 * Whether to fit the object into the maximum width/height by
 * zooming it as necessary.
 */
void object_show_centered (SDL_Surface *surface,
                           object      *tmp,
                           int          x,
                           int          y,
                           int          w,
                           int          h,
                           bool         fit)
{
    HARD_ASSERT(surface != NULL);
    HARD_ASSERT(tmp != NULL);

    if (FaceList[tmp->face].sprite == NULL) {
        return;
    }

    /* Will be used for coordinate calculations. */
    uint16_t face = tmp->face;

    /* If the item is animated, try to use the first animation face for
     * coordinate calculations to prevent 'jumping' of the animation. */
    if (tmp->animation_id > 0) {
        check_animation_status(tmp->animation_id);

        if (animations[tmp->animation_id].num_animations) {
            uint16_t face_id;

            face_id = animations[tmp->animation_id].frame * tmp->direction;

            if (FaceList[animations[tmp->animation_id].faces[face_id]].sprite) {
                face = animations[tmp->animation_id].faces[face_id];
            }
        }
    }

    int border_left = FaceList[face].sprite->border_left;
    int border_up = FaceList[face].sprite->border_up;
    if (tmp->glow[0] != '\0') {
        border_left -= SPRITE_GLOW_SIZE * 2;
        border_up -= SPRITE_GLOW_SIZE * 2;
    }

    int xlen = FaceList[face].sprite->bitmap->w - border_left -
               FaceList[face].sprite->border_right;
    int ylen = FaceList[face].sprite->bitmap->h - border_up -
               FaceList[face].sprite->border_down;
    if (tmp->glow[0] != '\0') {
        xlen += SPRITE_GLOW_SIZE * 2;
        ylen += SPRITE_GLOW_SIZE * 2;
    }

    double zoom_x = 1.0, zoom_y = 1.0;
    if (fit) {
        int xlen2 = xlen, ylen2 = ylen;

        if (xlen2 != w) {
            double factor = (double) w / xlen2;
            xlen2 *= factor;
            ylen2 *= factor;
        }

        if (ylen2 != h) {
            double factor = (double) h / ylen2;
            xlen2 *= factor;
            ylen2 *= factor;
        }

        if (xlen2 != xlen) {
            zoom_x = ((double) xlen2 + 0.5) / xlen;
            xlen = xlen2;
            border_left *= zoom_x;
        }

        if (ylen2 != ylen) {
            zoom_y = ((double) ylen2 + 0.5) / ylen;
            ylen = ylen2;
            border_up *= zoom_y;
        }
    }

    SDL_Rect box;
    if (xlen > w) {
        box.w = w;
        int temp = (xlen - w) / 2;
        box.x = border_left + temp;
        border_left = 0;
    } else {
        box.w = xlen;
        box.x = border_left;
        border_left = (w - xlen) / 2;
    }

    if (ylen > h) {
        box.h = h;
        int temp = (ylen - h) / 2;
        box.y = border_up + temp;
        border_up = 0;
    } else {
        box.h = ylen;
        box.y = border_up;
        border_up = (h - ylen) / 2;
    }

    if (face != tmp->face) {
        int temp = border_left - box.x;

        box.x = 0;
        box.w = FaceList[tmp->face].sprite->bitmap->w * zoom_x;
        border_left = temp;

        temp = border_up - box.y + (FaceList[face].sprite->bitmap->h * zoom_y -
                                    FaceList[tmp->face].sprite->bitmap->h *
                                    zoom_y);
        box.y = 0;
        box.h = FaceList[tmp->face].sprite->bitmap->h * zoom_y;
        border_up = temp;

        if (border_left < 0) {
            box.x = -border_left;
            box.w = FaceList[tmp->face].sprite->bitmap->w * zoom_x +
                    border_left;

            if (box.w > w) {
                box.w = w;
            }

            border_left = 0;
        } else {
            if (box.w + border_left > w) {
                box.w -= ((box.w + border_left) - w);
            }
        }

        if (border_up < 0) {
            box.y = -border_up;
            box.h = FaceList[tmp->face].sprite->bitmap->h * zoom_y + border_up;

            if (box.h > h) {
                box.h = h;
            }

            border_up = 0;
        } else {
            if (box.h + border_up > h) {
                box.h -= ((box.h + border_up) - h);
            }
        }
    }

    sprite_effects_t effects;
    memset(&effects, 0, sizeof(effects));
    snprintf(VS(effects.glow), "%s", tmp->glow);
    effects.glow_speed = tmp->glow_speed;
    effects.glow_state = tmp->glow_state;
    effects.zoom_x = zoom_x * 100.0;
    effects.zoom_y = zoom_y * 100.0;

    if (effects.glow[0] != '\0') {
        BIT_SET(effects.flags, SPRITE_FLAG_DARK);
        effects.dark_level = 0;
    }

    surface_show_effects(surface, x + border_left, y + border_up, &box,
                         FaceList[tmp->face].sprite->bitmap, &effects);
}