tcp和udp等协议在传输层都对应一个sock结构,该结构是实现协议的重要结构体,而传输层实现的就是对该结构体的管理。利用一个哈希链表根据端口号保存sock结构体。有了保存sock结构的数据结构后,还需要一系列的操作函数。代码如下。
/*
* See if a socket number is in use.
*/
// 看socket的端口是否在使用
static int sk_inuse(struct proto *prot, int num)
{
struct sock *sk;
// 根据端口号取得哈希链表中的一个链表
for(sk = prot->sock_array[num & (SOCK_ARRAY_SIZE -1 )];
sk != NULL; sk=sk->next)
{
if (sk->num == num)
return(1);
}
return(0);
}
/*
* Pick a new socket number
*/
// 随机获取一个端口
unsigned short get_new_socknum(struct proto *prot, unsigned short base)
{
static int start=0;
/*
* Used to cycle through the port numbers so the
* chances of a confused connection drop.
*/
int i, j;
int best = 0;
int size = 32767; /* a big num. */
struct sock *sk;
// 大于1024
if (base == 0)
base = PROT_SOCK+1+(start % 1024);
if (base <= PROT_SOCK)
{
base += PROT_SOCK+(start % 1024);
}
/* Now look through the entire array and try to find an empty ptr. */
for(i=0; i < SOCK_ARRAY_SIZE; i++)
{
j = 0;
// 找到一条链表
sk = prot->sock_array[(i+base+1) &(SOCK_ARRAY_SIZE -1)];
// 找到链表中的最后一个节点
while(sk != NULL)
{
sk = sk->next;
j++;
}
// 该链表上还没有节点,说明这个端口还没有被使用过,返回该端口号,更新start变量
if (j == 0)
{
start =(i+1+start )%1024;
return(i+base+1);
}
/*
j为本次循环的队列的节点数,best记录新端口所属队列的索引,
size为本次循环为止节点数最少的队列的节点数,为了避免单个队列过长,
找可用端口的时候,不仅要找到一个可用的端口,而且尽量保证端口所对
应的队列不会过长,避免查找的时候比较慢,所以for循环是为了找出哈希链表
中节点数最少的队列对应的索引。然后往该队列插入一个新的端口节点
*/
if (j < size)
{
best = i;
size = j;
}
}
/* Now make sure the one we want is not in use. */
// 在一条队列中找到一个未使用的端口号,SOCK_ARRAY_SIZE保证哈希后对应的是同一个队列
while(sk_inuse(prot, base +best+1))
{
best += SOCK_ARRAY_SIZE;
}
return(best+base+1);
}
/*
* Add a socket into the socket tables by number.
*/
void put_sock(unsigned short num, struct sock *sk)
{
struct sock *sk1;
struct sock *sk2;
int mask;
unsigned long flags;
sk->num = num;
sk->next = NULL;
num = num &(SOCK_ARRAY_SIZE -1);
/* We can't have an interrupt re-enter here. */
save_flags(flags);
cli();
// 使用的socket数
sk->prot->inuse += 1;
// 最多使用的socket数
if (sk->prot->highestinuse < sk->prot->inuse)
sk->prot->highestinuse = sk->prot->inuse;
// 链表为空,sk成为第一个节点
if (sk->prot->sock_array[num] == NULL)
{
sk->prot->sock_array[num] = sk;
restore_flags(flags);
return;
}
restore_flags(flags);
// mask为0xff000000 => 0xffff0000 => 0xffffff00 => 0xffffffff
for(mask = 0xff000000; mask != 0xffffffff; mask = (mask >> 8) | mask)
{
if ((mask & sk->saddr) &&
(mask & sk->saddr) != (mask & 0xffffffff))
{
mask = mask << 8;
break;
}
}
cli();
// 根据端口找到对应的链表,找到对应的位置插入队列
sk1 = sk->prot->sock_array[num];
for(sk2 = sk1; sk2 != NULL; sk2=sk2->next)
{
if (!(sk2->saddr & mask))
{
if (sk2 == sk1)
{
sk->next = sk->prot->sock_array[num];
sk->prot->sock_array[num] = sk;
sti();
return;
}
sk->next = sk2;
sk1->next= sk;
sti();
return;
}
sk1 = sk2;
}
/* Goes at the end. */
sk->next = NULL;
sk1->next = sk;
sti();
}
/*
* Remove a socket from the socket tables.
*/
static void remove_sock(struct sock *sk1)
{
struct sock *sk2;
unsigned long flags;
if (!sk1->prot)
{
printk("sock.c: remove_sock: sk1->prot == NULL\n");
return;
}
/* We can't have this changing out from under us. */
save_flags(flags);
cli();
sk2 = sk1->prot->sock_array[sk1->num &(SOCK_ARRAY_SIZE -1)];
// 是队列的第一个节点
if (sk2 == sk1)
{
sk1->prot->inuse -= 1;
sk1->prot->sock_array[sk1->num &(SOCK_ARRAY_SIZE -1)] = sk1->next;
restore_flags(flags);
return;
}
// 找sk1
while(sk2 && sk2->next != sk1)
{
sk2 = sk2->next;
}
// 找到
if (sk2)
{
sk1->prot->inuse -= 1;
sk2->next = sk1->next;
restore_flags(flags);
return;
}
restore_flags(flags);
}
/*
* Destroy an AF_INET socket
*/
void destroy_sock(struct sock *sk)
{
struct sk_buff *skb;
sk->inuse = 1; /* just to be safe. */
/* In case it's sleeping somewhere. */
if (!sk->dead)
sk->write_space(sk);
remove_sock(sk);
/* Now we can no longer get new packets. */
delete_timer(sk);
/* Nor send them */
del_timer(&sk->retransmit_timer);
while ((skb = tcp_dequeue_partial(sk)) != NULL) {
IS_SKB(skb);
kfree_skb(skb, FREE_WRITE);
}
/* Cleanup up the write buffer. */
while((skb = skb_dequeue(&sk->write_queue)) != NULL) {
IS_SKB(skb);
kfree_skb(skb, FREE_WRITE);
}
/*
* Don't discard received data until the user side kills its
* half of the socket.
*/
if (sk->dead)
{
while((skb=skb_dequeue(&sk->receive_queue))!=NULL)
{
/*
* This will take care of closing sockets that were
* listening and didn't accept everything.
*/
// 处理listen型的socket,监听套接字接收队列里的skb关联的sock结构是一个新建的而不是sk
if (skb->sk != NULL && skb->sk != sk)
{
IS_SKB(skb);
skb->sk->dead = 1;
// 关闭连接
skb->sk->prot->close(skb->sk, 0);
}
IS_SKB(skb);
kfree_skb(skb, FREE_READ);
}
}
/* Now we need to clean up the send head. */
cli();
// 清空为了重传而缓存的数据包
for(skb = sk->send_head; skb != NULL; )
{
struct sk_buff *skb2;
/*
* We need to remove skb from the transmit queue,
* or maybe the arp queue.
*/
if (skb->next && skb->prev) {
/* printk("destroy_sock: unlinked skb\n");*/
IS_SKB(skb);
skb_unlink(skb);
}
skb->dev = NULL;
// unlink后link3指针仍然指向下一个skb节点
skb2 = skb->link3;
kfree_skb(skb, FREE_WRITE);
skb = skb2;
}
sk->send_head = NULL;
sti();
/* And now the backlog. */
// 还没来得及移到receive_queue队列的而缓存在back_log队列的skb
while((skb=skb_dequeue(&sk->back_log))!=NULL)
{
/* this should never happen. */
/* printk("cleaning back_log\n");*/
kfree_skb(skb, FREE_READ);
}
/* Now if it has a half accepted/ closed socket. */
if (sk->pair)
{
sk->pair->dead = 1;
sk->pair->prot->close(sk->pair, 0);
sk->pair = NULL;
}
/*
* Now if everything is gone we can free the socket
* structure, otherwise we need to keep it around until
* everything is gone.
*/
if (sk->dead && sk->rmem_alloc == 0 && sk->wmem_alloc == 0)
{
kfree_s((void *)sk,sizeof(*sk));
}
else
{
/* this should never happen. */
/* actually it can if an ack has just been sent. */
sk->destroy = 1;
sk->ack_backlog = 0;
sk->inuse = 0;
reset_timer(sk, TIME_DESTROY, SOCK_DESTROY_TIME);
}
}
struct sock *get_sock(struct proto *prot, unsigned short num,
unsigned long raddr,
unsigned short rnum, unsigned long laddr)
{
struct sock *s;
struct sock *result = NULL;
int badness = -1;
unsigned short hnum;
hnum = ntohs(num);
/*
* SOCK_ARRAY_SIZE must be a power of two. This will work better
* than a prime unless 3 or more sockets end up using the same
* array entry. This should not be a problem because most
* well known sockets don't overlap that much, and for
* the other ones, we can just be careful about picking our
* socket number when we choose an arbitrary one.
*/
for(s = prot->sock_array[hnum & (SOCK_ARRAY_SIZE - 1)];
s != NULL; s = s->next)
{
int score = 0;
if (s->num != hnum)
continue;
if(s->dead && (s->state == TCP_CLOSE))
continue;
/* local address matches? */
if (s->saddr) {
if (s->saddr != laddr)
continue;
score++;
}
/* remote address matches? */
if (s->daddr) {
if (s->daddr != raddr)
continue;
score++;
}
/* remote port matches? */
if (s->dummy_th.dest) {
if (s->dummy_th.dest != rnum)
continue;
score++;
}
/* perfect match? */
// 全匹配,直接返回
if (score == 3)
return s;
/* no, check if this is the best so far.. */
if (score <= badness)
continue;
// 记录最好的匹配项
result = s;
badness = score;
}
return result;
}
协议每次新建一个socket的时候就会在底层生成一个sock结构体,然后插入大到哈希链表中,收到数据时候根据ip和端口从哈希链表中找到对应的sock结构体。