/*----------------------------------------------------------------------- Destroy a table. -----------------------------------------------------------------------*/ void dynatab_destroy(dynatab_t *ptab) { assert(ptab != NULL); if (ptab->buf) dp_FREE(ptab->buf); ptab->buf = NULL; /* Paranoid */ dp_FREE(ptab); }
/*-------------------------------------------------------------------------- Delete a particular player from the table. --------------------------------------------------------------------------*/ dp_result_t pv_deletePlayer(pv_t *pv, int player) { int i; pv_peer_t *peer; if (!pv) return dp_RES_BUG; DPRINT(("pv_deletePlayer(dp, %d)\n", player)); /* Get this player's table. */ peer = (pv_peer_t *)assoctab_subscript(pv->peers, player); if (!peer) { DPRINT(("pv_deletePlayer: no table for player %d\n", player)); return dp_RES_EMPTY; } /* Free all memory pointed to by the variables in peer->vars */ for (i=0; i < peer->vars->n_used; i++) { pv_var_t *pvar; assoctab_item_t *pe; pe = assoctab_getkey(peer->vars, i); if (!pe) break; /* horrible error */ pvar = (pv_var_t *) &pe->value; /* Destroy their values */ if (pvar->buf) dp_FREE(pvar->buf); } if (peer->incoming.buf) dp_FREE(peer->incoming.buf); /* Destroy it, and remove it from the table. */ assoctab_destroy(peer->vars); if (assoctab_subscript_delete(pv->peers, player)) return dp_RES_BUG; return dp_RES_OK; }
/*----------------------------------------------------------------------- Destroy a serial driver. -----------------------------------------------------------------------*/ void ser_destroy(ser_t *ser) { if (ser) { serio_close(&ser->serio); dp_FREE(ser); } }
/*-------------------------------------------------------------------------- Create a pv_t. --------------------------------------------------------------------------*/ pv_t *pv_create(struct dp_s *dp) { pv_t *pv; pv = (pv_t *)dp_MALLOC(sizeof(pv_t)); if (!pv) return NULL; memset(pv, 0, sizeof(pv_t)); pv->peers = assoctab_create(sizeof(pv_peer_t)); if (!pv->peers) { assoctab_destroy(pv->peers); dp_FREE(pv); return NULL; } pv->next_send = dp->now; pv->cur_key_index = -1; pv->cur_ndests = 0; pv->new_ndests = 0; pv->cur_nkeys = 0; pv->cur_offset = 0; pv->dp = dp; return pv; }
/*-------------------------------------------------------------------------- Set variable 'key' for a player. Value is copied onto the heap, and must be freed later with pv_set (overwriting frees), pv_deletePlayer or pv_destroy. --------------------------------------------------------------------------*/ dp_result_t pv_set(pv_t *pv, int player, int key, size_t len, void *buf, int flags) { pv_peer_t *peer; pv_var_t *pvar; if (!pv) return dp_RES_BUG; DPRINT(("pv_set(pv, player %d, key %d, len %d, buf %p, flags %x):\n", player, key, len, buf, flags)); #ifdef DPRINTBUFS DPRINT(("pv_set: buf = ")); dprint_buf(buf, len); #endif if (len > dp_PLAYERDATA_LEN_MAX) return dp_RES_BADSIZE; /* Get this player's table. */ peer = (pv_peer_t *)assoctab_subscript(pv->peers, player); if (!peer) { /* No peer yet. Create one. */ peer = pv_addPlayer(pv, player); if (!peer) return dp_RES_NOMEM; } /* Add a key/value pair to it */ pvar = (pv_var_t *)assoctab_subscript_grow(peer->vars, key); if (!pvar) { DPRINT(("pv_set: can't grow player %d's vars[%d]!\n", player, key)); return dp_RES_NOMEM; } /* Delete old value from heap if present and not big enough */ if (!pvar->buf || pvar->len < len) { if (pvar->buf) dp_FREE(pvar->buf); pvar->buf = dp_MALLOC(len); } if (!pvar->buf) return dp_RES_NOMEM; /* Fill the key/value pair with the given data */ pvar->key = key; pvar->flags = flags; pvar->len = len; memcpy(pvar->buf, buf, len); pvar->crc = dp_crc32((unsigned char *)buf, len); DPRINT(("pv_set: player %d key %d len %d crc is %x\n", player, key, len, pvar->crc)); /* Inform other players of the change unless told not to. */ if (!(flags & dp_PLAYERDATA_FLAG_NOFLOOD)) { DPRINT(("Setting peer->dirty TRUE for player %d\n", player)); peer->dirty = TRUE; pvar->flags |= dp_PLAYERDATA_FLAG_DIRTY; } return dp_RES_OK; }
/*----------------------------------------------------------------------- Destroy a delay queue. -----------------------------------------------------------------------*/ void delay_destroy(delay_t *pq) { dp_FREE(pq); }
/*----------------------------------------------------------------------- Restore the state of a pv_peer_t from disk and add it to the pv_t. -----------------------------------------------------------------------*/ static dp_result_t pv_peer_thaw(pv_t *pv, FILE *fp) { pv_peer_t *peer; int i; short dirty; unsigned long n_vars; long sig; dpid_t id; dp_result_t err; /* Header */ if ((fread(&sig, sizeof(sig), 1, fp) != 1) || (fread(&dirty, sizeof(dirty), 1, fp) != 1) || (fread(&id, sizeof(id), 1, fp) != 1) || (fread(&n_vars, sizeof(n_vars), 1, fp) != 1)) { DPRINT(("pv_peer_thaw: can't read header\n")); return dp_RES_EMPTY; } if (sig != 0x12340009) { DPRINT(("pv_peer_thaw: bad sig\n")); return dp_RES_BAD; } if (n_vars > dp_PLAYERDATA_NKEYS_MAX) { DPRINT(("pv_peer_thaw: bad n_vars %d\n", n_vars)); return dp_RES_BAD; } if ((dirty != FALSE) && (dirty != TRUE)) { DPRINT(("pv_peer_thaw: bad dirty\n")); return dp_RES_BAD; } DPRINT(("pv_peer_thaw: id %d, pv %p, n_vars %d\n", id, pv, n_vars)); peer = pv_addPlayer(pv, id); if (!peer) return dp_RES_NOMEM; /* Body */ for (i=0; i < n_vars; i++) { /* Grab the variable */ pv_var_t var, *pvar; err = pv_var_thaw(&var, fp); if (err != dp_RES_OK) { DPRINT(("pv_peer_thaw: pv_var_thaw returns %d\n", err)); return err; } DPRINT(("pv_peer_thaw: peer %d, var %d, len %d\n", id, var.key, var.len)); /* Add it to the peer's var table. */ pvar = (pv_var_t *)assoctab_subscript_grow(peer->vars, var.key); if (!pvar) { DPRINT(("pv_peer_thaw: can't grow player %d's vars[%d]!\n", id, var.key)); return dp_RES_NOMEM; } /* Delete old value from heap if present */ if (pvar->buf) dp_FREE(pvar->buf); /* Copy variable at last. */ *pvar = var; } /* Ditch the incoming.buf allocated by pv_addPlayer, as pv_var_thaw * allocates its own. */ if (peer->incoming.buf) dp_FREE(peer->incoming.buf); DPRINT(("pv_peer_thaw: thawing incoming\n")); err = pv_var_thaw(&peer->incoming, fp); if (err != dp_RES_OK) return err; peer->allocated = peer->incoming.len; peer->dirty = dirty; /* No trailer */ return dp_RES_OK; }