📄 sock.c
字号:
/* * Simple resource managers for sockets. *//* * Write buffer destructor automatically called from kfree_skb. */void sock_wfree(struct sk_buff *skb){ struct sock *sk = skb->sk; /* In case it might be waiting for more memory. */ atomic_sub(skb->truesize, &sk->wmem_alloc); sk->write_space(sk);}/* * Read buffer destructor automatically called from kfree_skb. */void sock_rfree(struct sk_buff *skb){ struct sock *sk = skb->sk; atomic_sub(skb->truesize, &sk->rmem_alloc);}/* * Allocate a skb from the socket's send buffer. */struct sk_buff *sock_wmalloc(struct sock *sk, unsigned long size, int force, int priority){ if (force || atomic_read(&sk->wmem_alloc) < sk->sndbuf) { struct sk_buff * skb = alloc_skb(size, priority); if (skb) { atomic_add(skb->truesize, &sk->wmem_alloc); skb->destructor = sock_wfree; skb->sk = sk; return skb; } } return NULL;}/* * Allocate a skb from the socket's receive buffer. */ struct sk_buff *sock_rmalloc(struct sock *sk, unsigned long size, int force, int priority){ if (force || atomic_read(&sk->rmem_alloc) < sk->rcvbuf) { struct sk_buff *skb = alloc_skb(size, priority); if (skb) { atomic_add(skb->truesize, &sk->rmem_alloc); skb->destructor = sock_rfree; skb->sk = sk; return skb; } } return NULL;}/* * Allocate a memory block from the socket's option memory buffer. */ void *sock_kmalloc(struct sock *sk, int size, int priority){ if (atomic_read(&sk->omem_alloc)+size < sysctl_optmem_max) { void *mem; /* First do the add, to avoid the race if kmalloc * might sleep. */ atomic_add(size, &sk->omem_alloc); mem = kmalloc(size, priority); if (mem) return mem; atomic_sub(size, &sk->omem_alloc); } return NULL;}/* * Free an option memory block. */void sock_kfree_s(struct sock *sk, void *mem, int size){ kfree_s(mem, size); atomic_sub(size, &sk->omem_alloc);}/* FIXME: this is insane. We are trying suppose to be controlling how * how much space we have for data bytes, not packet headers. * This really points out that we need a better system for doing the * receive buffer. -- erics * WARNING: This is currently ONLY used in tcp. If you need it else where * this will probably not be what you want. Possibly these two routines * should move over to the ipv4 directory. */unsigned long sock_rspace(struct sock *sk){ int amt = 0; if (sk != NULL) { /* This used to have some bizarre complications that * to attempt to reserve some amount of space. This doesn't * make sense, since the number returned here does not * actually reflect allocated space, but rather the amount * of space we committed to. We gamble that we won't * run out of memory, and returning a smaller number does * not change the gamble. If we lose the gamble tcp still * works, it may just slow down for retransmissions. */ amt = sk->rcvbuf - atomic_read(&sk->rmem_alloc); if (amt < 0) amt = 0; } return amt;}/* It is almost wait_for_tcp_memory minus release_sock/lock_sock. I think, these locks should be removed for datagram sockets. */static void sock_wait_for_wmem(struct sock * sk){ struct wait_queue wait = { current, NULL }; sk->socket->flags &= ~SO_NOSPACE; add_wait_queue(sk->sleep, &wait); for (;;) { if (signal_pending(current)) break; current->state = TASK_INTERRUPTIBLE; if (atomic_read(&sk->wmem_alloc) < sk->sndbuf) break; if (sk->shutdown & SEND_SHUTDOWN) break; if (sk->err) break; schedule(); } current->state = TASK_RUNNING; remove_wait_queue(sk->sleep, &wait);}/* * Generic send/receive buffer handlers */struct sk_buff *sock_alloc_send_skb(struct sock *sk, unsigned long size, unsigned long fallback, int noblock, int *errcode){ int err; struct sk_buff *skb; while (1) { unsigned long try_size = size; err = sock_error(sk); if (err != 0) goto failure; /* * We should send SIGPIPE in these cases according to * 1003.1g draft 6.4. If we (the user) did a shutdown() * call however we should not. * * Note: This routine isnt just used for datagrams and * anyway some datagram protocols have a notion of * close down. */ err = -EPIPE; if (sk->shutdown&SEND_SHUTDOWN) goto failure; if (fallback) { /* The buffer get won't block, or use the atomic queue. * It does produce annoying no free page messages still. */ skb = sock_wmalloc(sk, size, 0, GFP_BUFFER); if (skb) break; try_size = fallback; } skb = sock_wmalloc(sk, try_size, 0, sk->allocation); if (skb) break; /* * This means we have too many buffers for this socket already. */ sk->socket->flags |= SO_NOSPACE; err = -EAGAIN; if (noblock) goto failure; err = -ERESTARTSYS; if (signal_pending(current)) goto failure; sock_wait_for_wmem(sk); } return skb;failure: *errcode = err; return NULL;}void __release_sock(struct sock *sk){#ifdef CONFIG_INET if (!sk->prot || !sk->backlog_rcv) return; /* See if we have any packets built up. */ start_bh_atomic(); while (!skb_queue_empty(&sk->back_log)) { struct sk_buff * skb = sk->back_log.next; __skb_unlink(skb, &sk->back_log); sk->backlog_rcv(sk, skb); } end_bh_atomic();#endif }/* * Generic socket manager library. Most simpler socket families * use this to manage their socket lists. At some point we should * hash these. By making this generic we get the lot hashed for free. */ void sklist_remove_socket(struct sock **list, struct sock *sk){ struct sock *s; start_bh_atomic(); s= *list; if(s==sk) { *list = s->next; end_bh_atomic(); return; } while(s && s->next) { if(s->next==sk) { s->next=sk->next; break; } s=s->next; } end_bh_atomic();}void sklist_insert_socket(struct sock **list, struct sock *sk){ start_bh_atomic(); sk->next= *list; *list=sk; end_bh_atomic();}/* * This is only called from user mode. Thus it protects itself against * interrupt users but doesn't worry about being called during work. * Once it is removed from the queue no interrupt or bottom half will * touch it and we are (fairly 8-) ) safe. */void sklist_destroy_socket(struct sock **list, struct sock *sk);/* * Handler for deferred kills. */static void sklist_destroy_timer(unsigned long data){ struct sock *sk=(struct sock *)data; sklist_destroy_socket(NULL,sk);}/* * Destroy a socket. We pass NULL for a list if we know the * socket is not on a list. */ void sklist_destroy_socket(struct sock **list,struct sock *sk){ struct sk_buff *skb; if(list) sklist_remove_socket(list, sk); while((skb=skb_dequeue(&sk->receive_queue))!=NULL) { kfree_skb(skb); } if(atomic_read(&sk->wmem_alloc) == 0 && atomic_read(&sk->rmem_alloc) == 0 && sk->dead) { sk_free(sk); } else { /* * Someone is using our buffers still.. defer */ init_timer(&sk->timer); sk->timer.expires=jiffies+SOCK_DESTROY_TIME; sk->timer.function=sklist_destroy_timer; sk->timer.data = (unsigned long)sk; add_timer(&sk->timer); }}/* * Set of default routines for initialising struct proto_ops when * the protocol does not support a particular function. In certain * cases where it makes no sense for a protocol to have a "do nothing" * function, some default processing is provided. */int sock_no_dup(struct socket *newsock, struct socket *oldsock){ struct sock *sk = oldsock->sk; return net_families[sk->family]->create(newsock, sk->protocol);}int sock_no_release(struct socket *sock, struct socket *peersock){ return 0;}int sock_no_bind(struct socket *sock, struct sockaddr *saddr, int len){ return -EOPNOTSUPP;}int sock_no_connect(struct socket *sock, struct sockaddr *saddr, int len, int flags){ return -EOPNOTSUPP;}int sock_no_socketpair(struct socket *sock1, struct socket *sock2){ return -EOPNOTSUPP;}int sock_no_accept(struct socket *sock, struct socket *newsock, int flags){ return -EOPNOTSUPP;}int sock_no_getname(struct socket *sock, struct sockaddr *saddr, int *len, int peer){ return -EOPNOTSUPP;}unsigned int sock_no_poll(struct file * file, struct socket *sock, poll_table *pt){ return 0;}int sock_no_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg){ return -EOPNOTSUPP;}int sock_no_listen(struct socket *sock, int backlog){ return -EOPNOTSUPP;}int sock_no_shutdown(struct socket *sock, int how){ return -EOPNOTSUPP;}int sock_no_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen){ return -EOPNOTSUPP;}int sock_no_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen){ return -EOPNOTSUPP;}/* * Note: if you add something that sleeps here then change sock_fcntl() * to do proper fd locking. */int sock_no_fcntl(struct socket *sock, unsigned int cmd, unsigned long arg){ struct sock *sk = sock->sk; switch(cmd) { case F_SETOWN: /* * This is a little restrictive, but it's the only * way to make sure that you can't send a sigurg to * another process. */ if (current->pgrp != -arg && current->pid != arg && !capable(CAP_KILL)) return(-EPERM); sk->proc = arg; return(0); case F_GETOWN: return(sk->proc); default: return(-EINVAL); }}int sock_no_sendmsg(struct socket *sock, struct msghdr *m, int flags, struct scm_cookie *scm){ return -EOPNOTSUPP;}int sock_no_recvmsg(struct socket *sock, struct msghdr *m, int flags, struct scm_cookie *scm){ return -EOPNOTSUPP;}/* * Default Socket Callbacks */void sock_def_wakeup(struct sock *sk){ if(!sk->dead) wake_up_interruptible(sk->sleep);}void sock_def_error_report(struct sock *sk){ if (!sk->dead) { wake_up_interruptible(sk->sleep); sock_wake_async(sk->socket,0); }}void sock_def_readable(struct sock *sk, int len){ if(!sk->dead) { wake_up_interruptible(sk->sleep); sock_wake_async(sk->socket,1); }}void sock_def_write_space(struct sock *sk){ /* Do not wake up a writer until he can make "significant" * progress. --DaveM */ if(!sk->dead && ((atomic_read(&sk->wmem_alloc) << 1) <= sk->sndbuf)) { wake_up_interruptible(sk->sleep); /* Should agree with poll, otherwise some programs break */ if (sock_writeable(sk)) sock_wake_async(sk->socket, 2); }}void sock_def_destruct(struct sock *sk){ if (sk->protinfo.destruct_hook) kfree(sk->protinfo.destruct_hook);}void sock_init_data(struct socket *sock, struct sock *sk){ skb_queue_head_init(&sk->receive_queue); skb_queue_head_init(&sk->write_queue); skb_queue_head_init(&sk->back_log); skb_queue_head_init(&sk->error_queue); init_timer(&sk->timer); sk->allocation = GFP_KERNEL; sk->rcvbuf = sysctl_rmem_default; sk->sndbuf = sysctl_wmem_default; sk->state = TCP_CLOSE; sk->zapped = 1; sk->socket = sock; if(sock) { sk->type = sock->type; sk->sleep = &sock->wait; sock->sk = sk; } sk->state_change = sock_def_wakeup; sk->data_ready = sock_def_readable; sk->write_space = sock_def_write_space; sk->error_report = sock_def_error_report; sk->destruct = sock_def_destruct; sk->peercred.pid = 0; sk->peercred.uid = -1; sk->peercred.gid = -1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -