linux下的connect程序,Linux connect的TCP连接方式源码实现

static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr,

int addr_len, int flags)

{

struct sockaddr_un *sunaddr = (struct sockaddr_un *)uaddr;

struct sock *sk = sock->sk;

struct net *net = sock_net(sk);

struct unix_sock *u = unix_sk(sk), *newu, *otheru;

struct sock *newsk = NULL;

struct sock *other = NULL;

struct sk_buff *skb = NULL;

unsigned hash;

int st;

int err;

long timeo;

err = unix_mkname(sunaddr, addr_len, &hash);

if (err < 0)

goto out;

addr_len = err;

if (test_bit(SOCK_PASSCRED, &sock->flags) && !u->addr &&

(err = unix_autobind(sock)) != 0)

goto out;

timeo = sock_sndtimeo(sk, flags & O_NONBLOCK);

/* First of all allocate resources.

If we will make it after state is locked,

we will have to recheck all again in any case.

*/

err = -ENOMEM;

/* create new sock for complete connection */

newsk = unix_create1(sock_net(sk), NULL);

if (newsk == NULL)

goto out;

/* Allocate skb for sending to listening sock */

skb = sock_wmalloc(newsk, 1, 0, GFP_KERNEL);

if (skb == NULL)

goto out;

restart:

/*  Find listening sock. */

other = unix_find_other(net, sunaddr, addr_len, sk->sk_type, hash, &err);

if (!other)

goto out;

/* Latch state of peer */

unix_state_lock(other);

/* Apparently VFS overslept socket death. Retry. */

if (sock_flag(other, SOCK_DEAD)) {

unix_state_unlock(other);

sock_put(other);

goto restart;

}

err = -ECONNREFUSED;

if (other->sk_state != TCP_LISTEN)

goto out_unlock;

if (other->sk_shutdown & RCV_SHUTDOWN)

goto out_unlock;

if (unix_recvq_full(other)) {

err = -EAGAIN;

if (!timeo)

goto out_unlock;

timeo = unix_wait_for_peer(other, timeo);

err = sock_intr_errno(timeo);

if (signal_pending(current))

goto out;

sock_put(other);

goto restart;

}

/* Latch our state.

It is tricky place. We need to grab our state lock and cannot

drop lock on peer. It is dangerous because deadlock is

possible. Connect to self case and simultaneous

attempt to connect are eliminated by checking socket

state. other is TCP_LISTEN, if sk is TCP_LISTEN we

check this before attempt to grab lock.

Well, and we have to recheck the state after socket locked.

*/

st = sk->sk_state;

switch (st) {

case TCP_CLOSE:

/* This is ok... continue with connect */

break;

case TCP_ESTABLISHED:

/* Socket is already connected */

err = -EISCONN;

goto out_unlock;

default:

err = -EINVAL;

goto out_unlock;

}

unix_state_lock_nested(sk);

if (sk->sk_state != st) {

unix_state_unlock(sk);

unix_state_unlock(other);

sock_put(other);

goto restart;

}

err = security_unix_stream_connect(sk, other, newsk);

if (err) {

unix_state_unlock(sk);

goto out_unlock;

}

/* The way is open! Fastly set all the necessary fields... */

sock_hold(sk);

unix_peer(newsk) = sk;

newsk->sk_state  = TCP_ESTABLISHED;

newsk->sk_type  = sk->sk_type;

init_peercred(newsk);

newu = unix_sk(newsk);

RCU_INIT_POINTER(newsk->sk_wq, &newu->peer_wq);

otheru = unix_sk(other);

/* copy address information from listening to new sock*/

if (otheru->addr) {

atomic_inc(&otheru->addr->refcnt);

newu->addr = otheru->addr;

}

if (otheru->dentry) {

newu->dentry = dget(otheru->dentry);

newu->mnt = mntget(otheru->mnt);

}

/* Set credentials */

copy_peercred(sk, other);

sock->state = SS_CONNECTED;

sk->sk_state = TCP_ESTABLISHED;

sock_hold(newsk);

smp_mb__after_atomic_inc(); /* sock_hold() does an atomic_inc() */

unix_peer(sk) = newsk;

unix_state_unlock(sk);

/* take ten and and send info to listening sock */

spin_lock(&other->sk_receive_queue.lock);

__skb_queue_tail(&other->sk_receive_queue, skb);

spin_unlock(&other->sk_receive_queue.lock);

unix_state_unlock(other);

other->sk_data_ready(other, 0);

sock_put(other);

return 0;

out_unlock:

if (other)

unix_state_unlock(other);

out:  kfree_skb(skb);  if (newsk)   unix_release_sock(newsk, 0);  if (other)   sock_put(other);  return err; }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值