static int inet_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer) { struct sockaddr_in *sin=(struct sockaddr_in *)uaddr; struct sock *sk; sin->sin_family = AF_INET; sk = (struct sock *) sock->data; if (peer) { if (!tcp_connected(sk->state)) return(-ENOTCONN); sin->sin_port = sk->dummy_th.dest; sin->sin_addr.s_addr = sk->daddr; } else { sin->sin_port = sk->dummy_th.source; /* 如果使用了通配地址,就用主设备地址作为源地址 */ if (sk->saddr == 0) sin->sin_addr.s_addr = ip_my_addr(); else sin->sin_addr.s_addr = sk->saddr; } *uaddr_len = sizeof(*sin); return(0); }
static int inet_shutdown(struct socket *sock, int how) { struct sock *sk=(struct sock*)sock->data; /* * This should really check to make sure * the socket is a TCP socket. (WHY AC...) */ how++; /* maps 0->1 has the advantage of making bit 1 rcvs and 1->2 bit 2 snds. 2->3 */ if ((how & ~SHUTDOWN_MASK) || how==0) /* MAXINT->0 */ return(-EINVAL); if (sock->state == SS_CONNECTING && sk->state == TCP_ESTABLISHED) sock->state = SS_CONNECTED; if (!tcp_connected(sk->state)) return(-ENOTCONN); sk->shutdown |= how; if (sk->prot->shutdown) sk->prot->shutdown(sk, how); return(0); }
static int inet6_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer) { struct sockaddr_in6 *sin=(struct sockaddr_in6 *)uaddr; struct sock *sk; sin->sin6_family = AF_INET6; sin->sin6_flowinfo = 0; sin->sin6_scope_id = 0; sk = sock->sk; if (peer) { if (!tcp_connected(sk->state)) return(-ENOTCONN); sin->sin6_port = sk->dport; memcpy(&sin->sin6_addr, &sk->net_pinfo.af_inet6.daddr, sizeof(struct in6_addr)); if (sk->net_pinfo.af_inet6.sndflow) sin->sin6_flowinfo = sk->net_pinfo.af_inet6.flow_label; } else { if (ipv6_addr_type(&sk->net_pinfo.af_inet6.rcv_saddr) == IPV6_ADDR_ANY) memcpy(&sin->sin6_addr, &sk->net_pinfo.af_inet6.saddr, sizeof(struct in6_addr)); else memcpy(&sin->sin6_addr, &sk->net_pinfo.af_inet6.rcv_saddr, sizeof(struct in6_addr)); sin->sin6_port = sk->sport; } if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL) sin->sin6_scope_id = sk->bound_dev_if; *uaddr_len = sizeof(*sin); return(0); }
static int inet_connect(struct socket *sock, struct sockaddr * uaddr, int addr_len, int flags) { struct sock *sk=(struct sock *)sock->data; int err; sock->conn = NULL; if (sock->state == SS_CONNECTING && tcp_connected(sk->state)) { sock->state = SS_CONNECTED; /* Connection completing after a connect/EINPROGRESS/select/connect */ return 0; /* Rock and roll */ } if (sock->state == SS_CONNECTING && sk->protocol == IPPROTO_TCP && (flags & O_NONBLOCK)) { /* INET协议簇中,只有IPPROTO_TCP协议是有可能等待的 */ if (sk->err != 0) { err=sk->err; sk->err=0; return -err; } return -EALREADY; /* Connecting is currently in progress */ } /* socket第一次调用connect函数,或者udp再次调用;设置socket状态位SS_CONNECTING */ if (sock->state != SS_CONNECTING) { /* We may need to bind the socket. */ if(inet_autobind(sk)!=0) return(-EAGAIN); if (sk->prot->connect == NULL) return(-EOPNOTSUPP); /* * TCP 更新sk->state为TCP_SYN_SENT * UDP 更新sk->state为TCP_ESTABLISHED */ err = sk->prot->connect(sk, (struct sockaddr_in *)uaddr, addr_len); if (err < 0) return(err); sock->state = SS_CONNECTING; } if (sk->state > TCP_FIN_WAIT2 && sock->state==SS_CONNECTING) { /* TCP_TIME_WAIT, 未完成套接字主动关闭中 TCP_CLOSE, 未完成套接字已经关闭 TCP_CLOSE_WAIT,未完成套接字被动关闭中 TCP_LAST_ACK, 未完成套接字被动关闭中 TCP_LISTEN, 异常数据流b、c同时发生,使得客户端socket升级为listen套接字 TCP_CLOSING 未完成套接字主动关闭中 无论哪一种状态,都代表连接过程出错 */ sock->state=SS_UNCONNECTED; cli(); err=sk->err; sk->err=0; sti(); return -err; } // 当前socket状态一定处于SS_CONNECTING状态 // tcp套接字因为设置了O_NONBLOCK选项,会直接返回;保持SS_CONNECTING状态 if (sk->state != TCP_ESTABLISHED &&(flags & O_NONBLOCK)) return(-EINPROGRESS); // 同步等待tcp连接完成 cli(); /* avoid the race condition */ while(sk->state == TCP_SYN_SENT || sk->state == TCP_SYN_RECV) // 连接过程中唯一合法的两种状态 { interruptible_sleep_on(sk->sleep); if (current->signal & ~current->blocked) { // 如果进程是被信号唤醒的,就立刻返回ERESTARTSYS错误,并在系统调用返回时处理信号 // 这样就会造成socket调用connect函数时处于SS_CONNECTING状态 sti(); return(-ERESTARTSYS); } /* This fixes a nasty in the tcp/ip code. There is a hideous hassle with icmp error packets wanting to close a tcp or udp socket. */ if(sk->err && sk->protocol == IPPROTO_TCP) { sti(); sock->state = SS_UNCONNECTED; err = -sk->err; sk->err=0; return err; /* set by tcp_err() */ } } sti(); // 非tcp协议在这里设置SS_CONNECTED标志, // tcp套接字会在这里,也可以在完成连接时,由内核异步修改 sock->state = SS_CONNECTED; if (sk->state != TCP_ESTABLISHED && sk->err) { sock->state = SS_UNCONNECTED; err=sk->err; sk->err=0; return(-err); } return(0); }
static int inet_connect(struct socket *sock, struct sockaddr * uaddr, int addr_len, int flags) { struct sock *sk=(struct sock *)sock->data; int err; sock->conn = NULL; if (sock->state == SS_CONNECTING && tcp_connected(sk->state)) { sock->state = SS_CONNECTED; /* Connection completing after a connect/EINPROGRESS/select/connect */ return 0; /* Rock and roll */ } if (sock->state == SS_CONNECTING && sk->protocol == IPPROTO_TCP && (flags & O_NONBLOCK)) { if (sk->err != 0) { err=sk->err; sk->err=0; return -err; } return -EALREADY; /* Connecting is currently in progress */ } if (sock->state != SS_CONNECTING) { /* We may need to bind the socket. */ if(inet_autobind(sk)!=0) return(-EAGAIN); if (sk->prot->connect == NULL) return(-EOPNOTSUPP); err = sk->prot->connect(sk, (struct sockaddr_in *)uaddr, addr_len); if (err < 0) return(err); sock->state = SS_CONNECTING; } if (sk->state > TCP_FIN_WAIT2 && sock->state==SS_CONNECTING) { sock->state=SS_UNCONNECTED; cli(); err=sk->err; sk->err=0; sti(); return -err; } if (sk->state != TCP_ESTABLISHED &&(flags & O_NONBLOCK)) return(-EINPROGRESS); cli(); /* avoid the race condition */ while(sk->state == TCP_SYN_SENT || sk->state == TCP_SYN_RECV) { interruptible_sleep_on(sk->sleep); if (current->signal & ~current->blocked) { sti(); return(-ERESTARTSYS); } /* This fixes a nasty in the tcp/ip code. There is a hideous hassle with icmp error packets wanting to close a tcp or udp socket. */ if(sk->err && sk->protocol == IPPROTO_TCP) { sti(); sock->state = SS_UNCONNECTED; err = -sk->err; sk->err=0; return err; /* set by tcp_err() */ } } sti(); sock->state = SS_CONNECTED; if (sk->state != TCP_ESTABLISHED && sk->err) { sock->state = SS_UNCONNECTED; err=sk->err; sk->err=0; return(-err); } return(0); }