This commit was manufactured by cvs2svn to create branch 'fedora'.
[linux-2.6.git] / net / tux / redirect.c
1 /*
2  * TUX - Integrated Application Protocols Layer and Object Cache
3  *
4  * Copyright (C) 2000, 2001, Ingo Molnar <mingo@redhat.com>
5  *
6  * redirect.c: redirect requests to other server sockets (such as Apache).
7  */
8
9 #include <net/tux.h>
10
11 /****************************************************************
12  *      This program is free software; you can redistribute it and/or modify
13  *      it under the terms of the GNU General Public License as published by
14  *      the Free Software Foundation; either version 2, or (at your option)
15  *      any later version.
16  *
17  *      This program is distributed in the hope that it will be useful,
18  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
19  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  *      GNU General Public License for more details.
21  *
22  *      You should have received a copy of the GNU General Public License
23  *      along with this program; if not, write to the Free Software
24  *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25  *
26  ****************************************************************/
27
28 static void dummy_destructor(struct open_request *req)
29 {
30 }
31
32 static struct or_calltable dummy = 
33 {
34         0,
35         NULL,
36         NULL,
37         &dummy_destructor,
38         NULL
39 };
40
41 static int redirect_sock (tux_req_t *req, const int port)
42 {
43         struct socket *sock = req->sock;
44         struct open_request *tcpreq;
45         struct sock *sk, *oldsk;
46         int err = -1;
47
48         /*
49          * Look up (optional) listening user-space socket.
50          */
51         local_bh_disable();
52         sk = tcp_v4_lookup_listener(INADDR_ANY, port, 0);
53         /*
54          * Look up localhost listeners as well.
55          */
56         if (!sk) {
57                 u32 daddr;
58                 ((unsigned char *)&daddr)[0] = 127;
59                 ((unsigned char *)&daddr)[1] = 0;
60                 ((unsigned char *)&daddr)[2] = 0;
61                 ((unsigned char *)&daddr)[3] = 1;
62                 sk = tcp_v4_lookup_listener(daddr, port, 0);
63         }
64         local_bh_enable();
65
66         /* No secondary server found */
67         if (!sk)
68                 goto out;
69
70         /*
71          * Requeue the 'old' socket as an accept-socket of
72          * the listening socket. This way we can shuffle
73          * a socket around. Since we've read the input data
74          * via the non-destructive MSG_PEEK, the secondary
75          * server can be used transparently.
76          */
77         oldsk = sock->sk;
78         lock_sock(sk);
79
80         if (sk->sk_state != TCP_LISTEN)
81                 goto out_unlock;
82
83         tcpreq = tcp_openreq_alloc();
84         if (!tcpreq)
85                 goto out_unlock;
86
87         unlink_tux_socket(req);
88
89         sock->sk = NULL;
90         sock->state = SS_UNCONNECTED;
91
92         tcpreq->class = &dummy;
93         write_lock_irq(&oldsk->sk_callback_lock);
94         oldsk->sk_socket = NULL;
95         oldsk->sk_sleep = NULL;
96         write_unlock_irq(&oldsk->sk_callback_lock);
97
98         tcp_sk(oldsk)->nonagle = 0;
99
100         tcp_acceptq_queue(sk, tcpreq, oldsk);
101
102         sk->sk_data_ready(sk, 0);
103
104         /*
105          * It's now completely up to the secondary
106          * server to handle this request.
107          */
108         sock_release(req->sock);
109         req->sock = NULL;
110         req->parsed_len = 0;
111         err = 0;
112         Dprintk("req %p redirected to secondary server!\n", req);
113
114 out_unlock:
115         release_sock(sk);
116         sock_put(sk);
117 out:
118         if (err)
119                 Dprintk("NO secondary server for req %p!\n", req);
120         return err;
121 }
122
123 void redirect_request (tux_req_t *req, int cachemiss)
124 {
125         if (tux_TDprintk && (req->status != 304)) {
126                 TDprintk("trying to redirect req %p, req->error: %d, req->status: %d.\n", req, req->error, req->status);
127                 print_req(req);
128         }
129
130         if (cachemiss)
131                 TUX_BUG();
132         if (req->error == TUX_ERROR_CONN_CLOSE)
133                 goto out_flush;
134         if (!req->sock)
135                 TUX_BUG();
136
137         if (!req->status)
138                 req->status = -1;
139         if (!req->proto->can_redirect || (req->status == 304) || redirect_sock(req, tux_clientport)) {
140                 if (req->parsed_len)
141                         trunc_headers(req);
142                 req->proto->illegal_request(req, cachemiss);
143                 return;
144         } else {
145                 if (req->data_sock)
146                         BUG();
147         }
148 out_flush:
149         clear_keepalive(req);
150         if (!tux_redirect_logging)
151                 req->status = 0;
152         flush_request(req, cachemiss);
153 }
154