12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817 |
- /*
- * libusbmuxd.c
- *
- * Copyright (C) 2009-2019 Nikias Bassen <nikias@gmx.li>
- * Copyright (C) 2009-2014 Martin Szulecki <m.szulecki@libimobiledevice.org>
- * Copyright (C) 2009 Paul Sladen <libiphone@paul.sladen.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
- #ifdef HAVE_CONFIG_H
- #include <config.h>
- #endif
- #include <stdint.h>
- #include <stdlib.h>
- #include <errno.h>
- #include <stdio.h>
- #include <string.h>
- #ifdef LIBUSBMUXD_STATIC
- #define USBMUXD_API
- #elif defined(_WIN32)
- #define USBMUXD_API __declspec( dllexport )
- #else
- #if __GNUC__ >= 4
- #define USBMUXD_API __attribute__((visibility("default")))
- #else
- #define USBMUXD_API
- #endif
- #endif
- #ifndef EPROTO
- #define EPROTO 134
- #endif
- #ifndef EBADMSG
- #define EBADMSG 104
- #endif
- #ifndef ECONNREFUSED
- #define ECONNREFUSED 107
- #endif
- #ifdef _WIN32
- #include <winsock2.h>
- #include <windows.h>
- #define sleep(x) Sleep(x*1000)
- #else
- #include <unistd.h>
- #include <signal.h>
- #include <sys/socket.h>
- #include <arpa/inet.h>
- #if defined(HAVE_PROGRAM_INVOCATION_SHORT_NAME) && !defined(HAVE_PROGRAM_INVOCATION_SHORT_NAME_ERRNO_H)
- extern char *program_invocation_short_name;
- #endif
- #ifdef __APPLE__
- extern int _NSGetExecutablePath(char* buf, uint32_t* bufsize);
- #include <sys/stat.h>
- #endif
- #endif
- #ifdef HAVE_INOTIFY
- #include <sys/inotify.h>
- #include <sys/select.h>
- #include <pthread.h>
- #define EVENT_SIZE (sizeof (struct inotify_event))
- #define EVENT_BUF_LEN (1024 * (EVENT_SIZE + 16))
- #define USBMUXD_DIRNAME "/var/run"
- #define USBMUXD_SOCKET_NAME "usbmuxd"
- static int use_inotify = 1;
- #endif /* HAVE_INOTIFY */
- #ifndef HAVE_STPNCPY
- static char* stpncpy(char *dst, const char *src, size_t len)
- {
- size_t n = strlen(src);
- if (n > len)
- n = len;
- return strncpy(dst, src, len) + n;
- }
- #endif
- #ifdef _MSC_VER
- #define strcasecmp _stricmp
- #endif
- #include <plist/plist.h>
- #define PLIST_LIBUSBMUX_VERSION 3
- static char *bundle_id = NULL;
- static char *prog_name = NULL;
- // usbmuxd public interface
- #include "usbmuxd.h"
- // usbmuxd protocol
- #include "usbmuxd-proto.h"
- // socket utility functions
- #include <libimobiledevice-glue/socket.h>
- // misc utility functions
- #include <libimobiledevice-glue/collection.h>
- // threads
- #include <libimobiledevice-glue/thread.h>
- static int libusbmuxd_debug = 0;
- #ifndef PACKAGE
- #define PACKAGE "libusbmuxd"
- #endif
- #ifndef PACKAGE_NAME
- #define PACKAGE_NAME PACKAGE
- #endif
- #define LIBUSBMUXD_DEBUG(level, format, ...) if (level <= libusbmuxd_debug) fprintf(stderr, ("[" PACKAGE "] " format), __VA_ARGS__); fflush(stderr);
- #define LIBUSBMUXD_ERROR(format, ...) LIBUSBMUXD_DEBUG(0, format, __VA_ARGS__)
- static struct collection devices;
- static THREAD_T devmon = THREAD_T_NULL;
- static int listenfd = -1;
- static int running = 0;
- static int cancelling = 0;
- static volatile int use_tag = 0;
- static volatile int proto_version = 1;
- static volatile int try_list_devices = 1;
- struct usbmuxd_subscription_context {
- usbmuxd_event_cb_t callback;
- void *user_data;
- };
- static struct usbmuxd_subscription_context *event_ctx = NULL;
- static struct collection listeners;
- thread_once_t listener_init_once = THREAD_ONCE_INIT;
- mutex_t listener_mutex;
- /**
- * Finds a device info record by its handle.
- * if the record is not found, NULL is returned.
- */
- static usbmuxd_device_info_t *devices_find(uint32_t handle)
- {
- FOREACH(usbmuxd_device_info_t *dev, &devices) {
- if (dev && dev->handle == handle) {
- return dev;
- }
- } ENDFOREACH
- return NULL;
- }
- /**
- * Creates a socket connection to usbmuxd.
- * For Mac/Linux it is a unix domain socket,
- * for Windows it is a tcp socket.
- */
- static int connect_usbmuxd_socket()
- {
- int res = -1;
- char *usbmuxd_socket_addr = getenv("USBMUXD_SOCKET_ADDRESS");
- if (usbmuxd_socket_addr) {
- if (strncmp(usbmuxd_socket_addr, "UNIX:", 5) == 0) {
- #if defined(_WIN32) || defined(__CYGWIN__)
- /* not supported, ignore */
- #else
- if (usbmuxd_socket_addr[5] != '\0') {
- res = socket_connect_unix(usbmuxd_socket_addr+5);
- if (res < 0) {
- res = -errno;
- }
- return res;
- }
- #endif
- } else {
- uint16_t port = 0;
- char *p = strrchr(usbmuxd_socket_addr, ':');
- if (p) {
- char *endp = NULL;
- long l_port = strtol(p+1, &endp, 10);
- if (endp && *endp == '\0') {
- if (l_port > 0 && l_port < 65536) {
- port = (uint16_t)l_port;
- }
- }
- }
- if (p && port > 0) {
- char *connect_addr = NULL;
- if (usbmuxd_socket_addr[0] == '[') {
- connect_addr = strdup(usbmuxd_socket_addr+1);
- connect_addr[p - usbmuxd_socket_addr - 1] = '\0';
- p = strrchr(connect_addr, ']');
- if (p) {
- *p = '\0';
- }
- } else {
- connect_addr = strdup(usbmuxd_socket_addr);
- connect_addr[p - usbmuxd_socket_addr] = '\0';
- }
- if (connect_addr && *connect_addr != '\0') {
- res = socket_connect(connect_addr, port);
- #ifdef HAVE_INOTIFY
- use_inotify = 0;
- #endif
- free(connect_addr);
- if (res < 0) {
- res = -errno;
- }
- return res;
- }
- free(connect_addr);
- }
- }
- }
- #if defined(_WIN32) || defined(__CYGWIN__)
- res = socket_connect("127.0.0.1", USBMUXD_SOCKET_PORT);
- #else
- res = socket_connect_unix(USBMUXD_SOCKET_FILE);
- #endif
- if (res < 0) {
- res = -errno;
- }
- return res;
- }
- static void sanitize_udid(usbmuxd_device_info_t *devinfo)
- {
- if (!devinfo)
- return;
- if (strlen(devinfo->udid) == 24) {
- memmove(&devinfo->udid[9], &devinfo->udid[8], 17);
- devinfo->udid[8] = '-';
- }
- if (strcasecmp(devinfo->udid, "ffffffffffffffffffffffffffffffffffffffff") == 0) {
- sprintf(devinfo->udid + 32, "%08x", devinfo->handle);
- }
- }
- static usbmuxd_device_info_t *device_info_from_plist(plist_t props)
- {
- usbmuxd_device_info_t* devinfo = NULL;
- plist_t n = NULL;
- uint64_t val = 0;
- char *strval = NULL;
- devinfo = (usbmuxd_device_info_t*)malloc(sizeof(usbmuxd_device_info_t));
- if (!devinfo)
- return NULL;
- memset(devinfo, 0, sizeof(usbmuxd_device_info_t));
- n = plist_dict_get_item(props, "DeviceID");
- if (n && plist_get_node_type(n) == PLIST_UINT) {
- plist_get_uint_val(n, &val);
- devinfo->handle = (uint32_t)val;
- }
- n = plist_dict_get_item(props, "ProductID");
- if (n && plist_get_node_type(n) == PLIST_UINT) {
- plist_get_uint_val(n, &val);
- devinfo->product_id = (uint32_t)val;
- }
- n = plist_dict_get_item(props, "SerialNumber");
- if (n && plist_get_node_type(n) == PLIST_STRING) {
- plist_get_string_val(n, &strval);
- if (strval) {
- char *t = stpncpy(devinfo->udid, strval, sizeof(devinfo->udid)-1);
- *t = '\0';
- sanitize_udid(devinfo);
- free(strval);
- }
- }
- n = plist_dict_get_item(props, "ConnectionType");
- if (n && plist_get_node_type(n) == PLIST_STRING) {
- plist_get_string_val(n, &strval);
- if (strval) {
- if (strcmp(strval, "USB") == 0) {
- devinfo->conn_type = CONNECTION_TYPE_USB;
- } else if (strcmp(strval, "Network") == 0) {
- devinfo->conn_type = CONNECTION_TYPE_NETWORK;
- n = plist_dict_get_item(props, "NetworkAddress");
- if (n && plist_get_node_type(n) == PLIST_DATA) {
- uint64_t addr_len = 0;
- const char *netaddr = plist_get_data_ptr(n, &addr_len);
- if (netaddr && addr_len > 0 && addr_len < sizeof(devinfo->conn_data)) {
- memcpy(devinfo->conn_data, netaddr, addr_len);
- }
- }
- } else {
- LIBUSBMUXD_ERROR("%s: Unexpected ConnectionType '%s'\n", __func__, strval);
- }
- free(strval);
- }
- }
- if (!devinfo->udid[0]) {
- LIBUSBMUXD_ERROR("%s: Failed to get SerialNumber (UDID)!\n", __func__);
- free(devinfo);
- return NULL;
- }
- if (!devinfo->conn_type) {
- LIBUSBMUXD_ERROR("%s: Failed to get ConnectionType!\n", __func__);
- free(devinfo);
- devinfo = NULL;
- } else if (devinfo->conn_type == CONNECTION_TYPE_NETWORK && !devinfo->conn_data[0]) {
- LIBUSBMUXD_ERROR("%s: Failed to get EscapedFullServiceName!\n", __func__);
- free(devinfo);
- devinfo = NULL;
- }
- return devinfo;
- }
- static usbmuxd_device_info_t *device_info_from_device_record(struct usbmuxd_device_record *dev)
- {
- if (!dev) {
- return NULL;
- }
- usbmuxd_device_info_t *devinfo = (usbmuxd_device_info_t*)malloc(sizeof(usbmuxd_device_info_t));
- if (!devinfo) {
- LIBUSBMUXD_ERROR("%s: Out of memory while allocating device info object\n", __func__);
- return NULL;
- }
- devinfo->handle = dev->device_id;
- devinfo->product_id = dev->product_id;
- char *t = stpncpy(devinfo->udid, dev->serial_number, sizeof(devinfo->udid)-2);
- *t = '\0';
- sanitize_udid(devinfo);
- return devinfo;
- }
- static int receive_packet(int sfd, struct usbmuxd_header *header, void **payload, int timeout)
- {
- int recv_len;
- struct usbmuxd_header hdr;
- char *payload_loc = NULL;
- header->length = 0;
- header->version = 0;
- header->message = 0;
- header->tag = 0;
- recv_len = socket_receive_timeout(sfd, &hdr, sizeof(hdr), 0, timeout);
- if (recv_len < 0) {
- if (!cancelling) {
- LIBUSBMUXD_DEBUG(1, "%s: Error receiving packet: %s\n", __func__, strerror(-recv_len));
- }
- return recv_len;
- }
- if ((size_t)recv_len < sizeof(hdr)) {
- LIBUSBMUXD_DEBUG(1, "%s: Received packet is too small, got %d bytes!\n", __func__, recv_len);
- return recv_len;
- }
- uint32_t payload_size = hdr.length - sizeof(hdr);
- if (payload_size > 0) {
- payload_loc = (char*)malloc(payload_size);
- uint32_t rsize = 0;
- do {
- int res = socket_receive_timeout(sfd, payload_loc + rsize, payload_size - rsize, 0, 5000);
- if (res < 0) {
- break;
- }
- rsize += res;
- } while (rsize < payload_size);
- if (rsize != payload_size) {
- LIBUSBMUXD_DEBUG(1, "%s: Error receiving payload of size %d (bytes received: %d)\n", __func__, payload_size, rsize);
- free(payload_loc);
- return -EBADMSG;
- }
- }
- if (hdr.message == MESSAGE_PLIST) {
- char *message = NULL;
- plist_t plist = NULL;
- plist_from_xml(payload_loc, payload_size, &plist);
- free(payload_loc);
- if (!plist) {
- LIBUSBMUXD_DEBUG(1, "%s: Error getting plist from payload!\n", __func__);
- return -EBADMSG;
- }
- plist_t node = plist_dict_get_item(plist, "MessageType");
- if (!node || plist_get_node_type(node) != PLIST_STRING) {
- *payload = plist;
- hdr.length = sizeof(hdr);
- memcpy(header, &hdr, sizeof(hdr));
- return hdr.length;
- }
- plist_get_string_val(node, &message);
- if (message) {
- uint64_t val = 0;
- if (strcmp(message, "Result") == 0) {
- /* result message */
- uint32_t dwval = 0;
- plist_t n = plist_dict_get_item(plist, "Number");
- plist_get_uint_val(n, &val);
- *payload = malloc(sizeof(uint32_t));
- dwval = val;
- memcpy(*payload, &dwval, sizeof(dwval));
- hdr.length = sizeof(hdr) + sizeof(dwval);
- hdr.message = MESSAGE_RESULT;
- } else if (strcmp(message, "Attached") == 0) {
- /* device add message */
- usbmuxd_device_info_t *devinfo = NULL;
- plist_t props = plist_dict_get_item(plist, "Properties");
- if (!props) {
- LIBUSBMUXD_DEBUG(1, "%s: Could not get properties for message '%s' from plist!\n", __func__, message);
- free(message);
- plist_free(plist);
- return -EBADMSG;
- }
- devinfo = device_info_from_plist(props);
- if (!devinfo) {
- LIBUSBMUXD_DEBUG(1, "%s: Could not create device info object from properties!\n", __func__);
- free(message);
- plist_free(plist);
- return -EBADMSG;
- }
- *payload = (void*)devinfo;
- hdr.length = sizeof(hdr) + sizeof(usbmuxd_device_info_t);
- hdr.message = MESSAGE_DEVICE_ADD;
- } else if (strcmp(message, "Detached") == 0) {
- /* device remove message */
- uint32_t dwval = 0;
- plist_t n = plist_dict_get_item(plist, "DeviceID");
- if (n) {
- plist_get_uint_val(n, &val);
- *payload = malloc(sizeof(uint32_t));
- dwval = val;
- memcpy(*payload, &dwval, sizeof(dwval));
- hdr.length = sizeof(hdr) + sizeof(dwval);
- hdr.message = MESSAGE_DEVICE_REMOVE;
- }
- } else if (strcmp(message, "Paired") == 0) {
- /* device pair message */
- uint32_t dwval = 0;
- plist_t n = plist_dict_get_item(plist, "DeviceID");
- if (n) {
- plist_get_uint_val(n, &val);
- *payload = malloc(sizeof(uint32_t));
- dwval = val;
- memcpy(*payload, &dwval, sizeof(dwval));
- hdr.length = sizeof(hdr) + sizeof(dwval);
- hdr.message = MESSAGE_DEVICE_PAIRED;
- }
- } else {
- char *xml = NULL;
- uint32_t len = 0;
- plist_to_xml(plist, &xml, &len);
- LIBUSBMUXD_DEBUG(1, "%s: Unexpected message '%s' in plist:\n%s\n", __func__, message, xml);
- free(xml);
- free(message);
- plist_free(plist);
- return -EBADMSG;
- }
- free(message);
- }
- plist_free(plist);
- } else if (hdr.message == MESSAGE_DEVICE_ADD) {
- usbmuxd_device_info_t *devinfo = device_info_from_device_record((struct usbmuxd_device_record*)payload_loc);
- free(payload_loc);
- *payload = devinfo;
- } else {
- *payload = payload_loc;
- }
- memcpy(header, &hdr, sizeof(hdr));
- return hdr.length;
- }
- /**
- * Retrieves the result code to a previously sent request.
- */
- static int usbmuxd_get_result(int sfd, uint32_t tag, uint32_t *result, void **result_plist)
- {
- struct usbmuxd_header hdr;
- int recv_len;
- uint32_t *res = NULL;
- if (!result) {
- return -EINVAL;
- }
- *result = -1;
- if (result_plist) {
- *result_plist = NULL;
- }
- recv_len = receive_packet(sfd, &hdr, (void**)&res, 5000);
- if (recv_len < 0 || (size_t)recv_len < sizeof(hdr)) {
- free(res);
- return (recv_len < 0 ? recv_len : -EPROTO);
- }
- if (hdr.message == MESSAGE_RESULT) {
- int ret = 0;
- if (hdr.tag != tag) {
- LIBUSBMUXD_DEBUG(1, "%s: WARNING: tag mismatch (%d != %d). Proceeding anyway.\n", __func__, hdr.tag, tag);
- }
- if (res) {
- memcpy(result, res, sizeof(uint32_t));
- ret = 1;
- }
- free(res);
- return ret;
- }
- if (hdr.message == MESSAGE_PLIST) {
- if (!result_plist) {
- LIBUSBMUXD_DEBUG(1, "%s: MESSAGE_PLIST result but result_plist pointer is NULL!\n", __func__);
- return -1;
- }
- *result_plist = (plist_t)res;
- *result = RESULT_OK;
- return 1;
- }
- LIBUSBMUXD_DEBUG(1, "%s: Unexpected message of type %d received!\n", __func__, hdr.message);
- free(res);
- return -EPROTO;
- }
- static int send_packet(int sfd, uint32_t message, uint32_t tag, void *payload, uint32_t payload_size)
- {
- struct usbmuxd_header header;
- header.length = sizeof(struct usbmuxd_header);
- header.version = proto_version;
- header.message = message;
- header.tag = tag;
- if (payload && (payload_size > 0)) {
- header.length += payload_size;
- }
- int sent = socket_send(sfd, &header, sizeof(header));
- if (sent != sizeof(header)) {
- LIBUSBMUXD_DEBUG(1, "%s: ERROR: could not send packet header\n", __func__);
- return -1;
- }
- if (payload && (payload_size > 0)) {
- uint32_t ssize = 0;
- do {
- int res = socket_send(sfd, (char*)payload + ssize, payload_size - ssize);
- if (res < 0) {
- break;
- }
- ssize += res;
- } while (ssize < payload_size);
- sent += ssize;
- }
- if (sent != (int)header.length) {
- LIBUSBMUXD_DEBUG(1, "%s: ERROR: could not send whole packet (sent %d of %d)\n", __func__, sent, header.length);
- socket_close(sfd);
- return -1;
- }
- return sent;
- }
- static int send_plist_packet(int sfd, uint32_t tag, plist_t message)
- {
- int res;
- char *payload = NULL;
- uint32_t payload_size = 0;
- plist_to_xml(message, &payload, &payload_size);
- res = send_packet(sfd, MESSAGE_PLIST, tag, payload, payload_size);
- free(payload);
- return res;
- }
- static void get_bundle_id()
- {
- #if defined (__APPLE__)
- char CONTENTS_INFO_PLIST[] = "Contents/Info.plist";
- char* execpath = malloc(1024);
- uint32_t size = 1024;
- if (_NSGetExecutablePath(execpath, &size) != 0) {
- free(execpath);
- return;
- }
- // strip off executable name
- char *p = execpath + strlen(execpath) - 1;
- while (p > execpath && *p != '/') p--;
- if (*p == '/') *p = '\0';
- // now walk back trying to find "/Contents/MacOS", and strip it off
- int macos_found = 0;
- while (p > execpath) {
- p--;
- if (*p != '/') continue;
- if (strcmp(p, "/.") == 0) {
- *p = '\0';
- } else if (!macos_found && strcmp(p, "/MacOS") == 0) {
- *p = '\0';
- macos_found++;
- } else if (macos_found && strcmp(p, "/Contents") == 0) {
- *p = '\0';
- break;
- } else {
- break;
- }
- }
- // now just append "/Contents/Info.plist"
- size_t len = strlen(execpath) + sizeof(CONTENTS_INFO_PLIST) + 1;
- char *infopl = malloc(len);
- snprintf(infopl, len, "%s/%s", execpath, CONTENTS_INFO_PLIST);
- free(execpath);
- struct stat fst;
- fst.st_size = 0;
- if (stat(infopl, &fst) != 0) {
- free(infopl);
- return;
- }
- size_t fsize = fst.st_size;
- if (fsize < 8) {
- free(infopl);
- return;
- }
- FILE *f = fopen(infopl, "r");
- free(infopl);
- if (!f)
- return;
- char *buf = malloc(fsize);
- if (!buf)
- return;
- if (fread(buf, 1, fsize, f) == fsize) {
- plist_t pl = NULL;
- if (memcmp(buf, "bplist00", 8) == 0) {
- plist_from_bin(buf, fst.st_size, &pl);
- } else {
- plist_from_xml(buf, fst.st_size, &pl);
- }
- if (pl) {
- plist_t bid = plist_dict_get_item(pl, "CFBundleIdentifier");
- if (plist_get_node_type(bid) == PLIST_STRING) {
- plist_get_string_val(bid, &bundle_id);
- }
- plist_free(pl);
- }
- }
- free(buf);
- fclose(f);
- #endif
- }
- static void get_prog_name()
- {
- #if defined(__APPLE__) || defined(__FreeBSD__)
- const char *pname = getprogname();
- if (pname) {
- prog_name = strdup(pname);
- }
- #elif defined (_WIN32)
- TCHAR *_pname = malloc((MAX_PATH+1) * sizeof(TCHAR));
- if (GetModuleFileName(NULL, _pname, MAX_PATH+1) > 0) {
- char* pname = NULL;
- #if defined(UNICODE) || defined(_UNICODE)
- char* __pname = NULL;
- int l = WideCharToMultiByte(CP_UTF8, 0, _pname, -1, NULL, 0, NULL, NULL);
- if (l > 0) {
- __pname = malloc(l);
- if (WideCharToMultiByte(CP_UTF8, 0, _pname, -1, __pname, l, NULL, NULL) > 0) {
- pname = __pname;
- }
- }
- #else
- pname = _pname;
- #endif
- if (pname) {
- char *p = pname+strlen(pname)-1;
- while (p > pname && *p != '\\' && *p != '/') p--;
- if (*p == '\\' || *p == '/') p++;
- prog_name = strdup(p);
- }
- #if defined(UNICODE) || defined(_UNICODE)
- free(__pname);
- #endif
- }
- free(_pname);
- #elif defined (HAVE_PROGRAM_INVOCATION_SHORT_NAME)
- char *pname = program_invocation_short_name;
- if (pname) {
- prog_name = strdup(pname);
- }
- #elif defined (__linux__)
- FILE *f = fopen("/proc/self/stat", "r");
- if (!f) {
- return;
- }
- char *tmpbuf = malloc(512);
- size_t r = fread(tmpbuf, 1, 512, f);
- if (r > 0) {
- char *p = tmpbuf;
- while (((size_t)(p-tmpbuf) < r) && (*p != '(') && (*p != '\0')) p++;
- if (*p == '(') {
- p++;
- char *pname = p;
- while (((size_t)(p-tmpbuf) < r) && (*p != ')') && (*p != '\0')) p++;
- if (*p == ')') {
- *p = '\0';
- prog_name = strdup(pname);
- }
- }
- }
- free(tmpbuf);
- fclose(f);
- #else
- #warning FIXME: no method to determine program name
- #endif
- }
- static plist_t create_plist_message(const char* message_type)
- {
- char client_version[128];
- snprintf(client_version, 128, PACKAGE_NAME " %s", libusbmuxd_version());
- if (!bundle_id) {
- get_bundle_id();
- }
- if (!prog_name) {
- get_prog_name();
- }
- plist_t plist = plist_new_dict();
- if (bundle_id) {
- plist_dict_set_item(plist, "BundleID", plist_new_string(bundle_id));
- }
- plist_dict_set_item(plist, "ClientVersionString", plist_new_string(client_version));
- plist_dict_set_item(plist, "MessageType", plist_new_string(message_type));
- if (prog_name) {
- plist_dict_set_item(plist, "ProgName", plist_new_string(prog_name));
- }
- plist_dict_set_item(plist, "kLibUSBMuxVersion", plist_new_uint(PLIST_LIBUSBMUX_VERSION));
- return plist;
- }
- static int send_listen_packet(int sfd, uint32_t tag)
- {
- int res = 0;
- if (proto_version == 1) {
- /* construct message plist */
- plist_t plist = create_plist_message("Listen");
- res = send_plist_packet(sfd, tag, plist);
- plist_free(plist);
- } else {
- /* binary packet */
- res = send_packet(sfd, MESSAGE_LISTEN, tag, NULL, 0);
- }
- return res;
- }
- static int send_connect_packet(int sfd, uint32_t tag, uint32_t device_id, uint16_t port)
- {
- int res = 0;
- if (proto_version == 1) {
- /* construct message plist */
- plist_t plist = create_plist_message("Connect");
- plist_dict_set_item(plist, "DeviceID", plist_new_uint(device_id));
- plist_dict_set_item(plist, "PortNumber", plist_new_uint(htons(port)));
- res = send_plist_packet(sfd, tag, plist);
- plist_free(plist);
- } else {
- /* binary packet */
- struct {
- uint32_t device_id;
- uint16_t port;
- uint16_t reserved;
- } conninfo;
- conninfo.device_id = device_id;
- conninfo.port = htons(port);
- conninfo.reserved = 0;
- res = send_packet(sfd, MESSAGE_CONNECT, tag, &conninfo, sizeof(conninfo));
- }
- return res;
- }
- static int send_list_devices_packet(int sfd, uint32_t tag)
- {
- int res = -1;
- /* construct message plist */
- plist_t plist = create_plist_message("ListDevices");
- res = send_plist_packet(sfd, tag, plist);
- plist_free(plist);
- return res;
- }
- static int send_read_buid_packet(int sfd, uint32_t tag)
- {
- int res = -1;
- /* construct message plist */
- plist_t plist = create_plist_message("ReadBUID");
- res = send_plist_packet(sfd, tag, plist);
- plist_free(plist);
- return res;
- }
- static int send_pair_record_packet(int sfd, uint32_t tag, const char* msgtype, const char* pair_record_id, uint32_t device_id, plist_t data)
- {
- int res = -1;
- /* construct message plist */
- plist_t plist = create_plist_message(msgtype);
- plist_dict_set_item(plist, "PairRecordID", plist_new_string(pair_record_id));
- if (data) {
- plist_dict_set_item(plist, "PairRecordData", plist_copy(data));
- }
- if (device_id > 0) {
- plist_dict_set_item(plist, "DeviceID", plist_new_uint(device_id));
- }
- res = send_plist_packet(sfd, tag, plist);
- plist_free(plist);
- return res;
- }
- /**
- * Generates an event, i.e. calls the callback function.
- * A reference to a populated usbmuxd_event_t with information about the event
- * and the corresponding device will be passed to the callback function.
- */
- static void generate_event(const usbmuxd_device_info_t *dev, enum usbmuxd_event_type event)
- {
- usbmuxd_event_t ev;
- if (!dev) {
- return;
- }
- ev.event = event;
- memcpy(&ev.device, dev, sizeof(usbmuxd_device_info_t));
- mutex_lock(&listener_mutex);
- FOREACH(struct usbmuxd_subscription_context* context, &listeners) {
- context->callback(&ev, context->user_data);
- } ENDFOREACH
- mutex_unlock(&listener_mutex);
- }
- static int usbmuxd_listen_poll()
- {
- int sfd;
- sfd = connect_usbmuxd_socket();
- if (sfd < 0) {
- while (1) {
- mutex_lock(&listener_mutex);
- int num = collection_count(&listeners);
- mutex_unlock(&listener_mutex);
- if (num <= 0) {
- break;
- }
- if ((sfd = connect_usbmuxd_socket()) >= 0) {
- break;
- }
- sleep(1);
- }
- }
- return sfd;
- }
- #ifdef HAVE_INOTIFY
- #ifndef HAVE_PSELECT
- static int pselect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timespec *timeout, const sigset_t *sigmask)
- {
- int ready;
- struct timeval tv;
- struct timeval *p_timeout;
- sigset_t origmask;
- if (timeout) {
- tv.tv_sec = timeout->tv_sec;
- tv.tv_usec = timeout->tv_nsec / 1000;
- p_timeout = &tv;
- } else {
- p_timeout = NULL;
- }
- pthread_sigmask(SIG_SETMASK, sigmask, &origmask);
- ready = select(nfds, readfds, writefds, exceptfds, p_timeout);
- pthread_sigmask(SIG_SETMASK, &origmask, NULL);
- return ready;
- }
- #endif
- static int usbmuxd_listen_inotify()
- {
- int inot_fd;
- int watch_d;
- int sfd;
- if (!use_inotify) {
- return -2;
- }
- sfd = connect_usbmuxd_socket();
- if (sfd >= 0)
- return sfd;
- sfd = -1;
- inot_fd = inotify_init1(IN_CLOEXEC);
- if (inot_fd < 0) {
- LIBUSBMUXD_DEBUG(1, "%s: Failed to setup inotify\n", __func__);
- return -2;
- }
- /* inotify is setup, listen for events that concern us */
- watch_d = inotify_add_watch (inot_fd, USBMUXD_DIRNAME, IN_CREATE);
- if (watch_d < 0) {
- LIBUSBMUXD_DEBUG(1, "%s: Failed to setup watch descriptor for socket dir\n", __func__);
- close (inot_fd);
- return -2;
- }
- while (1) {
- fd_set rfds;
- struct timespec tv = {1, 0};
- FD_ZERO(&rfds);
- FD_SET(inot_fd, &rfds);
- int r = pselect(inot_fd+1, &rfds, NULL, NULL, &tv, NULL);
- if (r < 0) {
- break;
- }
- if (r == 0) {
- continue;
- }
- ssize_t len, i;
- char buff[EVENT_BUF_LEN] = {0};
- i = 0;
- len = read (inot_fd, buff, EVENT_BUF_LEN -1);
- if (len < 0)
- goto end;
- while (i < len) {
- struct inotify_event *pevent = (struct inotify_event *) & buff[i];
- /* check that it's ours */
- if (pevent->mask & IN_CREATE &&
- pevent->len &&
- pevent->name[0] != 0 &&
- strcmp(pevent->name, USBMUXD_SOCKET_NAME) == 0) {
- /* retry if usbmuxd isn't ready yet */
- int retry = 10;
- while (--retry >= 0) {
- if ((sfd = connect_usbmuxd_socket ()) >= 0) {
- break;
- }
- sleep(1);
- }
- goto end;
- }
- i += EVENT_SIZE + pevent->len;
- }
- }
- end:
- inotify_rm_watch(inot_fd, watch_d);
- close(inot_fd);
- return sfd;
- }
- #endif /* HAVE_INOTIFY */
- /**
- * Tries to connect to usbmuxd and wait if it is not running.
- */
- static int usbmuxd_listen()
- {
- int sfd;
- uint32_t res = -1;
- int tag;
- retry:
- #ifdef HAVE_INOTIFY
- sfd = usbmuxd_listen_inotify();
- if (sfd == -2)
- sfd = usbmuxd_listen_poll();
- #else
- sfd = usbmuxd_listen_poll();
- #endif
- if (sfd < 0) {
- if (!cancelling) {
- LIBUSBMUXD_DEBUG(1, "%s: ERROR: usbmuxd was supposed to be running here...\n", __func__);
- }
- return sfd;
- }
- tag = ++use_tag;
- if (send_listen_packet(sfd, tag) <= 0) {
- LIBUSBMUXD_DEBUG(1, "%s: ERROR: could not send listen packet\n", __func__);
- socket_close(sfd);
- return -1;
- }
- if ((usbmuxd_get_result(sfd, tag, &res, NULL) == 1) && (res != 0)) {
- socket_close(sfd);
- if ((res == RESULT_BADVERSION) && (proto_version == 1)) {
- proto_version = 0;
- goto retry;
- }
- LIBUSBMUXD_DEBUG(1, "%s: ERROR: did not get OK but %d\n", __func__, res);
- return -1;
- }
- return sfd;
- }
- /**
- * Waits for an event to occur, i.e. a packet coming from usbmuxd.
- * Calls generate_event to pass the event via callback to the client program.
- */
- static int get_next_event(int sfd)
- {
- struct usbmuxd_header hdr;
- void *payload = NULL;
- /* block until we receive something */
- if (receive_packet(sfd, &hdr, &payload, 0) < 0) {
- if (!cancelling) {
- LIBUSBMUXD_DEBUG(1, "%s: Error in usbmuxd connection, disconnecting all devices!\n", __func__);
- }
- // when then usbmuxd connection fails,
- // generate remove events for every device that
- // is still present so applications know about it
- FOREACH(usbmuxd_device_info_t *dev, &devices) {
- generate_event(dev, UE_DEVICE_REMOVE);
- collection_remove(&devices, dev);
- free(dev);
- } ENDFOREACH
- return -EIO;
- }
- if ((hdr.length > sizeof(hdr)) && !payload) {
- LIBUSBMUXD_DEBUG(1, "%s: Invalid packet received, payload is missing!\n", __func__);
- return -EBADMSG;
- }
- if (hdr.message == MESSAGE_DEVICE_ADD) {
- usbmuxd_device_info_t *devinfo = (usbmuxd_device_info_t*)payload;
- collection_add(&devices, devinfo);
- generate_event(devinfo, UE_DEVICE_ADD);
- payload = NULL;
- } else if (hdr.message == MESSAGE_DEVICE_REMOVE) {
- uint32_t handle;
- usbmuxd_device_info_t *devinfo;
- memcpy(&handle, payload, sizeof(uint32_t));
- devinfo = devices_find(handle);
- if (!devinfo) {
- LIBUSBMUXD_DEBUG(1, "%s: WARNING: got device remove message for handle %d, but couldn't find the corresponding handle in the device list. This event will be ignored.\n", __func__, handle);
- } else {
- generate_event(devinfo, UE_DEVICE_REMOVE);
- collection_remove(&devices, devinfo);
- free(devinfo);
- }
- } else if (hdr.message == MESSAGE_DEVICE_PAIRED) {
- uint32_t handle;
- usbmuxd_device_info_t *devinfo;
- memcpy(&handle, payload, sizeof(uint32_t));
- devinfo = devices_find(handle);
- if (!devinfo) {
- LIBUSBMUXD_DEBUG(1, "%s: WARNING: got paired message for device handle %d, but couldn't find the corresponding handle in the device list. This event will be ignored.\n", __func__, handle);
- } else {
- generate_event(devinfo, UE_DEVICE_PAIRED);
- }
- } else if (hdr.length > 0) {
- LIBUSBMUXD_DEBUG(1, "%s: Unexpected message type %d length %d received!\n", __func__, hdr.message, hdr.length);
- }
- free(payload);
- return 0;
- }
- static void device_monitor_cleanup(void* data)
- {
- FOREACH(usbmuxd_device_info_t *dev, &devices) {
- collection_remove(&devices, dev);
- free(dev);
- } ENDFOREACH
- collection_free(&devices);
- socket_close(listenfd);
- listenfd = -1;
- }
- /**
- * Device Monitor thread function.
- *
- * This function sets up a connection to usbmuxd
- */
- static void *device_monitor(void *data)
- {
- running = 1;
- collection_init(&devices);
- cancelling = 0;
- #ifdef HAVE_THREAD_CLEANUP
- thread_cleanup_push(device_monitor_cleanup, NULL);
- #endif
- do {
- listenfd = usbmuxd_listen();
- if (listenfd < 0) {
- continue;
- }
- while (running) {
- int res = get_next_event(listenfd);
- if (res < 0) {
- break;
- }
- }
- mutex_lock(&listener_mutex);
- if (collection_count(&listeners) == 0) {
- running = 0;
- }
- mutex_unlock(&listener_mutex);
- } while (running);
- #ifdef HAVE_THREAD_CLEANUP
- thread_cleanup_pop(1);
- #else
- device_monitor_cleanup(NULL);
- #endif
- return NULL;
- }
- static void init_listeners(void)
- {
- collection_init(&listeners);
- mutex_init(&listener_mutex);
- }
- int usbmuxd_events_subscribe(usbmuxd_subscription_context_t *context, usbmuxd_event_cb_t callback, void *user_data)
- {
- if (!context || !callback) {
- return -EINVAL;
- }
- thread_once(&listener_init_once, init_listeners);
- mutex_lock(&listener_mutex);
- *context = malloc(sizeof(struct usbmuxd_subscription_context));
- if (!*context) {
- mutex_unlock(&listener_mutex);
- LIBUSBMUXD_ERROR("ERROR: %s: malloc failed\n", __func__);
- return -ENOMEM;
- }
- (*context)->callback = callback;
- (*context)->user_data = user_data;
- collection_add(&listeners, *context);
- if (devmon == THREAD_T_NULL || !thread_alive(devmon)) {
- mutex_unlock(&listener_mutex);
- int res = thread_new(&devmon, device_monitor, NULL);
- if (res != 0) {
- free(*context);
- LIBUSBMUXD_DEBUG(1, "%s: ERROR: Could not start device watcher thread!\n", __func__);
- return res;
- }
- } else {
- /* we need to submit DEVICE_ADD events to the new listener */
- FOREACH(usbmuxd_device_info_t *dev, &devices) {
- if (dev) {
- usbmuxd_event_t ev;
- ev.event = UE_DEVICE_ADD;
- memcpy(&ev.device, dev, sizeof(usbmuxd_device_info_t));
- (*context)->callback(&ev, (*context)->user_data);
- }
- } ENDFOREACH
- mutex_unlock(&listener_mutex);
- }
- return 0;
- }
- int usbmuxd_events_unsubscribe(usbmuxd_subscription_context_t context)
- {
- int ret = 0;
- int num = 0;
- if (!context) {
- return -EINVAL;
- }
- mutex_lock(&listener_mutex);
- if (collection_remove(&listeners, context) == 0) {
- FOREACH(usbmuxd_device_info_t *dev, &devices) {
- if (dev) {
- usbmuxd_event_t ev;
- ev.event = UE_DEVICE_REMOVE;
- memcpy(&ev.device, dev, sizeof(usbmuxd_device_info_t));
- (context)->callback(&ev, (context)->user_data);
- }
- } ENDFOREACH
- free(context);
- }
- num = collection_count(&listeners);
- mutex_unlock(&listener_mutex);
- if (num == 0) {
- int res = 0;
- cancelling = 1;
- socket_shutdown(listenfd, SHUT_RDWR);
- if (thread_alive(devmon)) {
- if (thread_cancel(devmon) < 0) {
- running = 0;
- }
- #if defined(HAVE_INOTIFY) && !defined(HAVE_PTHREAD_CANCEL)
- pthread_kill(devmon, SIGINT);
- #endif
- res = thread_join(devmon);
- thread_free(devmon);
- devmon = THREAD_T_NULL;
- }
- if ((res != 0) && (res != ESRCH)) {
- ret = res;
- }
- }
- return ret;
- }
- int usbmuxd_subscribe(usbmuxd_event_cb_t callback, void *user_data)
- {
- if (!callback) {
- return -EINVAL;
- }
- if (event_ctx) {
- usbmuxd_events_unsubscribe(event_ctx);
- event_ctx = NULL;
- }
- return usbmuxd_events_subscribe(&event_ctx, callback, user_data);
- }
- int usbmuxd_unsubscribe(void)
- {
- int res = usbmuxd_events_unsubscribe(event_ctx);
- event_ctx = NULL;
- return res;
- }
- int usbmuxd_get_device_list(usbmuxd_device_info_t **device_list)
- {
- int sfd;
- int tag;
- int listen_success = 0;
- uint32_t res;
- struct collection tmpdevs;
- usbmuxd_device_info_t *newlist = NULL;
- struct usbmuxd_header hdr;
- int dev_cnt = 0;
- void *payload = NULL;
- *device_list = NULL;
- retry:
- sfd = connect_usbmuxd_socket();
- if (sfd < 0) {
- LIBUSBMUXD_DEBUG(1, "%s: error opening socket!\n", __func__);
- return sfd;
- }
- tag = ++use_tag;
- if ((proto_version == 1) && (try_list_devices)) {
- if (send_list_devices_packet(sfd, tag) > 0) {
- plist_t list = NULL;
- if ((usbmuxd_get_result(sfd, tag, &res, &list) == 1) && (res == 0)) {
- plist_t devlist = plist_dict_get_item(list, "DeviceList");
- if (devlist && plist_get_node_type(devlist) == PLIST_ARRAY) {
- collection_init(&tmpdevs);
- uint32_t numdevs = plist_array_get_size(devlist);
- uint32_t i;
- for (i = 0; i < numdevs; i++) {
- plist_t pdev = plist_array_get_item(devlist, i);
- plist_t props = plist_dict_get_item(pdev, "Properties");
- usbmuxd_device_info_t *devinfo = device_info_from_plist(props);
- if (!devinfo) {
- socket_close(sfd);
- LIBUSBMUXD_DEBUG(1, "%s: Could not create device info object from properties!\n", __func__);
- plist_free(list);
- return -1;
- }
- collection_add(&tmpdevs, devinfo);
- }
- plist_free(list);
- goto got_device_list;
- }
- } else {
- if (res == RESULT_BADVERSION) {
- proto_version = 0;
- }
- socket_close(sfd);
- try_list_devices = 0;
- plist_free(list);
- goto retry;
- }
- plist_free(list);
- }
- }
- tag = ++use_tag;
- if (send_listen_packet(sfd, tag) > 0) {
- res = -1;
- // get response
- if ((usbmuxd_get_result(sfd, tag, &res, NULL) == 1) && (res == 0)) {
- listen_success = 1;
- } else {
- socket_close(sfd);
- if ((res == RESULT_BADVERSION) && (proto_version == 1)) {
- proto_version = 0;
- goto retry;
- }
- LIBUSBMUXD_DEBUG(1, "%s: Did not get response to scan request (with result=0)...\n", __func__);
- return res;
- }
- }
- if (!listen_success) {
- socket_close(sfd);
- LIBUSBMUXD_DEBUG(1, "%s: Could not send listen request!\n", __func__);
- return -1;
- }
- collection_init(&tmpdevs);
- // receive device list
- while (1) {
- if (receive_packet(sfd, &hdr, &payload, 100) > 0) {
- if (hdr.message == MESSAGE_DEVICE_ADD) {
- usbmuxd_device_info_t *devinfo = payload;
- collection_add(&tmpdevs, devinfo);
- payload = NULL;
- } else if (hdr.message == MESSAGE_DEVICE_REMOVE) {
- uint32_t handle;
- usbmuxd_device_info_t *devinfo = NULL;
- memcpy(&handle, payload, sizeof(uint32_t));
- FOREACH(usbmuxd_device_info_t *di, &tmpdevs) {
- if (di && di->handle == handle) {
- devinfo = di;
- break;
- }
- } ENDFOREACH
- if (devinfo) {
- collection_remove(&tmpdevs, devinfo);
- free(devinfo);
- }
- } else {
- LIBUSBMUXD_DEBUG(1, "%s: Unexpected message %d\n", __func__, hdr.message);
- }
- free(payload);
- } else {
- // we _should_ have all of them now.
- // or perhaps an error occurred.
- break;
- }
- }
- got_device_list:
- // explicitly close connection
- socket_close(sfd);
- // create copy of device info entries from collection
- newlist = (usbmuxd_device_info_t*)malloc(sizeof(usbmuxd_device_info_t) * (collection_count(&tmpdevs) + 1));
- dev_cnt = 0;
- FOREACH(usbmuxd_device_info_t *di, &tmpdevs) {
- if (di) {
- memcpy(&newlist[dev_cnt], di, sizeof(usbmuxd_device_info_t));
- free(di);
- dev_cnt++;
- }
- } ENDFOREACH
- collection_free(&tmpdevs);
- memset(&newlist[dev_cnt], 0, sizeof(usbmuxd_device_info_t));
- *device_list = newlist;
- return dev_cnt;
- }
- int usbmuxd_device_list_free(usbmuxd_device_info_t **device_list)
- {
- if (device_list) {
- free(*device_list);
- }
- return 0;
- }
- int usbmuxd_get_device_by_udid(const char *udid, usbmuxd_device_info_t *device)
- {
- usbmuxd_device_info_t *dev_list = NULL;
- usbmuxd_device_info_t *dev = NULL;
- int result = 0;
- int i;
- if (!device) {
- return -EINVAL;
- }
- if (usbmuxd_get_device_list(&dev_list) < 0) {
- return -ENODEV;
- }
- for (i = 0; dev_list[i].handle > 0; i++) {
- if (!udid) {
- if (dev_list[i].conn_type == CONNECTION_TYPE_USB) {
- dev = &dev_list[i];
- break;
- }
- } else if (!strcmp(udid, dev_list[i].udid)) {
- if (dev_list[i].conn_type == CONNECTION_TYPE_USB) {
- dev = &dev_list[i];
- break;
- }
- }
- }
- if (dev) {
- device->handle = dev->handle;
- device->product_id = dev->product_id;
- char *t = stpncpy(device->udid, dev->udid, sizeof(device->udid)-1);
- *t = '\0';
- device->conn_type = dev->conn_type;
- memcpy(device->conn_data, dev->conn_data, sizeof(device->conn_data));
- result = 1;
- }
- usbmuxd_device_list_free(&dev_list);
- return result;
- }
- int usbmuxd_get_device(const char *udid, usbmuxd_device_info_t *device, enum usbmux_lookup_options options)
- {
- usbmuxd_device_info_t *dev_list = NULL;
- usbmuxd_device_info_t *dev_network = NULL;
- usbmuxd_device_info_t *dev_usbmuxd = NULL;
- usbmuxd_device_info_t *dev = NULL;
- int result = 0;
- int i;
- if (!device) {
- return -EINVAL;
- }
- if (usbmuxd_get_device_list(&dev_list) < 0) {
- return -ENODEV;
- }
- if (options == 0) {
- options = DEVICE_LOOKUP_USBMUX;
- }
- for (i = 0; dev_list[i].handle > 0; i++) {
- if (!udid) {
- if ((options & DEVICE_LOOKUP_USBMUX) && (dev_list[i].conn_type == CONNECTION_TYPE_USB)) {
- dev_usbmuxd = &dev_list[i];
- break;
- }
- if ((options & DEVICE_LOOKUP_NETWORK) && (dev_list[i].conn_type == CONNECTION_TYPE_NETWORK)) {
- dev_network = &dev_list[i];
- break;
- }
- } else if (!strcmp(udid, dev_list[i].udid)) {
- if ((options & DEVICE_LOOKUP_USBMUX) && (dev_list[i].conn_type == CONNECTION_TYPE_USB)) {
- dev_usbmuxd = &dev_list[i];
- } else if ((options & DEVICE_LOOKUP_NETWORK) && (dev_list[i].conn_type == CONNECTION_TYPE_NETWORK)) {
- dev_network = &dev_list[i];
- }
- }
- if (dev_usbmuxd && dev_network) {
- break;
- }
- }
- if (dev_network && dev_usbmuxd) {
- dev = (options & DEVICE_LOOKUP_PREFER_NETWORK) ? dev_network : dev_usbmuxd;
- } else if (dev_network) {
- dev = dev_network;
- } else if (dev_usbmuxd) {
- dev = dev_usbmuxd;
- }
- if (dev) {
- device->handle = dev->handle;
- device->product_id = dev->product_id;
- char *t = stpncpy(device->udid, dev->udid, sizeof(device->udid)-1);
- *t = '\0';
- device->conn_type = dev->conn_type;
- memcpy(device->conn_data, dev->conn_data, sizeof(device->conn_data));
- result = 1;
- }
- free(dev_list);
- return result;
- }
- int usbmuxd_connect(const uint32_t handle, const unsigned short port)
- {
- int sfd;
- int tag;
- int connected = 0;
- int result = EBADF;
- retry:
- sfd = connect_usbmuxd_socket();
- if (sfd < 0) {
- LIBUSBMUXD_DEBUG(1, "%s: Error: Connection to usbmuxd failed: %s\n", __func__, strerror(-sfd));
- return sfd;
- }
- tag = ++use_tag;
- if (send_connect_packet(sfd, tag, handle, (uint16_t)port) <= 0) {
- LIBUSBMUXD_DEBUG(1, "%s: Error sending connect message!\n", __func__);
- } else {
- // read ACK
- uint32_t res = -1;
- LIBUSBMUXD_DEBUG(2, "%s: Reading connect result...\n", __func__);
- if (usbmuxd_get_result(sfd, tag, &res, NULL) == 1) {
- if (res == 0) {
- LIBUSBMUXD_DEBUG(2, "%s: Connect success!\n", __func__);
- connected = 1;
- } else {
- if ((res == RESULT_BADVERSION) && (proto_version == 1)) {
- proto_version = 0;
- socket_close(sfd);
- goto retry;
- }
- LIBUSBMUXD_DEBUG(1, "%s: Connect failed, Error code=%d\n", __func__, res);
- if (res == RESULT_CONNREFUSED) {
- result = ECONNREFUSED;
- } else if (res == RESULT_BADDEV) {
- result = ENODEV;
- } else {
- result = EBADF;
- }
- }
- }
- }
- if (connected) {
- return sfd;
- }
- socket_close(sfd);
- return -result;
- }
- int usbmuxd_disconnect(int sfd)
- {
- return socket_close(sfd);
- }
- int usbmuxd_send(int sfd, const char *data, uint32_t len, uint32_t *sent_bytes)
- {
- int num_sent;
- if (sfd < 0) {
- return -EINVAL;
- }
- num_sent = socket_send(sfd, (void*)data, len);
- if (num_sent < 0) {
- *sent_bytes = 0;
- LIBUSBMUXD_DEBUG(1, "%s: Error %d when sending: %s\n", __func__, -num_sent, strerror(-num_sent));
- return num_sent;
- }
- if ((uint32_t)num_sent < len) {
- LIBUSBMUXD_DEBUG(1, "%s: Warning: Did not send enough (only %d of %d)\n", __func__, num_sent, len);
- }
- *sent_bytes = num_sent;
- return 0;
- }
- int usbmuxd_recv_timeout(int sfd, char *data, uint32_t len, uint32_t *recv_bytes, unsigned int timeout)
- {
- int num_recv = socket_receive_timeout(sfd, (void*)data, len, 0, timeout);
- if (num_recv < 0) {
- *recv_bytes = 0;
- return num_recv;
- }
- *recv_bytes = num_recv;
- return 0;
- }
- int usbmuxd_recv(int sfd, char *data, uint32_t len, uint32_t *recv_bytes)
- {
- return usbmuxd_recv_timeout(sfd, data, len, recv_bytes, 5000);
- }
- int usbmuxd_read_buid(char **buid)
- {
- int sfd;
- int tag;
- int ret = -1;
- if (!buid) {
- return -EINVAL;
- }
- *buid = NULL;
- sfd = connect_usbmuxd_socket();
- if (sfd < 0) {
- LIBUSBMUXD_DEBUG(1, "%s: Error: Connection to usbmuxd failed: %s\n", __func__, strerror(-sfd));
- return sfd;
- }
- proto_version = 1;
- tag = ++use_tag;
- if (send_read_buid_packet(sfd, tag) <= 0) {
- LIBUSBMUXD_DEBUG(1, "%s: Error sending ReadBUID message!\n", __func__);
- } else {
- uint32_t rc = 0;
- plist_t pl = NULL;
- ret = usbmuxd_get_result(sfd, tag, &rc, &pl);
- if ((ret == 1) && (rc == 0)) {
- plist_t node = plist_dict_get_item(pl, "BUID");
- if (node && plist_get_node_type(node) == PLIST_STRING) {
- plist_get_string_val(node, buid);
- }
- ret = 0;
- } else if (ret == 1) {
- ret = -(int)rc;
- }
- plist_free(pl);
- }
- socket_close(sfd);
- return ret;
- }
- int usbmuxd_read_pair_record(const char* record_id, char **record_data, uint32_t *record_size)
- {
- int sfd;
- int tag;
- int ret = -1;
- if (!record_id || !record_data || !record_size) {
- return -EINVAL;
- }
- *record_data = NULL;
- *record_size = 0;
- sfd = connect_usbmuxd_socket();
- if (sfd < 0) {
- LIBUSBMUXD_DEBUG(1, "%s: Error: Connection to usbmuxd failed: %s\n", __func__, strerror(-sfd));
- return sfd;
- }
- proto_version = 1;
- tag = ++use_tag;
- if (send_pair_record_packet(sfd, tag, "ReadPairRecord", record_id, 0, NULL) <= 0) {
- LIBUSBMUXD_DEBUG(1, "%s: Error sending ReadPairRecord message!\n", __func__);
- } else {
- uint32_t rc = 0;
- plist_t pl = NULL;
- ret = usbmuxd_get_result(sfd, tag, &rc, &pl);
- if ((ret == 1) && (rc == 0)) {
- plist_t node = plist_dict_get_item(pl, "PairRecordData");
- if (node && plist_get_node_type(node) == PLIST_DATA) {
- uint64_t int64val = 0;
- plist_get_data_val(node, record_data, &int64val);
- if (*record_data && int64val > 0) {
- *record_size = (uint32_t)int64val;
- ret = 0;
- }
- }
- } else if (ret == 1) {
- ret = -(int)rc;
- }
- plist_free(pl);
- }
- socket_close(sfd);
- return ret;
- }
- int usbmuxd_save_pair_record_with_device_id(const char* record_id, uint32_t device_id, const char *record_data, uint32_t record_size)
- {
- int sfd;
- int tag;
- int ret = -1;
- if (!record_id || !record_data || !record_size) {
- return -EINVAL;
- }
- sfd = connect_usbmuxd_socket();
- if (sfd < 0) {
- LIBUSBMUXD_DEBUG(1, "%s: Error: Connection to usbmuxd failed: %s\n", __func__, strerror(-sfd));
- return sfd;
- }
- proto_version = 1;
- tag = ++use_tag;
- plist_t data = plist_new_data(record_data, record_size);
- if (send_pair_record_packet(sfd, tag, "SavePairRecord", record_id, device_id, data) <= 0) {
- LIBUSBMUXD_DEBUG(1, "%s: Error sending SavePairRecord message!\n", __func__);
- } else {
- uint32_t rc = 0;
- ret = usbmuxd_get_result(sfd, tag, &rc, NULL);
- if ((ret == 1) && (rc == 0)) {
- ret = 0;
- } else if (ret == 1) {
- ret = -(int)rc;
- LIBUSBMUXD_DEBUG(1, "%s: Error: saving pair record failed: %d\n", __func__, ret);
- }
- }
- plist_free(data);
- socket_close(sfd);
- return ret;
- }
- int usbmuxd_save_pair_record(const char* record_id, const char *record_data, uint32_t record_size)
- {
- return usbmuxd_save_pair_record_with_device_id(record_id, 0, record_data, record_size);
- }
- int usbmuxd_delete_pair_record(const char* record_id)
- {
- int sfd;
- int tag;
- int ret = -1;
- if (!record_id) {
- return -EINVAL;
- }
- sfd = connect_usbmuxd_socket();
- if (sfd < 0) {
- LIBUSBMUXD_DEBUG(1, "%s: Error: Connection to usbmuxd failed: %s\n", __func__, strerror(-sfd));
- return sfd;
- }
- proto_version = 1;
- tag = ++use_tag;
- if (send_pair_record_packet(sfd, tag, "DeletePairRecord", record_id, 0, NULL) <= 0) {
- LIBUSBMUXD_DEBUG(1, "%s: Error sending DeletePairRecord message!\n", __func__);
- } else {
- uint32_t rc = 0;
- ret = usbmuxd_get_result(sfd, tag, &rc, NULL);
- if ((ret == 1) && (rc == 0)) {
- ret = 0;
- } else if (ret == 1) {
- ret = -(int)rc;
- LIBUSBMUXD_DEBUG(1, "%s: Error: deleting pair record failed: %d\n", __func__, ret);
- }
- }
- socket_close(sfd);
- return ret;
- }
- void libusbmuxd_set_use_inotify(int set)
- {
- #ifdef HAVE_INOTIFY
- use_inotify = set;
- #endif
- }
- void libusbmuxd_set_debug_level(int level)
- {
- libusbmuxd_debug = level;
- socket_set_verbose(level);
- }
- const char* libusbmuxd_version()
- {
- #ifndef PACKAGE_VERSION
- #error PACKAGE_VERSION is not defined
- #endif
- return PACKAGE_VERSION;
- }
|