static jdwpTransportError handshake() { char *hello = "JDWP-Handshake"; unsigned int i; for (i=0; i<strlen(hello); i++) { jbyte b; int rv = shmemBase_receiveByte(connection, &b); if (rv != 0) { RETURN_IO_ERROR("receive failed during handshake"); } if ((char)b != hello[i]) { RETURN_IO_ERROR("handshake failed - debugger sent unexpected message"); } } for (i=0; i<strlen(hello); i++) { int rv = shmemBase_sendByte(connection, (jbyte)hello[i]); if (rv != 0) { RETURN_IO_ERROR("write failed during handshake"); } } return JDWPTRANSPORT_ERROR_NONE; }
static jdwpTransportError JNICALL socketTransport_startListening(jdwpTransportEnv* env, const char* address, char** actualAddress) { struct sockaddr_in sa; int err; memset((void *)&sa,0,sizeof(struct sockaddr_in)); sa.sin_family = AF_INET; /* no address provided */ if ((address == NULL) || (address[0] == '\0')) { address = "0"; } err = parseAddress(address, &sa, INADDR_ANY); if (err != JDWPTRANSPORT_ERROR_NONE) { return err; } serverSocketFD = dbgsysSocket(AF_INET, SOCK_STREAM, 0); if (serverSocketFD < 0) { RETURN_IO_ERROR("socket creation failed"); } err = setOptions(serverSocketFD); if (err) { return err; } err = dbgsysBind(serverSocketFD, (struct sockaddr *)&sa, sizeof(sa)); if (err < 0) { RETURN_IO_ERROR("bind failed"); } err = dbgsysListen(serverSocketFD, 1); if (err < 0) { RETURN_IO_ERROR("listen failed"); } { char buf[20]; int len = sizeof(sa); jint portNum; err = dbgsysGetSocketName(serverSocketFD, (struct sockaddr *)&sa, &len); portNum = dbgsysNetworkToHostShort(sa.sin_port); sprintf(buf, "%d", portNum); *actualAddress = (*callback->alloc)((int)strlen(buf) + 1); if (*actualAddress == NULL) { RETURN_ERROR(JDWPTRANSPORT_ERROR_OUT_OF_MEMORY, "out of memory"); } else { strcpy(*actualAddress, buf); } } return JDWPTRANSPORT_ERROR_NONE; }
static jdwpTransportError handshake(int fd, jlong timeout) { const char *hello = "JDWP-Handshake"; char b[16]; int rv, helloLen, received; if (timeout > 0) { dbgsysConfigureBlocking(fd, JNI_FALSE); } helloLen = (int)strlen(hello); received = 0; while (received < helloLen) { int n; char *buf; if (timeout > 0) { rv = dbgsysPoll(fd, JNI_TRUE, JNI_FALSE, (long)timeout); if (rv <= 0) { setLastError(0, "timeout during handshake"); return JDWPTRANSPORT_ERROR_IO_ERROR; } } buf = b; buf += received; n = recv_fully(fd, buf, helloLen-received); if (n == 0) { setLastError(0, "handshake failed - connection prematurally closed"); return JDWPTRANSPORT_ERROR_IO_ERROR; } if (n < 0) { RETURN_IO_ERROR("recv failed during handshake"); } received += n; } if (timeout > 0) { dbgsysConfigureBlocking(fd, JNI_TRUE); } if (strncmp(b, hello, received) != 0) { char msg[80+2*16]; b[received] = '\0'; /* * We should really use snprintf here but it's not available on Windows. * We can't use jio_snprintf without linking the transport against the VM. */ sprintf(msg, "handshake failed - received >%s< - expected >%s<", b, hello); setLastError(0, msg); return JDWPTRANSPORT_ERROR_IO_ERROR; } if (send_fully(fd, (char*)hello, helloLen) != helloLen) { RETURN_IO_ERROR("send failed during handshake"); } return JDWPTRANSPORT_ERROR_NONE; }
static jdwpTransportError handshake(int fd, jlong timeout) { char *hello = "JDWP-Handshake"; char b[16]; int rv, received, i; if (timeout > 0) { dbgsysConfigureBlocking(fd, JNI_FALSE); } received = 0; while (received < (int)strlen(hello)) { int n; char *buf; if (timeout > 0) { rv = dbgsysPoll(fd, JNI_TRUE, JNI_FALSE, (long)timeout); if (rv <= 0) { setLastError(0, "timeout during handshake"); return JDWPTRANSPORT_ERROR_IO_ERROR; } } buf = b; buf += received; n = dbgsysRecv(fd, buf, strlen(hello)-received, 0); if (n == 0) { setLastError(0, "handshake failed - connection prematurally closed"); return JDWPTRANSPORT_ERROR_IO_ERROR; } if (n < 0) { RETURN_IO_ERROR("recv failed during handshake"); } received += n; } if (timeout > 0) { dbgsysConfigureBlocking(fd, JNI_TRUE); } for (i=0; i<(int)strlen(hello); i++) { if (b[i] != hello[i]) { char msg[64]; strcpy(msg, "handshake failed - received >"); strncat(msg, b, strlen(hello)); strcat(msg, "< - excepted >"); strcat(msg, hello); strcat(msg, "<"); setLastError(0, msg); return JDWPTRANSPORT_ERROR_IO_ERROR; } } if (dbgsysSend(fd, hello, strlen(hello), 0) != (int)strlen(hello)) { RETURN_IO_ERROR("send failed during handshake"); } return JDWPTRANSPORT_ERROR_NONE; }
static jdwpTransportError JNICALL shmemAttach(jdwpTransportEnv* env, const char *address, jlong attachTimeout, jlong handshakeTimeout) { jint rc; if (connection != NULL) { RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_STATE, "already connected"); } rc = shmemBase_attach(address, (long)attachTimeout, &connection); if (rc != SYS_OK) { if (rc == SYS_NOMEM) { RETURN_ERROR(JDWPTRANSPORT_ERROR_OUT_OF_MEMORY, "out of memory"); } if (rc == SYS_TIMEOUT) { RETURN_ERROR(JDWPTRANSPORT_ERROR_TIMEOUT, "Timed out waiting to attach"); } RETURN_IO_ERROR("failed to attach to shared memory connection"); } rc = handshake(); if (rc != JDWPTRANSPORT_ERROR_NONE) { shmemBase_closeConnection(connection); connection = NULL; } return rc; }
static jdwpTransportError JNICALL shmemAccept(jdwpTransportEnv* env, jlong acceptTimeout, jlong handshakeTimeout) { jint rc; if (connection != NULL) { RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_STATE, "already connected"); } if (transport == NULL) { RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_STATE, "transport not listening"); } rc = shmemBase_accept(transport, (long)acceptTimeout, &connection); if (rc != SYS_OK) { if (rc == SYS_TIMEOUT) { RETURN_ERROR(JDWPTRANSPORT_ERROR_TIMEOUT, "Timed out waiting for connection"); } else { RETURN_IO_ERROR("failed to accept shared memory connection"); } } rc = handshake(); if (rc != JDWPTRANSPORT_ERROR_NONE) { shmemBase_closeConnection(connection); connection = NULL; } return rc; }
static jdwpTransportError JNICALL shmemStartListening(jdwpTransportEnv* env, const char *address, char **actualAddress) { jint rc; if (connection != NULL || transport != NULL) { RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_STATE, "already connected or already listening"); } rc = shmemBase_listen(address, &transport); /* * If a name was selected by the function above, find it and return * it in place of the original arg. */ if (rc == SYS_OK) { char *name; char *name2; rc = shmemBase_name(transport, &name); if (rc == SYS_OK) { name2 = (callbacks->alloc)((int)strlen(name) + 1); if (name2 == NULL) { RETURN_ERROR(JDWPTRANSPORT_ERROR_OUT_OF_MEMORY, "out of memory"); } else { strcpy(name2, name); *actualAddress = name2; } } } else { RETURN_IO_ERROR("failed to create shared memory listener"); } return JDWPTRANSPORT_ERROR_NONE; }
static jdwpTransportError setOptions(int fd) { jvalue dontcare; int err; dontcare.i = 0; /* keep compiler happy */ err = dbgsysSetSocketOption(fd, SO_REUSEADDR, JNI_TRUE, dontcare); if (err < 0) { RETURN_IO_ERROR("setsockopt SO_REUSEADDR failed"); } err = dbgsysSetSocketOption(fd, TCP_NODELAY, JNI_TRUE, dontcare); if (err < 0) { RETURN_IO_ERROR("setsockopt TCPNODELAY failed"); } return JDWPTRANSPORT_ERROR_NONE; }
static jdwpTransportError JNICALL socketTransport_stopListening(jdwpTransportEnv *env) { if (serverSocketFD < 0) { RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_STATE, "connection not open"); } if (dbgsysSocketClose(serverSocketFD) < 0) { RETURN_IO_ERROR("close failed"); } serverSocketFD = -1; return JDWPTRANSPORT_ERROR_NONE; }
static jdwpTransportError JNICALL shmemReadPacket(jdwpTransportEnv* env, jdwpPacket *packet) { if (packet == NULL) { RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT, "packet is null"); } if (connection == NULL) { RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_STATE, "not connected"); } if (shmemBase_receivePacket(connection, packet) == SYS_OK) { return JDWPTRANSPORT_ERROR_NONE; } else { RETURN_IO_ERROR("receive packet failed"); } }
static jdwpTransportError JNICALL socketTransport_close(jdwpTransportEnv* env) { int fd = socketFD; socketFD = -1; if (fd < 0) { return JDWPTRANSPORT_ERROR_NONE; } if (dbgsysSocketClose(fd) < 0) { /* * close failed - it's pointless to restore socketFD here because * any subsequent close will likely fail aswell. */ RETURN_IO_ERROR("close failed"); } return JDWPTRANSPORT_ERROR_NONE; }
static jdwpTransportError JNICALL shmemWritePacket(jdwpTransportEnv* env, const jdwpPacket *packet) { if (packet == NULL) { RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT, "packet is null"); } if (packet->type.cmd.len < 11) { RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT, "invalid length"); } if (connection == NULL) { RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_STATE, "not connected"); } if (shmemBase_sendPacket(connection, packet) == SYS_OK) { return JDWPTRANSPORT_ERROR_NONE; } else { RETURN_IO_ERROR("write packet failed"); } }
static jdwpTransportError JNICALL socketTransport_writePacket(jdwpTransportEnv* env, const jdwpPacket *packet) { jint len, data_len, id; /* * room for header and up to MAX_DATA_SIZE data bytes */ char header[HEADER_SIZE + MAX_DATA_SIZE]; jbyte *data; /* packet can't be null */ if (packet == NULL) { RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT, "packet is NULL"); } len = packet->type.cmd.len; /* includes header */ data_len = len - HEADER_SIZE; /* bad packet */ if (data_len < 0) { RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT, "invalid length"); } /* prepare the header for transmission */ len = (jint)dbgsysHostToNetworkLong(len); id = (jint)dbgsysHostToNetworkLong(packet->type.cmd.id); memcpy(header + 0, &len, 4); memcpy(header + 4, &id, 4); header[8] = packet->type.cmd.flags; if (packet->type.cmd.flags & JDWPTRANSPORT_FLAGS_REPLY) { jshort errorCode = dbgsysHostToNetworkShort(packet->type.reply.errorCode); memcpy(header + 9, &errorCode, 2); } else { header[9] = packet->type.cmd.cmdSet; header[10] = packet->type.cmd.cmd; } data = packet->type.cmd.data; /* Do one send for short packets, two for longer ones */ if (data_len <= MAX_DATA_SIZE) { memcpy(header + HEADER_SIZE, data, data_len); if (send_fully(socketFD, (char *)&header, HEADER_SIZE + data_len) != HEADER_SIZE + data_len) { RETURN_IO_ERROR("send failed"); } } else { memcpy(header + HEADER_SIZE, data, MAX_DATA_SIZE); if (send_fully(socketFD, (char *)&header, HEADER_SIZE + MAX_DATA_SIZE) != HEADER_SIZE + MAX_DATA_SIZE) { RETURN_IO_ERROR("send failed"); } /* Send the remaining data bytes right out of the data area. */ if (send_fully(socketFD, (char *)data + MAX_DATA_SIZE, data_len - MAX_DATA_SIZE) != data_len - MAX_DATA_SIZE) { RETURN_IO_ERROR("send failed"); } } return JDWPTRANSPORT_ERROR_NONE; }
static jdwpTransportError JNICALL socketTransport_attach(jdwpTransportEnv* env, const char* addressString, jlong attachTimeout, jlong handshakeTimeout) { struct sockaddr_in sa; int err; if (addressString == NULL || addressString[0] == '\0') { RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT, "address is missing"); } err = parseAddress(addressString, &sa, 0x7f000001); if (err != JDWPTRANSPORT_ERROR_NONE) { return err; } socketFD = dbgsysSocket(AF_INET, SOCK_STREAM, 0); if (socketFD < 0) { RETURN_IO_ERROR("unable to create socket"); } err = setOptions(socketFD); if (err) { return err; } /* * To do a timed connect we make the socket non-blocking * and poll with a timeout; */ if (attachTimeout > 0) { dbgsysConfigureBlocking(socketFD, JNI_FALSE); } err = dbgsysConnect(socketFD, (struct sockaddr *)&sa, sizeof(sa)); if (err == DBG_EINPROGRESS && attachTimeout > 0) { err = dbgsysFinishConnect(socketFD, (long)attachTimeout); if (err == DBG_ETIMEOUT) { dbgsysConfigureBlocking(socketFD, JNI_TRUE); RETURN_ERROR(JDWPTRANSPORT_ERROR_TIMEOUT, "connect timed out"); } } if (err < 0) { RETURN_IO_ERROR("connect failed"); } if (attachTimeout > 0) { dbgsysConfigureBlocking(socketFD, JNI_TRUE); } err = handshake(socketFD, handshakeTimeout); if (err) { dbgsysSocketClose(socketFD); socketFD = -1; return err; } return JDWPTRANSPORT_ERROR_NONE; }