Skip to content

Commit

Permalink
Major rework to support Linux's in-box USB/IP implementation. It stil…
Browse files Browse the repository at this point in the history
…l works best on Windows, but interrupt devices seem to do fine on Linux
  • Loading branch information
cgutman committed Jul 27, 2014
1 parent 449733d commit e132ecc
Show file tree
Hide file tree
Showing 25 changed files with 463 additions and 150 deletions.
1 change: 1 addition & 0 deletions jni/Android.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include $(call all-subdir-makefiles)
10 changes: 10 additions & 0 deletions jni/Application.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Application.mk for USB/IP Server

# Our minimum version is Android 3.1
APP_PLATFORM := android-12

# Build for all ABIs
APP_ABI := all

# We want an optimized build
APP_OPTIM := release
12 changes: 12 additions & 0 deletions jni/errno/Android.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Android.mk for errno
MY_LOCAL_PATH := $(call my-dir)

include $(call all-subdir-makefiles)

LOCAL_PATH := $(MY_LOCAL_PATH)

include $(CLEAR_VARS)
LOCAL_MODULE := errno
LOCAL_SRC_FILES := errno_jni.c

include $(BUILD_SHARED_LIBRARY)
11 changes: 11 additions & 0 deletions jni/errno/errno_jni.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#include <stdlib.h>
#include <jni.h>

#include <errno.h>

JNIEXPORT jint JNICALL
Java_org_cgutman_usbip_errno_Errno_getErrno(
JNIEnv *env, jobject this)
{
return errno;
}
Binary file added libs/arm64-v8a/liberrno.so
Binary file not shown.
Binary file added libs/armeabi-v7a/liberrno.so
Binary file not shown.
Binary file added libs/armeabi/liberrno.so
Binary file not shown.
Binary file added libs/mips/liberrno.so
Binary file not shown.
Binary file added libs/mips64/liberrno.so
Binary file not shown.
Binary file added libs/x86/liberrno.so
Binary file not shown.
Binary file added libs/x86_64/liberrno.so
Binary file not shown.
12 changes: 12 additions & 0 deletions src/org/cgutman/usbip/errno/Errno.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.cgutman.usbip.errno;

public class Errno {
static {
System.loadLibrary("errno");
}

// This is a really nasty hack to try to grab the error
// from a USB API request. It may return an undefined result
// if say the GC runs before this gets called.
public static native int getErrno();
}
31 changes: 19 additions & 12 deletions src/org/cgutman/usbip/server/UsbIpServer.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package org.cgutman.usbip.server;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Map;
Expand All @@ -15,6 +13,7 @@
import org.cgutman.usbip.server.protocol.cli.ImportDeviceRequest;
import org.cgutman.usbip.server.protocol.dev.UsbIpDevicePacket;
import org.cgutman.usbip.server.protocol.dev.UsbIpSubmitUrb;
import org.cgutman.usbip.server.protocol.dev.UsbIpUnlinkUrb;

public class UsbIpServer {
public static final int PORT = 3240;
Expand All @@ -25,14 +24,19 @@ public class UsbIpServer {
private ConcurrentHashMap<Socket, Thread> connections = new ConcurrentHashMap<Socket, Thread>();

// Returns true if a device is now attached
private boolean handleRequest(InputStream in, OutputStream out) throws IOException {
CommonPacket inMsg = CommonPacket.read(in);
private boolean handleRequest(Socket s) throws IOException {
CommonPacket inMsg = CommonPacket.read(s.getInputStream());
CommonPacket outMsg;

if (inMsg == null) {
s.close();
return false;
}

boolean res = false;
System.out.printf("In code: 0x%x\n", inMsg.code);
if (inMsg.code == ProtoDefs.OP_REQ_DEVLIST) {
DevListReply dlReply = new DevListReply();
DevListReply dlReply = new DevListReply(inMsg.version);
dlReply.devInfoList = handler.getDevices();
if (dlReply.devInfoList == null) {
dlReply.status = ProtoDefs.ST_NA;
Expand All @@ -41,9 +45,9 @@ private boolean handleRequest(InputStream in, OutputStream out) throws IOExcepti
}
else if (inMsg.code == ProtoDefs.OP_REQ_IMPORT) {
ImportDeviceRequest imReq = (ImportDeviceRequest)inMsg;
ImportDeviceReply imReply = new ImportDeviceReply();
ImportDeviceReply imReply = new ImportDeviceReply(inMsg.version);

res = handler.attachToDevice(imReq.busid);
res = handler.attachToDevice(s, imReq.busid);
if (res) {
imReply.devInfo = handler.getDeviceByBusId(imReq.busid);
if (imReply.devInfo == null) {
Expand All @@ -64,7 +68,7 @@ else if (inMsg.code == ProtoDefs.OP_REQ_IMPORT) {
}

System.out.printf("Out code: 0x%x\n", outMsg.code);
out.write(outMsg.serialize());
s.getOutputStream().write(outMsg.serialize());
return res;
}

Expand All @@ -74,6 +78,9 @@ private boolean handleDevRequest(Socket s) throws IOException {
if (inMsg.command == UsbIpDevicePacket.USBIP_CMD_SUBMIT) {
handler.submitUrbRequest(s, (UsbIpSubmitUrb) inMsg);
}
else if (inMsg.command == UsbIpDevicePacket.USBIP_CMD_UNLINK) {
handler.abortUrbRequest(s, (UsbIpUnlinkUrb) inMsg);
}
else {
return false;
}
Expand All @@ -100,19 +107,19 @@ private void handleClient(final Socket s) {
@Override
public void run() {
try {
// Disable Nagle
s.setTcpNoDelay(true);
s.setKeepAlive(true);

InputStream in = s.getInputStream();
OutputStream out = s.getOutputStream();
while (!isInterrupted()) {
if (handleRequest(in, out)) {
if (handleRequest(s)) {
while (handleDevRequest(s));
}
}
} catch (IOException e) {
System.out.println("Client disconnected");
} finally {
handler.cleanupSocket(s);

try {
s.close();
} catch (IOException e) {}
Expand Down
8 changes: 6 additions & 2 deletions src/org/cgutman/usbip/server/UsbRequestHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,17 @@
import java.util.List;

import org.cgutman.usbip.server.protocol.dev.UsbIpSubmitUrb;
import org.cgutman.usbip.server.protocol.dev.UsbIpUnlinkUrb;

public interface UsbRequestHandler {
public List<UsbDeviceInfo> getDevices();
public UsbDeviceInfo getDeviceByBusId(String busId);

public boolean attachToDevice(String busId);
public void detachFromDevice(String busId);
public boolean attachToDevice(Socket s, String busId);
public void detachFromDevice(Socket s, String busId);

public void submitUrbRequest(Socket s, UsbIpSubmitUrb msg);
public void abortUrbRequest(Socket s, UsbIpUnlinkUrb msg);

public void cleanupSocket(Socket s);
}
2 changes: 1 addition & 1 deletion src/org/cgutman/usbip/server/protocol/ProtoDefs.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package org.cgutman.usbip.server.protocol;

public class ProtoDefs {
public static final short USBIP_VERSION = 0x0106;
/* public static final short USBIP_VERSION = 0x0111; */

public static final short OP_REQUEST = (short) (0x80 << 8);
public static final short OP_REPLY = (0x00 << 8);
Expand Down
10 changes: 5 additions & 5 deletions src/org/cgutman/usbip/server/protocol/cli/CommonPacket.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@ public CommonPacket(short version, short code, int status) {
public static CommonPacket read(InputStream in) throws IOException {
ByteBuffer bb = ByteBuffer.allocate(8);
StreamUtils.readAll(in, bb.array());

short version = bb.getShort();
if (version != ProtoDefs.USBIP_VERSION) {
throw new IOException("Unsupported protocol version: "+version);
}
// We should check the version here, but it seems they like to
// increment it without actually changing the protocol, so I'm
// not going to.
bb.getShort();

CommonPacket pkt;
short code = bb.getShort();
Expand Down
4 changes: 2 additions & 2 deletions src/org/cgutman/usbip/server/protocol/cli/DevListReply.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ public DevListReply(byte[] header) {
super(header);
}

public DevListReply() {
super(ProtoDefs.USBIP_VERSION, ProtoDefs.OP_REP_DEVLIST, ProtoDefs.ST_OK);
public DevListReply(short version) {
super(version, ProtoDefs.OP_REP_DEVLIST, ProtoDefs.ST_OK);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ public ImportDeviceReply(byte[] header) {
super(header);
}

public ImportDeviceReply() {
super(ProtoDefs.USBIP_VERSION, ProtoDefs.OP_REP_IMPORT, ProtoDefs.ST_OK);
public ImportDeviceReply(short version) {
super(version, ProtoDefs.OP_REP_IMPORT, ProtoDefs.ST_OK);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ public abstract class UsbIpDevicePacket {
public static final int USBIP_DIR_IN = 1;

public static final int USBIP_STATUS_ENDPOINT_HALTED = -32;
public static final int USBIP_STATUS_URB_ABORTED = -54;
public static final int USBIP_STATUS_DATA_OVERRUN = -75;
public static final int USBIP_STATUS_URB_TIMED_OUT = -110;
public static final int USBIP_STATUS_SHORT_TRANSFER = -121;

public static final int USBIP_SHORT_XFER_OKAY = 0x01;


public static final int USBIP_HEADER_SIZE = 48;

public int command;
Expand Down Expand Up @@ -58,6 +58,8 @@ public static UsbIpDevicePacket read(InputStream in) throws IOException {
{
case USBIP_CMD_SUBMIT:
return UsbIpSubmitUrb.read(bb.array(), in);
case USBIP_CMD_UNLINK:
return UsbIpUnlinkUrb.read(bb.array(), in);
default:
System.err.println("Unknown command: "+command);
return null;
Expand Down
48 changes: 48 additions & 0 deletions src/org/cgutman/usbip/server/protocol/dev/UsbIpUnlinkUrb.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package org.cgutman.usbip.server.protocol.dev;

import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

import org.cgutman.usbip.utils.StreamUtils;

public class UsbIpUnlinkUrb extends UsbIpDevicePacket {
public int seqNumToUnlink;

public static final int WIRE_SIZE = 4;

public UsbIpUnlinkUrb(byte[] header) {
super(header);
}

public static UsbIpUnlinkUrb read(byte[] header, InputStream in) throws IOException {
UsbIpUnlinkUrb msg = new UsbIpUnlinkUrb(header);

byte[] continuationHeader = new byte[WIRE_SIZE];
StreamUtils.readAll(in, continuationHeader);

ByteBuffer bb = ByteBuffer.wrap(continuationHeader).order(ByteOrder.BIG_ENDIAN);
msg.seqNumToUnlink = bb.getInt();

// Finish reading the remaining bytes of the header as padding
for (int i = 0; i < UsbIpDevicePacket.USBIP_HEADER_SIZE - (header.length + bb.position()); i++) {
in.read();
}

return msg;
}

@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(super.toString());
sb.append(String.format("Sequence number to unlink: %d\n", seqNumToUnlink));
return sb.toString();
}

@Override
protected byte[] serializeInternal() {
throw new UnsupportedOperationException("Serializing not supported");
}
}
28 changes: 28 additions & 0 deletions src/org/cgutman/usbip/server/protocol/dev/UsbIpUnlinkUrbReply.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package org.cgutman.usbip.server.protocol.dev;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;

public class UsbIpUnlinkUrbReply extends UsbIpDevicePacket {
public int status;

public UsbIpUnlinkUrbReply(int seqNum, int devId, int dir, int ep) {
super(UsbIpDevicePacket.USBIP_RET_UNLINK, seqNum, devId, dir, ep);
}

protected byte[] serializeInternal() {
ByteBuffer bb = ByteBuffer.allocate(UsbIpDevicePacket.USBIP_HEADER_SIZE - 20).order(ByteOrder.BIG_ENDIAN);

bb.putInt(status);

return bb.array();
}

@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(super.toString());
sb.append(String.format("Status: 0x%x\n", status));
return sb.toString();
}
}
Loading

0 comments on commit e132ecc

Please sign in to comment.