static int inet_read(struct socket *sock, char *ubuf, int size, int noblock) { struct sock *sk = (struct sock *) sock->data; if(sk->err) return inet_error(sk); /* We may need to bind the socket. */ if(inet_autobind(sk)) return(-EAGAIN); return(sk->prot->read(sk, (unsigned char *) ubuf, size, noblock, 0)); }
static int inet_recvfrom(struct socket *sock, void *ubuf, int size, int noblock, unsigned flags, struct sockaddr *sin, int *addr_len ) { struct sock *sk = (struct sock *) sock->data; if (sk->prot->recvfrom == NULL) return(-EOPNOTSUPP); if(sk->err) return inet_error(sk); /* We may need to bind the socket. */ if(inet_autobind(sk)!=0) return(-EAGAIN); return(sk->prot->recvfrom(sk, (unsigned char *) ubuf, size, noblock, flags, (struct sockaddr_in*)sin, addr_len)); }
static int inet_send(struct socket *sock, void *ubuf, int size, int noblock, unsigned flags) { struct sock *sk = (struct sock *) sock->data; if (sk->shutdown & SEND_SHUTDOWN) { send_sig(SIGPIPE, current, 1); // 向已经关闭的管道中写入数据,返回EPIPE错误 return(-EPIPE); } if(sk->err) return inet_error(sk); /* We may need to bind the socket. */ if(inet_autobind(sk)!=0) return(-EAGAIN); return(sk->prot->write(sk, (unsigned char *) ubuf, size, noblock, flags)); }
static int inet_sendto(struct socket *sock, void *ubuf, int size, int noblock, unsigned flags, struct sockaddr *sin, int addr_len) { struct sock *sk = (struct sock *) sock->data; if (sk->shutdown & SEND_SHUTDOWN) { send_sig(SIGPIPE, current, 1); return(-EPIPE); } if (sk->prot->sendto == NULL) return(-EOPNOTSUPP); if(sk->err) return inet_error(sk); /* We may need to bind the socket. */ if(inet_autobind(sk)!=0) return -EAGAIN; return(sk->prot->sendto(sk, (unsigned char *) ubuf, size, noblock, flags, (struct sockaddr_in *)sin, addr_len)); }
static int inet_listen(struct socket *sock, int backlog) { struct sock *sk = (struct sock *) sock->data; if(inet_autobind(sk)!=0) return -EAGAIN; /* We might as well re use these. */ /* * note that the backlog is "unsigned char", so truncate it * somewhere. We might as well truncate it to what everybody * else does.. */ if ((unsigned) backlog > 128) backlog = 128; sk->max_ack_backlog = backlog; if (sk->state != TCP_LISTEN) { sk->ack_backlog = 0; sk->state = TCP_LISTEN; } 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); }