⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 packet.c

📁 使用最广泛的radius的linux的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
}static int packet_entry_cmp(const void *one, const void *two){	const RADIUS_PACKET * const *a = one;	const RADIUS_PACKET * const *b = two;	return fr_packet_cmp(*a, *b);}/* *	A particular socket can have 256 RADIUS ID's outstanding to *	any one destination IP/port.  So we have a structure that *	manages destination IP & port, and has an array of 256 ID's. * *	The only magic here is that we map the socket number (0..256) *	into an "internal" socket number 0..31, that we use to set *	bits in the ID array.  If a bit is 1, then that ID is in use *	for that socket, and the request MUST be in the packet hash! * *	Note that as a minor memory leak, we don't have an API to free *	this structure, except when we discard the whole packet list. *	This means that if destinations are added and removed, they *	won't be removed from this tree. */typedef struct fr_packet_dst2id_t {	fr_ipaddr_t	dst_ipaddr;	int		dst_port;	uint32_t	id[1];	/* really id[256] */} fr_packet_dst2id_t;static uint32_t packet_dst2id_hash(const void *data){	uint32_t hash;	const fr_packet_dst2id_t *pd = data;	hash = fr_hash(&pd->dst_port, sizeof(pd->dst_port));	switch (pd->dst_ipaddr.af) {	case AF_INET:		hash = fr_hash_update(&pd->dst_ipaddr.ipaddr.ip4addr,					sizeof(pd->dst_ipaddr.ipaddr.ip4addr),					hash);		break;	case AF_INET6:		hash = fr_hash_update(&pd->dst_ipaddr.ipaddr.ip6addr,					sizeof(pd->dst_ipaddr.ipaddr.ip6addr),					hash);		break;	default:		break;	}	return hash;}static int packet_dst2id_cmp(const void *one, const void *two){	const fr_packet_dst2id_t *a = one;	const fr_packet_dst2id_t *b = two;	if (a->dst_port < b->dst_port) return -1;	if (a->dst_port > b->dst_port) return +1;	return fr_ipaddr_cmp(&a->dst_ipaddr, &b->dst_ipaddr);}static void packet_dst2id_free(void *data){	free(data);}void fr_packet_list_free(fr_packet_list_t *pl){	if (!pl) return;	fr_hash_table_free(pl->ht);	fr_hash_table_free(pl->dst2id_ht);	free(pl);}/* *	Caller is responsible for managing the packet entries. */fr_packet_list_t *fr_packet_list_create(int alloc_id){	int i;	fr_packet_list_t	*pl;	pl = malloc(sizeof(*pl));	if (!pl) return NULL;	memset(pl, 0, sizeof(*pl));	pl->ht = fr_hash_table_create(packet_entry_hash,					packet_entry_cmp,					NULL);	if (!pl->ht) {		fr_packet_list_free(pl);		return NULL;	}	for (i = 0; i < MAX_SOCKETS; i++) {		pl->sockets[i].sockfd = -1;	}	if (alloc_id) {		pl->alloc_id = 1;		pl->dst2id_ht = fr_hash_table_create(packet_dst2id_hash,						       packet_dst2id_cmp,						       packet_dst2id_free);		if (!pl->dst2id_ht) {			fr_packet_list_free(pl);			return NULL;		}	}	return pl;}/* *	If pl->alloc_id is set, then fr_packet_list_id_alloc() MUST *	be called before inserting the packet into the list! */int fr_packet_list_insert(fr_packet_list_t *pl,			    RADIUS_PACKET **request_p){	if (!pl || !request_p || !*request_p) return 0;	(*request_p)->hash = fr_request_packet_hash(*request_p);	return fr_hash_table_insert(pl->ht, request_p);}RADIUS_PACKET **fr_packet_list_find(fr_packet_list_t *pl,				      RADIUS_PACKET *request){	if (!pl || !request) return 0;	return fr_hash_table_finddata(pl->ht, &request);}/* *	This presumes that the reply has dst_ipaddr && dst_port set up *	correctly (i.e. real IP, or "*"). */RADIUS_PACKET **fr_packet_list_find_byreply(fr_packet_list_t *pl,					      RADIUS_PACKET *reply){	RADIUS_PACKET my_request, *request;	fr_packet_socket_t *ps;	if (!pl || !reply) return NULL;	ps = fr_socket_find(pl, reply->sockfd);	if (!ps) return NULL;	/*	 *	Initialize request from reply, AND from the source	 *	IP & port of this socket.  The client may have bound	 *	the socket to 0, in which case it's some random port,	 *	that is NOT in the original request->src_port.	 */	my_request.sockfd = reply->sockfd;	my_request.id = reply->id;	if (ps->inaddr_any) {		my_request.src_ipaddr = ps->ipaddr;	} else {		my_request.src_ipaddr = reply->dst_ipaddr;	}	my_request.src_port = ps->port;;	my_request.dst_ipaddr = reply->src_ipaddr;	my_request.dst_port = reply->src_port;	my_request.hash = 0;	request = &my_request;	return fr_hash_table_finddata(pl->ht, &request);}RADIUS_PACKET **fr_packet_list_yank(fr_packet_list_t *pl,				      RADIUS_PACKET *request){	if (!pl || !request) return NULL;	return fr_hash_table_yank(pl->ht, &request);}int fr_packet_list_num_elements(fr_packet_list_t *pl){	if (!pl) return 0;	return fr_hash_table_num_elements(pl->ht);}/* *	1 == ID was allocated & assigned *	0 == error allocating memory *	-1 == all ID's are used, caller should open a new socket. * *	Note that this ALSO assigns a socket to use, and updates *	packet->request->src_ipaddr && packet->request->src_port * *	In multi-threaded systems, the calls to id_alloc && id_free *	should be protected by a mutex.  This does NOT have to be *	the same mutex as the one protecting the insert/find/yank *	calls! */int fr_packet_list_id_alloc(fr_packet_list_t *pl,			      RADIUS_PACKET *request){	int i, id, start;	uint32_t free_mask;	fr_packet_dst2id_t my_pd, *pd;	fr_packet_socket_t *ps;	if (!pl || !pl->alloc_id || !request) return 0;	my_pd.dst_ipaddr = request->dst_ipaddr;	my_pd.dst_port = request->dst_port;	pd = fr_hash_table_finddata(pl->dst2id_ht, &my_pd);	if (!pd) {		pd = malloc(sizeof(*pd) + 255 * sizeof(pd->id[0]));		if (!pd) return 0;		memset(pd, 0, sizeof(*pd) + 255 * sizeof(pd->id[0]));		pd->dst_ipaddr = request->dst_ipaddr;		pd->dst_port = request->dst_port;		if (!fr_hash_table_insert(pl->dst2id_ht, pd)) {			free(pd);			return 0;		}	}	/*	 *	FIXME: Go to an LRU system.  This prevents ID re-use	 *	for as long as possible.  The main problem with that	 *	approach is that it requires us to populate the	 *	LRU/FIFO when we add a new socket, or a new destination,	 *	which can be expensive.	 *	 *	The LRU can be avoided if the caller takes care to free	 *	Id's only when all responses have been received, OR after	 *	a timeout.	 */	id = start = (int) fr_rand() & 0xff;	while (pd->id[id] == pl->mask) { /* all sockets are using this ID */		id++;		id &= 0xff;		if (id == start) return 0;	}	free_mask = ~((~pd->id[id]) & pl->mask);	start = -1;	for (i = 0; i < MAX_SOCKETS; i++) {		if (pl->sockets[i].sockfd == -1) continue; /* paranoia */		if ((free_mask & (1 << i)) == 0) {			start = i;			break;		}	}	if (start < 0) return 0; /* bad error */	pd->id[id] |= (1 << start);	ps = &pl->sockets[start];	ps->num_outgoing++;	pl->num_outgoing++;	/*	 *	Set the ID, source IP, and source port.	 */	request->id = id;	request->sockfd = ps->sockfd;	request->src_ipaddr = ps->ipaddr;	request->src_port = ps->port;	return 1;}/* *	Should be called AFTER yanking it from the list, so that *	any newly inserted entries don't collide with this one. */int fr_packet_list_id_free(fr_packet_list_t *pl,			     RADIUS_PACKET *request){	fr_packet_socket_t *ps;	fr_packet_dst2id_t my_pd, *pd;	if (!pl || !request) return 0;	ps = fr_socket_find(pl, request->sockfd);	if (!ps) return 0;	my_pd.dst_ipaddr = request->dst_ipaddr;	my_pd.dst_port = request->dst_port;	pd = fr_hash_table_finddata(pl->dst2id_ht, &my_pd);	if (!pd) return 0;	pd->id[request->id] &= ~(1 << ps->offset);	request->hash = 0;	/* invalidate the cached hash */	ps->num_outgoing--;	pl->num_outgoing--;	return 1;}int fr_packet_list_walk(fr_packet_list_t *pl, void *ctx,			  fr_hash_table_walk_t callback){	if (!pl || !callback) return 0;	return fr_hash_table_walk(pl->ht, callback, ctx);}int fr_packet_list_fd_set(fr_packet_list_t *pl, fd_set *set){	int i, maxfd;	if (!pl || !set) return 0;	maxfd = -1;	for (i = 0; i < MAX_SOCKETS; i++) {		if (pl->sockets[i].sockfd == -1) continue;		FD_SET(pl->sockets[i].sockfd, set);		if (pl->sockets[i].sockfd > maxfd) {			maxfd = pl->sockets[i].sockfd;		}	}	if (maxfd < 0) return -1;	return maxfd + 1;}/* *	Round-robins the receivers, without priority. * *	FIXME: Add sockfd, if -1, do round-robin, else do sockfd *		IF in fdset. */RADIUS_PACKET *fr_packet_list_recv(fr_packet_list_t *pl, fd_set *set){	int start;	RADIUS_PACKET *packet;	if (!pl || !set) return NULL;	start = pl->last_recv;	do {		start++;		start &= SOCKOFFSET_MASK;		if (pl->sockets[start].sockfd == -1) continue;		if (!FD_ISSET(pl->sockets[start].sockfd, set)) continue;		packet = rad_recv(pl->sockets[start].sockfd, 0);		if (!packet) continue;		/*		 *	Call fr_packet_list_find_byreply().  If it		 *	doesn't find anything, discard the reply.		 */		pl->last_recv = start;		return packet;	} while (start != pl->last_recv);	return NULL;}int fr_packet_list_num_incoming(fr_packet_list_t *pl){	int num_elements;	if (!pl) return 0;	num_elements = fr_hash_table_num_elements(pl->ht);	if (num_elements < pl->num_outgoing) return 0; /* panic! */	return num_elements - pl->num_outgoing;}int fr_packet_list_num_outgoing(fr_packet_list_t *pl){	if (!pl) return 0;	return pl->num_outgoing;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -