ser_t *ser_create(void) { ser_t *ser; ser = dp_MALLOC(sizeof(ser_t)); if (!ser) return NULL; ser->myAdr = ser_ADR_NONE; ser->yourAdr = ser_ADR_NONE; // no connection yet ser->nextHdl = ser_HDL_ME; // first adr2hdl sets my adr #if 0 ser->start = 0; ser->end = 0; ser->length = 0; ser->rbufsize = ser_READSIZE; ser->sigpos = 0; ser->state = LOOKING_FOR_HDR; ser->empty = TRUE; #else ser->got = 0; ser->head = 0; ser->len = 0; ser->sigpos = 0; #endif return ser; }
/*----------------------------------------------------------------------- Return the address of the given element of the table. If the table isn't that big, grow. Start all elements with 0. Returns NULL on failure. -----------------------------------------------------------------------*/ void *dynatab_subscript_grow(dynatab_t *tab, int subscript) { assert(tab != NULL); if (subscript < 0) return NULL; if (subscript >= tab->n_alloced) { void *newbuf; int new_n_alloced = tab->n_alloced + 16; if (new_n_alloced < subscript + 1) new_n_alloced = subscript + 16; if (tab->buf) newbuf = dp_REALLOC(tab->buf, new_n_alloced * tab->unit); else newbuf = dp_MALLOC(new_n_alloced * tab->unit); if (!newbuf) return NULL; tab->buf = newbuf; /* tab[n_alloced...new_n_alloced] = 0; */ /* memset(dynatab_subscript(tab, tab->n_alloced), 0, new area)); */ memset((char *)tab->buf + (tab->n_alloced * tab->unit), 0, (new_n_alloced - tab->n_alloced) * tab->unit); tab->n_alloced = new_n_alloced; } if (tab->n_alloced < subscript + 1) { /* BUG: Should have enough allocated by now. */ return NULL; } if (tab->n_used < subscript + 1) tab->n_used = subscript + 1; return ((char *)tab->buf) + (subscript * tab->unit); }
/*----------------------------------------------------------------------- Restore the state of a pv_var_t from disk. On entry, buf is not allocated. On exit, buf is set to a buffer of just the right size from malloc. -----------------------------------------------------------------------*/ static dp_result_t pv_var_thaw(pv_var_t *pvar, FILE *fp) { /* Read in the variable */ if (fread(pvar, sizeof(pv_var_t), 1, fp) != 1) { DPRINT(("pv_var_thaw: can't read var\n")); return dp_RES_EMPTY; } if (pvar->buf != (char *)0x12345678) { /* check signature */ DPRINT(("pv_var_thaw: bad sig %p\n", pvar->buf)); return dp_RES_BAD; } if (pvar->len > dp_PLAYERDATA_LEN_MAX) { DPRINT(("pv_var_thaw: bad len %d\n", pvar->len)); return dp_RES_BADSIZE; } DPRINT(("pv_var_thaw: key %d len %d offset %d type %3.3s\n", pvar->key, pvar->len, pvar->offset, pvar->type)); pvar->buf = dp_MALLOC(pvar->len + 1); /* kludge: avoid zero length */ if (!pvar->buf) { DPRINT(("pv_var_thaw: can't allocate %d bytes\n", pvar->len+1)); return dp_RES_NOMEM; } if (pvar->len && (fread(pvar->buf, pvar->len, 1, fp) != 1)) { DPRINT(("pv_var_thaw: can't read %d bytes\n", pvar->len)); return dp_RES_EMPTY; } return dp_RES_OK; }
/*-------------------------------------------------------------------------- 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; }
/*----------------------------------------------------------------------- Create a delay queue. Returns NULL on failure. Default speed is 1700 bytes/sec; default backbone delay is 100 milliseconds. -----------------------------------------------------------------------*/ delay_t *delay_create(void) { delay_t *q = (delay_t *)dp_MALLOC(sizeof(delay_t)); if (q) { memset(q, 0, sizeof(delay_t)); delay_setBytesPerSec(q, 2000); /* roughly 20 kbps */ delay_setDelayMillisec(q, 50); /* 50 milliseconds */ } return q; }
/*-------------------------------------------------------------------------- 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; }
/*----------------------------------------------------------------------- Create a table whose elements all have the given size. Returns NULL on failure. -----------------------------------------------------------------------*/ dynatab_t *dynatab_create(size_t element_size) { dynatab_t *pdt; assert(element_size > 0); pdt = (dynatab_t *)dp_MALLOC(sizeof(dynatab_t)); if (!pdt) return NULL; pdt->buf = NULL; pdt->unit = element_size; pdt->n_used = 0; pdt->n_alloced = 0; return pdt; }
/*----------------------------------------------------------------------- Inserts a record into the table before the nth record. Grows the table. Returns NULL on failure. -----------------------------------------------------------------------*/ void *dynatab_subscript_insert(dynatab_t *tab, int n) { void *p; assert(tab != NULL); if (n < 0) return NULL; if (n > tab->n_used) return NULL; if (tab->n_used >= tab->n_alloced) { void *newbuf; int new_n_alloced = tab->n_alloced + 16; if (new_n_alloced < tab->n_used + 1) new_n_alloced = tab->n_used + 16; if (tab->buf) newbuf = dp_REALLOC(tab->buf, new_n_alloced * tab->unit); else newbuf = dp_MALLOC(new_n_alloced * tab->unit); if (!newbuf) return NULL; tab->buf = newbuf; /* tab[n_alloced...new_n_alloced] = 0; */ /* memset(dynatab_subscript(tab, tab->n_alloced), 0, new area)); */ memset((char *)tab->buf + (tab->n_alloced * tab->unit), 0, (new_n_alloced - tab->n_alloced) * tab->unit); tab->n_alloced = new_n_alloced; } if (tab->n_alloced < tab->n_used + 1) { /* BUG: Should have enough allocated by now. */ return NULL; } /* Make pointer to new record */ p = ((char *)tab->buf) + (n * tab->unit); /* If needed, move elements up to make space */ if (n < tab->n_used) { void* dest = ((char *)p) + tab->unit; size_t count = (tab->n_used - n) * tab->unit; memmove(dest, p, count); } tab->n_used = tab->n_used + 1; /* Zero out new record */ memset(p, 0, tab->unit); return ((char *)p); }
/*-------------------------------------------------------------------------- Add a particular player to the table. --------------------------------------------------------------------------*/ static pv_peer_t *pv_addPlayer(pv_t *pv, int player) { /* No peer yet. Create one. */ pv_peer_t *peer = (pv_peer_t *)assoctab_subscript_grow(pv->peers, player); if (!peer) { DPRINT(("pv_addPlayer(%d): can't grow peers!\n", player)); return NULL; } if (peer->vars) return peer; peer->vars = assoctab_create(sizeof(pv_var_t)); peer->incoming.key = dp_PLAYERDATA_KEY_NONE; peer->allocated = dpio_MAXLEN_RELIABLE; peer->incoming.buf = dp_MALLOC(peer->allocated); if (!peer->incoming.buf) return NULL; /* bug */ DPRINT(("pv_addPlayer: created variable table for player %d\n", player)); return peer; }