/* * KTCPVS An implementation of the TCP Virtual Server daemon inside * kernel for the LINUX operating system. KTCPVS can be used * to build a moderately scalable and highly available server * based on a cluster of servers, with more flexibility. * * redirect.c: redirect requests to other server sockets * * Version: $Id: redirect.c,v 1.2 2003/05/23 02:08:34 wensong Exp $ * * Authors: Wensong Zhang * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * */ //#include #include #include #include #include "tcp_vs.h" /* Note: most code of redirecting to local socket is taken from TUX */ static void dummy_destructor(struct request_sock *req) { } static struct request_sock_ops dummy = { .destructor = &dummy_destructor, }; int redirect_to_local(struct tcp_vs_conn *conn, __u32 addr, __u16 port) { struct socket *sock; struct open_request *tcpreq; struct sock *sk, *oldsk; //struct tcp_opt *tp; int rc = 0; sock = conn->csock; /* search for local listening user-space socket */ local_bh_disable(); sk = inet_lookup_listener(&tcp_hashinfo, addr, ntohs(port), 0); local_bh_enable(); /* No socket found */ if (!sk) { TCP_VS_ERR_RL("no server found\n"); rc = -1; goto out; } oldsk = sock->sk; lock_sock(sk); if (sk->sk_state != TCP_LISTEN) { rc = -1; goto out_unlock; } tcpreq = reqsk_alloc(&dummy); if (!tcpreq) { rc = -1; goto out_unlock; } sock->sk = NULL; sock->state = SS_UNCONNECTED; write_lock_irq(&oldsk->sk_callback_lock); oldsk->sk_socket = NULL; oldsk->sk_sleep = NULL; write_unlock_irq(&oldsk->sk_callback_lock); //tcp_acceptq_queue(sk, tcpreq, oldsk); inet_csk_reqsk_queue_add(sk, tcpreq, oldsk); tcp_sk(oldsk)->nonagle = 0; sk->sk_data_ready(sk, 0); out_unlock: release_sock(sk); sock_put(sk); out: return rc; }