Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[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 #include <linux/module.h>
11 #include <linux/init.h>
12
13 /****************************************************************
14  *      This program is free software; you can redistribute it and/or modify
15  *      it under the terms of the GNU General Public License as published by
16  *      the Free Software Foundation; either version 2, or (at your option)
17  *      any later version.
18  *
19  *      This program is distributed in the hope that it will be useful,
20  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
21  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  *      GNU General Public License for more details.
23  *
24  *      You should have received a copy of the GNU General Public License
25  *      along with this program; if not, write to the Free Software
26  *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27  *
28  ****************************************************************/
29
30 static void nop_destructor(struct request_sock *req)
31 {
32 }
33
34 static struct request_sock_ops tux_req =
35 {
36         .destructor = &nop_destructor,
37 };
38
39 static int redirect_sock (tux_req_t *req, const int port)
40 {
41         struct socket *sock = req->sock;
42         struct request_sock *tcpreq;
43         struct sock *sk, *oldsk;
44         int err = -1;
45
46         /*
47          * Look up (optional) listening user-space socket.
48          */
49         local_bh_disable();
50         sk = inet_lookup_listener(&tcp_hashinfo, INADDR_ANY, port, 0);
51         /*
52          * Look up localhost listeners as well.
53          */
54         if (!sk) {
55                 u32 daddr;
56                 ((unsigned char *)&daddr)[0] = 127;
57                 ((unsigned char *)&daddr)[1] = 0;
58                 ((unsigned char *)&daddr)[2] = 0;
59                 ((unsigned char *)&daddr)[3] = 1;
60                 sk = inet_lookup_listener(&tcp_hashinfo, daddr, port, 0);
61         }
62         local_bh_enable();
63
64         /* No secondary server found */
65         if (!sk)
66                 goto out;
67         if (sk->sk_family != AF_INET) {
68                 sock_put(sk);
69                 goto out;
70         }
71
72         /*
73          * Requeue the 'old' socket as an accept-socket of
74          * the listening socket. This way we can shuffle
75          * a socket around. Since we've read the input data
76          * via the non-destructive MSG_PEEK, the secondary
77          * server can be used transparently.
78          */
79         oldsk = sock->sk;
80         lock_sock(sk);
81
82         if (sk->sk_state != TCP_LISTEN)
83                 goto out_unlock;
84
85         tcpreq = reqsk_alloc(&tux_req);
86         if (!tcpreq)
87                 goto out_unlock;
88
89         unlink_tux_socket(req);
90
91         sock->sk = NULL;
92         sock->state = SS_UNCONNECTED;
93
94         write_lock_irq(&oldsk->sk_callback_lock);
95         oldsk->sk_socket = NULL;
96         oldsk->sk_sleep = NULL;
97         write_unlock_irq(&oldsk->sk_callback_lock);
98
99         tcp_sk(oldsk)->nonagle = 0;
100
101         inet_csk_reqsk_queue_add(sk, tcpreq, oldsk);
102
103         sk->sk_data_ready(sk, 0);
104
105         /*
106          * It's now completely up to the secondary
107          * server to handle this request.
108          */
109         if (req->fd != -1) {
110                 tux_close(req->fd);
111                 req->fd = -1;
112         } else
113                 sock_release(req->sock);
114         req->sock = NULL;
115         req->parsed_len = 0;
116         err = 0;
117         Dprintk("req %p redirected to secondary server!\n", req);
118
119 out_unlock:
120         release_sock(sk);
121         sock_put(sk);
122 out:
123         if (err)
124                 Dprintk("NO secondary server for req %p!\n", req);
125         return err;
126 }
127
128 void redirect_request (tux_req_t *req, int cachemiss)
129 {
130         if (tux_TDprintk && (req->status != 304)) {
131                 TDprintk("trying to redirect req %p, req->error: %d, req->status: %d.\n", req, req->error, req->status);
132                 print_req(req);
133         }
134
135         if (cachemiss)
136                 TUX_BUG();
137         if (req->error == TUX_ERROR_CONN_CLOSE)
138                 goto out_flush;
139         if (!req->sock)
140                 TUX_BUG();
141
142         if (!req->status)
143                 req->status = -1;
144         if (!req->proto->can_redirect || (req->status == 304) || redirect_sock(req, tux_clientport)) {
145                 if (req->parsed_len)
146                         trunc_headers(req);
147                 req->proto->illegal_request(req, cachemiss);
148                 return;
149         } else {
150                 if (req->data_sock)
151                         BUG();
152         }
153 out_flush:
154         clear_keepalive(req);
155         if (!tux_redirect_logging)
156                 req->status = 0;
157         flush_request(req, cachemiss);
158 }
159
160 int init_tux_request_slabs(void)
161 {
162         tux_req.slab = kmem_cache_create("tux-request",
163                         sizeof(struct request_sock), 0, SLAB_HWCACHE_ALIGN,
164                         NULL, NULL);
165
166         return tux_req.slab == NULL;
167 }
168
169 void free_tux_request_slabs(void)
170 {
171         kmem_cache_destroy(tux_req.slab);
172 }