Processes the syn-ack packet which notes the start of tcp conversation
@param packet
161640
protected void processSynAckPacket(Packet packet) {
        String serverIp = packet.getSrcIpAddr();
        int serverPort = packet.getSrcPort();
        String clientIp = packet.getDestIpAddr();
        int clientPort = packet.getDestPort();
        String clientId = makeClientId(clientIp, clientPort);
        TcpServerScript serverFragmentWriter = scriptFragments.get(clientId);
        if ( serverFragmentWriter == null ) {
            serverFragmentWriter = new TcpServerScript(emitterFactory.getRptScriptEmitter(OUTPUT_TYPE,
                    "tcp-server-"
                            + serverIp + "-" + serverPort + "-client-" + clientIp + "-" + clientPort + "-ServerSide"));
        }
        else if ( serverFragmentWriter.getState() != ScriptState.CLOSED ) {
            throw new RptScriptsCreatorFailureException(
                    "Attempting to open already opened tcp connection from server composer:" + clientId);
        }
        serverFragmentWriter.writeAccept(serverIp, serverPort, packet);
        scriptFragments.put(clientId, serverFragmentWriter);
    }
750882
protected void processRequest() {
        final int timeout = getHTTPContext().getReadTimeout();
        final TCPReadCompletedCallback callback = HttpICLReadCallback.getRef();

        // keep looping on processing information until we fully parse the message
        // and hand it off, or until the reads for more data go async
        VirtualConnection rc = null;
        do {
            if (handleNewInformation()) {
                // new information triggered an error message, so we're done
                return;
            }
            // Note: handleNewInformation will allocate the read buffers
            if (!isPartiallyParsed()) {
                // we're done parsing at this point. Note: cannot take any action
                // with information after this call because it may go all the way
                // from the channel above us back to the persist read, must exit
                // this callstack immediately
                handleNewRequest();
                return;
            }
            rc = this.myTSC.getReadInterface().read(1, callback, false, timeout);
        } while (null != rc);
    }
606959
private void processAsyncSessionStoppedCallback (CommsByteBuffer buffer, Conversation conversation) {
     if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) SibTr.entry(this, tc, "processAsyncSessionStoppedCallback", new Object[]{buffer, conversation});

     final short connectionObjectId = buffer.getShort();
     final short clientSessionId    = buffer.getShort();

     if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) SibTr.debug(this, tc, "connectionObjectId="+connectionObjectId);
     if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) SibTr.debug(this, tc, "clientSessionId="+clientSessionId);

     // Obtain the proxy queue group
     final ClientConversationState convState = (ClientConversationState) conversation.getAttachment();
     final ProxyQueueConversationGroup pqcg = convState.getProxyQueueConversationGroup();
     if (pqcg == null) {
       if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) SibTr.debug(this, tc, "ProxyQueueConversationGroup=null");
       SIErrorException e = new SIErrorException(nls.getFormattedMessage("NULL_PROXY_QUEUE_CONV_GROUP_CWSICO8020", new Object[] {}, null));
       FFDCFilter.processException(e, CLASS_NAME + ".processAsyncSessionStoppedCallback", CommsConstants.PROXYRECEIVELISTENER_SESSION_STOPPED_01, this);
       SibTr.error(tc, "NULL_PROXY_QUEUE_CONV_GROUP_CWSICO8020", e);
       throw e;
     }

     // Obtain the required proxy queue from the proxy queue group and ensure its of the right class (ie not read ahead)
     final ProxyQueue proxyQueue = pqcg.find(clientSessionId);
     if (proxyQueue instanceof AsynchConsumerProxyQueue) {
       final ConsumerSessionProxy consumerSessionProxy = ((AsynchConsumerProxyQueue)proxyQueue).getConsumerSessionProxy();

       //Drive the ConsumerSessionProxy.stoppableConsumerSessionStopped method on a different thread.
       ClientAsynchEventThreadPool.getInstance().dispatchStoppableConsumerSessionStopped(consumerSessionProxy);
     } else {
       if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) SibTr.debug(this, tc, "proxyQueue not an instance of AsynchConsumerProxyQueue is an instance of "+ proxyQueue.getClass().getName());
       SIErrorException e = new SIErrorException(nls.getFormattedMessage("WRONG_CLASS_CWSICO8021", new Object[] {proxyQueue.getClass().getName()}, null));
       FFDCFilter.processException(e, CLASS_NAME + ".processAsyncSessionStoppedCallback", CommsConstants.PROXYRECEIVELISTENER_SESSION_STOPPED_02, this);
       SibTr.error(tc, "WRONG_CLASS_CWSICO8021", e);
       throw e;
     }

     if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) SibTr.exit(this, tc, "processAsyncSessionStoppedCallback");
   }
81726
public void processResponse(ResponseEvent response) {
    ClientTransaction trans = response.getClientTransaction();
    if (trans == null) {
      return;
    }

    SipTransaction sip_trans = null;

    synchronized (respTransactions) {
      sip_trans = (SipTransaction) respTransactions.get(trans);
    }

    if (sip_trans == null) {
      return;
    }

    if (response.getResponse().getStatusCode() > 199) {
      synchronized (respTransactions) {
        respTransactions.remove(trans);
      }
    }

    // check for listener handling
    MessageListener listener = sip_trans.getClientListener();
    if (listener != null) {
      listener.processEvent(response);
      return;
    }

    // if no listener, use the default blocking mechanism
    synchronized (sip_trans.getBlock()) {
      sip_trans.getEvents().addLast(response);
      sip_trans.getBlock().notifyEvent();
    }
  }
1310197
@Override
    public void processConnect(WebSocketChannel channel, WSURI location, String[] protocols) {
        LOG.entering(CLASS_NAME, "connect", channel);

        nextHandler.processConnect(channel, location, protocols);
    }
643920
@Override
    public void write(final Packet packet) {
        log.debug("write - state: {}", state);
        if (closing || state.getState() == RTMP.STATE_DISCONNECTED) {
            // Connection is being closed, don't send any new packets
            return;
        }
        IoBuffer data;
        try {
            Red5.setConnectionLocal(this);
            data = encoder.encode(packet);
        } catch (Exception e) {
            log.error("Could not encode message {}", packet, e);
            return;
        } finally {
            Red5.setConnectionLocal(null);
        }

        if (data != null) {
            // Mark packet as being written
            writingMessage(packet);
            //add to pending
            pendingMessages.add(new PendingData(data, packet));
        } else {
            log.info("Response buffer was null after encoding");
        }
    }
114242
public function onPingRequestPacket(PingRequestPacket $packet)
    {
        //a ping data contains a long, but because the client just expects the same data back no point in parsing/reencoding it
        $ping = new PingResponsePacket();
        $ping->setPingData($packet->getPingData());

        //disconnect the client with the ping response
        $this->disconnectClient($ping);
    }
585921
private void onLossPacket(Packet p) {
        if (p.respHeader == null) {
            p.respHeader = new ResponseHeader(-1, -1, ErrorCode.OK);
        }
        switch (getStatus()) {
        case AUTH_FAILED:
            p.respHeader.setErr(ErrorCode.AUTHENT_FAILED);
            break;
        case CLOSED:
            p.respHeader.setErr(ErrorCode.CLIENT_CLOSED);
            break;
        default:
            p.respHeader.setErr(ErrorCode.CONNECTION_LOSS);
        }
        finishPacket(p);
    }
1221920
def handle_packet(self, packet):
        """"""
        if self.packet_callback:
            # forward to callback
            self.packet_callback(packet)
        else:
            print('packet', packet)
62787
@Override
	public void process(Packet message, MessageContext ctx)
	{
		Container c = ctx.getServerHandler().player.openContainer;
		if (message.windowId != c.windowId || !(c instanceof MalisisInventoryContainer))
			return;

		MalisisInventoryContainer container = (MalisisInventoryContainer) c;
		container.handleAction(message.action, message.inventoryId, message.slotNumber, message.code);
		container.detectAndSendChanges();
	}
361114
public void processRequest(RequestEvent requestEvent) {
		final SipProvider sipProvider = (SipProvider)requestEvent.getSource();
		ServerTransaction requestTransaction =  requestEvent.getServerTransaction();
		final Dialog dialog = requestEvent.getDialog();
		if(logger.isDebugEnabled()) {
			logger.debug("processRequest - dialog=" + dialog);
			if (dialog != null){
				logger.debug("processRequest - dialog.getDialogId()=" + dialog.getDialogId());
			}
		}
		final Request request = requestEvent.getRequest();
		// self routing makes the application data cloned, so we make sure to nullify it
		((MessageExt)request).setApplicationData(null);
		final String requestMethod = request.getMethod();

		final RouteHeader routeHeader = (RouteHeader) request
				.getHeader(RouteHeader.NAME);

		// congestion control is done here only if we drop messages to avoid generating STX
		if(CongestionControlPolicy.DropMessage.equals(congestionControlPolicy) && controlCongestion(request, null, dialog, routeHeader, sipProvider)) {
			return;
		}

		if((rejectSipMessages || memoryToHigh) && CongestionControlPolicy.DropMessage.equals(congestionControlPolicy)) {
			String method = requestEvent.getRequest().getMethod();
			boolean goodMethod = method.equals(Request.ACK) || method.equals(Request.PRACK) || method.equals(Request.BYE) || method.equals(Request.CANCEL) || method.equals(Request.UPDATE) || method.equals(Request.INFO);
			if(logger.isDebugEnabled()) {
				logger.debug("congestion control good method " + goodMethod + ", dialog "  + dialog + " routeHeader " + routeHeader);
			}
			if(!goodMethod) {
				if(dialog == null && (routeHeader == null || ((Parameters)routeHeader.getAddress().getURI()).getParameter(MessageDispatcher.RR_PARAM_PROXY_APP) == null)) {
					logger.error("dropping request, memory is too high or too many messages present in queues");
					return;
				}
			}
		}

		try {
			if(logger.isDebugEnabled()) {
				logger.debug("sipApplicationDispatcher " + this + ", Got a request event "  + request.toString());
			}
			if (!Request.ACK.equals(requestMethod) && requestTransaction == null ) {
				try {
					//folsson fix : Workaround broken Cisco 7940/7912
				    if(request.getHeader(MaxForwardsHeader.NAME) == null){
					    request.setHeader(SipFactoryImpl.headerFactory.createMaxForwardsHeader(70));
					}
				    requestTransaction = sipProvider.getNewServerTransaction(request);
				    JainSipUtils.setTransactionTimers(((TransactionExt)requestTransaction), this);
				} catch ( TransactionUnavailableException tae) {
					logger.error("cannot get a new Server transaction for this request " + request, tae);
					// Sends a 500 Internal server error and stops processing.
					MessageDispatcher.sendErrorResponse(this, Response.SERVER_INTERNAL_ERROR, requestTransaction, request, sipProvider);
	                return;
				} catch ( TransactionAlreadyExistsException taex ) {
					// This is a retransmission so just return.
					return;
				}
			}
			final ServerTransaction transaction = requestTransaction;

			if(logger.isDebugEnabled()) {
				logger.debug("ServerTx ref "  + transaction);
				logger.debug("Dialog ref "  + dialog);
			}

			final SipServletRequestImpl sipServletRequest = (SipServletRequestImpl) sipFactoryImpl.getMobicentsSipServletMessageFactory().createSipServletRequest(
						request,
						null,
						transaction,
						dialog,
						JainSipUtils.DIALOG_CREATING_METHODS.contains(requestMethod));
			updateRequestsStatistics(request, true);

			if(logger.isDebugEnabled()) {
				logger.debug("processRequest - routing state=" + sipServletRequest.getRoutingState());
			}

			// Check if the request is meant for me. If so, strip the topmost
			// Route header.

			//Popping the router header if it's for the container as
			//specified in JSR 289 - Section 15.8
			if(!isRouteExternal(routeHeader)) {
				if(logger.isDebugEnabled()) {
					logger.debug("processRequest - not external - =routeHeader" + routeHeader);
				}
				request.removeFirst(RouteHeader.NAME);
				sipServletRequest.setPoppedRoute(routeHeader);
				final Parameters poppedAddress = (Parameters)routeHeader.getAddress().getURI();
				if(poppedAddress.getParameter(MessageDispatcher.RR_PARAM_PROXY_APP) != null ||
						// Issue 2850 :	Use Request-URI custom Mobicents parameters to route request for misbehaving agents, workaround for Cisco-SIPGateway/IOS-12.x user agent
						(request.getRequestURI() instanceof javax.sip.address.SipURI && ((Parameters)request.getRequestURI()).getParameter(MessageDispatcher.RR_PARAM_PROXY_APP) != null)) {
					if(logger.isDebugEnabled()) {
						logger.debug("the request is for a proxy application, thus it is a subsequent request ");
					}
					sipServletRequest.setRoutingState(RoutingState.SUBSEQUENT);
				}
				if(transaction != null) {
					if(logger.isDebugEnabled()) {
						logger.debug("processRequest - transaction not null, transaction.getDialog()=" + transaction.getDialog());
						if (transaction.getDialog() != null){
							logger.debug("processRequest - transaction dialog not null, transaction.getDialog().getDialogId()=" + transaction.getDialog().getDialogId());
						}
					}
					TransactionApplicationData transactionApplicationData = (TransactionApplicationData)transaction.getApplicationData();
					if(transactionApplicationData != null && transactionApplicationData.getInitialPoppedRoute() == null) {
						if (transaction.getDialog() != null){
							logger.debug("processRequest - setInitialPoppedRoute, routeHeader.getAddress()=" + routeHeader.getAddress());
						}
						transactionApplicationData.setInitialPoppedRoute(new AddressImpl(routeHeader.getAddress(), null, ModifiableRule.NotModifiable));
					}
				}
			}
			if(logger.isDebugEnabled()) {
				logger.debug("Routing State " + sipServletRequest.getRoutingState());
			}

			try {
				// congestion control is done here so that the STX is created and a response can be generated back
				// and that
				if(controlCongestion(request, sipServletRequest, dialog, routeHeader, sipProvider)) {
					return;
				}

				if(logger.isDebugEnabled()) {
					logger.debug("processRequest - dispatching request with sipServletRequest.getAppSessionId()=" + sipServletRequest.getAppSessionId());
				}

				messageDispatcherFactory.getRequestDispatcher(sipServletRequest, this).
					dispatchMessage(sipProvider, sipServletRequest);
			} catch (DispatcherException e) {
				// Change log level from Error to debug: https://github.com/RestComm/jain-sip/issues/116
				if (logger.isDebugEnabled()) {
					logger.debug("Unexpected exception while processing request " + request,e);
				}
				// Sends an error response if the subsequent request is not an ACK (otherwise it violates RF3261) and stops processing.
				if(!Request.ACK.equalsIgnoreCase(requestMethod)) {
					MessageDispatcher.sendErrorResponse(this, e.getErrorCode(), sipServletRequest, sipProvider);
				}
				return;
			} catch (Throwable e) {
				// Change log level from Error to debug: https://github.com/RestComm/jain-sip/issues/116
				if (logger.isDebugEnabled()) {
					logger.debug("Unexpected exception while processing request " + request,e);
				}
				// Sends a 500 Internal server error if the subsequent request is not an ACK (otherwise it violates RF3261) and stops processing.
				if(!Request.ACK.equalsIgnoreCase(requestMethod)) {
					MessageDispatcher.sendErrorResponse(this, Response.SERVER_INTERNAL_ERROR, sipServletRequest, sipProvider);
				}
				return;
			}
		} catch (Throwable e) {
			// Change log level from Error to debug: https://github.com/RestComm/jain-sip/issues/116
			if (logger.isDebugEnabled()) {
				logger.debug("Unexpected exception while processing request " + request,e);
			}
			// Sends a 500 Internal server error if the subsequent request is not an ACK (otherwise it violates RF3261) and stops processing.
			if(!Request.ACK.equalsIgnoreCase(request.getMethod())) {
				MessageDispatcher.sendErrorResponse(this, Response.SERVER_INTERNAL_ERROR, requestTransaction, request, sipProvider);
			}
			return;
		}
	}
199219
private void handlePacket(Stanza packet) {
        if (packet instanceof Presence) {
            Presence presence = (Presence) packet;

            // The workgroup can send us a number of different presence packets. We
            // check for different packet extensions to see what type of presence
            // packet it is.

            Resourcepart queueName = presence.getFrom().getResourceOrNull();
            WorkgroupQueue queue = queues.get(queueName);
            // If there isn't already an entry for the queue, create a new one.
            if (queue == null) {
                queue = new WorkgroupQueue(queueName);
                queues.put(queueName, queue);
            }

            // QueueOverview packet extensions contain basic information about a queue.
            QueueOverview queueOverview = presence.getExtension(QueueOverview.ELEMENT_NAME, QueueOverview.NAMESPACE);
            if (queueOverview != null) {
                if (queueOverview.getStatus() == null) {
                    queue.setStatus(WorkgroupQueue.Status.CLOSED);
                }
                else {
                    queue.setStatus(queueOverview.getStatus());
                }
                queue.setAverageWaitTime(queueOverview.getAverageWaitTime());
                queue.setOldestEntry(queueOverview.getOldestEntry());
                // Fire event.
                fireQueueUsersEvent(queue, queueOverview.getStatus(),
                        queueOverview.getAverageWaitTime(), queueOverview.getOldestEntry(),
                        null);
                return;
            }

            // QueueDetails packet extensions contain information about the users in
            // a queue.
            QueueDetails queueDetails = packet.getExtension(QueueDetails.ELEMENT_NAME, QueueDetails.NAMESPACE);
            if (queueDetails != null) {
                queue.setUsers(queueDetails.getUsers());
                // Fire event.
                fireQueueUsersEvent(queue, null, -1, null, queueDetails.getUsers());
                return;
            }

            // Notify agent packets gives an overview of agent activity in a queue.
            StandardExtensionElement notifyAgents = presence.getExtension("notify-agents", "http://jabber.org/protocol/workgroup");
            if (notifyAgents != null) {
                int currentChats = Integer.parseInt(notifyAgents.getFirstElement("current-chats", "http://jabber.org/protocol/workgroup").getText());
                int maxChats = Integer.parseInt(notifyAgents.getFirstElement("max-chats", "http://jabber.org/protocol/workgroup").getText());
                queue.setCurrentChats(currentChats);
                queue.setMaxChats(maxChats);
                // Fire event.
                // TODO: might need another event for current chats and max chats of queue
                return;
            }
        }
        else if (packet instanceof Message) {
            Message message = (Message) packet;

            // Check if a room invitation was sent and if the sender is the workgroup
            MUCUser mucUser = message.getExtension("x",
                    "http://jabber.org/protocol/muc#user");
            MUCUser.Invite invite = mucUser != null ? mucUser.getInvite() : null;
            if (invite != null && workgroupJID.equals(invite.getFrom())) {
                String sessionID = null;
                Map<String, List<String>> metaData = null;

                SessionID sessionIDExt = message.getExtension(SessionID.ELEMENT_NAME,
                        SessionID.NAMESPACE);
                if (sessionIDExt != null) {
                    sessionID = sessionIDExt.getSessionID();
                }

                MetaData metaDataExt = message.getExtension(MetaData.ELEMENT_NAME,
                        MetaData.NAMESPACE);
                if (metaDataExt != null) {
                    metaData = metaDataExt.getMetaData();
                }

                this.fireInvitationEvent(message.getFrom(), sessionID, message.getBody(),
                        message.getFrom(), metaData);
            }
        }
    }
474209
void process_record(InputRecord r, boolean expectingFinished)
            throws IOException {

        checkThrown();

        /*
         * Store the incoming handshake data, then see if we can
         * now process any completed handshake messages
         */
        input.incomingRecord(r);

        /*
         * We don't need to create a separate delegatable task
         * for finished messages.
         */
        if ((conn != null) || expectingFinished) {
            processLoop();
        } else {
            delegateTask(new PrivilegedExceptionAction<Void>() {
                public Void run() throws Exception {
                    processLoop();
                    return null;
                }
            });
        }
    }
81639
protected void processReceivedMessage(DatagramPacket packet, byte[] buffer) {

		String received = new String(buffer).trim();
		String tokens[] = received.split("\\|");
		if (tokens.length != 3) {
			logger.warn("Malformed UDP message received (" + received + ")!");
			return;
		}

		// Check prefix and nodeID
		if (!namespace.equals(tokens[0]) || nodeID.equals(tokens[1])) {
			return;
		}
		if (tokens[1].isEmpty()) {
			logger.warn("Empty nodeID received!");
			return;
		}

		// Get source hostname or IP
		String host;
		try {
			InetAddress address = packet.getAddress();
			if (useHostname) {
				host = address.getHostName();
				if (host == null || host.isEmpty() || host.contains("localhost")) {
					host = address.getHostAddress();
				}
			} else {
				host = address.getHostAddress();
				if (host == null || host.isEmpty() || host.startsWith("127.")) {
					host = address.getHostName();
				}
			}
			if (host == null || host.isEmpty()) {
				logger.warn("Unable to detect sender's hostname!");
				return;
			}
		} catch (Exception cause) {
			logger.warn("Unable to detect sender's IP address or hostname!", cause);
			return;
		}
		int port = 0;
		try {
			port = Integer.parseInt(tokens[2]);
			if (port < 1) {
				logger.warn("Invalid port number (" + port + ")!");
				return;
			}
		} catch (Exception cause) {
			logger.warn("Invalid port number format (" + tokens[2] + ")!");
			return;
		}

		// Notify TCP Transporter
		transporter.udpPacketReceived(tokens[1], host.toLowerCase(), port);
	}
1278805
private void freePacket(Packet packet) {
        if (packet != null && packet.getData() != null) {
            packet.clearData();
        }
    }
334067
private void processConnectionInfo(CommsByteBuffer buffer, Conversation conversation)
   {
      if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) SibTr.entry(this, tc, "processConnectionInfo",
                                           new Object[]{buffer, conversation});

      ClientConversationState convState = (ClientConversationState) conversation.getAttachment();

      short connectionObjectId = buffer.getShort();           // BIT16 ConnectionObjectID
      String meName = buffer.getString();                     // STR   MEName

      // Set the connection object ID in the conversation state
      convState.setConnectionObjectID(connectionObjectId);

      // Create the connection proxy and save it away in the conversation state
      final ConnectionProxy connectionProxy;

      // The type of connection proxy we create is dependent on FAP version.  Fap version 5 supports
      // a connection which MSSIXAResourceProvider.  This is done so that PEV (introduced in line with
      // FAP 5) can perform remote recovery of resources.
      if (conversation.getHandshakeProperties().getFapLevel() >= JFapChannelConstants.FAP_VERSION_5)
      {
         connectionProxy = new MSSIXAResourceProvidingConnectionProxy(conversation);
      }
      else
      {
         connectionProxy = new ConnectionProxy(conversation);
      }

      convState.setSICoreConnection(connectionProxy);

      // Set in the ME name
      connectionProxy.setMeName(meName);

      // Now get the unique Id if there was one, and set it in the connection proxy
      short idLength = buffer.getShort();
      if (idLength != 0)
      {
         if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) SibTr.debug(tc, "Got unique id of length:", idLength);

         byte[] uniqueId = buffer.get(idLength);

         if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) SibTr.bytes(tc, uniqueId);

         connectionProxy.setInitialUniqueId(uniqueId);
      }
      else
      {
         if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) SibTr.debug(tc, "No unique Id was returned");
      }

      // Get the ME Uuid
      String meUuid = buffer.getString();
      if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) SibTr.debug(tc, "ME Uuid: ", meUuid);
      connectionProxy.setMeUuid(meUuid);

      // Get the resolved User Id
      String resolvedUserId = buffer.getString();
      if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) SibTr.debug(tc, "Resolved UserId: ", resolvedUserId);
      connectionProxy.setResolvedUserId(resolvedUserId);

      if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) SibTr.exit(tc, "processConnectionInfo");
   }
