예제 #1
0
static jint OSNetworkSystem_sendDirect(JNIEnv* env, jobject, jobject fileDescriptor, jint address, jint offset, jint length, jint port, jobject inetAddress) {
    NetFd fd(env, fileDescriptor);
    if (fd.isClosed()) {
        return -1;
    }

    sockaddr_storage receiver;
    if (inetAddress != NULL && !inetAddressToSocketAddress(env, inetAddress, port, &receiver)) {
        return -1;
    }

    int flags = 0;
    char* buf = reinterpret_cast<char*>(static_cast<uintptr_t>(address + offset));
    sockaddr* to = inetAddress ? reinterpret_cast<sockaddr*>(&receiver) : NULL;
    socklen_t toLength = inetAddress ? sizeof(receiver) : 0;

    ssize_t bytesSent;
    {
        int intFd = fd.get();
        AsynchronousSocketCloseMonitor monitor(intFd);
        bytesSent = NET_FAILURE_RETRY(fd, sendto(intFd, buf, length, flags, to, toLength));
    }
    if (env->ExceptionOccurred()) {
        return -1;
    }
    if (bytesSent == -1) {
        if (errno == ECONNRESET || errno == ECONNREFUSED) {
            return 0;
        } else {
            jniThrowSocketException(env, errno);
        }
    }
    return bytesSent;
}
예제 #2
0
// TODO: can we merge this with recvDirect?
static jint OSNetworkSystem_readDirect(JNIEnv* env, jobject, jobject fileDescriptor,
        jint address, jint count) {
    NetFd fd(env, fileDescriptor);
    if (fd.isClosed()) {
        return 0;
    }

    jbyte* dst = reinterpret_cast<jbyte*>(static_cast<uintptr_t>(address));
    ssize_t bytesReceived;
    {
        int intFd = fd.get();
        AsynchronousSocketCloseMonitor monitor(intFd);
        bytesReceived = NET_FAILURE_RETRY(fd, read(intFd, dst, count));
    }
    if (env->ExceptionOccurred()) {
        return -1;
    }
    if (bytesReceived == 0) {
        return -1;
    } else if (bytesReceived == -1) {
        if (errno == EAGAIN || errno == EWOULDBLOCK) {
            // We were asked to read a non-blocking socket with no data
            // available, so report "no bytes read".
            return 0;
        } else {
            jniThrowSocketException(env, errno);
            return 0;
        }
    } else {
        return bytesReceived;
    }
}
예제 #3
0
static jint OSNetworkSystem_writeDirect(JNIEnv* env, jobject,
        jobject fileDescriptor, jint address, jint offset, jint count) {
    if (count <= 0) {
        return 0;
    }

    NetFd fd(env, fileDescriptor);
    if (fd.isClosed()) {
        return 0;
    }

    jbyte* src = reinterpret_cast<jbyte*>(static_cast<uintptr_t>(address + offset));

    ssize_t bytesSent;
    {
        int intFd = fd.get();
        AsynchronousSocketCloseMonitor monitor(intFd);
        bytesSent = NET_FAILURE_RETRY(fd, write(intFd, src, count));
    }
    if (env->ExceptionOccurred()) {
        return -1;
    }

    if (bytesSent == -1) {
        if (errno == EAGAIN || errno == EWOULDBLOCK) {
            // We were asked to write to a non-blocking socket, but were told
            // it would block, so report "no bytes written".
            return 0;
        } else {
            jniThrowSocketException(env, errno);
            return 0;
        }
    }
    return bytesSent;
}
/*
 * Reads a network packet into the user-supplied buffer.  Return the
 * length of the packet, or a 0 if there was a timeout or an
 * unacceptable packet was acquired.
 *
 * Assumes that the caller has validated the offset & byteCount values.
 */
static jint RawSocket_recvPacket(JNIEnv* env, jclass, jobject fileDescriptor,
    jbyteArray packet, jint offset, jint byteCount, jint port,
    jint timeout_millis)
{
  NetFd fd(env, fileDescriptor);
  if (fd.isClosed()) {
    return 0;
  }

  ScopedByteArrayRW body(env, packet);
  jbyte* packetData = body.get();
  if (packetData == NULL) {
    return 0;
  }

  packetData += offset;

  pollfd fds[1];
  fds[0].fd = fd.get();
  fds[0].events = POLLIN;
  int retval = poll(fds, 1, timeout_millis);
  if (retval <= 0) {
    return 0;
  }

  unsigned int size = 0;
  {
    int packetSize = byteCount;
    int intFd = fd.get();
    AsynchronousSocketCloseMonitor monitor(intFd);
    size = NET_FAILURE_RETRY(fd, read(intFd, packetData, packetSize));
  }

  if (env->ExceptionOccurred()) {
    return 0;
  }

  if (port != -1) {
    // quick check for UDP type & UDP port
    // the packet is an IP header, UDP header, and UDP payload
    if ((size < (sizeof(struct iphdr) + sizeof(struct udphdr)))) {
      return 0;  // runt packet
    }

    u_int8_t ip_proto = ((iphdr *) packetData)->protocol;
    if (ip_proto != IPPROTO_UDP) {
      return 0;  // something other than UDP
    }

    __be16 destPort = htons((reinterpret_cast<udphdr*>(packetData + sizeof(iphdr)))->dest);
    if (destPort != port) {
      return 0; // something other than requested port
    }
  }

  return size;
}
예제 #5
0
// TODO: can we merge this with readDirect?
static jint OSNetworkSystem_recvDirect(JNIEnv* env, jobject, jobject fileDescriptor, jobject packet,
        jint address, jint offset, jint length, jboolean peek, jboolean connected) {
    NetFd fd(env, fileDescriptor);
    if (fd.isClosed()) {
        return 0;
    }

    char* buf = reinterpret_cast<char*>(static_cast<uintptr_t>(address + offset));
    const int flags = peek ? MSG_PEEK : 0;
    sockaddr_storage ss;
    memset(&ss, 0, sizeof(ss));
    socklen_t sockAddrLen = sizeof(ss);
    sockaddr* from = connected ? NULL : reinterpret_cast<sockaddr*>(&ss);
    socklen_t* fromLength = connected ? NULL : &sockAddrLen;

    ssize_t bytesReceived;
    {
        int intFd = fd.get();
        AsynchronousSocketCloseMonitor monitor(intFd);
        bytesReceived = NET_FAILURE_RETRY(fd, recvfrom(intFd, buf, length, flags, from, fromLength));
    }
    if (env->ExceptionOccurred()) {
        return -1;
    }
    if (bytesReceived == -1) {
        if (connected && errno == ECONNREFUSED) {
            jniThrowException(env, "java/net/PortUnreachableException", "");
        } else if (errno == EAGAIN || errno == EWOULDBLOCK) {
            jniThrowSocketTimeoutException(env, errno);
        } else {
            jniThrowSocketException(env, errno);
        }
        return 0;
    }

    if (packet != NULL) {
        env->SetIntField(packet, gCachedFields.dpack_length, bytesReceived);
        if (!connected) {
            jbyteArray addr = socketAddressToByteArray(env, &ss);
            if (addr == NULL) {
                return 0;
            }
            int port = getSocketAddressPort(&ss);
            jobject sender = byteArrayToInetAddress(env, addr);
            if (sender == NULL) {
                return 0;
            }
            env->SetObjectField(packet, gCachedFields.dpack_address, sender);
            env->SetIntField(packet, gCachedFields.dpack_port, port);
        }
    }
    return bytesReceived;
}
/*
 * Writes the L3 (IP) packet to the raw socket supplied in the
 * FileDescriptor instance.
 *
 * Assumes that the caller has validated the offset & byteCount values.
 */
