Ejemplo n.º 1
0
int
_font_init_stubs (void)
{
    static int inited = FALSE;
    static void *handle = NULL;

    if (inited)
        return inited;
    if (!handle)
        handle = DLOPEN_SELF();

    INIT_SYMBOL(client_auth_generation);
    INIT_SYMBOL(ClientSignal);
    INIT_SYMBOL(DeleteFontClientID);
    INIT_SYMBOL(VErrorF);
    INIT_SYMBOL(find_old_font);
    INIT_SYMBOL(GetClientResolutions);
    INIT_SYMBOL(GetDefaultPointSize);
    INIT_SYMBOL(GetNewFontClientID);
    INIT_SYMBOL(GetTimeInMillis);
    INIT_SYMBOL(init_fs_handlers);
    INIT_SYMBOL(RegisterFPEFunctions);
    INIT_SYMBOL(remove_fs_handlers);
    INIT_SYMBOL(set_font_authorizations);
    INIT_SYMBOL(StoreFontClientFont);
    INIT_SYMBOL(MakeAtom);
    INIT_SYMBOL(ValidAtom);
    INIT_SYMBOL(NameForAtom);
    INIT_SYMBOL(register_fpe_functions);
    INIT_DATA(serverClient);
    INIT_DATA(serverGeneration);

    inited = TRUE;
    return inited;
}
Ejemplo n.º 2
0
ZEND_API int _zend_hash_index_update_or_next_insert(HashTable *ht, ulong h, void *pData, uint nDataSize, void **pDest, int flag ZEND_FILE_LINE_DC)
{
	uint nIndex;
	Bucket *p;
#ifdef ZEND_SIGNALS
	TSRMLS_FETCH();
#endif

	IS_CONSISTENT(ht);
	CHECK_INIT(ht);

	if (flag & HASH_NEXT_INSERT) {
		h = ht->nNextFreeElement;
	}
	nIndex = h & ht->nTableMask;

	p = ht->arBuckets[nIndex];
	while (p != NULL) {
		if ((p->nKeyLength == 0) && (p->h == h)) {
			if (flag & HASH_NEXT_INSERT || flag & HASH_ADD) {
				return FAILURE;
			}
			ZEND_ASSERT(p->pData != pData);
			HANDLE_BLOCK_INTERRUPTIONS();
			if (ht->pDestructor) {
				ht->pDestructor(p->pData);
			}
			UPDATE_DATA(ht, p, pData, nDataSize);
			HANDLE_UNBLOCK_INTERRUPTIONS();
			if (pDest) {
				*pDest = p->pData;
			}
			return SUCCESS;
		}
		p = p->pNext;
	}
	p = (Bucket *) pemalloc_rel(sizeof(Bucket), ht->persistent);
	p->arKey = NULL;
	p->nKeyLength = 0; /* Numeric indices are marked by making the nKeyLength == 0 */
	p->h = h;
	INIT_DATA(ht, p, pData, nDataSize);
	if (pDest) {
		*pDest = p->pData;
	}

	CONNECT_TO_BUCKET_DLLIST(p, ht->arBuckets[nIndex]);

	HANDLE_BLOCK_INTERRUPTIONS();
	ht->arBuckets[nIndex] = p;
	CONNECT_TO_GLOBAL_DLLIST(p, ht);
	HANDLE_UNBLOCK_INTERRUPTIONS();

	if ((long)h >= (long)ht->nNextFreeElement) {
		ht->nNextFreeElement = h < LONG_MAX ? h + 1 : LONG_MAX;
	}
	ht->nNumOfElements++;
	ZEND_HASH_IF_FULL_DO_RESIZE(ht);
	return SUCCESS;
}
Ejemplo n.º 3
0
/* nr_turn_stun_ctx functions */
static int nr_turn_stun_ctx_create(nr_turn_client_ctx *tctx, int mode,
                                   NR_async_cb success_cb,
                                   NR_async_cb error_cb,
                                   nr_turn_stun_ctx **ctxp)
{
  nr_turn_stun_ctx *sctx = 0;
  int r,_status;
  char label[256];

  if (!(sctx=RCALLOC(sizeof(nr_turn_stun_ctx))))
    ABORT(R_NO_MEMORY);

  /* TODO([email protected]): label by phase */
  snprintf(label, sizeof(label), "%s:%s", tctx->label, ":TURN");

  if ((r=nr_stun_client_ctx_create(label, tctx->sock, &tctx->turn_server_addr,
                                   TURN_RTO, &sctx->stun))) {
    ABORT(r);
  }

  /* Set the STUN auth parameters, but don't set authentication on.
     For that we need the nonce, set in nr_turn_stun_set_auth_params.
  */
  sctx->stun->auth_params.username=tctx->username;
  INIT_DATA(sctx->stun->auth_params.password,
            tctx->password->data, tctx->password->len);

  sctx->tctx=tctx;
  sctx->success_cb=success_cb;
  sctx->error_cb=error_cb;
  sctx->mode=mode;
  sctx->last_error_code=0;

  /* Add ourselves to the tctx's list */
  STAILQ_INSERT_TAIL(&tctx->stun_ctxs, sctx, entry);
  *ctxp=sctx;

  _status=0;
abort:
  if (_status) {
    nr_turn_stun_ctx_destroy(&sctx);
  }
  return(_status);
}
Ejemplo n.º 4
0
int nr_turn_client_deallocate(nr_turn_client_ctx *ctx)
{
  int r,_status;
  nr_stun_message *aloc = 0;
  nr_stun_client_auth_params auth;
  nr_stun_client_refresh_request_params refresh;

  if (ctx->state != NR_TURN_CLIENT_STATE_ALLOCATED)
    return(0);

  r_log(NR_LOG_TURN, LOG_INFO, "TURN(%s): deallocating", ctx->label);

  refresh.lifetime_secs = 0;

  auth.username = ctx->username;
  INIT_DATA(auth.password, ctx->password->data, ctx->password->len);

  auth.realm = ctx->realm;
  auth.nonce = ctx->nonce;

  auth.authenticate = 1;

  if ((r=nr_stun_build_refresh_request(&auth, &refresh, &aloc)))
    ABORT(r);

  // We are only sending a single request here because we are in the process of
  // shutting everything down. Theoretically we should probably start a seperate
  // STUN transaction which outlives the TURN context.
  if ((r=nr_turn_client_send_stun_request(ctx, aloc, 0)))
    ABORT(r);

  ctx->state = NR_TURN_CLIENT_STATE_DEALLOCATING;

  _status=0;
abort:
  nr_stun_message_destroy(&aloc);
  return(_status);
}
Ejemplo n.º 5
0
ZEND_API int _zend_hash_quick_add_or_update(HashTable *ht, const char *arKey, uint nKeyLength, ulong h, void *pData, uint nDataSize, void **pDest, int flag ZEND_FILE_LINE_DC)
{
    uint nIndex;
    Bucket *p;
#ifdef ZEND_SIGNALS
    TSRMLS_FETCH();
#endif

    IS_CONSISTENT(ht);

    if (nKeyLength == 0) {
        return zend_hash_index_update(ht, h, pData, nDataSize, pDest);
    }

    CHECK_INIT(ht);
    nIndex = h & ht->nTableMask;

    p = ht->arBuckets[nIndex];
    while (p != NULL) {
        if (p->arKey == arKey ||
                ((p->h == h) && (p->nKeyLength == nKeyLength) && !memcmp(p->arKey, arKey, nKeyLength))) {
            if (flag & HASH_ADD) {
                return FAILURE;
            }
            HANDLE_BLOCK_INTERRUPTIONS();
#if ZEND_DEBUG
            if (p->pData == pData) {
                ZEND_PUTS("Fatal error in zend_hash_update: p->pData == pData\n");
                HANDLE_UNBLOCK_INTERRUPTIONS();
                return FAILURE;
            }
#endif
            if (ht->pDestructor) {
                ht->pDestructor(p->pData);
            }
            UPDATE_DATA(ht, p, pData, nDataSize);
            if (pDest) {
                *pDest = p->pData;
            }
            HANDLE_UNBLOCK_INTERRUPTIONS();
            return SUCCESS;
        }
        p = p->pNext;
    }

    if (IS_INTERNED(arKey)) {
        p = (Bucket *) pemalloc(sizeof(Bucket), ht->persistent);
        if (!p) {
            return FAILURE;
        }
        p->arKey = arKey;
    } else {
        p = (Bucket *) pemalloc(sizeof(Bucket) + nKeyLength, ht->persistent);
        if (!p) {
            return FAILURE;
        }
        p->arKey = (const char*)(p + 1);
        memcpy((char*)p->arKey, arKey, nKeyLength);
    }

    p->nKeyLength = nKeyLength;
    INIT_DATA(ht, p, pData, nDataSize);
    p->h = h;

    CONNECT_TO_BUCKET_DLLIST(p, ht->arBuckets[nIndex]);

    if (pDest) {
        *pDest = p->pData;
    }

    HANDLE_BLOCK_INTERRUPTIONS();
    ht->arBuckets[nIndex] = p;
    CONNECT_TO_GLOBAL_DLLIST(p, ht);
    HANDLE_UNBLOCK_INTERRUPTIONS();

    ht->nNumOfElements++;
    ZEND_HASH_IF_FULL_DO_RESIZE(ht);		/* If the Hash table is full, resize it */
    return SUCCESS;
}
Ejemplo n.º 6
0
/* 数字键值的插入修改 */
ZEND_API int _zend_hash_index_update_or_next_insert(HashTable *ht, ulong h,
						    void *pData, uint nDataSize,
						    void **pDest,
						    int flag ZEND_FILE_LINE_DC)
{
	uint nIndex;
	Bucket *p;
#ifdef ZEND_SIGNALS
	TSRMLS_FETCH();
#endif

	IS_CONSISTENT(ht); // 调试信息
	CHECK_INIT(ht);

	// 如果是新增元素,则h等于下一个数字索引的位置
	if (flag & HASH_NEXT_INSERT) {
		h = ht->nNextFreeElement;
	}
	// 计算键值在HashTable中的存储位置为nIndex
	nIndex = h & ht->nTableMask;

	p = ht->arBuckets[nIndex]; /* 取得索引对应的Bucket的指针 */
	// 循环Bucket中含有nIndex键值的链表
	while (p != NULL) {
		// p 不为NULL说明Bucket中存在键值为nIndex的元素
		if ((p->nKeyLength == 0) &&
		    (p->h == h)) { // 如果是数字键值且键值相同
			if (flag & HASH_NEXT_INSERT ||
			    flag & HASH_ADD) { // 如果是新增元素,则插入失败
				return FAILURE;
			}
			HANDLE_BLOCK_INTERRUPTIONS();
#if ZEND_DEBUG
			if (p->pData == pData) {
				ZEND_PUTS("Fatal error in "
					  "zend_hash_index_update: p->pData == "
					  "pData\n");
				HANDLE_UNBLOCK_INTERRUPTIONS();
				return FAILURE;
			}
#endif
			// 上面的代码return ,说明是更新Bucket中已有键值元素值
			if (ht->pDestructor) { // 如果数据元素存在,则将原来的数据销毁
				ht->pDestructor(p->pData);
			}
			UPDATE_DATA(ht, p, pData, nDataSize); // 更新数据值
			HANDLE_UNBLOCK_INTERRUPTIONS();
			if ((long)h >= (long)ht->nNextFreeElement) {
				ht->nNextFreeElement =
				    h < LONG_MAX ? h + 1 : LONG_MAX;
			}
			// 如果需要返回更新值,则将返回值赋值给pDest
			if (pDest) {
				*pDest = p->pData;
			}
			return SUCCESS;
		}
		// 移动到链表的下一个元素
		p = p->pNext;
	}
	// 如果是新增,为新增元素分配一个Bucket空间
	p = (Bucket *)pemalloc_rel(sizeof(Bucket), ht->persistent);
	if (!p) {
		return FAILURE;
	}
	// 赋值
	p->arKey = NULL;
	p->nKeyLength =
	    0; /* Numeric indices are marked by making the nKeyLength == 0 */
	p->h = h;
	INIT_DATA(ht, p, pData, nDataSize);
	// 如果需要返回更新值,则将返回值赋值给pDest
	if (pDest) {
		*pDest = p->pData;
	}

	CONNECT_TO_BUCKET_DLLIST(
	    p, ht->arBuckets[nIndex]); // 将Bucket加入到对应的桶双向链表中

	HANDLE_BLOCK_INTERRUPTIONS();
	ht->arBuckets[nIndex] = p;
	CONNECT_TO_GLOBAL_DLLIST(
	    p, ht); // 将新的Bucket元素添加到哈希表的双向链表中
	HANDLE_UNBLOCK_INTERRUPTIONS();

	if ((long)h >= (long)ht->nNextFreeElement) {
		ht->nNextFreeElement = h < LONG_MAX ? h + 1 : LONG_MAX;
	}
	ht->nNumOfElements++;
	ZEND_HASH_IF_FULL_DO_RESIZE(
	    ht); /* 如果此时数组的容量满了,则重新分配空间。*/
	return SUCCESS;
}
Ejemplo n.º 7
0
/* 插入新值到哈希表中 */
ZEND_API int _zend_hash_add_or_update(HashTable *ht, const char *arKey,
				      uint nKeyLength, void *pData,
				      uint nDataSize, void **pDest,
				      int flag ZEND_FILE_LINE_DC)
{
	ulong h;
	uint nIndex;
	Bucket *p;
#ifdef ZEND_SIGNALS
	TSRMLS_FETCH();
#endif

	IS_CONSISTENT(ht);

	/* 键值不能为空字符串 */
	if (nKeyLength <= 0) {
#if ZEND_DEBUG
		ZEND_PUTS("zend_hash_update: Can't put in empty key\n");
#endif
		return FAILURE;
	}

	/* 检查哈希表是否以及初始化,如果没有初始化则进行初始化 */
	CHECK_INIT(ht);

	/* 计算key代表的哈希值以及获取其在arBuckets数组中的下标 */
	h = zend_inline_hash_func(arKey, nKeyLength);
	nIndex = h & ht->nTableMask;

	p = ht->arBuckets[nIndex];
	while (p != NULL) {
		if (p->arKey == arKey ||
		    ((p->h == h) && (p->nKeyLength == nKeyLength) &&
		     !memcmp(p->arKey, arKey, nKeyLength))) { /* 需要更新 */
			if (flag &
			    HASH_ADD) { /* 如果是插入的话就返回,不能插入具有相同键值的元素
					   */
				return FAILURE;
			}
			HANDLE_BLOCK_INTERRUPTIONS();
#if ZEND_DEBUG
			if (p->pData == pData) {
				ZEND_PUTS("Fatal error in zend_hash_update: "
					  "p->pData == pData\n");
				HANDLE_UNBLOCK_INTERRUPTIONS();
				return FAILURE;
			}
#endif
			if (ht->pDestructor) { /* 如果有析构函数,则将指向数据的指针释放掉
						  */
				ht->pDestructor(p->pData);
			}

			/* 更新数据 */
			UPDATE_DATA(ht, p, pData, nDataSize);
			if (pDest) {
				*pDest = p->pData;
			}
			HANDLE_UNBLOCK_INTERRUPTIONS();
			return SUCCESS;
		}
		/* 移动到具有相同hash值的bucket链表中的下一个bucket */
		p = p->pNext;
	}

	if (IS_INTERNED(arKey)) {
		p = (Bucket *)pemalloc(sizeof(Bucket), ht->persistent);
		if (!p) {
			return FAILURE;
		}
		p->arKey = arKey;
	} else {
		p = (Bucket *)pemalloc(sizeof(Bucket) + nKeyLength,
				       ht->persistent);
		if (!p) {
			return FAILURE;
		}
		p->arKey = (const char *)(p + 1);
		memcpy((char *)p->arKey, arKey, nKeyLength);
	}

	/* 设置新的bucket的属性值及添加到哈希表中 */
	p->nKeyLength = nKeyLength;
	INIT_DATA(ht, p, pData, nDataSize);
	p->h = h;
	CONNECT_TO_BUCKET_DLLIST(p, ht->arBuckets[nIndex]);
	if (pDest) {
		*pDest = p->pData;
	}

	HANDLE_BLOCK_INTERRUPTIONS();
	CONNECT_TO_GLOBAL_DLLIST(p, ht);
	ht->arBuckets[nIndex] = p;
	HANDLE_UNBLOCK_INTERRUPTIONS();

	ht->nNumOfElements++;
	ZEND_HASH_IF_FULL_DO_RESIZE(
	    ht); /* If the Hash table is full, resize it */
	return SUCCESS;
}
Ejemplo n.º 8
0
int nr_ice_candidate_pair_create(nr_ice_peer_ctx *pctx, nr_ice_candidate *lcand,nr_ice_candidate *rcand,nr_ice_cand_pair **pairp)
  {
    nr_ice_cand_pair *pair=0;
    UINT8 o_priority, a_priority;
    char *lufrag,*rufrag;
    char *lpwd,*rpwd;
    char *l2ruser=0,*r2lpass=0;
    int r,_status;
    UINT4 RTO;
    nr_ice_candidate tmpcand;
    UINT8 t_priority;

    if(!(pair=RCALLOC(sizeof(nr_ice_cand_pair))))
      ABORT(R_NO_MEMORY);
    
    pair->pctx=pctx;
    
    nr_ice_candidate_pair_compute_codeword(pair,lcand,rcand);
    
    if(r=nr_concat_strings(&pair->as_string,pair->codeword,"|",lcand->addr.as_string,"|",
         rcand->addr.as_string,"(",lcand->label,"|",rcand->label,")",0))
      ABORT(r);

    nr_ice_candidate_pair_set_state(pctx,pair,NR_ICE_PAIR_STATE_FROZEN);
    pair->local=lcand;
    pair->remote=rcand;

    /* Priority computation S 5.7.2 */
    if(pctx->ctx->flags & NR_ICE_CTX_FLAGS_OFFERER)
    {
      assert(!(pctx->ctx->flags & NR_ICE_CTX_FLAGS_ANSWERER));
      
      o_priority=lcand->priority;
      a_priority=rcand->priority;
    }
    else{
      o_priority=rcand->priority;
      a_priority=lcand->priority;
    }
    pair->priority=(MIN(o_priority, a_priority))<<32 | 
      (MAX(o_priority, a_priority))<<1 | (o_priority > a_priority?0:1);
    
    r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): Pairing candidate %s (%x):%s (%x) priority=%llu (%llx) codeword=%s",pctx->ctx->label,lcand->addr.as_string,lcand->priority,rcand->addr.as_string,rcand->priority,pair->priority,pair->priority,pair->codeword);

    /* Foundation */
    if(r=nr_concat_strings(&pair->foundation,lcand->foundation,"|",
      rcand->foundation,0))
      ABORT(r);


    /* OK, now the STUN data */
    lufrag=lcand->stream->ufrag?lcand->stream->ufrag:pctx->ctx->ufrag;
    lpwd=lcand->stream->pwd?lcand->stream->pwd:pctx->ctx->pwd;
    rufrag=rcand->stream->ufrag?rcand->stream->ufrag:pctx->peer_ufrag;
    rpwd=rcand->stream->pwd?rcand->stream->pwd:pctx->peer_pwd;


    /* Compute the RTO per S 16 */
    RTO = MAX(100, (pctx->ctx->Ta * pctx->waiting_pairs));

    /* Make a bogus candidate to compute a theoretical peer reflexive
     * priority per S 7.1.1.1 */
    memcpy(&tmpcand, lcand, sizeof(tmpcand));
    tmpcand.type = PEER_REFLEXIVE;
    if (r=nr_ice_candidate_compute_priority(&tmpcand))
      ABORT(r);
    t_priority = tmpcand.priority;

    /* Our sending context */
    if(r=nr_concat_strings(&l2ruser,lufrag,":",rufrag,0))
      ABORT(r);
    if(r=nr_stun_client_ctx_create(pair->as_string,
      lcand->osock,
      &rcand->addr,RTO,&pair->stun_client))
      ABORT(r);
    if(!(pair->stun_client->params.ice_binding_request.username=r_strdup(l2ruser)))
      ABORT(R_NO_MEMORY);
    if(r=r_data_make(&pair->stun_client->params.ice_binding_request.password,(UCHAR *)lpwd,strlen(lpwd)))
      ABORT(r);
    pair->stun_client->params.ice_binding_request.priority=t_priority;
    pair->stun_client->params.ice_binding_request.control = pctx->controlling?
      NR_ICE_CONTROLLING:NR_ICE_CONTROLLED;

    pair->stun_client->params.ice_binding_request.tiebreaker=pctx->tiebreaker;

    /* Our receiving username/passwords. Stash these for later 
       injection into the stun server ctx*/
    if(r=nr_concat_strings(&pair->r2l_user,rufrag,":",lufrag,0))
      ABORT(r);
    if(!(r2lpass=r_strdup(rpwd)))
      ABORT(R_NO_MEMORY);
    INIT_DATA(pair->r2l_pwd,(UCHAR *)r2lpass,strlen(r2lpass));
    
    *pairp=pair;

    _status=0;
  abort:
    RFREE(l2ruser);
    if(_status){
      RFREE(r2lpass);
    }
    return(_status);
  }
