LightMessaging.h 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531
  1. #ifndef __APPLE_API_PRIVATE
  2. #define __APPLE_API_PRIVATE
  3. #include "sandbox.h"
  4. #undef __APPLE_API_PRIVATE
  5. #else
  6. #include "sandbox.h"
  7. #endif
  8. #ifndef LIGHTMESSAGING_USE_ROCKETBOOTSTRAP
  9. #define LIGHTMESSAGING_USE_ROCKETBOOTSTRAP 1
  10. #endif
  11. #ifndef LIGHTMESSAGING_TIMEOUT
  12. #define LIGHTMESSAGING_TIMEOUT MACH_MSG_TIMEOUT_NONE
  13. #define _LIGHTMESSAGING_TIMEOUT_FLAGS 0
  14. #else
  15. #define _LIGHTMESSAGING_TIMEOUT_FLAGS (MACH_SEND_TIMEOUT | MACH_RCV_TIMEOUT)
  16. #endif
  17. #import <CoreGraphics/CoreGraphics.h>
  18. #import <ImageIO/ImageIO.h>
  19. #include <mach/mach.h>
  20. #include <mach/mach_init.h>
  21. #if LIGHTMESSAGING_USE_ROCKETBOOTSTRAP
  22. #include "../rocketbootstrap/rocketbootstrap.h"
  23. #else
  24. #include "bootstrap.h"
  25. #endif
  26. #ifdef __OBJC__
  27. #ifndef __has_feature
  28. #define __has_feature(x) 0
  29. #endif
  30. #if __has_feature(objc_arc)
  31. #define LMBridgedCast_(a, b) (__bridge a)(b)
  32. #else
  33. #define LMBridgedCast_(a, b) (a)(b)
  34. #endif
  35. #endif
  36. typedef struct {
  37. mach_port_t serverPort;
  38. name_t serverName;
  39. } LMConnection;
  40. typedef LMConnection *LMConnectionRef;
  41. #define __LMMaxInlineSize 4096 + sizeof(LMMessage)
  42. typedef struct __LMMessage {
  43. mach_msg_header_t head;
  44. mach_msg_body_t body;
  45. union {
  46. struct {
  47. mach_msg_ool_descriptor_t descriptor;
  48. } out_of_line;
  49. struct {
  50. uint32_t length;
  51. uint8_t bytes[0];
  52. } in_line;
  53. } data;
  54. } LMMessage;
  55. typedef struct __LMResponseBuffer {
  56. LMMessage message;
  57. uint8_t slack[__LMMaxInlineSize - sizeof(LMMessage) + MAX_TRAILER_SIZE];
  58. } LMResponseBuffer;
  59. static inline uint32_t LMBufferSizeForLength(uint32_t length)
  60. {
  61. if (length + sizeof(LMMessage) > __LMMaxInlineSize)
  62. return sizeof(LMMessage);
  63. else
  64. return ((sizeof(LMMessage) + length) + 3) & ~0x3;
  65. }
  66. static inline void LMMessageCopyInline(LMMessage *message, const void *data, uint32_t length)
  67. {
  68. message->data.in_line.length = length;
  69. if (data) {
  70. memcpy(message->data.in_line.bytes, data, length);
  71. }
  72. }
  73. static inline void LMMessageAssignOutOfLine(LMMessage *message, const void *data, uint32_t length)
  74. {
  75. message->head.msgh_bits |= MACH_MSGH_BITS_COMPLEX;
  76. message->body.msgh_descriptor_count = 1;
  77. message->data.out_of_line.descriptor.type = MACH_MSG_OOL_DESCRIPTOR;
  78. message->data.out_of_line.descriptor.copy = MACH_MSG_VIRTUAL_COPY;
  79. message->data.out_of_line.descriptor.deallocate = false;
  80. message->data.out_of_line.descriptor.address = (void *)data;
  81. message->data.out_of_line.descriptor.size = length;
  82. }
  83. static inline void LMMessageAssignData(LMMessage *message, const void *data, uint32_t length)
  84. {
  85. if (length == 0) {
  86. message->body.msgh_descriptor_count = 0;
  87. message->data.in_line.length = length;
  88. } else if (message->head.msgh_size != sizeof(LMMessage)) {
  89. message->body.msgh_descriptor_count = 0;
  90. message->data.in_line.length = length;
  91. memcpy(message->data.in_line.bytes, data, length);
  92. } else {
  93. LMMessageAssignOutOfLine(message, data, length);
  94. }
  95. }
  96. static inline void *LMMessageGetData(LMMessage *message)
  97. {
  98. if (message->body.msgh_descriptor_count)
  99. return message->data.out_of_line.descriptor.address;
  100. if (message->data.in_line.length == 0)
  101. return NULL;
  102. return &message->data.in_line.bytes;
  103. }
  104. static inline uint32_t LMMessageGetDataLength(LMMessage *message)
  105. {
  106. if (message->body.msgh_descriptor_count)
  107. return message->data.out_of_line.descriptor.size;
  108. uint32_t result = message->data.in_line.length;
  109. // Clip to the maximum size of a message buffer, prevents clients from forcing reads outside the region
  110. if (result > __LMMaxInlineSize - offsetof(LMMessage, data.in_line.bytes))
  111. return __LMMaxInlineSize - offsetof(LMMessage, data.in_line.bytes);
  112. // Client specified the right size, yay!
  113. return result;
  114. }
  115. static inline mach_msg_return_t LMMachMsg(LMConnection *connection, mach_msg_header_t *msg, mach_msg_option_t option, mach_msg_size_t send_size, mach_msg_size_t rcv_size, mach_port_name_t rcv_name, mach_msg_timeout_t timeout, mach_port_name_t notify)
  116. {
  117. for (;;) {
  118. kern_return_t err;
  119. if (connection->serverPort == MACH_PORT_NULL) {
  120. mach_port_t selfTask = mach_task_self();
  121. if ((kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_5_0) && (kCFCoreFoundationVersionNumber < 800.0)) {
  122. int sandbox_result = sandbox_check(getpid(), "mach-lookup", (enum sandbox_filter_type)(SANDBOX_FILTER_LOCAL_NAME | SANDBOX_CHECK_NO_REPORT), connection->serverName);
  123. if (sandbox_result) {
  124. return sandbox_result;
  125. }
  126. }
  127. // Lookup remote port
  128. mach_port_t bootstrap = MACH_PORT_NULL;
  129. task_get_bootstrap_port(selfTask, &bootstrap);
  130. #if LIGHTMESSAGING_USE_ROCKETBOOTSTRAP
  131. err = rocketbootstrap_look_up(bootstrap, connection->serverName, &connection->serverPort);
  132. #else
  133. err = bootstrap_look_up(bootstrap, connection->serverName, &connection->serverPort);
  134. #endif
  135. if (err)
  136. return err;
  137. }
  138. msg->msgh_remote_port = connection->serverPort;
  139. err = mach_msg(msg, option, send_size, rcv_size, rcv_name, timeout, notify);
  140. if (err != MACH_SEND_INVALID_DEST)
  141. return err;
  142. mach_port_deallocate(mach_task_self(), msg->msgh_remote_port);
  143. connection->serverPort = MACH_PORT_NULL;
  144. }
  145. }
  146. static inline kern_return_t LMConnectionSendOneWay(LMConnectionRef connection, SInt32 messageId, const void *data, uint32_t length)
  147. {
  148. // Send message
  149. uint32_t size = LMBufferSizeForLength(length);
  150. uint8_t buffer[size];
  151. LMMessage *message = (LMMessage *)&buffer[0];
  152. memset(message, 0, sizeof(LMMessage));
  153. message->head.msgh_id = messageId;
  154. message->head.msgh_size = size;
  155. message->head.msgh_local_port = MACH_PORT_NULL;
  156. message->head.msgh_reserved = 0;
  157. message->head.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
  158. LMMessageAssignData(message, data, length);
  159. return LMMachMsg(connection, &message->head, MACH_SEND_MSG, size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
  160. }
  161. static inline kern_return_t LMConnectionSendEmptyOneWay(LMConnectionRef connection, SInt32 messageId)
  162. {
  163. // TODO: Optimize so we don't use the additional stack space
  164. uint32_t size = sizeof(mach_msg_header_t) + sizeof(mach_msg_body_t);
  165. LMMessage message;
  166. memset(&message, 0, size);
  167. message.head.msgh_id = messageId;
  168. message.head.msgh_size = size;
  169. message.head.msgh_local_port = MACH_PORT_NULL;
  170. message.head.msgh_reserved = 0;
  171. message.head.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
  172. return LMMachMsg(connection, &message.head, MACH_SEND_MSG, size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
  173. }
  174. static inline kern_return_t LMConnectionSendTwoWay(LMConnectionRef connection, SInt32 messageId, const void *data, uint32_t length, LMResponseBuffer *responseBuffer)
  175. {
  176. // Create a reply port
  177. mach_port_t selfTask = mach_task_self();
  178. mach_port_name_t replyPort = MACH_PORT_NULL;
  179. int err = mach_port_allocate(selfTask, MACH_PORT_RIGHT_RECEIVE, &replyPort);
  180. if (err) {
  181. responseBuffer->message.body.msgh_descriptor_count = 0;
  182. return err;
  183. }
  184. // Send message
  185. uint32_t size = LMBufferSizeForLength(length);
  186. LMMessage *message = &responseBuffer->message;
  187. memset(message, 0, sizeof(LMMessage));
  188. message->head.msgh_id = messageId;
  189. message->head.msgh_size = size;
  190. message->head.msgh_local_port = replyPort;
  191. message->head.msgh_reserved = 0;
  192. message->head.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE);
  193. LMMessageAssignData(message, data, length);
  194. err = LMMachMsg(connection, &message->head, MACH_SEND_MSG | MACH_RCV_MSG | _LIGHTMESSAGING_TIMEOUT_FLAGS, size, sizeof(LMResponseBuffer), replyPort, LIGHTMESSAGING_TIMEOUT, MACH_PORT_NULL);
  195. if (err)
  196. responseBuffer->message.body.msgh_descriptor_count = 0;
  197. // Cleanup
  198. mach_port_mod_refs(selfTask, replyPort, MACH_PORT_RIGHT_RECEIVE, -1);
  199. return err;
  200. }
  201. static inline void LMResponseBufferFree(LMResponseBuffer *responseBuffer)
  202. {
  203. if (responseBuffer->message.body.msgh_descriptor_count != 0 && responseBuffer->message.data.out_of_line.descriptor.type == MACH_MSG_OOL_DESCRIPTOR) {
  204. vm_deallocate(mach_task_self(), (vm_address_t)responseBuffer->message.data.out_of_line.descriptor.address, responseBuffer->message.data.out_of_line.descriptor.size);
  205. responseBuffer->message.body.msgh_descriptor_count = 0;
  206. }
  207. }
  208. #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
  209. static inline kern_return_t LMStartServiceWithUserInfo(name_t serverName, CFRunLoopRef runLoop, CFMachPortCallBack callback, void *userInfo)
  210. {
  211. // TODO: Figure out what the real interface is, implement service stopping, handle failures correctly
  212. mach_port_t bootstrap = MACH_PORT_NULL;
  213. task_get_bootstrap_port(mach_task_self(), &bootstrap);
  214. CFMachPortContext context = { 0, userInfo, NULL, NULL, NULL };
  215. CFMachPortRef machPort = CFMachPortCreate(kCFAllocatorDefault, callback, &context, NULL);
  216. CFRunLoopSourceRef machPortSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, machPort, 0);
  217. CFRunLoopAddSource(runLoop, machPortSource, kCFRunLoopCommonModes);
  218. mach_port_t port = CFMachPortGetPort(machPort);
  219. #if LIGHTMESSAGING_USE_ROCKETBOOTSTRAP
  220. rocketbootstrap_unlock(serverName);
  221. #endif
  222. return bootstrap_register(bootstrap, serverName, port);
  223. }
  224. #pragma GCC diagnostic warning "-Wdeprecated-declarations"
  225. static inline kern_return_t LMStartService(name_t serverName, CFRunLoopRef runLoop, CFMachPortCallBack callback)
  226. {
  227. return LMStartServiceWithUserInfo(serverName, runLoop, callback, NULL);
  228. }
  229. static inline kern_return_t LMCheckInService(name_t serverName, CFRunLoopRef runLoop, CFMachPortCallBack callback, void *userInfo)
  230. {
  231. // TODO: Figure out what the real interface is, implement service stopping, handle failures correctly
  232. mach_port_t bootstrap = MACH_PORT_NULL;
  233. task_get_bootstrap_port(mach_task_self(), &bootstrap);
  234. CFMachPortContext context = { 0, userInfo, NULL, NULL, NULL };
  235. mach_port_t port = MACH_PORT_NULL;
  236. kern_return_t result = bootstrap_check_in(bootstrap, serverName, &port);
  237. if (result)
  238. return result;
  239. CFMachPortRef machPort = CFMachPortCreateWithPort(kCFAllocatorDefault, port, callback, &context, NULL);
  240. CFRunLoopSourceRef machPortSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, machPort, 0);
  241. CFRunLoopAddSource(runLoop, machPortSource, kCFRunLoopCommonModes);
  242. #if LIGHTMESSAGING_USE_ROCKETBOOTSTRAP
  243. rocketbootstrap_unlock(serverName);
  244. #endif
  245. return 0;
  246. }
  247. static inline bool LMDataWithSizeIsValidMessage(const void *data, CFIndex size)
  248. {
  249. if (size < sizeof(mach_msg_header_t) + sizeof(mach_msg_body_t))
  250. return false;
  251. const LMMessage *message = (const LMMessage *)data;
  252. if (message->body.msgh_descriptor_count)
  253. return size >= sizeof(mach_msg_header_t) + sizeof(mach_msg_body_t) + sizeof(mach_msg_ool_descriptor_t);
  254. if (size < sizeof(mach_msg_header_t) + sizeof(mach_msg_body_t) + sizeof(uint32_t))
  255. return false;
  256. if (size < sizeof(mach_msg_header_t) + sizeof(mach_msg_body_t) + sizeof(uint32_t) + message->data.in_line.length)
  257. return false;
  258. return true;
  259. }
  260. static inline kern_return_t LMSendReply(mach_port_t replyPort, const void *data, uint32_t length)
  261. {
  262. if (replyPort == MACH_PORT_NULL)
  263. return 0;
  264. uint32_t size = LMBufferSizeForLength(length);
  265. uint8_t buffer[size];
  266. memset(buffer, 0, sizeof(LMMessage));
  267. LMMessage *response = (LMMessage *)&buffer[0];
  268. response->head.msgh_id = 0;
  269. response->head.msgh_size = size;
  270. response->head.msgh_remote_port = replyPort;
  271. response->head.msgh_local_port = MACH_PORT_NULL;
  272. response->head.msgh_reserved = 0;
  273. response->head.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE, 0);
  274. LMMessageAssignData(response, data, length);
  275. // Send message
  276. kern_return_t err = mach_msg(&response->head, MACH_SEND_MSG, size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
  277. if (err) {
  278. // Cleanup leaked SEND_ONCE
  279. mach_port_mod_refs(mach_task_self(), replyPort, MACH_PORT_RIGHT_SEND_ONCE, -1);
  280. }
  281. return err;
  282. }
  283. static inline kern_return_t LMSendIntegerReply(mach_port_t replyPort, int integer)
  284. {
  285. return LMSendReply(replyPort, &integer, sizeof(integer));
  286. }
  287. static inline kern_return_t LMSendCFDataReply(mach_port_t replyPort, CFDataRef data)
  288. {
  289. if (data) {
  290. return LMSendReply(replyPort, CFDataGetBytePtr(data), CFDataGetLength(data));
  291. } else {
  292. return LMSendReply(replyPort, NULL, 0);
  293. }
  294. }
  295. #ifdef __OBJC__
  296. #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
  297. static inline id LMPropertyListForData(NSData *data)
  298. {
  299. if ([NSPropertyListSerialization respondsToSelector:@selector(propertyListWithData:options:format:error:)])
  300. return [NSPropertyListSerialization propertyListWithData:data options:0 format:NULL error:NULL];
  301. return [NSPropertyListSerialization propertyListFromData:data mutabilityOption:0 format:NULL errorDescription:NULL];
  302. }
  303. static inline NSData *LMDataForPropertyList(id propertyList)
  304. {
  305. if ([NSPropertyListSerialization respondsToSelector:@selector(dataWithPropertyList:options:format:error:)])
  306. return [NSPropertyListSerialization dataWithPropertyList:propertyList format:NSPropertyListBinaryFormat_v1_0 options:0 error:NULL];
  307. return [NSPropertyListSerialization dataFromPropertyList:propertyList format:NSPropertyListBinaryFormat_v1_0 errorDescription:NULL];
  308. }
  309. #pragma GCC diagnostic warning "-Wdeprecated-declarations"
  310. static inline kern_return_t LMSendNSDataReply(mach_port_t replyPort, NSData *data)
  311. {
  312. return LMSendReply(replyPort, [data bytes], [data length]);
  313. }
  314. static inline kern_return_t LMSendPropertyListReply(mach_port_t replyPort, id propertyList)
  315. {
  316. if (propertyList)
  317. return LMSendNSDataReply(replyPort, LMDataForPropertyList(propertyList));
  318. else
  319. return LMSendReply(replyPort, NULL, 0);
  320. }
  321. #endif
  322. // Remote functions
  323. static inline bool LMConnectionSendOneWayData(LMConnectionRef connection, SInt32 messageId, CFDataRef data)
  324. {
  325. if (data)
  326. return LMConnectionSendOneWay(connection, messageId, CFDataGetBytePtr(data), CFDataGetLength(data)) == 0;
  327. else
  328. return LMConnectionSendOneWay(connection, messageId, NULL, 0) == 0;
  329. }
  330. static inline kern_return_t LMConnectionSendTwoWayData(LMConnectionRef connection, SInt32 messageId, CFDataRef data, LMResponseBuffer *buffer)
  331. {
  332. if (data)
  333. return LMConnectionSendTwoWay(connection, messageId, CFDataGetBytePtr(data), CFDataGetLength(data), buffer);
  334. else
  335. return LMConnectionSendTwoWay(connection, messageId, NULL, 0, buffer);
  336. }
  337. static inline int32_t LMResponseConsumeInteger(LMResponseBuffer *buffer)
  338. {
  339. int32_t result = LMMessageGetDataLength(&buffer->message) == sizeof(int32_t) ? *(int32_t *)buffer->message.data.in_line.bytes : 0;
  340. LMResponseBufferFree(buffer);
  341. return result;
  342. }
  343. #ifdef __OBJC__
  344. static inline kern_return_t LMConnectionSendTwoWayPropertyList(LMConnectionRef connection, SInt32 messageId, id propertyList, LMResponseBuffer *buffer)
  345. {
  346. return LMConnectionSendTwoWayData(connection, messageId, propertyList ? LMBridgedCast_(CFDataRef, LMDataForPropertyList(propertyList)) : NULL, buffer);
  347. }
  348. static inline id LMResponseConsumePropertyList(LMResponseBuffer *buffer)
  349. {
  350. uint32_t length = LMMessageGetDataLength(&buffer->message);
  351. id result;
  352. if (length) {
  353. CFDataRef data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (const UInt8 *)LMMessageGetData(&buffer->message), length, kCFAllocatorNull);
  354. result = LMPropertyListForData(LMBridgedCast_(NSData *, data));
  355. CFRelease(data);
  356. } else {
  357. result = nil;
  358. }
  359. LMResponseBufferFree(buffer);
  360. return result;
  361. }
  362. #ifdef UIKIT_EXTERN
  363. #import <UIKit/UIImage.h>
  364. typedef struct __attribute__((aligned(0x1))) __attribute__((packed)) {
  365. uint32_t width;
  366. uint32_t height;
  367. uint32_t bitsPerComponent;
  368. uint32_t bitsPerPixel;
  369. uint32_t bytesPerRow;
  370. CGBitmapInfo bitmapInfo;
  371. float scale;
  372. UIImageOrientation orientation;
  373. } LMImageHeader;
  374. typedef struct {
  375. LMMessage response;
  376. LMImageHeader imageHeader;
  377. } LMImageMessage;
  378. static void LMCGDataProviderReleaseCallback(void *info, const void *data, size_t size)
  379. {
  380. vm_deallocate(mach_task_self(), (vm_address_t)data, size);
  381. }
  382. static inline UIImage *LMResponseConsumeImage(LMResponseBuffer *buffer)
  383. {
  384. if (buffer->message.body.msgh_descriptor_count != 0 && buffer->message.data.out_of_line.descriptor.type == MACH_MSG_OOL_DESCRIPTOR) {
  385. const void *bytes = buffer->message.data.out_of_line.descriptor.address;
  386. const LMImageMessage *message = (const LMImageMessage *)buffer;
  387. const LMImageHeader *header = &message->imageHeader;
  388. CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, bytes, buffer->message.data.out_of_line.descriptor.size, LMCGDataProviderReleaseCallback);
  389. if (provider) {
  390. CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
  391. CGImageRef cgImage = CGImageCreate(header->width, header->height, header->bitsPerComponent, header->bitsPerPixel, header->bytesPerRow, colorSpace, header->bitmapInfo, provider, NULL, false, kCGRenderingIntentDefault);
  392. CGColorSpaceRelease(colorSpace);
  393. CGDataProviderRelease(provider);
  394. if (cgImage) {
  395. UIImage *image;
  396. if ([UIImage respondsToSelector:@selector(imageWithCGImage:scale:orientation:)]) {
  397. image = [UIImage imageWithCGImage:cgImage scale:header->scale orientation:header->orientation];
  398. } else {
  399. image = [UIImage imageWithCGImage:cgImage];
  400. }
  401. CGImageRelease(cgImage);
  402. return image;
  403. }
  404. return nil;
  405. }
  406. }
  407. LMResponseBufferFree(buffer);
  408. return nil;
  409. }
  410. typedef struct CGAccessSession *CGAccessSessionRef;
  411. CGAccessSessionRef CGAccessSessionCreate(CGDataProviderRef provider);
  412. void *CGAccessSessionGetBytePointer(CGAccessSessionRef session);
  413. size_t CGAccessSessionGetBytes(CGAccessSessionRef session,void *buffer,size_t bytes);
  414. void CGAccessSessionRelease(CGAccessSessionRef session);
  415. static inline kern_return_t LMSendImageReply(mach_port_t replyPort, UIImage *image)
  416. {
  417. if (replyPort == MACH_PORT_NULL)
  418. return 0;
  419. LMImageMessage buffer;
  420. memset(&buffer, 0, sizeof(buffer));
  421. buffer.response.head.msgh_id = 0;
  422. buffer.response.head.msgh_size = sizeof(buffer);
  423. buffer.response.head.msgh_remote_port = replyPort;
  424. buffer.response.head.msgh_local_port = MACH_PORT_NULL;
  425. buffer.response.head.msgh_reserved = 0;
  426. buffer.response.head.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE, 0);
  427. CFDataRef imageData = NULL;
  428. CGAccessSessionRef accessSession = NULL;
  429. if (image) {
  430. CGImageRef cgImage = image.CGImage;
  431. if (cgImage) {
  432. buffer.imageHeader.width = CGImageGetWidth(cgImage);
  433. buffer.imageHeader.height = CGImageGetHeight(cgImage);
  434. buffer.imageHeader.bitsPerComponent = CGImageGetBitsPerComponent(cgImage);
  435. buffer.imageHeader.bitsPerPixel = CGImageGetBitsPerPixel(cgImage);
  436. buffer.imageHeader.bytesPerRow = CGImageGetBytesPerRow(cgImage);
  437. buffer.imageHeader.bitmapInfo = CGImageGetBitmapInfo(cgImage);
  438. buffer.imageHeader.scale = [image respondsToSelector:@selector(scale)] ? [image scale] : 1.0f;
  439. buffer.imageHeader.orientation = image.imageOrientation;
  440. CGDataProviderRef dataProvider = CGImageGetDataProvider(cgImage);
  441. bool hasLoadedData = false;
  442. if (&CGAccessSessionCreate != NULL) {
  443. accessSession = CGAccessSessionCreate(dataProvider);
  444. if (accessSession) {
  445. void *pointer = CGAccessSessionGetBytePointer(accessSession);
  446. if (pointer) {
  447. LMMessageAssignOutOfLine(&buffer.response, pointer, buffer.imageHeader.bytesPerRow * buffer.imageHeader.height);
  448. hasLoadedData = true;
  449. }
  450. }
  451. }
  452. if (!hasLoadedData) {
  453. if (accessSession) {
  454. CGAccessSessionRelease(accessSession);
  455. accessSession = NULL;
  456. }
  457. imageData = CGDataProviderCopyData(dataProvider);
  458. if (imageData) {
  459. LMMessageAssignOutOfLine(&buffer.response, CFDataGetBytePtr(imageData), CFDataGetLength(imageData));
  460. }
  461. }
  462. }
  463. }
  464. // Send message
  465. kern_return_t err = mach_msg(&buffer.response.head, MACH_SEND_MSG, sizeof(buffer), 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
  466. if (err) {
  467. // Cleanup leaked SEND_ONCE
  468. mach_port_mod_refs(mach_task_self(), replyPort, MACH_PORT_RIGHT_SEND_ONCE, -1);
  469. }
  470. if (imageData) {
  471. CFRelease(imageData);
  472. }
  473. if (accessSession) {
  474. CGAccessSessionRelease(accessSession);
  475. }
  476. return err;
  477. }
  478. #endif
  479. #endif