static int RawSocket_sendPacket(JNIEnv* env, jclass, jobject fileDescriptor,
    jstring interfaceName, jshort protocolType, jbyteArray destMac,
    jbyteArray packet, jint offset, jint byteCount)
{
  NetFd fd(env, fileDescriptor);

  if (fd.isClosed()) {
    return 0;
  }

  ScopedUtfChars ifname(env, interfaceName);
  if (ifname.c_str() == NULL) {
    return 0;
  }

  ScopedByteArrayRO byteArray(env, packet);
  if (byteArray.get() == NULL) {
    return 0;
  }

  ScopedByteArrayRO mac(env, destMac);
  if (mac.get() == NULL) {
    return 0;
  }

  sockunion su;
  memset(&su, 0, sizeof(su));
  su.sll.sll_hatype = htons(1); // ARPHRD_ETHER
  su.sll.sll_halen = mac.size();
  memcpy(&su.sll.sll_addr, mac.get(), mac.size());
  su.sll.sll_family = AF_PACKET;
  su.sll.sll_protocol = htons(protocolType);
  su.sll.sll_ifindex = if_nametoindex(ifname.c_str());

  int err;
  {
    int intFd = fd.get();
    AsynchronousSocketCloseMonitor monitor(intFd);
    err = NET_FAILURE_RETRY(fd, sendto(intFd, byteArray.get() + offset,
        byteCount, 0, &su.sa, sizeof(su)));
  }

  return err;
}
예제 #7
0
static void OSNetworkSystem_accept(JNIEnv* env, jobject, jobject serverFileDescriptor,
        jobject newSocket, jobject clientFileDescriptor) {

    if (newSocket == NULL) {
        jniThrowNullPointerException(env, NULL);
        return;
    }

    NetFd serverFd(env, serverFileDescriptor);
    if (serverFd.isClosed()) {
        return;
    }

    sockaddr_storage ss;
    socklen_t addrLen = sizeof(ss);
    sockaddr* sa = reinterpret_cast<sockaddr*>(&ss);

    int clientFd;
    {
        int intFd = serverFd.get();
        AsynchronousSocketCloseMonitor monitor(intFd);
        clientFd = NET_FAILURE_RETRY(serverFd, accept(intFd, sa, &addrLen));
    }
    if (env->ExceptionOccurred()) {
        return;
    }
    if (clientFd == -1) {
        if (errno == EAGAIN || errno == EWOULDBLOCK) {
            jniThrowSocketTimeoutException(env, errno);
        } else {
            jniThrowSocketException(env, errno);
        }
        return;
    }

    // Reset the inherited read timeout to the Java-specified default of 0.
    timeval timeout(toTimeval(0));
    int rc = setsockopt(clientFd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
    if (rc == -1) {
        LOGE("couldn't reset SO_RCVTIMEO on accepted socket fd %i: %s", clientFd, strerror(errno));
        jniThrowSocketException(env, errno);
    }

    /*
     * For network sockets, put the peer address and port in instance variables.
     * We don't bother to do this for UNIX domain sockets, since most peers are
     * anonymous anyway.
     */
    if (ss.ss_family == AF_INET || ss.ss_family == AF_INET6) {
        // Remote address and port.
        jobject remoteAddress = socketAddressToInetAddress(env, &ss);
        if (remoteAddress == NULL) {
            close(clientFd);
            return;
        }
        int remotePort = getSocketAddressPort(&ss);
        env->SetObjectField(newSocket, gCachedFields.socketimpl_address, remoteAddress);
        env->SetIntField(newSocket, gCachedFields.socketimpl_port, remotePort);

        // Local port.
        memset(&ss, 0, addrLen);
        int rc = getsockname(clientFd, sa, &addrLen);
        if (rc == -1) {
            close(clientFd);
            jniThrowSocketException(env, errno);
            return;
        }
        int localPort = getSocketAddressPort(&ss);
        env->SetIntField(newSocket, gCachedFields.socketimpl_localport, localPort);
    }

    jniSetFileDescriptorOfFD(env, clientFileDescriptor, clientFd);
}