open method

  1. @override
Future<void> open()
override

Open the transport (idempotent).

Implementation

@override
Future<void> open() async {
  if (!Platform.isLinux) {
    throw UnsupportedError('SocketCanTransport requires Linux');
  }
  if (_isClosed) throw StateError('SocketCanTransport already closed');
  if (_isOpen) return;

  _fd = _bindings.socket(kPfCan, kSockRaw, kCanRaw);
  if (_fd < 0) {
    throw StateError(
      'socket(PF_CAN, SOCK_RAW, CAN_RAW) failed (rc=$_fd) — '
      'kernel CAN module not loaded?',
    );
  }

  final ifReq = allocIfReq(interfaceName);
  try {
    final rc = _bindings.ioctl(_fd, kSiocgIfIndex, ifReq.cast<Void>());
    if (rc != 0) {
      throw StateError(
        'ioctl(SIOCGIFINDEX, "$interfaceName") failed (rc=$rc) — '
        'interface does not exist?',
      );
    }
    final ifIndex = readIfReqIfIndex(ifReq);
    final addr = allocSockaddrCan(ifIndex);
    try {
      final br =
          _bindings.bind(_fd, addr.cast<Void>(), kSockAddrCanSize);
      if (br != 0) {
        throw StateError('bind(sockaddr_can) failed (rc=$br)');
      }
    } finally {
      calloc.free(addr);
    }
  } finally {
    calloc.free(ifReq);
  }

  if (enableFd) {
    // Enable CAN-FD frames at the socket level. Failure here is
    // typically a kernel-too-old / interface-not-FD-capable
    // condition — fail loudly so the integrator catches it early.
    final optval = calloc<Uint32>(1);
    try {
      optval.value = 1;
      final rc = _bindings.setsockopt(
        _fd, kSolCanRaw, kCanRawFdFrames,
        optval.cast<Void>(), 4,
      );
      if (rc != 0) {
        throw StateError(
          'setsockopt(SOL_CAN_RAW, CAN_RAW_FD_FRAMES) failed (rc=$rc)',
        );
      }
    } finally {
      calloc.free(optval);
    }
  }

  _readBufSize = enableFd ? kCanFdFrameSize : kCanFrameSize;
  _readBuf = malloc<Uint8>(_readBufSize);
  _isOpen = true;
  _pollTimer = Timer.periodic(pollInterval, (_) => _drainOne());
}