• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 // #undef NDEBUG
17 
18 #include "guest/commands/usbforward/usb_server.h"
19 
20 #include <string>
21 #include <vector>
22 #include <strings.h>
23 #include <log/log.h>
24 #include <libusb/libusb.h>
25 #include "common/libs/fs/shared_select.h"
26 #include "common/libs/usbforward/protocol.h"
27 #include "guest/commands/usbforward/transport_request.h"
28 
29 namespace usb_forward {
30 namespace {
31 // USBServer exports device kExportedVendorID:kExportedProductID to the server.
32 // We will not support exporting multiple USB devices as there's no practical
33 // need for this.
34 constexpr uint16_t kExportedVendorID = 0x18d1;
35 constexpr uint16_t kExportedProductID = 0x4ee7;
36 
37 // Use default BUS and DEVICE IDs so that it's easier to attach over USB/IP.
38 constexpr uint8_t kDefaultBusID = 1;
39 constexpr uint8_t kDefaultDevID = 1;
40 
GetDevice()41 std::shared_ptr<libusb_device_handle> GetDevice() {
42   std::shared_ptr<libusb_device_handle> res(
43       libusb_open_device_with_vid_pid(nullptr, kExportedVendorID,
44                                       kExportedProductID),
45       [](libusb_device_handle* h) {
46         // Apparently, deleter is called even on an uninitialized shared_ptr.
47         if (h != nullptr) {
48           libusb_release_interface(h, 0);
49           libusb_close(h);
50         }
51       });
52 
53   if (res) libusb_claim_interface(res.get(), 0);
54 
55   return res;
56 }
57 
58 }  // anonymous namespace
59 
GetDeviceInfo(DeviceInfo * info,std::vector<InterfaceInfo> * ifaces)60 bool USBServer::GetDeviceInfo(
61     DeviceInfo* info, std::vector<InterfaceInfo>* ifaces) {
62   if (!handle_) return false;
63 
64   // This function does not modify the reference count of the returned device,
65   // so do not feel compelled to unreference it when you are done.
66   libusb_device* dev = libusb_get_device(handle_.get());
67 
68   libusb_device_descriptor desc;
69   libusb_config_descriptor* conf;
70   memset(info, 0, sizeof(*info));
71 
72   int res = libusb_get_device_descriptor(dev, &desc);
73   if (res < 0) {
74     // This shouldn't really happen.
75     ALOGE("libusb_get_device_descriptor failed %d", res);
76     return false;
77   }
78 
79   res = libusb_get_active_config_descriptor(dev, &conf);
80   if (res < 0) {
81     // This shouldn't really happen.
82     ALOGE("libusb_get_active_config_descriptor failed %d", res);
83     libusb_free_config_descriptor(conf);
84     return false;
85   }
86 
87   info->vendor_id = desc.idVendor;
88   info->product_id = desc.idProduct;
89   info->dev_version = desc.bcdDevice;
90   info->dev_class = desc.bDeviceClass;
91   info->dev_subclass = desc.bDeviceSubClass;
92   info->dev_protocol = desc.bDeviceProtocol;
93   info->speed = libusb_get_device_speed(dev);
94   info->num_configurations = desc.bNumConfigurations;
95   info->num_interfaces = conf->bNumInterfaces;
96   info->cur_configuration = conf->bConfigurationValue;
97   info->bus_id = kDefaultBusID;
98   info->dev_id = kDefaultDevID;
99 
100   if (ifaces != nullptr) {
101     for (int ifidx = 0; ifidx < conf->bNumInterfaces; ++ifidx) {
102       const libusb_interface& iface = conf->interface[ifidx];
103       for (int altidx = 0; altidx < iface.num_altsetting; ++altidx) {
104         const libusb_interface_descriptor& alt = iface.altsetting[altidx];
105         ifaces->push_back(InterfaceInfo{alt.bInterfaceClass,
106                                         alt.bInterfaceSubClass,
107                                         alt.bInterfaceProtocol, 0});
108       }
109     }
110   }
111   libusb_free_config_descriptor(conf);
112   return true;
113 }
114 
USBServer(const cvd::SharedFD & fd)115 USBServer::USBServer(const cvd::SharedFD& fd)
116     : fd_{fd},
117       device_event_fd_{cvd::SharedFD::Event(0, 0)},
118       thread_event_fd_{cvd::SharedFD::Event(0, 0)} {}
119 
HandleDeviceList(uint32_t tag)120 void USBServer::HandleDeviceList(uint32_t tag) {
121   // Iterate all devices and send structure for every found device.
122   // Write header: number of devices.
123   DeviceInfo info;
124   std::vector<InterfaceInfo> ifaces;
125   bool found = GetDeviceInfo(&info, &ifaces);
126 
127   cvd::LockGuard<cvd::Mutex> lock(write_mutex_);
128   ResponseHeader rsp{StatusSuccess, tag};
129   fd_->Write(&rsp, sizeof(rsp));
130   if (found) {
131     uint32_t cnt = 1;
132     fd_->Write(&cnt, sizeof(cnt));
133     fd_->Write(&info, sizeof(info));
134     fd_->Write(ifaces.data(), ifaces.size() * sizeof(InterfaceInfo));
135   } else {
136     // No devices.
137     uint32_t cnt = 0;
138     fd_->Write(&cnt, sizeof(cnt));
139   }
140 }
141 
HandleAttach(uint32_t tag)142 void USBServer::HandleAttach(uint32_t tag) {
143   // We read the request, but it no longer plays any significant role here.
144   AttachRequest req;
145   if (fd_->Read(&req, sizeof(req)) != sizeof(req)) return;
146 
147   cvd::LockGuard<cvd::Mutex> lock(write_mutex_);
148   ResponseHeader rsp{handle_ ? StatusSuccess : StatusFailure, tag};
149   fd_->Write(&rsp, sizeof(rsp));
150 }
151 
HandleHeartbeat(uint32_t tag)152 void USBServer::HandleHeartbeat(uint32_t tag) {
153   cvd::LockGuard<cvd::Mutex> lock(write_mutex_);
154   ResponseHeader rsp{handle_ ? StatusSuccess : StatusFailure, tag};
155   fd_->Write(&rsp, sizeof(rsp));
156 }
157 
HandleControlTransfer(uint32_t tag)158 void USBServer::HandleControlTransfer(uint32_t tag) {
159   ControlTransfer req;
160   // If disconnected prematurely, don't send response.
161   if (fd_->Read(&req, sizeof(req)) != sizeof(req)) return;
162 
163   // Technically speaking this isn't endpoint, but names, masks, values and
164   // meaning here is exactly same.
165   bool is_data_in =
166       ((req.type & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_IN);
167 
168   std::unique_ptr<TransportRequest> treq(new TransportRequest(
169       handle_,
170       [this, is_data_in, tag](bool is_success, const uint8_t* data,
171                               int32_t length) {
172         OnTransferComplete(tag, is_data_in, is_success, data, length);
173       },
174       req));
175 
176   if (!is_data_in && req.length) {
177     // If disconnected prematurely, don't send response.
178     int32_t got = 0;
179     while (got < req.length) {
180       auto read = fd_->Read(&treq->Buffer()[got], req.length - got);
181       if (fd_->GetErrno() != 0) {
182         ALOGE("Failed to read from client: %s", fd_->StrError());
183         return;
184       } else if (read == 0) {
185         ALOGE("Failed to read from client: short read");
186         return;
187       }
188       got += read;
189     }
190   }
191 
192   // At this point we store transport request internally until it completes.
193   TransportRequest* treq_ptr = treq.get();
194   {
195     cvd::LockGuard<cvd::Mutex> lock(requests_mutex_);
196     requests_in_flight_[tag] = std::move(treq);
197   }
198 
199   if (!treq_ptr->Submit()) {
200     OnTransferComplete(tag, is_data_in, false, nullptr, 0);
201   }
202 }
203 
HandleDataTransfer(uint32_t tag)204 void USBServer::HandleDataTransfer(uint32_t tag) {
205   DataTransfer req;
206   // If disconnected prematurely, don't send response.
207   if (fd_->Read(&req, sizeof(req)) != sizeof(req)) return;
208 
209   bool is_data_in = !req.is_host_to_device;
210 
211   std::unique_ptr<TransportRequest> treq(new TransportRequest(
212       handle_,
213       [this, is_data_in, tag](bool is_success, const uint8_t* data,
214                               int32_t length) {
215         OnTransferComplete(tag, is_data_in, is_success, data, length);
216       },
217       req));
218 
219   if (!is_data_in && req.length) {
220     // If disconnected prematurely, don't send response.
221     int32_t got = 0;
222     while (got < req.length) {
223       auto read = fd_->Read(&treq->Buffer()[got], req.length - got);
224       if (fd_->GetErrno() != 0) {
225         ALOGE("Failed to read from client: %s", fd_->StrError());
226         return;
227       } else if (read == 0) {
228         ALOGE("Failed to read from client: short read");
229         return;
230       }
231       got += read;
232     }
233   }
234 
235   // At this point we store transport request internally until it completes.
236   TransportRequest* treq_ptr = treq.get();
237   {
238     cvd::LockGuard<cvd::Mutex> lock(requests_mutex_);
239     requests_in_flight_[tag] = std::move(treq);
240   }
241 
242   if (!treq_ptr->Submit()) {
243     OnTransferComplete(tag, is_data_in, false, nullptr, 0);
244   }
245 }
246 
OnTransferComplete(uint32_t tag,bool is_data_in,bool is_success,const uint8_t * buffer,int32_t actual_length)247 void USBServer::OnTransferComplete(uint32_t tag, bool is_data_in,
248                                    bool is_success, const uint8_t* buffer,
249                                    int32_t actual_length) {
250   ResponseHeader rsp{is_success ? StatusSuccess : StatusFailure, tag};
251 
252   cvd::LockGuard<cvd::Mutex> lock(write_mutex_);
253   fd_->Write(&rsp, sizeof(rsp));
254   if (is_success && is_data_in) {
255     fd_->Write(&actual_length, sizeof(actual_length));
256     if (actual_length > 0) {
257       // NOTE: don't use buffer_ here directly, as libusb uses first few bytes
258       // to store control data there.
259       int32_t sent = 0;
260       while (sent < actual_length) {
261         int packet_size = fd_->Write(&buffer[sent], actual_length - sent);
262         sent += packet_size;
263         ALOGV("Sending response, %d / %d bytes sent", sent, actual_length);
264         if (fd_->GetErrno() != 0) {
265           ALOGE("Send failed: %s", fd_->StrError());
266           return;
267         }
268       }
269     }
270   }
271 
272   {
273     cvd::LockGuard<cvd::Mutex> lock(requests_mutex_);
274     requests_in_flight_.erase(tag);
275   }
276 }
277 
HandleDeviceEvent(libusb_context *,libusb_device *,libusb_hotplug_event event,void * self_raw)278 int USBServer::HandleDeviceEvent(libusb_context*, libusb_device*,
279                                  libusb_hotplug_event event, void* self_raw) {
280   auto self = reinterpret_cast<USBServer*>(self_raw);
281   int64_t dummy = 1;
282   self->device_event_fd_->Write(&dummy, sizeof(dummy));
283   return 0;
284 }
285 
ProcessLibUSBRequests(void * self_raw)286 void* USBServer::ProcessLibUSBRequests(void* self_raw) {
287   USBServer* self = reinterpret_cast<USBServer*>(self_raw);
288   ALOGI("Starting hotplug thread.");
289 
290   cvd::SharedFDSet rset;
291   while (true) {
292     // Do not wait if there's no event.
293     timeval select_timeout{0, 0};
294     rset.Zero();
295     rset.Set(self->thread_event_fd_);
296     int ret = cvd::Select(&rset, nullptr, nullptr, &select_timeout);
297     if (ret > 0) break;
298 
299     timeval libusb_timeout{1, 0};
300     libusb_handle_events_timeout_completed(nullptr, &libusb_timeout, nullptr);
301   }
302 
303   int64_t dummy;
304   self->thread_event_fd_->Read(&dummy, sizeof(dummy));
305   ALOGI("Shutting down hotplug thread.");
306   return nullptr;
307 }
308 
InitLibUSB()309 void USBServer::InitLibUSB() {
310   if (libusb_init(nullptr) != 0) return;
311   libusb_hotplug_register_callback(
312       nullptr,
313       libusb_hotplug_event(LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT),
314       libusb_hotplug_flag(0), kExportedVendorID, kExportedProductID,
315       LIBUSB_HOTPLUG_MATCH_ANY, &USBServer::HandleDeviceEvent, this,
316       &hotplug_handle_);
317   handle_ = GetDevice();
318   libusb_thread_.reset(new cvd::ScopedThread(&ProcessLibUSBRequests, this));
319 }
320 
ExitLibUSB()321 void USBServer::ExitLibUSB() {
322   if (!libusb_thread_) return;
323   libusb_hotplug_deregister_callback(nullptr, hotplug_handle_);
324   int64_t dummy = 1;
325   thread_event_fd_->Write(&dummy, sizeof(dummy));
326   libusb_thread_.reset();
327   handle_.reset();
328   libusb_exit(nullptr);
329 }
330 
Serve()331 void USBServer::Serve() {
332   cvd::SharedFDSet rset;
333   while (true) {
334     timeval retry_timeout{1, 0};
335     timeval* select_timeout = nullptr;
336     if (!handle_) {
337       select_timeout = &retry_timeout;
338     }
339 
340     rset.Zero();
341     rset.Set(fd_);
342     rset.Set(device_event_fd_);
343     int ret = cvd::Select(&rset, nullptr, nullptr, select_timeout);
344 
345     // device_event_fd_ is reset each time libusb notices device has re-appeared
346     // or is gone. In both cases, the existing handle is no longer valid.
347     if (rset.IsSet(device_event_fd_)) {
348       int64_t dummy;
349       device_event_fd_->Read(&dummy, sizeof(dummy));
350       handle_.reset();
351     }
352 
353     if (!handle_) {
354       ExitLibUSB();
355       InitLibUSB();
356       if (handle_) {
357         ALOGI("Device present.");
358       }
359     }
360 
361     if (ret < 0) continue;
362 
363     if (rset.IsSet(fd_)) {
364       RequestHeader req;
365       if (fd_->Read(&req, sizeof(req)) != sizeof(req)) {
366         // There's nobody on the other side.
367         sleep(3);
368         continue;
369       }
370 
371       switch (req.command) {
372         case CmdDeviceList:
373           ALOGV("Processing DeviceList command, tag=%d", req.tag);
374           HandleDeviceList(req.tag);
375           break;
376 
377         case CmdAttach:
378           ALOGV("Processing Attach command, tag=%d", req.tag);
379           HandleAttach(req.tag);
380           break;
381 
382         case CmdControlTransfer:
383           ALOGV("Processing ControlTransfer command, tag=%d", req.tag);
384           HandleControlTransfer(req.tag);
385           break;
386 
387         case CmdDataTransfer:
388           ALOGV("Processing DataTransfer command, tag=%d", req.tag);
389           HandleDataTransfer(req.tag);
390           break;
391 
392         case CmdHeartbeat:
393           ALOGV("Processing Heartbeat command, tag=%d", req.tag);
394           HandleHeartbeat(req.tag);
395           break;
396 
397         default:
398           ALOGE("Discarding unknown command %08x, tag=%d", req.command,
399                 req.tag);
400       }
401     }
402   }
403 }
404 
405 }  // namespace usb_forward
406