📄 browser_conn.c
字号:
/* * Copyright (c) 1998-2001 Caucho Technology -- all rights reserved * * Caucho Technology permits redistribution, modification and use * of this file in source and binary form ("the Software") under the * Caucho Developer Source License ("the License"). The following * conditions must be met: * * 1. Each copy or derived work of the Software must preserve the copyright * notice and this notice unmodified. * * 2. Redistributions of the Software in source or binary form must include * an unmodified copy of the License, normally in a plain ASCII text * * 3. The names "Resin" or "Caucho" are trademarks of Caucho Technology and * may not be used to endorse products derived from this software. * "Resin" or "Caucho" may not appear in the names of products derived * from this software. * * 4. Caucho Technology requests that attribution be given to Resin * in any manner possible. We suggest using the "Resin Powered" * button or creating a "powered by Resin(tm)" link to * http://www.caucho.com for each page served by Resin. * * This Software is provided "AS IS," without a warranty of any kind. * ALL EXPRESS OR IMPLIED REPRESENTATIONS AND WARRANTIES, INCLUDING ANY * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. * * CAUCHO TECHNOLOGY AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES * SUFFERED BY LICENSEE OR ANY THIRD PARTY AS A RESULT OF USING OR * DISTRIBUTING SOFTWARE. IN NO EVENT WILL CAUCHO OR ITS LICENSORS BE LIABLE * FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR * INABILITY TO USE SOFTWARE, EVEN IF HE HAS BEEN ADVISED OF THE POSSIBILITY * OF SUCH DAMAGES. * * @author Scott Ferguson */#include <linux/kernel.h>#include <linux/sched.h>#include <linux/interrupt.h>#include <linux/in.h>#include <linux/inet.h>#include <linux/time.h>#include <net/ip.h>#include <asm/uaccess.h>#include "hardcore.h"static browser_t *g_browser_ready;static spinlock_t g_ready_lock = SPIN_LOCK_UNLOCKED;static browser_t *g_browser_free;static browser_t *g_browser_list;static int g_has_accept = 0;/** * Wakes the browser connection, readying it for execution by browser_execute. */voidbrowser_wake(browser_t *browser){ if (browser->is_active) return; spin_lock_irq(&g_ready_lock); if (! browser->is_active) { browser->is_active = 1; browser->next = g_browser_ready; g_browser_ready = browser; } spin_unlock_irq(&g_ready_lock); resind_wake();}/** * The server socket receives callbacks when accepting a new client socket. * Each client is associated with a connection_t structure. */static voidaccept_state_change(struct sock *sock){ LOG(("resin: accept state_change %p %d %p\n", sock, sock->state, sock->socket)); if (sock->state == TCP_ESTABLISHED) { g_has_accept = 1; // Wake the server to actually accept the request resind_wake(); }}/** * Handles the callback when the socket to the browser changes state. * Normally, this only occurs on socket close. * * @param sock the socket between resind and the client */static voidbrowser_state_change(struct sock *sock){ browser_t *browser = sock->user_data; LOG(("resin: browser state_change %x %d\n", sock, sock->state)); if (sock->state == TCP_CLOSE && browser) { sock->user_data = 0; browser->state = RHC_BROWSER_QUIT; browser->is_dead = 1; browser_wake(browser); }}/** * Handles the callback when the socket to the browser has more data to * read. * * @param sock the socket between resind and the browser * @param bytes in theory, the number of bytes to read. In reality, this * seems to be unused. */static voidbrowser_data_ready(struct sock *sock, int bytes){ browser_t *browser = sock->user_data; LOG(("resin: browser read %x %d %p %d\n", sock, sock->state, browser, bytes)); if (sock->state == TCP_ESTABLISHED && browser) browser_wake(browser);}/** * Handles the callback when the socket to the browser has space for * a write * * @param sock the socket between resind and the browser */static voidbrowser_write_space(struct sock *sock){ browser_t *browser = sock->user_data; if (browser && browser->state == RHC_BROWSER_WRITE) { LOG(("resin: browser write %x %d %p %d\n", sock, sock->state, browser, browser->state)); browser_wake(browser); }}/** * create a new browser browserection */static voidbrowser_create(){ browser_t *browser = kmalloc(sizeof(browser_t), GFP_KERNEL); if (browser) { memset(browser, 0, sizeof(browser_t)); browser->resin = &g_resin; browser->next = g_browser_free; g_browser_free = browser; browser->next_browser = g_browser_list; if (g_browser_list) g_browser_list->prev_browser = browser; g_browser_list = browser; } else LOG(("can't allocate\n"));}/** * Allocate a new browser object */static browser_t *browser_allocate(resin_t *resin){ browser_t *browser = g_browser_free; if (browser) { g_browser_free = g_browser_free->next; browser->next = 0; browser->is_active = 0; browser->is_dead = 0; browser->cache = 0; } return browser;}/** * Accept a socket from the server socket. */static intbrowser_accept(resin_t *resin){ struct sock *ss = resin->accept_socket->sk; struct sock *sock; browser_t *browser; struct timeval time_now; int err; if (! ss) return 0; sock = ss->prot->accept(ss, O_NONBLOCK, &err); if (! sock) return 0; LOG(("accept %p\n", sock)); browser = browser_allocate(resin); // can't allocate the browser, so kill it // XXX: how does the listen queue work? if (! browser) { sock->prot->close(sock, 0); return 1; } // Technically the wrong socket structure, but sendmsg needs the socket // Hopefully, this won't confuse anything. sock->socket = browser->resin->accept_socket; browser->browser_sock = sock; browser->is_dead = 0; browser->cin_offset = 0; browser->cin_length = 0; browser->post_offset = 0; browser->in_header = 0; browser->keepalive = 0; browser->request_length = -1; browser->srun_conn = 0; browser->srun_sock = 0; do_gettimeofday(&time_now); browser->now = time_now.tv_sec; browser->cache = 0; browser->expires = 0; browser->cout_offset = 0; browser->cout_length = 0; browser->iov_index = 0; sock->user_data = browser; browser->old_state_change = sock->state_change; sock->state_change = browser_state_change; browser->old_data_ready = sock->data_ready; sock->data_ready = browser_data_ready; browser->old_write_space = sock->write_space; sock->write_space = browser_write_space; // Wake the browser in case it has some data browser->state = RHC_BROWSER_START; browser_wake(browser); return 1;}/** * Closes a browser */voidbrowser_close(browser_t *browser){ LOG(("close %p\n", browser)); if (browser->browser_sock) { struct sock *sock = browser->browser_sock; browser->browser_sock = 0; sock->socket = 0; sock->user_data = 0; sock->state_change = browser->old_state_change; sock->data_ready = browser->old_data_ready; sock->write_space = browser->old_write_space; sock->prot->close(sock, 0); } // make the srun available to subsequent requests if (browser->srun_conn) srun_recycle(browser->srun_conn); browser->srun_conn = 0; browser->srun_sock = 0; if (browser->cache) cache_kill(browser); browser->next = g_browser_free; g_browser_free = browser;}/** * Reads from a socket * * @param sock the socket receiving the browser * @param buf the buffer receiving the data * @param len the length of the expected data * * @return the number of bytes actually received */intsocket_recv(struct sock *sock, char *buf, int len){ mm_segment_t oldfs; struct msghdr msg; struct iovec iov; int addr_len = 0; if (! sock || len <= 0) return -1; msg.msg_name = 0; msg.msg_namelen = 0; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = 0; msg.msg_controllen = 0; iov.iov_base = buf; iov.iov_len = len; LOG(("socket read %d\n", len)); oldfs = get_fs(); set_fs(KERNEL_DS); len = sock->prot->recvmsg(sock, &msg, len, 1, 0, &addr_len); set_fs(oldfs); LOG(("post read %d\n", len)); return len;}/** * Reads from the client socket into the client in buffer (cin_*) * * If there isn't enough room in the buffer, e.g. for pipelined requests, * shift the buffer down. * * @param browser the browser */static intbrowser_recv(browser_t *browser){ char *buf = browser->cin_buf; int head = browser->cin_offset; int tail = browser->cin_length; int capacity = sizeof(browser->cin_buf); int len; LOG(("stuff in %d head %d tail %d cap %d\n", browser->in_header, head, tail, capacity)); if (browser->in_header) { } else if (head == tail) { browser->cin_offset = 0; tail = 0; } else if (2 * head < capacity || capacity < 2 * tail) { int i; int delta = tail - head; for (i = 0; i < delta; i++) buf[i] = buf[i + head]; browser->cin_offset = 0; tail = delta; } LOG(("pre-recv tail:%d\n", tail)); len = socket_recv(browser->browser_sock, buf + tail, capacity - tail); LOG(("post-recv tail:%d %d\n", tail, len)); if (len > 0) browser->cin_length = tail + len; else if (len == -EAGAIN || len == -EWOULDBLOCK) browser->cin_length = tail; else { browser->cin_length = tail; browser->state = RHC_BROWSER_QUIT; browser_wake(browser); } return len;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -