All Downloads are FREE. Search and download functionalities are using the official Maven repository.

pcap.jdk7.internal.DefaultWaitForMultipleObjectsSelector Maven / Gradle / Ivy

/*
 * Copyright (c) 2020-2021 Pcap Project
 * SPDX-License-Identifier: MIT OR Apache-2.0
 */
package pcap.jdk7.internal;

import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import java.util.Collections;
import java.util.Iterator;
import pcap.spi.Selectable;
import pcap.spi.Selection;
import pcap.spi.Selector;
import pcap.spi.Timeout;
import pcap.spi.exception.NoSuchSelectableException;
import pcap.spi.exception.TimeoutException;
import pcap.spi.util.Consumer;

class DefaultWaitForMultipleObjectsSelector extends AbstractSelector {

  private static final int EINTR = 4;

  private NativeMappings.HANDLE[] handles = new NativeMappings.HANDLE[0];

  DefaultWaitForMultipleObjectsSelector() {
    super.isClosed = false;
  }

  Iterable toIterableSelectable(int rc, int timeout) throws TimeoutException {
    if (rc == 0x00000102) {
      throw new TimeoutException(String.format("Timeout: %d ms.", timeout));
    }
    if (rc < 0) {
      return Collections.EMPTY_LIST;
    }
    final DefaultSelection selection = registered.get(handles[rc]);
    selection.setReadyOperation(selection.interestOperations());
    return new SelectableList(selection.pcap);
  }

  private NativeMappings.HANDLE[] add(DefaultSelection selection, int size) {
    NativeMappings.HANDLE[] newHandles = new NativeMappings.HANDLE[size];
    NativeMappings.HANDLE handle =
        NativeMappings.PLATFORM_DEPENDENT.pcap_getevent(selection.pcap.pointer);
    newHandles[handles.length] = handle;
    selection.pcap.selector = this;
    registered.put(handle, selection);
    return newHandles;
  }

  @Override
  public Selector register(Selectable pcap) throws IllegalArgumentException, IllegalStateException {
    register(pcap, Selection.OPERATION_READ, null);
    return this;
  }

  @Override
  Selection register(Selectable selectable, int interestOperations, Object attachment)
      throws IllegalArgumentException, IllegalStateException {
    DefaultSelection selection = validateRegister(selectable, attachment);
    if (!registered.isEmpty()) {
      // register new pcap
      NativeMappings.HANDLE[] newHandles = add(selection, handles.length + 1);
      System.arraycopy(handles, 0, newHandles, 0, handles.length);
      this.handles = newHandles;
    } else {
      this.handles = add(selection, 1);
    }
    selection.interestOperations(interestOperations);
    selection.attach(attachment);
    return selection;
  }

  @Override
  void interestOperations(DefaultSelection selection, int interestOperations) {
    selection.interestOperations(interestOperations);
  }

  @Override
  public Iterable select(Timeout timeout)
      throws TimeoutException, NoSuchSelectableException, IllegalStateException,
          IllegalArgumentException {
    validateSelect(timeout);
    int ts = (int) timeout.microSecond() / 1000;
    int rc;
    do {
      rc = Kernel32.INSTANCE.WaitForMultipleObjects(registered.size(), handles, false, ts);
    } while (rc < 0 && EINTR == Native.getLastError());
    return toIterableSelectable(rc, ts);
  }

  @Override
  public int select(Consumer consumer, Timeout timeout)
      throws TimeoutException, NoSuchSelectableException, IllegalStateException,
          IllegalArgumentException {
    validateSelect(timeout);
    int ts = (int) timeout.microSecond() / 1000;
    int rc;
    do {
      rc = Kernel32.INSTANCE.WaitForMultipleObjects(registered.size(), handles, false, ts);
    } while (rc < 0 && EINTR == Native.getLastError());
    return callback(rc, timeout, consumer);
  }

  int callback(int rc, Timeout timeout, Consumer consumer) throws TimeoutException {
    if (rc == 0x00000102) {
      throw new TimeoutException(String.format("Timeout: %s ms.", timeout));
    }
    if (rc < 0) {
      return 0;
    }
    final DefaultSelection selection = registered.get(handles[rc]);
    selection.setReadyOperation(selection.interestOperations());
    consumer.accept(selection);
    return 1;
  }

  @Override
  protected void cancel(DefaultPcap pcap) {
    NativeMappings.HANDLE handle = NativeMappings.PLATFORM_DEPENDENT.pcap_getevent(pcap.pointer);
    for (int i = 0; i < registered.size(); i++) {
      if (Pointer.nativeValue(handle.getPointer())
          == Pointer.nativeValue(handles[i].getPointer())) {
        NativeMappings.HANDLE[] newHandles = new NativeMappings.HANDLE[handles.length - 1];
        int index = 0;
        for (int j = 0; j < handles.length; j++) {
          if (j != i) {
            newHandles[index] = handles[index];
            index++;
          } else {
            registered.remove(handle);
          }
        }
        break;
      }
    }
  }

  @Override
  public void close() throws Exception {
    Iterator iterator = registered.values().iterator();
    while (iterator.hasNext()) {
      iterator.next().pcap.selector = null;
      iterator.remove();
    }
    isClosed = true;
  }

  public interface Kernel32 extends Library {

    Kernel32 INSTANCE = Native.load("kernel32", Kernel32.class);

    int WaitForMultipleObjects(
        int nCount, NativeMappings.HANDLE[] hHandle, boolean bWaitAll, int dwMilliseconds);
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy