org.apache.tomcat.util.net.SocketWrapperBase Maven / Gradle / Ivy
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.tomcat.util.net;
import java.io.EOFException;
import java.io.IOException;
import java.net.SocketTimeoutException;
import java.nio.ByteBuffer;
import java.nio.channels.CompletionHandler;
import java.nio.channels.InterruptedByTimeoutException;
import java.nio.channels.ReadPendingException;
import java.nio.channels.WritePendingException;
import java.util.concurrent.Executor;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.ReentrantLock;
import jakarta.servlet.ServletConnection;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.util.ExceptionUtils;
import org.apache.tomcat.util.res.StringManager;
public abstract class SocketWrapperBase {
private static final Log log = LogFactory.getLog(SocketWrapperBase.class);
protected static final StringManager sm = StringManager.getManager(SocketWrapperBase.class);
/*
* At 100,000 connections a second there are enough IDs here for ~3,000,000
* years before it overflows (and then we have another 3,000,000 years
* before it gets back to zero).
*
* Local testing shows that 5 threads can obtain 60,000,000+ IDs a second
* from a single AtomicLong. That is about about 17ns per request. It does
* not appear that the introduction of this counter will cause a bottleneck
* for connection processing.
*/
private static final AtomicLong connectionIdGenerator = new AtomicLong(0);
private E socket;
private final AbstractEndpoint endpoint;
private final ReentrantLock lock = new ReentrantLock();
protected final AtomicBoolean closed = new AtomicBoolean(false);
// Volatile because I/O and setting the timeout values occurs on a different
// thread to the thread checking the timeout.
private volatile long readTimeout = -1;
private volatile long writeTimeout = -1;
protected volatile IOException previousIOException = null;
private volatile int keepAliveLeft = 100;
private String negotiatedProtocol = null;
private final String connectionId;
/*
* Following cached for speed / reduced GC
*/
protected String localAddr = null;
protected String localName = null;
protected int localPort = -1;
protected String remoteAddr = null;
protected String remoteHost = null;
protected int remotePort = -1;
protected volatile ServletConnection servletConnection = null;
/**
* Used to record the first IOException that occurs during non-blocking
* read/writes that can't be usefully propagated up the stack since there is
* no user code or appropriate container code in the stack to handle it.
*/
private volatile IOException error = null;
/**
* The buffers used for communicating with the socket.
*/
protected volatile SocketBufferHandler socketBufferHandler = null;
/**
* The max size of the individual buffered write buffers
*/
protected int bufferedWriteSize = 64 * 1024; // 64k default write buffer
/**
* Additional buffer used for non-blocking writes. Non-blocking writes need
* to return immediately even if the data cannot be written immediately but
* the socket buffer may not be big enough to hold all of the unwritten
* data. This structure provides an additional buffer to hold the data until
* it can be written.
* Not that while the Servlet API only allows one non-blocking write at a
* time, due to buffering and the possible need to write HTTP headers, this
* layer may see multiple writes.
*/
protected final WriteBuffer nonBlockingWriteBuffer = new WriteBuffer(bufferedWriteSize);
/*
* Asynchronous operations.
*/
protected final Semaphore readPending;
protected volatile OperationState> readOperation = null;
protected final Semaphore writePending;
protected volatile OperationState> writeOperation = null;
/**
* The org.apache.coyote.Processor instance currently associated with the
* wrapper. Only populated when required to maintain wrapper<->Processor
* mapping between calls to
* {@link AbstractEndpoint.Handler#process(SocketWrapperBase, SocketEvent)}.
*/
private final AtomicReference