170531
func (d *Datapath) processApplicationAckPacket(tcpPacket *packet.Packet, context *pucontext.PUContext, conn *connection.TCPConnection) error {

	// Only process the first Ack of a connection. This means that we have received
	// as SynAck packet and we can now process the ACK.
	if conn.GetState() == connection.TCPSynAckReceived && tcpPacket.IsEmptyTCPPayload() {
		// Create a new token that includes the source and destinatio nonse
		// These are both challenges signed by the secret key and random for every
		// connection minimizing the chances of a replay attack
		token, err := d.tokenAccessor.CreateAckPacketToken(context, &conn.Auth)
		if err != nil {
			return err
		}

		tcpOptions := d.createTCPAuthenticationOption([]byte{})

		// Attach the tags to the packet
		if err := tcpPacket.TCPDataAttach(tcpOptions, token); err != nil {
			return err
		}

		conn.SetState(connection.TCPAckSend)

		// If its not a service connection, we release it to the kernel. Subsequent
		// packets after the first data packet, that might be already in the queue
		// will be transmitted through the kernel directly. Service connections are
		// delegated to the service module
		if !conn.ServiceConnection && tcpPacket.SourceAddress().String() != tcpPacket.DestinationAddress().String() &&
			!(tcpPacket.SourceAddress().IsLoopback() && tcpPacket.DestinationAddress().IsLoopback()) {
			if err := d.conntrack.UpdateApplicationFlowMark(
				tcpPacket.SourceAddress(),
				tcpPacket.DestinationAddress(),
				tcpPacket.IPProto(),
				tcpPacket.SourcePort(),
				tcpPacket.DestPort(),
				constants.DefaultConnMark,
			); err != nil {
				zap.L().Error("Failed to update conntrack table for flow after ack packet",
					zap.String("context", string(conn.Auth.LocalContext)),
					zap.String("app-conn", tcpPacket.L4ReverseFlowHash()),
					zap.String("state", fmt.Sprintf("%d", conn.GetState())),
					zap.Error(err),
				)
			}
		}

		return nil
	}

	// If we are already in the connection.TCPData connection just forward the packet
	if conn.GetState() == connection.TCPData {
		return nil
	}

	if conn.GetState() == connection.UnknownState {
		// Check if the destination is in the external services approved cache
		// and if yes, allow the packet to go and release the flow.
		_, policy, perr := context.ApplicationACLPolicyFromAddr(tcpPacket.DestinationAddress(), tcpPacket.DestPort())

		if perr != nil {
			// If it is an SSH PU, we let the connection go through
			// It means it is a new SSH Session connection, we mark
			// the packet and let it go through.
			if context.Type() == common.SSHSessionPU {
				if err := d.conntrack.UpdateApplicationFlowMark(
					tcpPacket.SourceAddress(),
					tcpPacket.DestinationAddress(),
					tcpPacket.IPProto(),
					tcpPacket.SourcePort(),
					tcpPacket.DestPort(),
					constants.DefaultConnMark,
				); err != nil {
					zap.L().Error("Failed to update conntrack entry for flow at Ack packet",
						zap.String("context", string(conn.Auth.LocalContext)),
						zap.String("app-conn", tcpPacket.L4ReverseFlowHash()),
						zap.String("state", fmt.Sprintf("%d", conn.GetState())),
						zap.Error(err),
					)
				}
				return nil
			}
			// Convert Ack to FinAck for all other pus
			return tcpPacket.ConvertAcktoFinAck()
		}

		if policy.Action.Rejected() {
			return errors.New("Reject the packet")
		}

		if err := d.conntrack.UpdateApplicationFlowMark(
			tcpPacket.SourceAddress(),
			tcpPacket.DestinationAddress(),
			tcpPacket.IPProto(),
			tcpPacket.SourcePort(),
			tcpPacket.DestPort(),
			constants.DefaultConnMark,
		); err != nil {
			zap.L().Error("Failed to update conntrack entry for flow at Ack packet",
				zap.String("context", string(conn.Auth.LocalContext)),
				zap.String("app-conn", tcpPacket.L4ReverseFlowHash()),
				zap.String("state", fmt.Sprintf("%d", conn.GetState())),
				zap.Error(err),
			)
		}
		return nil
	}

	// Here we capture the first data packet after an ACK packet by modyfing the
	// state. We will not release the caches though to deal with re-transmissions.
	// We will let the caches expire.
	if conn.GetState() == connection.TCPAckSend {
		conn.SetState(connection.TCPData)
		return nil
	}

	return fmt.Errorf("received application ack packet in the wrong state: %d", conn.GetState())
}