http://lxr.linux.no/linux+v2.6.30/net/ipv4/tcp_ipv4.c

 144/* This will initiate an outgoing connection. */
 145int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
 146{
 147        struct inet_sock *inet = inet_sk(sk);
 148        struct tcp_sock *tp = tcp_sk(sk);
 149        struct sockaddr_in *usin = (struct sockaddr_in *)uaddr;
 150        struct rtable *rt;
 151        __be32 daddr, nexthop;
 152        int tmp;
 153        int err;
 154
 155        if (addr_len < sizeof(struct sockaddr_in))
 156                return -EINVAL;
 157
 158        if (usin->sin_family != AF_INET)
 159                return -EAFNOSUPPORT;
 160
 161        nexthop = daddr = usin->sin_addr.s_addr;
 162        if (inet->opt && inet->opt->srr) {
 163                if (!daddr)
 164                        return -EINVAL;
 165                nexthop = inet->opt->faddr;
 166        }
 167
 168        tmp = ip_route_connect(&rt, nexthop, inet->saddr,
 169                               RT_CONN_FLAGS(sk), sk->sk_bound_dev_if,
 170                               IPPROTO_TCP,
 171                               inet->sport, usin->sin_port, sk, 1);
 172        if (tmp < 0) {
 173                if (tmp == -ENETUNREACH)
 174                        IP_INC_STATS_BH(sock_net(sk), IPSTATS_MIB_OUTNOROUTES);
 175                return tmp;
 176        }
 177
 178        if (rt->rt_flags & (RTCF_MULTICAST | RTCF_BROADCAST)) {
 179                ip_rt_put(rt);
 180                return -ENETUNREACH;
 181        }
 182
 183        if (!inet->opt || !inet->opt->srr)
 184                daddr = rt->rt_dst;
 185
 186        if (!inet->saddr)
 187                inet->saddr = rt->rt_src;
 188        inet->rcv_saddr = inet->saddr;
 189
 190        if (tp->rx_opt.ts_recent_stamp && inet->daddr != daddr) {
 191                /* Reset inherited state */
 192                tp->rx_opt.ts_recent       = 0;
 193                tp->rx_opt.ts_recent_stamp = 0;
 194                tp->write_seq              = 0;
 195        }
 196
 197        if (tcp_death_row.sysctl_tw_recycle &&
 198            !tp->rx_opt.ts_recent_stamp && rt->rt_dst == daddr) {
 199                struct inet_peer *peer = rt_get_peer(rt);
 200                /*
 201                 * VJ's idea. We save last timestamp seen from
 202                 * the destination in peer table, when entering state
 203                 * TIME-WAIT * and initialize rx_opt.ts_recent from it,
 204                 * when trying new connection.
 205                 */
 206                if (peer != NULL &&
 207                    peer->tcp_ts_stamp + TCP_PAWS_MSL >= get_seconds()) {
 208                        tp->rx_opt.ts_recent_stamp = peer->tcp_ts_stamp;
 209                        tp->rx_opt.ts_recent = peer->tcp_ts;
 210                }
 211        }
 212
 213        inet->dport = usin->sin_port;
 214        inet->daddr = daddr;
 215
 216        inet_csk(sk)->icsk_ext_hdr_len = 0;
 217        if (inet->opt)
 218                inet_csk(sk)->icsk_ext_hdr_len = inet->opt->optlen;
 219
 220        tp->rx_opt.mss_clamp = 536;
 221
 222        /* Socket identity is still unknown (sport may be zero).
 223         * However we set state to SYN-SENT and not releasing socket
 224         * lock select source port, enter ourselves into the hash tables and
 225         * complete initialization after this.
 226         */
 227        tcp_set_state(sk, TCP_SYN_SENT);
 228        err = inet_hash_connect(&tcp_death_row, sk);
 229        if (err)
 230                goto failure;
 231
 232        err = ip_route_newports(&rt, IPPROTO_TCP,
 233                                inet->sport, inet->dport, sk);
 234        if (err)
 235                goto failure;
 236
 237        /* OK, now commit destination to socket.  */
 238        sk->sk_gso_type = SKB_GSO_TCPV4;
 239        sk_setup_caps(sk, &rt->u.dst);
 240
 241        if (!tp->write_seq)
 242                tp->write_seq = secure_tcp_sequence_number(inet->saddr,
 243                                                           inet->daddr,
 244                                                           inet->sport,
 245                                                           usin->sin_port);
 246
 247        inet->id = tp->write_seq ^ jiffies;
 248
 249        err = tcp_connect(sk);
 250        rt = NULL;
 251        if (err)
 252                goto failure;
 253
 254        return 0;
 255
 256failure:
 257        /*
 258         * This unhashes the socket and releases the local port,
 259         * if necessary.
 260         */
 261        tcp_set_state(sk, TCP_CLOSE);
 262        ip_rt_put(rt);
 263        sk->sk_route_caps = 0;
 264        inet->dport = 0;
 265        return err;
 266}
 267



Reply via email to