📄 jk_ajp_common.c
字号:
}
/*
* Handle the CPING/CPONG initial query
*/
static int ajp_handle_cping_cpong(ajp_endpoint_t * ae, int timeout, jk_logger_t *l)
{
int cmd;
jk_msg_buf_t *msg;
JK_TRACE_ENTER(l);
msg = jk_b_new(&ae->pool);
jk_b_set_buffer_size(msg, 16); /* 16 is way too large but I'm lazy :-) */
jk_b_reset(msg);
jk_b_append_byte(msg, AJP13_CPING_REQUEST);
/* Send CPing query */
if (ajp_connection_tcp_send_message(ae, msg, l) != JK_TRUE) {
jk_log(l, JK_LOG_INFO,
"can't send cping query");
JK_TRACE_EXIT(l);
return JK_FALSE;
}
/* wait for Pong reply for timeout milliseconds
*/
if (ajp_is_input_event(ae, timeout, l) == JK_FALSE) {
jk_log(l, JK_LOG_INFO, "timeout in reply pong");
JK_TRACE_EXIT(l);
return JK_FALSE;
}
/* Read and check for Pong reply
*/
if (ajp_connection_tcp_get_message(ae, msg, l) != JK_TRUE) {
jk_log(l, JK_LOG_INFO,
"awaited reply cpong, not received");
JK_TRACE_EXIT(l);
return JK_FALSE;
}
if ((cmd = jk_b_get_byte(msg)) != AJP13_CPONG_REPLY) {
jk_log(l, JK_LOG_INFO,
"awaited reply cpong, received %d instead",
cmd);
JK_TRACE_EXIT(l);
return JK_FALSE;
}
JK_TRACE_EXIT(l);
return JK_TRUE;
}
int ajp_connect_to_endpoint(ajp_endpoint_t * ae, jk_logger_t *l)
{
char buf[32];
int rc = JK_TRUE;
JK_TRACE_ENTER(l);
ae->sd = jk_open_socket(&ae->worker->worker_inet_addr,
ae->worker->keepalive,
ae->worker->socket_timeout,
ae->worker->socket_buf, l);
if (ae->sd >= 0) {
if (JK_IS_DEBUG_LEVEL(l)) {
jk_log(l, JK_LOG_DEBUG,
"Connected socket %d to (%s)",
ae->sd,
jk_dump_hinfo(&ae->worker->worker_inet_addr, buf));
}
/* set last_access only if needed */
if (ae->worker->cache_timeout > 0 || ae->worker->recycle_timeout > 0)
ae->last_access = time(NULL);
/* Check if we must execute a logon after the physical connect */
if (ae->worker->logon != NULL) {
rc = ae->worker->logon(ae, l);
JK_TRACE_EXIT(l);
return rc;
}
/* should we send a CPING to validate connection ? */
if (ae->worker->connect_timeout > 0) {
rc = ajp_handle_cping_cpong (ae,
ae->worker->connect_timeout, l);
JK_TRACE_EXIT(l);
return rc;
}
JK_TRACE_EXIT(l);
return JK_TRUE;
}
jk_log(l, JK_LOG_INFO,
"Failed opening socket to (%s) with (errno=%d)",
jk_dump_hinfo(&ae->worker->worker_inet_addr, buf), errno);
JK_TRACE_EXIT(l);
return JK_FALSE;
}
/*
* Send a message to endpoint, using corresponding PROTO HEADER
*/
int ajp_connection_tcp_send_message(ajp_endpoint_t * ae,
jk_msg_buf_t *msg, jk_logger_t *l)
{
int rc;
JK_TRACE_ENTER(l);
if (ae->proto == AJP13_PROTO) {
jk_b_end(msg, AJP13_WS_HEADER);
if (JK_IS_DEBUG_LEVEL(l))
jk_dump_buff(l, JK_LOG_DEBUG, "sending to ajp13", msg);
}
else if (ae->proto == AJP14_PROTO) {
jk_b_end(msg, AJP14_WS_HEADER);
if (JK_IS_DEBUG_LEVEL(l))
jk_dump_buff(l, JK_LOG_DEBUG, "sending to ajp14", msg);
}
else {
jk_log(l, JK_LOG_ERROR,
"unknown protocol %d, supported are AJP13/AJP14", ae->proto);
JK_TRACE_EXIT(l);
return JK_FATAL_ERROR;
}
if ((rc = jk_tcp_socket_sendfull(ae->sd, msg->buf,
msg->len)) > 0) {
ae->endpoint.wr += msg->len;
JK_TRACE_EXIT(l);
return JK_TRUE;
}
jk_log(l, JK_LOG_ERROR,
"sendfull returned %d with errno=%d ", rc, errno);
JK_TRACE_EXIT(l);
return JK_FALSE;
}
/*
* Receive a message from endpoint, checking PROTO HEADER
*/
int ajp_connection_tcp_get_message(ajp_endpoint_t * ae,
jk_msg_buf_t *msg, jk_logger_t *l)
{
unsigned char head[AJP_HEADER_LEN];
int rc;
int msglen;
unsigned int header;
char buf[32];
JK_TRACE_ENTER(l);
rc = jk_tcp_socket_recvfull(ae->sd, head, AJP_HEADER_LEN);
if (rc < 0) {
if (rc == JK_SOCKET_EOF) {
jk_log(l, JK_LOG_INFO,
"Tomcat has forced a connection close for socket %d",
ae->sd);
JK_TRACE_EXIT(l);
}
else {
jk_log(l, JK_LOG_ERROR,
"Can't receive the response message from tomcat, "
"network problems or tomcat is down (%s), err=%d",
jk_dump_hinfo(&ae->worker->worker_inet_addr, buf), rc);
JK_TRACE_EXIT(l);
}
return JK_FALSE;
}
ae->endpoint.rd += rc;
header = ((unsigned int)head[0] << 8) | head[1];
if (ae->proto == AJP13_PROTO) {
if (header != AJP13_SW_HEADER) {
if (header == AJP14_SW_HEADER) {
jk_log(l, JK_LOG_ERROR,
"received AJP14 reply on an AJP13 connection from %s",
jk_dump_hinfo(&ae->worker->worker_inet_addr, buf));
}
else {
jk_log(l, JK_LOG_ERROR,
"wrong message format 0x%04x from %s",
header, jk_dump_hinfo(&ae->worker->worker_inet_addr,
buf));
}
JK_TRACE_EXIT(l);
return JK_FALSE;
}
}
else if (ae->proto == AJP14_PROTO) {
if (header != AJP14_SW_HEADER) {
if (header == AJP13_SW_HEADER) {
jk_log(l, JK_LOG_ERROR,
"received AJP13 reply on an AJP14 connection from %s",
jk_dump_hinfo(&ae->worker->worker_inet_addr, buf));
}
else {
jk_log(l, JK_LOG_ERROR,
"wrong message format 0x%04x from %s",
header, jk_dump_hinfo(&ae->worker->worker_inet_addr,
buf));
}
JK_TRACE_EXIT(l);
return JK_FALSE;
}
}
msglen = ((head[2] & 0xff) << 8);
msglen += (head[3] & 0xFF);
if (msglen > msg->maxlen) {
jk_log(l, JK_LOG_ERROR,
"wrong message size %d %d from %s",
msglen, msg->maxlen,
jk_dump_hinfo(&ae->worker->worker_inet_addr, buf));
JK_TRACE_EXIT(l);
return JK_FALSE;
}
msg->len = msglen;
msg->pos = 0;
rc = jk_tcp_socket_recvfull(ae->sd, msg->buf, msglen);
if (rc < 0) {
jk_log(l, JK_LOG_ERROR,
"ERROR: can't receive the response message from tomcat, "
"network problems or tomcat (%s) is down %d",
jk_dump_hinfo(&ae->worker->worker_inet_addr, buf), rc);
JK_TRACE_EXIT(l);
return JK_FALSE;
}
ae->endpoint.rd += rc;
if (ae->proto == AJP13_PROTO) {
if (JK_IS_DEBUG_LEVEL(l))
jk_dump_buff(l, JK_LOG_DEBUG, "received from ajp13", msg);
}
else if (ae->proto == AJP14_PROTO) {
if (JK_IS_DEBUG_LEVEL(l))
jk_dump_buff(l, JK_LOG_DEBUG, "received from ajp14", msg);
}
JK_TRACE_EXIT(l);
return JK_TRUE;
}
/*
* Read all the data from the socket.
*
* Socket API doesn't guaranty that all the data will be kept in a
* single read, so we must loop until all awaited data is received
*/
static int ajp_read_fully_from_server(jk_ws_service_t *s, jk_logger_t *l,
unsigned char *buf, unsigned int len)
{
unsigned int rdlen = 0;
unsigned int padded_len = len;
JK_TRACE_ENTER(l);
if (s->is_chunked && s->no_more_chunks) {
JK_TRACE_EXIT(l);
return 0;
}
if (s->is_chunked) {
/* Corner case: buf must be large enough to hold next
* chunk size (if we're on or near a chunk border).
* Pad the length to a reasonable value, otherwise the
* read fails and the remaining chunks are tossed.
*/
padded_len = (len < CHUNK_BUFFER_PAD) ? len : len - CHUNK_BUFFER_PAD;
}
while (rdlen < padded_len) {
unsigned int this_time = 0;
if (!s->read(s, buf + rdlen, len - rdlen, &this_time)) {
/* Remote Client read failed. */
JK_TRACE_EXIT(l);
return JK_CLIENT_ERROR;
}
if (0 == this_time) {
if (s->is_chunked) {
s->no_more_chunks = 1; /* read no more */
}
break;
}
rdlen += this_time;
}
return (int)rdlen;
}
/*
* Read data from AJP13/AJP14 protocol
* Returns -1 on error, else number of bytes read
*/
static int ajp_read_into_msg_buff(ajp_endpoint_t * ae,
jk_ws_service_t *r,
jk_msg_buf_t *msg, int len, jk_logger_t *l)
{
unsigned char *read_buf = msg->buf;
JK_TRACE_ENTER(l);
jk_b_reset(msg);
read_buf += AJP_HEADER_LEN; /* leave some space for the buffer headers */
read_buf += AJP_HEADER_SZ_LEN; /* leave some space for the read length */
/* Pick the max size since we don't know the content_length */
if (r->is_chunked && len == 0) {
len = AJP13_MAX_SEND_BODY_SZ;
}
if ((len = ajp_read_fully_from_server(r, l, read_buf, len)) < 0) {
jk_log(l, JK_LOG_INFO,
"Receiving data from client failed. "
"Connection aborted or network problems");
JK_TRACE_EXIT(l);
return JK_CLIENT_ERROR;
}
if (!r->is_chunked) {
ae->left_bytes_to_send -= len;
}
if (len > 0) {
/* Recipient recognizes empty packet as end of stream, not
an empty body packet */
if (0 != jk_b_append_int(msg, (unsigned short)len)) {
jk_log(l, JK_LOG_INFO,
"Failed appending message length");
JK_TRACE_EXIT(l);
return JK_CLIENT_ERROR;
}
}
msg->len += len;
JK_TRACE_EXIT(l);
return len;
}
/*
* send request to Tomcat via Ajp13
* - first try to find reuseable socket
* - if no one available, try to connect
* - send request, but send must be see as asynchronous,
* since send() call will return noerror about 95% of time
* Hopefully we'll get more information on next read.
*
* nb: reqmsg is the original request msg buffer
* repmsg is the reply msg buffer which could be scratched
*/
static int ajp_send_request(jk_endpoint_t *e,
jk_ws_service_t *s,
jk_logger_t *l,
ajp_endpoint_t * ae, ajp_operation_t * op)
{
int err = 0;
int postlen;
JK_TRACE_ENTER(l);
/* Up to now, we can recover */
op->recoverable = JK_TRUE;
/*
* First try to reuse open connections...
*/
while ((ae->sd > 0)) {
int rc = 0;
err = 0;
if (ae->worker->socket_timeout) {
if (!jk_is_socket_connected(ae->sd)) {
jk_log(l, JK_LOG_INFO,
"Socket %d is not connected any more (errno=%d)",
ae->sd, errno);
jk_close_socket(ae->sd);
ae->sd = -1;
err++;
}
}
if (ae->worker->prepost_timeout != 0 && !err) {
/* handle cping/cpong if prepost_timeout is set
* If the socket is disconnected no need to handle
* the cping/cpong
*/
if (ajp_handle_cping_cpong(ae, ae->worker->prepost_timeout, l) ==
JK_FALSE)
err++;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -