JNIEXPORT void JNICALL Java_de_entropia_can_CanSocket__1sendFrame (JNIEnv *env, jclass obj, jint fd, jint if_idx, jint canid, jbyteArray data) { const int flags = 0; ssize_t nbytes; struct sockaddr_can addr; struct can_frame frame; memset(&addr, 0, sizeof(addr)); memset(&frame, 0, sizeof(frame)); addr.can_family = AF_CAN; addr.can_ifindex = if_idx; const jsize len = env->GetArrayLength(data); if (env->ExceptionCheck() == JNI_TRUE) { return; } frame.can_id = canid; frame.can_dlc = static_cast<__u8>(len); env->GetByteArrayRegion(data, 0, len, reinterpret_cast<jbyte *>(&frame.data)); if (env->ExceptionCheck() == JNI_TRUE) { return; } nbytes = sendto(fd, &frame, sizeof(frame), flags, reinterpret_cast<struct sockaddr *>(&addr), sizeof(addr)); if (nbytes == -1) { throwIOExceptionErrno(env, errno); } else if (nbytes != sizeof(frame)) { throwIOExceptionMsg(env, "send partial frame"); } }
static void throwIOExceptionErrno(JNIEnv *env, const int exc_errno) { char message[ERRNO_BUFFER_LEN]; const char *const msg = (char *) strerror_r(exc_errno, message, ERRNO_BUFFER_LEN); if (((long)msg) == 0) { // POSIX strerror_r, success throwIOExceptionMsg(env, std::string(message)); } else if (((long)msg) == -1) { // POSIX strerror_r, failure // (Strictly, POSIX only guarantees a value other than 0. The safest // way to implement this function is to use C++ and overload on the // type of strerror_r to accurately distinguish GNU from POSIX. But // realistic implementations will always return -1.) snprintf(message, ERRNO_BUFFER_LEN, "errno %d", exc_errno); throwIOExceptionMsg(env, std::string(message)); } else { // glibc strerror_r returning a string throwIOExceptionMsg(env, std::string(msg)); } }
JNIEXPORT jobject JNICALL Java_de_entropia_can_CanSocket__1recvFrame (JNIEnv *env, jclass obj, jint fd) { const int flags = 0; ssize_t nbytes; struct sockaddr_can addr; socklen_t len = sizeof(addr); struct can_frame frame; memset(&addr, 0, sizeof(addr)); memset(&frame, 0, sizeof(frame)); nbytes = recvfrom(fd, &frame, sizeof(frame), flags, reinterpret_cast<struct sockaddr *>(&addr), &len); if (len != sizeof(addr)) { throwIllegalArgumentException(env, "illegal AF_CAN address"); return nullptr; } if (nbytes == -1) { throwIOExceptionErrno(env, errno); return nullptr; } else if (nbytes != sizeof(frame)) { throwIOExceptionMsg(env, "invalid length of received frame"); return nullptr; } const jsize fsize = static_cast<jsize>(std::min(static_cast<size_t>(frame.can_dlc), nbytes - offsetof(struct can_frame, data))); const jclass can_frame_clazz = env->FindClass("de/entropia/can/" "CanSocket$CanFrame"); if (can_frame_clazz == nullptr) { return nullptr; } const jmethodID can_frame_cstr = env->GetMethodID(can_frame_clazz, "<init>", "(II[B)V"); if (can_frame_cstr == nullptr) { return nullptr; } const jbyteArray data = env->NewByteArray(fsize); if (data == nullptr) { if (env->ExceptionCheck() != JNI_TRUE) { throwOutOfMemoryError(env, "could not allocate ByteArray"); } return nullptr; } env->SetByteArrayRegion(data, 0, fsize, reinterpret_cast<jbyte *>(&frame.data)); if (env->ExceptionCheck() == JNI_TRUE) { return nullptr; } const jobject ret = env->NewObject(can_frame_clazz, can_frame_cstr, addr.can_ifindex, frame.can_id, data); return ret; }
static void throwIOExceptionErrno(JNIEnv *env, const int exc_errno) { char message[ERRNO_BUFFER_LEN]; const char *const msg = strerror_r(exc_errno, message, ERRNO_BUFFER_LEN); throwIOExceptionMsg(env, msg); }