Ejemplo n.º 9
0
ZEND_API int _zend_hash_add_or_update(HashTable *ht, const char *arKey, uint nKeyLength, void *pData, uint nDataSize, void **pDest, int flag ZEND_FILE_LINE_DC)
{
	ulong h;
	uint nIndex;
	Bucket *p;

	IS_CONSISTENT(ht);

	if (nKeyLength <= 0) {
#if ZEND_DEBUG
		ZEND_PUTS("zend_hash_update: Can't put in empty key\n");
#endif
		return FAILURE;
	}

	h = zend_inline_hash_func(arKey, nKeyLength);
	nIndex = h & ht->nTableMask;

	p = ht->arBuckets[nIndex];
	while (p != NULL) {
		if ((p->h == h) && (p->nKeyLength == nKeyLength)) {
			if (!memcmp(p->arKey, arKey, nKeyLength)) {
				if (flag & HASH_ADD) {
					return FAILURE;
				}
				HANDLE_BLOCK_INTERRUPTIONS();
#if ZEND_DEBUG
				if (p->pData == pData) {
					ZEND_PUTS("Fatal error in zend_hash_update: p->pData == pData\n");
					HANDLE_UNBLOCK_INTERRUPTIONS();
					return FAILURE;
				}
#endif
				if (ht->pDestructor) {
					ht->pDestructor(p->pData);
				}
				UPDATE_DATA(ht, p, pData, nDataSize);
				if (pDest) {
					*pDest = p->pData;
				}
				HANDLE_UNBLOCK_INTERRUPTIONS();
				return SUCCESS;
			}
		}
		p = p->pNext;
	}
	
	p = (Bucket *) pemalloc(sizeof(Bucket) - 1 + nKeyLength, ht->persistent);
	if (!p) {
		return FAILURE;
	}
	memcpy(p->arKey, arKey, nKeyLength);
	p->nKeyLength = nKeyLength;
	INIT_DATA(ht, p, pData, nDataSize);
	p->h = h;
	CONNECT_TO_BUCKET_DLLIST(p, ht->arBuckets[nIndex]);
	if (pDest) {
		*pDest = p->pData;
	}

	HANDLE_BLOCK_INTERRUPTIONS();
	CONNECT_TO_GLOBAL_DLLIST(p, ht);
	ht->arBuckets[nIndex] = p;
	HANDLE_UNBLOCK_INTERRUPTIONS();

	ht->nNumOfElements++;
	ZEND_HASH_IF_FULL_DO_RESIZE(ht);		/* If the Hash table is full, resize it */
	return SUCCESS;
}
Ejemplo n.º 10
0
// flag参数: HASH_UPDATE HASH_NEXT_INSERT
ZEND_API int _zend_hash_index_update_or_next_insert(HashTable *ht, ulong h, void *pData, uint nDataSize, void **pDest, int flag ZEND_FILE_LINE_DC)
{
	uint nIndex;
	Bucket *p;

	IS_CONSISTENT(ht);

	if (flag & HASH_NEXT_INSERT) {
		h = ht->nNextFreeElement;
	}
	nIndex = h & ht->nTableMask;

	p = ht->arBuckets[nIndex];
	while (p != NULL) {
		if ((p->nKeyLength == 0) && (p->h == h)) {
			// 没看到有针对HAHS_ADD的宏
			// 这个case什么时候会触发?
			if (flag & HASH_NEXT_INSERT || flag & HASH_ADD) {
				return FAILURE;
			}
			HANDLE_BLOCK_INTERRUPTIONS();
#if ZEND_DEBUG
			if (p->pData == pData) {
				ZEND_PUTS("Fatal error in zend_hash_index_update: p->pData == pData\n");
				HANDLE_UNBLOCK_INTERRUPTIONS();
				return FAILURE;
			}
#endif
			if (ht->pDestructor) {
				ht->pDestructor(p->pData);
			}
			UPDATE_DATA(ht, p, pData, nDataSize);
			HANDLE_UNBLOCK_INTERRUPTIONS();
			if ((long)h >= (long)ht->nNextFreeElement) {
				ht->nNextFreeElement = h < LONG_MAX ? h + 1 : LONG_MAX;
			}
			if (pDest) {
				*pDest = p->pData;
			}
			return SUCCESS;
		}
		p = p->pNext;
	}
	p = (Bucket *) pemalloc_rel(sizeof(Bucket) - 1, ht->persistent);
	if (!p) {
		return FAILURE;
	}
	p->nKeyLength = 0; /* Numeric indices are marked by making the nKeyLength == 0 */
	p->h = h;
	INIT_DATA(ht, p, pData, nDataSize);
	if (pDest) {
		*pDest = p->pData;
	}

	CONNECT_TO_BUCKET_DLLIST(p, ht->arBuckets[nIndex]);

	HANDLE_BLOCK_INTERRUPTIONS();
	ht->arBuckets[nIndex] = p;
	CONNECT_TO_GLOBAL_DLLIST(p, ht);
	HANDLE_UNBLOCK_INTERRUPTIONS();

	// 上线就是LONG_MAX
	// max(h+1, nNextFreeElement)
	if ((long)h >= (long)ht->nNextFreeElement) {
		ht->nNextFreeElement = h < LONG_MAX ? h + 1 : LONG_MAX;
	}
	ht->nNumOfElements++;
	ZEND_HASH_IF_FULL_DO_RESIZE(ht);
	return SUCCESS;
}