📄 srun_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/spinlock.h>#include <net/ip.h>#include <asm/uaccess.h>#include "hardcore.h"/** * srun_conn.c handles the connection from resin.o to the JVM process. *//** * Convert an IPV4 address to an integer. Used as a cheap way of handling * 127.0.0.1 */#define IP(a,b,c,d) ((a << 24) + (b << 16) + (c << 8) + (d))// list of sruns needing closingstatic srun_conn_t *g_srun_close_list;// lock for all srun modificationsstatic spinlock_t g_srun_lock = SPIN_LOCK_UNLOCKED;static void browser_busy(browser_t *browser);/** * Readies an srun for a close. The actual close will happen later. */static voidsrun_start_close(srun_conn_t *srun){ srun_conn_t *prev = srun->prev; srun_conn_t *next = srun->next; if (srun->is_dead) return; srun->is_dead = 1; LOG(("start close %p\n", srun)); if (next) next->prev = prev; if (prev) prev->next = next; if (srun->parent && srun->parent->conn_head == srun) srun->parent->conn_head = next; srun->next = g_srun_close_list; g_srun_close_list = srun;}/** * Handles the callback when the socket to the srun changes state. * This will happen when the socket connects or when it closes. * * When the connection closes, the kernel will call the data_ready * callback after the state_change callback. * * @param sock the socket between resind and the srun */static voidsrun_state_change(struct sock *sock){ srun_conn_t *srun = sock->user_data; browser_t *browser; if (! srun) { LOG(("resin: srun state_change %x %d null\n", sock, sock->state, srun)); return; } browser = srun->browser; LOG(("resin: srun state_change %x %d %x %s\n", sock, sock->state, srun, browser_state_name(browser))); // called when the connection to the srun completes if (sock->state == TCP_ESTABLISHED) { // if the state maching is waiting for the connection, move // to SRUN_START and wake the state machine. if (browser && browser->state == RHC_SRUN_CONNECTING) { browser->state = RHC_SRUN_START; browser_wake(browser); } } // called when the srun connection closes else { // if the srun is in the idle list, just remove it if (! browser) { } // if we're trying to connect to the srun, just quit else if (browser->state == RHC_SRUN_CONNECTING) { browser->state = RHC_BROWSER_QUIT; browser->srun_conn = 0; browser->srun_sock = 0; browser_wake(browser); } // if we're in the middle of a connection, close the connection else { browser->state = RHC_BROWSER_QUIT; browser->srun_conn = 0; browser->srun_sock = 0; browser_busy(browser); browser_wake(browser); } sock->user_data = 0; // If this callback, occurs, the socket has already been closed (??) // srun->sock = 0; // Add this srun to the list of sruns to be collected when the // main thread wakes again. srun_start_close(srun); }}/** * Handles the data_ready callback when the srun socket has more data to * read. * * The data_ready callback also occurs when the socket is closed, after * the state_change callback. * * @param sock the socket between resind and the srun * @param bytes in theory, the number of bytes to read. In reality, this * seems to be unused. */static voidsrun_data_ready(struct sock *sock, int bytes){ srun_conn_t *srun = sock->user_data; browser_t *browser = srun ? srun->browser : 0; LOG(("resin: srun read sock-state:%d browser-state:%s bytes:%d\n", sock->state, browser_state_name(browser), bytes)); /* If the srun connection has data, mark it and wake the daemon. */ if (browser && sock->state == TCP_ESTABLISHED) { if (browser->state >= RHC_SRUN_START && browser->state <= RHC_SRUN_RECV_DATA) { browser_wake(browser); } }}/** * Connects to a srun. * * @param srun the srun to connect to * @param conn the client connection object * * @return 0 on success */intsrun_connect(srun_t *srun, browser_t *browser){ struct sockaddr_in sin; struct socket *sock; struct srun_conn_t *srun_conn; int error; LOG(("connect %p r:%p\n", browser->srun_sock, srun)); // XXX: error?? temporary if (browser->srun_sock) return -1; browser->state = RHC_SRUN_CONNECTING; browser->sin_offset = 0; browser->sin_length = 0; // If there's an srun in the recycle list, use it. if (srun->conn_head) { struct srun_conn_t *next; srun_conn = srun->conn_head; next = srun_conn->next; if (next) next->prev = 0; srun->conn_head = next; srun_conn->prev = 0; srun_conn->next = 0; browser->srun_conn = srun_conn; srun_conn->browser = browser; browser->srun_sock = srun_conn->sock; browser->state = RHC_SRUN_START; // wake the browser's state machine browser_wake(browser); LOG(("reuse srun:%p next:%p\n", srun_conn, srun->conn_head)); return 1; } /* * Otherwise create a new socket connection to the srun. */ error = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock); if (error < 0) { LOG(("error %d\n", error)); return error; } sin.sin_family = AF_INET; sin.sin_addr = srun->addr; sin.sin_port = htons(srun->port); LOG(("resin: connect(%u.%u.%u.%u:%d)\n", NIPQUAD(sin.sin_addr.s_addr), ntohs(sin.sin_port))); srun_conn = kmalloc(sizeof(srun_conn_t), GFP_KERNEL); memset(srun_conn, 0, sizeof(srun_conn_t)); srun_conn->parent = srun; srun_conn->browser = browser; browser->srun_conn = srun_conn; browser->srun_sock = sock; srun_conn->sock = sock; if (sock->sk) { sock->sk->user_data = srun_conn; srun_conn->old_state_change = sock->sk->state_change; sock->sk->state_change = srun_state_change; srun_conn->old_data_ready = sock->sk->data_ready; sock->sk->data_ready = srun_data_ready; } else { // in theory, this should never happen LOG(("no sk\n")); return -1; } // start connecting to the srun. error = sock->ops->connect(sock, (struct sockaddr *) &sin, sizeof(sin), O_NONBLOCK); LOG(("resin: connect(%u.%u.%u.%u:%d) -> %d\n", NIPQUAD(sin.sin_addr.s_addr), ntohs(sin.sin_port), error)); if (error >= 0) { // The connection succeeded immediately (loopback), so move to // the SRUN_START state and wake the state machine. browser->state = RHC_SRUN_START; browser_wake(browser); } else if (error == -EAGAIN || error == -EINPROGRESS) { // The connection would block. In other words, we'll need to wait // for the TCP connection to complete and callback at srun_state_change. } else { // The connection failed immediately. Free the socket and send an // error message to the browser. kfree(srun_conn); browser->state = RHC_BROWSER_QUIT; browser->srun_conn = 0; browser->srun_sock = 0; sock_release(sock); browser_busy(browser); browser_wake(browser); } return 1;}/** * Sends the connection failed error message to the browser.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -