1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 % %
4 % %
5 % DDDD IIIII SSSSS TTTTT RRRR IIIII BBBB U U TTTTT EEEEE %
6 % D D I SS T R R I B B U U T E %
7 % D D I SSS T RRRR I BBBB U U T EEE %
8 % D D I SS T R R I B B U U T E %
9 % DDDDA IIIII SSSSS T R R IIIII BBBB UUU T EEEEE %
10 % %
11 % CCCC AAA CCCC H H EEEEE %
12 % C A A C H H E %
13 % C AAAAA C HHHHH EEE %
14 % C A A C H H E %
15 % CCCC A A CCCC H H EEEEE %
16 % %
17 % %
18 % MagickCore Distributed Pixel Cache Methods %
19 % %
20 % Software Design %
21 % Cristy %
22 % January 2013 %
23 % %
24 % %
25 % Copyright 1999-2021 ImageMagick Studio LLC, a non-profit organization %
26 % dedicated to making software imaging solutions freely available. %
27 % %
28 % You may not use this file except in compliance with the License. You may %
29 % obtain a copy of the License at %
30 % %
31 % https://imagemagick.org/script/license.php %
32 % %
33 % Unless required by applicable law or agreed to in writing, software %
34 % distributed under the License is distributed on an "AS IS" BASIS, %
35 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
36 % See the License for the specific language governing permissions and %
37 % limitations under the License. %
38 % %
39 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
40 %
41 % A distributed pixel cache is an extension of the traditional pixel cache
42 % available on a single host. The distributed pixel cache may span multiple
43 % servers so that it can grow in size and transactional capacity to support
44 % very large images. Start up the pixel cache server on one or more machines.
45 % When you read or operate on an image and the local pixel cache resources are
46 % exhausted, ImageMagick contacts one or more of these remote pixel servers to
47 % store or retrieve pixels.
48 %
49 */
50
51 /*
52 Include declarations.
53 */
54 #include "MagickCore/studio.h"
55 #include "MagickCore/cache.h"
56 #include "MagickCore/cache-private.h"
57 #include "MagickCore/distribute-cache.h"
58 #include "MagickCore/distribute-cache-private.h"
59 #include "MagickCore/exception.h"
60 #include "MagickCore/exception-private.h"
61 #include "MagickCore/geometry.h"
62 #include "MagickCore/image.h"
63 #include "MagickCore/image-private.h"
64 #include "MagickCore/list.h"
65 #include "MagickCore/locale_.h"
66 #include "MagickCore/memory_.h"
67 #include "MagickCore/nt-base-private.h"
68 #include "MagickCore/pixel.h"
69 #include "MagickCore/policy.h"
70 #include "MagickCore/random_.h"
71 #include "MagickCore/registry.h"
72 #include "MagickCore/splay-tree.h"
73 #include "MagickCore/string_.h"
74 #include "MagickCore/string-private.h"
75 #include "MagickCore/version.h"
76 #include "MagickCore/version-private.h"
77 #undef MAGICKCORE_HAVE_DISTRIBUTE_CACHE
78 #if defined(MAGICKCORE_HAVE_SOCKET) && defined(MAGICKCORE_THREAD_SUPPORT)
79 #include <netinet/in.h>
80 #include <netdb.h>
81 #include <sys/socket.h>
82 #include <arpa/inet.h>
83 #define CHAR_TYPE_CAST
84 #define CLOSE_SOCKET(socket) (void) close(socket)
85 #define HANDLER_RETURN_TYPE void *
86 #define HANDLER_RETURN_VALUE (void *) NULL
87 #define SOCKET_TYPE int
88 #define LENGTH_TYPE size_t
89 #define MAGICKCORE_HAVE_DISTRIBUTE_CACHE 1
90 #elif defined(MAGICKCORE_WINDOWS_SUPPORT) && !defined(__MINGW32__)
91 #define CHAR_TYPE_CAST (char *)
92 #define CLOSE_SOCKET(socket) (void) closesocket(socket)
93 #define HANDLER_RETURN_TYPE DWORD WINAPI
94 #define HANDLER_RETURN_VALUE 0
95 #define SOCKET_TYPE SOCKET
96 #define LENGTH_TYPE int
97 #define MAGICKCORE_HAVE_DISTRIBUTE_CACHE 1
98 #else
99 #ifdef __VMS
100 #define CLOSE_SOCKET(socket) (void) close(socket)
101 #else
102 #define CLOSE_SOCKET(socket)
103 #endif
104 #define HANDLER_RETURN_TYPE void *
105 #define HANDLER_RETURN_VALUE (void *) NULL
106 #define SOCKET_TYPE int
107 #undef send
108 #undef recv
109 #define send(file,buffer,length,flags) 0
110 #define recv(file,buffer,length,flags) 0
111 #endif
112
113 /*
114 Define declarations.
115 */
116 #define DPCHostname "127.0.0.1"
117 #define DPCPendingConnections 10
118 #define DPCPort 6668
119 #define DPCSessionKeyLength 8
120 #ifndef MSG_NOSIGNAL
121 # define MSG_NOSIGNAL 0
122 #endif
123
124 /*
125 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
126 % %
127 % %
128 % %
129 + A c q u i r e D i s t r i b u t e C a c h e I n f o %
130 % %
131 % %
132 % %
133 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
134 %
135 % AcquireDistributeCacheInfo() allocates the DistributeCacheInfo structure.
136 %
137 % The format of the AcquireDistributeCacheInfo method is:
138 %
139 % DistributeCacheInfo *AcquireDistributeCacheInfo(ExceptionInfo *exception)
140 %
141 % A description of each parameter follows:
142 %
143 % o exception: return any errors or warnings in this structure.
144 %
145 */
146
dpc_read(int file,const MagickSizeType length,unsigned char * magick_restrict message)147 static inline MagickOffsetType dpc_read(int file,const MagickSizeType length,
148 unsigned char *magick_restrict message)
149 {
150 MagickOffsetType
151 i;
152
153 ssize_t
154 count;
155
156 #if !MAGICKCORE_HAVE_DISTRIBUTE_CACHE
157 magick_unreferenced(file);
158 magick_unreferenced(message);
159 #endif
160 count=0;
161 for (i=0; i < (MagickOffsetType) length; i+=count)
162 {
163 count=recv(file,CHAR_TYPE_CAST message+i,(LENGTH_TYPE) MagickMin(length-i,
164 (MagickSizeType) MAGICK_SSIZE_MAX),0);
165 if (count <= 0)
166 {
167 count=0;
168 if (errno != EINTR)
169 break;
170 }
171 }
172 return(i);
173 }
174
ConnectPixelCacheServer(const char * hostname,const int port,size_t * session_key,ExceptionInfo * exception)175 static int ConnectPixelCacheServer(const char *hostname,const int port,
176 size_t *session_key,ExceptionInfo *exception)
177 {
178 #if MAGICKCORE_HAVE_DISTRIBUTE_CACHE
179 char
180 service[MagickPathExtent],
181 *shared_secret;
182
183 int
184 status;
185
186 SOCKET_TYPE
187 client_socket;
188
189 ssize_t
190 count;
191
192 struct addrinfo
193 hint,
194 *result;
195
196 unsigned char
197 secret[MagickPathExtent];
198
199 /*
200 Connect to distributed pixel cache and get session key.
201 */
202 *session_key=0;
203 shared_secret=GetPolicyValue("cache:shared-secret");
204 if (shared_secret == (char *) NULL)
205 {
206 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
207 "DistributedPixelCache","'%s'","shared secret expected");
208 return(-1);
209 }
210 shared_secret=DestroyString(shared_secret);
211 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
212 NTInitializeWinsock(MagickTrue);
213 #endif
214 (void) memset(&hint,0,sizeof(hint));
215 hint.ai_family=AF_INET;
216 hint.ai_socktype=SOCK_STREAM;
217 hint.ai_flags=AI_PASSIVE;
218 (void) FormatLocaleString(service,MagickPathExtent,"%d",port);
219 status=getaddrinfo(hostname,service,&hint,&result);
220 if (status != 0)
221 {
222 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
223 "DistributedPixelCache","'%s'",hostname);
224 return(-1);
225 }
226 client_socket=socket(result->ai_family,result->ai_socktype,
227 result->ai_protocol);
228 if (client_socket == -1)
229 {
230 freeaddrinfo(result);
231 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
232 "DistributedPixelCache","'%s'",hostname);
233 return(-1);
234 }
235 status=connect(client_socket,result->ai_addr,(socklen_t) result->ai_addrlen);
236 if (status == -1)
237 {
238 CLOSE_SOCKET(client_socket);
239 freeaddrinfo(result);
240 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
241 "DistributedPixelCache","'%s'",hostname);
242 return(-1);
243 }
244 count=recv(client_socket,CHAR_TYPE_CAST secret,MagickPathExtent,0);
245 if (count != -1)
246 {
247 StringInfo
248 *nonce;
249
250 nonce=AcquireStringInfo((size_t) count);
251 (void) memcpy(GetStringInfoDatum(nonce),secret,(size_t) count);
252 *session_key=GetMagickSignature(nonce);
253 nonce=DestroyStringInfo(nonce);
254 }
255 if (*session_key == 0)
256 {
257 CLOSE_SOCKET(client_socket);
258 client_socket=(SOCKET_TYPE) (-1);
259 }
260 freeaddrinfo(result);
261 return(client_socket);
262 #else
263 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
264 "DelegateLibrarySupportNotBuiltIn","distributed pixel cache");
265 return(MagickFalse);
266 #endif
267 }
268
GetHostname(int * port,ExceptionInfo * exception)269 static char *GetHostname(int *port,ExceptionInfo *exception)
270 {
271 char
272 *host,
273 *hosts,
274 **hostlist;
275
276 int
277 argc;
278
279 ssize_t
280 i;
281
282 static size_t
283 id = 0;
284
285 /*
286 Parse host list (e.g. 192.168.100.1:6668,192.168.100.2:6668).
287 */
288 hosts=(char *) GetImageRegistry(StringRegistryType,"cache:hosts",exception);
289 if (hosts == (char *) NULL)
290 {
291 *port=DPCPort;
292 return(AcquireString(DPCHostname));
293 }
294 (void) SubstituteString(&hosts,","," ");
295 hostlist=StringToArgv(hosts,&argc);
296 hosts=DestroyString(hosts);
297 if (hostlist == (char **) NULL)
298 {
299 *port=DPCPort;
300 return(AcquireString(DPCHostname));
301 }
302 hosts=AcquireString(hostlist[(id++ % (argc-1))+1]);
303 for (i=0; i < (ssize_t) argc; i++)
304 hostlist[i]=DestroyString(hostlist[i]);
305 hostlist=(char **) RelinquishMagickMemory(hostlist);
306 (void) SubstituteString(&hosts,":"," ");
307 hostlist=StringToArgv(hosts,&argc);
308 if (hostlist == (char **) NULL)
309 {
310 *port=DPCPort;
311 return(AcquireString(DPCHostname));
312 }
313 host=AcquireString(hostlist[1]);
314 if (hostlist[2] == (char *) NULL)
315 *port=DPCPort;
316 else
317 *port=StringToLong(hostlist[2]);
318 for (i=0; i < (ssize_t) argc; i++)
319 hostlist[i]=DestroyString(hostlist[i]);
320 hostlist=(char **) RelinquishMagickMemory(hostlist);
321 return(host);
322 }
323
AcquireDistributeCacheInfo(ExceptionInfo * exception)324 MagickPrivate DistributeCacheInfo *AcquireDistributeCacheInfo(
325 ExceptionInfo *exception)
326 {
327 char
328 *hostname;
329
330 DistributeCacheInfo
331 *server_info;
332
333 size_t
334 session_key;
335
336 /*
337 Connect to the distributed pixel cache server.
338 */
339 server_info=(DistributeCacheInfo *) AcquireCriticalMemory(
340 sizeof(*server_info));
341 (void) memset(server_info,0,sizeof(*server_info));
342 server_info->signature=MagickCoreSignature;
343 server_info->port=0;
344 hostname=GetHostname(&server_info->port,exception);
345 session_key=0;
346 server_info->file=ConnectPixelCacheServer(hostname,server_info->port,
347 &session_key,exception);
348 if (server_info->file == -1)
349 server_info=DestroyDistributeCacheInfo(server_info);
350 else
351 {
352 server_info->session_key=session_key;
353 (void) CopyMagickString(server_info->hostname,hostname,MagickPathExtent);
354 server_info->debug=IsEventLogging();
355 }
356 hostname=DestroyString(hostname);
357 return(server_info);
358 }
359
360 /*
361 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
362 % %
363 % %
364 % %
365 + D e s t r o y D i s t r i b u t e C a c h e I n f o %
366 % %
367 % %
368 % %
369 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
370 %
371 % DestroyDistributeCacheInfo() deallocates memory associated with an
372 % DistributeCacheInfo structure.
373 %
374 % The format of the DestroyDistributeCacheInfo method is:
375 %
376 % DistributeCacheInfo *DestroyDistributeCacheInfo(
377 % DistributeCacheInfo *server_info)
378 %
379 % A description of each parameter follows:
380 %
381 % o server_info: the distributed cache info.
382 %
383 */
DestroyDistributeCacheInfo(DistributeCacheInfo * server_info)384 MagickPrivate DistributeCacheInfo *DestroyDistributeCacheInfo(
385 DistributeCacheInfo *server_info)
386 {
387 assert(server_info != (DistributeCacheInfo *) NULL);
388 assert(server_info->signature == MagickCoreSignature);
389 if (server_info->file > 0)
390 CLOSE_SOCKET(server_info->file);
391 server_info->signature=(~MagickCoreSignature);
392 server_info=(DistributeCacheInfo *) RelinquishMagickMemory(server_info);
393 return(server_info);
394 }
395
396 /*
397 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
398 % %
399 % %
400 % %
401 + D i s t r i b u t e P i x e l C a c h e S e r v e r %
402 % %
403 % %
404 % %
405 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
406 %
407 % DistributePixelCacheServer() waits on the specified port for commands to
408 % create, read, update, or destroy a pixel cache.
409 %
410 % The format of the DistributePixelCacheServer() method is:
411 %
412 % void DistributePixelCacheServer(const int port)
413 %
414 % A description of each parameter follows:
415 %
416 % o port: connect the distributed pixel cache at this port.
417 %
418 % o exception: return any errors or warnings in this structure.
419 %
420 */
421
dpc_send(int file,const MagickSizeType length,const unsigned char * magick_restrict message)422 static inline MagickOffsetType dpc_send(int file,const MagickSizeType length,
423 const unsigned char *magick_restrict message)
424 {
425 MagickOffsetType
426 count,
427 i;
428
429 #if !MAGICKCORE_HAVE_DISTRIBUTE_CACHE
430 magick_unreferenced(file);
431 magick_unreferenced(message);
432 #endif
433
434 /*
435 Ensure a complete message is sent.
436 */
437 count=0;
438 for (i=0; i < (MagickOffsetType) length; i+=count)
439 {
440 count=(MagickOffsetType) send(file,CHAR_TYPE_CAST message+i,(LENGTH_TYPE)
441 MagickMin(length-i,(MagickSizeType) MAGICK_SSIZE_MAX),MSG_NOSIGNAL);
442 if (count <= 0)
443 {
444 count=0;
445 if (errno != EINTR)
446 break;
447 }
448 }
449 return(i);
450 }
451
452 #if !MAGICKCORE_HAVE_DISTRIBUTE_CACHE
DistributePixelCacheServer(const int port,ExceptionInfo * Exception)453 MagickExport void DistributePixelCacheServer(const int port,
454 ExceptionInfo *Exception)
455 {
456 magick_unreferenced(port);
457 ThrowFatalException(MissingDelegateError,"DelegateLibrarySupportNotBuiltIn");
458 }
459 #else
DestroyDistributeCache(SplayTreeInfo * registry,const size_t session_key)460 static MagickBooleanType DestroyDistributeCache(SplayTreeInfo *registry,
461 const size_t session_key)
462 {
463 /*
464 Destroy distributed pixel cache.
465 */
466 return(DeleteNodeFromSplayTree(registry,(const void *) session_key));
467 }
468
OpenDistributeCache(SplayTreeInfo * registry,int file,const size_t session_key,ExceptionInfo * exception)469 static MagickBooleanType OpenDistributeCache(SplayTreeInfo *registry,int file,
470 const size_t session_key,ExceptionInfo *exception)
471 {
472 Image
473 *image;
474
475 MagickBooleanType
476 status;
477
478 MagickOffsetType
479 count;
480
481 MagickSizeType
482 length;
483
484 unsigned char
485 message[MagickPathExtent],
486 *p;
487
488 /*
489 Open distributed pixel cache.
490 */
491 image=AcquireImage((ImageInfo *) NULL,exception);
492 if (image == (Image *) NULL)
493 return(MagickFalse);
494 length=sizeof(image->storage_class)+sizeof(image->colorspace)+
495 sizeof(image->alpha_trait)+sizeof(image->channels)+sizeof(image->columns)+
496 sizeof(image->rows)+sizeof(image->number_channels)+MaxPixelChannels*
497 sizeof(*image->channel_map)+sizeof(image->metacontent_extent);
498 count=dpc_read(file,length,message);
499 if (count != (MagickOffsetType) length)
500 return(MagickFalse);
501 /*
502 Deserialize the image attributes.
503 */
504 p=message;
505 (void) memcpy(&image->storage_class,p,sizeof(image->storage_class));
506 p+=sizeof(image->storage_class);
507 (void) memcpy(&image->colorspace,p,sizeof(image->colorspace));
508 p+=sizeof(image->colorspace);
509 (void) memcpy(&image->alpha_trait,p,sizeof(image->alpha_trait));
510 p+=sizeof(image->alpha_trait);
511 (void) memcpy(&image->channels,p,sizeof(image->channels));
512 p+=sizeof(image->channels);
513 (void) memcpy(&image->columns,p,sizeof(image->columns));
514 p+=sizeof(image->columns);
515 (void) memcpy(&image->rows,p,sizeof(image->rows));
516 p+=sizeof(image->rows);
517 (void) memcpy(&image->number_channels,p,sizeof(image->number_channels));
518 p+=sizeof(image->number_channels);
519 (void) memcpy(image->channel_map,p,MaxPixelChannels*
520 sizeof(*image->channel_map));
521 p+=MaxPixelChannels*sizeof(*image->channel_map);
522 (void) memcpy(&image->metacontent_extent,p,sizeof(image->metacontent_extent));
523 p+=sizeof(image->metacontent_extent);
524 if (SyncImagePixelCache(image,exception) == MagickFalse)
525 return(MagickFalse);
526 status=AddValueToSplayTree(registry,(const void *) session_key,image);
527 return(status);
528 }
529
ReadDistributeCacheMetacontent(SplayTreeInfo * registry,int file,const size_t session_key,ExceptionInfo * exception)530 static MagickBooleanType ReadDistributeCacheMetacontent(SplayTreeInfo *registry,
531 int file,const size_t session_key,ExceptionInfo *exception)
532 {
533 const Quantum
534 *p;
535
536 const unsigned char
537 *metacontent;
538
539 Image
540 *image;
541
542 MagickOffsetType
543 count;
544
545 MagickSizeType
546 length;
547
548 RectangleInfo
549 region;
550
551 unsigned char
552 message[MagickPathExtent],
553 *q;
554
555 /*
556 Read distributed pixel cache metacontent.
557 */
558 image=(Image *) GetValueFromSplayTree(registry,(const void *) session_key);
559 if (image == (Image *) NULL)
560 return(MagickFalse);
561 length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
562 sizeof(region.y)+sizeof(length);
563 count=dpc_read(file,length,message);
564 if (count != (MagickOffsetType) length)
565 return(MagickFalse);
566 q=message;
567 (void) memcpy(®ion.width,q,sizeof(region.width));
568 q+=sizeof(region.width);
569 (void) memcpy(®ion.height,q,sizeof(region.height));
570 q+=sizeof(region.height);
571 (void) memcpy(®ion.x,q,sizeof(region.x));
572 q+=sizeof(region.x);
573 (void) memcpy(®ion.y,q,sizeof(region.y));
574 q+=sizeof(region.y);
575 (void) memcpy(&length,q,sizeof(length));
576 q+=sizeof(length);
577 p=GetVirtualPixels(image,region.x,region.y,region.width,region.height,
578 exception);
579 if (p == (const Quantum *) NULL)
580 return(MagickFalse);
581 metacontent=(const unsigned char *) GetVirtualMetacontent(image);
582 count=dpc_send(file,length,metacontent);
583 if (count != (MagickOffsetType) length)
584 return(MagickFalse);
585 return(MagickTrue);
586 }
587
ReadDistributeCachePixels(SplayTreeInfo * registry,int file,const size_t session_key,ExceptionInfo * exception)588 static MagickBooleanType ReadDistributeCachePixels(SplayTreeInfo *registry,
589 int file,const size_t session_key,ExceptionInfo *exception)
590 {
591 const Quantum
592 *p;
593
594 Image
595 *image;
596
597 MagickOffsetType
598 count;
599
600 MagickSizeType
601 length;
602
603 RectangleInfo
604 region;
605
606 unsigned char
607 message[MagickPathExtent],
608 *q;
609
610 /*
611 Read distributed pixel cache pixels.
612 */
613 image=(Image *) GetValueFromSplayTree(registry,(const void *) session_key);
614 if (image == (Image *) NULL)
615 return(MagickFalse);
616 length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
617 sizeof(region.y)+sizeof(length);
618 count=dpc_read(file,length,message);
619 if (count != (MagickOffsetType) length)
620 return(MagickFalse);
621 q=message;
622 (void) memcpy(®ion.width,q,sizeof(region.width));
623 q+=sizeof(region.width);
624 (void) memcpy(®ion.height,q,sizeof(region.height));
625 q+=sizeof(region.height);
626 (void) memcpy(®ion.x,q,sizeof(region.x));
627 q+=sizeof(region.x);
628 (void) memcpy(®ion.y,q,sizeof(region.y));
629 q+=sizeof(region.y);
630 (void) memcpy(&length,q,sizeof(length));
631 q+=sizeof(length);
632 p=GetVirtualPixels(image,region.x,region.y,region.width,region.height,
633 exception);
634 if (p == (const Quantum *) NULL)
635 return(MagickFalse);
636 count=dpc_send(file,length,(unsigned char *) p);
637 if (count != (MagickOffsetType) length)
638 return(MagickFalse);
639 return(MagickTrue);
640 }
641
RelinquishImageRegistry(void * image)642 static void *RelinquishImageRegistry(void *image)
643 {
644 return((void *) DestroyImageList((Image *) image));
645 }
646
WriteDistributeCacheMetacontent(SplayTreeInfo * registry,int file,const size_t session_key,ExceptionInfo * exception)647 static MagickBooleanType WriteDistributeCacheMetacontent(
648 SplayTreeInfo *registry,int file,const size_t session_key,
649 ExceptionInfo *exception)
650 {
651 Image
652 *image;
653
654 MagickOffsetType
655 count;
656
657 MagickSizeType
658 length;
659
660 Quantum
661 *q;
662
663 RectangleInfo
664 region;
665
666 unsigned char
667 message[MagickPathExtent],
668 *metacontent,
669 *p;
670
671 /*
672 Write distributed pixel cache metacontent.
673 */
674 image=(Image *) GetValueFromSplayTree(registry,(const void *) session_key);
675 if (image == (Image *) NULL)
676 return(MagickFalse);
677 length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
678 sizeof(region.y)+sizeof(length);
679 count=dpc_read(file,length,message);
680 if (count != (MagickOffsetType) length)
681 return(MagickFalse);
682 p=message;
683 (void) memcpy(®ion.width,p,sizeof(region.width));
684 p+=sizeof(region.width);
685 (void) memcpy(®ion.height,p,sizeof(region.height));
686 p+=sizeof(region.height);
687 (void) memcpy(®ion.x,p,sizeof(region.x));
688 p+=sizeof(region.x);
689 (void) memcpy(®ion.y,p,sizeof(region.y));
690 p+=sizeof(region.y);
691 (void) memcpy(&length,p,sizeof(length));
692 p+=sizeof(length);
693 q=GetAuthenticPixels(image,region.x,region.y,region.width,region.height,
694 exception);
695 if (q == (Quantum *) NULL)
696 return(MagickFalse);
697 metacontent=(unsigned char *) GetAuthenticMetacontent(image);
698 count=dpc_read(file,length,metacontent);
699 if (count != (MagickOffsetType) length)
700 return(MagickFalse);
701 return(SyncAuthenticPixels(image,exception));
702 }
703
WriteDistributeCachePixels(SplayTreeInfo * registry,int file,const size_t session_key,ExceptionInfo * exception)704 static MagickBooleanType WriteDistributeCachePixels(SplayTreeInfo *registry,
705 int file,const size_t session_key,ExceptionInfo *exception)
706 {
707 Image
708 *image;
709
710 MagickOffsetType
711 count;
712
713 MagickSizeType
714 length;
715
716 Quantum
717 *q;
718
719 RectangleInfo
720 region;
721
722 unsigned char
723 message[MagickPathExtent],
724 *p;
725
726 /*
727 Write distributed pixel cache pixels.
728 */
729 image=(Image *) GetValueFromSplayTree(registry,(const void *) session_key);
730 if (image == (Image *) NULL)
731 return(MagickFalse);
732 length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
733 sizeof(region.y)+sizeof(length);
734 count=dpc_read(file,length,message);
735 if (count != (MagickOffsetType) length)
736 return(MagickFalse);
737 p=message;
738 (void) memcpy(®ion.width,p,sizeof(region.width));
739 p+=sizeof(region.width);
740 (void) memcpy(®ion.height,p,sizeof(region.height));
741 p+=sizeof(region.height);
742 (void) memcpy(®ion.x,p,sizeof(region.x));
743 p+=sizeof(region.x);
744 (void) memcpy(®ion.y,p,sizeof(region.y));
745 p+=sizeof(region.y);
746 (void) memcpy(&length,p,sizeof(length));
747 p+=sizeof(length);
748 q=GetAuthenticPixels(image,region.x,region.y,region.width,region.height,
749 exception);
750 if (q == (Quantum *) NULL)
751 return(MagickFalse);
752 count=dpc_read(file,length,(unsigned char *) q);
753 if (count != (MagickOffsetType) length)
754 return(MagickFalse);
755 return(SyncAuthenticPixels(image,exception));
756 }
757
DistributePixelCacheClient(void * socket)758 static HANDLER_RETURN_TYPE DistributePixelCacheClient(void *socket)
759 {
760 char
761 *shared_secret;
762
763 ExceptionInfo
764 *exception;
765
766 MagickBooleanType
767 status;
768
769 MagickOffsetType
770 count;
771
772 RandomInfo
773 *random_info;
774
775 size_t
776 key,
777 session_key;
778
779 SOCKET_TYPE
780 client_socket;
781
782 SplayTreeInfo
783 *registry;
784
785 StringInfo
786 *secret;
787
788 unsigned char
789 command,
790 *p,
791 session[2*MagickPathExtent];
792
793 /*
794 Distributed pixel cache client.
795 */
796 shared_secret=GetPolicyValue("cache:shared-secret");
797 if (shared_secret == (char *) NULL)
798 ThrowFatalException(CacheFatalError,"shared secret expected");
799 p=session;
800 (void) CopyMagickString((char *) p,shared_secret,MagickPathExtent);
801 p+=strlen(shared_secret);
802 shared_secret=DestroyString(shared_secret);
803 random_info=AcquireRandomInfo();
804 secret=GetRandomKey(random_info,DPCSessionKeyLength);
805 (void) memcpy(p,GetStringInfoDatum(secret),DPCSessionKeyLength);
806 session_key=GetMagickSignature(secret);
807 random_info=DestroyRandomInfo(random_info);
808 exception=AcquireExceptionInfo();
809 registry=NewSplayTree((int (*)(const void *,const void *)) NULL,
810 (void *(*)(void *)) NULL,RelinquishImageRegistry);
811 client_socket=(*(SOCKET_TYPE *) socket);
812 count=dpc_send(client_socket,DPCSessionKeyLength,GetStringInfoDatum(secret));
813 secret=DestroyStringInfo(secret);
814 for ( ; ; )
815 {
816 count=dpc_read(client_socket,1,(unsigned char *) &command);
817 if (count <= 0)
818 break;
819 count=dpc_read(client_socket,sizeof(key),(unsigned char *) &key);
820 if ((count != (MagickOffsetType) sizeof(key)) || (key != session_key))
821 break;
822 status=MagickFalse;
823 switch (command)
824 {
825 case 'o':
826 {
827 status=OpenDistributeCache(registry,client_socket,session_key,
828 exception);
829 count=dpc_send(client_socket,sizeof(status),(unsigned char *) &status);
830 break;
831 }
832 case 'r':
833 {
834 status=ReadDistributeCachePixels(registry,client_socket,session_key,
835 exception);
836 break;
837 }
838 case 'R':
839 {
840 status=ReadDistributeCacheMetacontent(registry,client_socket,
841 session_key,exception);
842 break;
843 }
844 case 'w':
845 {
846 status=WriteDistributeCachePixels(registry,client_socket,session_key,
847 exception);
848 break;
849 }
850 case 'W':
851 {
852 status=WriteDistributeCacheMetacontent(registry,client_socket,
853 session_key,exception);
854 break;
855 }
856 case 'd':
857 {
858 status=DestroyDistributeCache(registry,session_key);
859 break;
860 }
861 default:
862 break;
863 }
864 if (status == MagickFalse)
865 break;
866 if (command == 'd')
867 break;
868 }
869 count=dpc_send(client_socket,sizeof(status),(unsigned char *) &status);
870 CLOSE_SOCKET(client_socket);
871 exception=DestroyExceptionInfo(exception);
872 registry=DestroySplayTree(registry);
873 return(HANDLER_RETURN_VALUE);
874 }
875
DistributePixelCacheServer(const int port,ExceptionInfo * exception)876 MagickExport void DistributePixelCacheServer(const int port,
877 ExceptionInfo *exception)
878 {
879 char
880 service[MagickPathExtent];
881
882 int
883 status;
884
885 #if defined(MAGICKCORE_THREAD_SUPPORT)
886 pthread_attr_t
887 attributes;
888
889 pthread_t
890 threads;
891 #elif defined(MAGICKCORE_WINDOWS_SUPPORT)
892 DWORD
893 threadID;
894 #else
895 Not implemented!
896 #endif
897
898 struct addrinfo
899 *p;
900
901 SOCKET_TYPE
902 server_socket;
903
904 struct addrinfo
905 hint,
906 *result;
907
908 struct sockaddr_in
909 address;
910
911 /*
912 Launch distributed pixel cache server.
913 */
914 assert(exception != (ExceptionInfo *) NULL);
915 assert(exception->signature == MagickCoreSignature);
916 magick_unreferenced(exception);
917 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
918 NTInitializeWinsock(MagickFalse);
919 #endif
920 (void) memset(&hint,0,sizeof(hint));
921 hint.ai_family=AF_INET;
922 hint.ai_socktype=SOCK_STREAM;
923 hint.ai_flags=AI_PASSIVE;
924 (void) FormatLocaleString(service,MagickPathExtent,"%d",port);
925 status=getaddrinfo((const char *) NULL,service,&hint,&result);
926 if (status != 0)
927 ThrowFatalException(CacheFatalError,"UnableToListen");
928 server_socket=(SOCKET_TYPE) 0;
929 for (p=result; p != (struct addrinfo *) NULL; p=p->ai_next)
930 {
931 int
932 one;
933
934 server_socket=socket(p->ai_family,p->ai_socktype,p->ai_protocol);
935 if (server_socket == -1)
936 continue;
937 one=1;
938 status=setsockopt(server_socket,SOL_SOCKET,SO_REUSEADDR,
939 CHAR_TYPE_CAST &one,(socklen_t) sizeof(one));
940 if (status == -1)
941 {
942 CLOSE_SOCKET(server_socket);
943 continue;
944 }
945 status=bind(server_socket,p->ai_addr,(socklen_t) p->ai_addrlen);
946 if (status == -1)
947 {
948 CLOSE_SOCKET(server_socket);
949 continue;
950 }
951 break;
952 }
953 if (p == (struct addrinfo *) NULL)
954 ThrowFatalException(CacheFatalError,"UnableToBind");
955 freeaddrinfo(result);
956 status=listen(server_socket,DPCPendingConnections);
957 if (status != 0)
958 ThrowFatalException(CacheFatalError,"UnableToListen");
959 #if defined(MAGICKCORE_THREAD_SUPPORT)
960 pthread_attr_init(&attributes);
961 #endif
962 for ( ; ; )
963 {
964 SOCKET_TYPE
965 client_socket;
966
967 socklen_t
968 length;
969
970 length=(socklen_t) sizeof(address);
971 client_socket=accept(server_socket,(struct sockaddr *) &address,&length);
972 if (client_socket == -1)
973 ThrowFatalException(CacheFatalError,"UnableToEstablishConnection");
974 #if defined(MAGICKCORE_THREAD_SUPPORT)
975 status=pthread_create(&threads,&attributes,DistributePixelCacheClient,
976 (void *) &client_socket);
977 if (status == -1)
978 ThrowFatalException(CacheFatalError,"UnableToCreateClientThread");
979 #elif defined(MAGICKCORE_WINDOWS_SUPPORT)
980 if (CreateThread(0,0,DistributePixelCacheClient,(void*) &client_socket,0,
981 &threadID) == (HANDLE) NULL)
982 ThrowFatalException(CacheFatalError,"UnableToCreateClientThread");
983 #else
984 Not implemented!
985 #endif
986 }
987 }
988 #endif
989
990 /*
991 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
992 % %
993 % %
994 % %
995 + G e t D i s t r i b u t e C a c h e F i l e %
996 % %
997 % %
998 % %
999 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1000 %
1001 % GetDistributeCacheFile() returns the file associated with this
1002 % DistributeCacheInfo structure.
1003 %
1004 % The format of the GetDistributeCacheFile method is:
1005 %
1006 % int GetDistributeCacheFile(const DistributeCacheInfo *server_info)
1007 %
1008 % A description of each parameter follows:
1009 %
1010 % o server_info: the distributed cache info.
1011 %
1012 */
GetDistributeCacheFile(const DistributeCacheInfo * server_info)1013 MagickPrivate int GetDistributeCacheFile(const DistributeCacheInfo *server_info)
1014 {
1015 assert(server_info != (DistributeCacheInfo *) NULL);
1016 assert(server_info->signature == MagickCoreSignature);
1017 return(server_info->file);
1018 }
1019
1020 /*
1021 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1022 % %
1023 % %
1024 % %
1025 + G e t D i s t r i b u t e C a c h e H o s t n a m e %
1026 % %
1027 % %
1028 % %
1029 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1030 %
1031 % GetDistributeCacheHostname() returns the hostname associated with this
1032 % DistributeCacheInfo structure.
1033 %
1034 % The format of the GetDistributeCacheHostname method is:
1035 %
1036 % const char *GetDistributeCacheHostname(
1037 % const DistributeCacheInfo *server_info)
1038 %
1039 % A description of each parameter follows:
1040 %
1041 % o server_info: the distributed cache info.
1042 %
1043 */
GetDistributeCacheHostname(const DistributeCacheInfo * server_info)1044 MagickPrivate const char *GetDistributeCacheHostname(
1045 const DistributeCacheInfo *server_info)
1046 {
1047 assert(server_info != (DistributeCacheInfo *) NULL);
1048 assert(server_info->signature == MagickCoreSignature);
1049 return(server_info->hostname);
1050 }
1051
1052 /*
1053 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1054 % %
1055 % %
1056 % %
1057 + G e t D i s t r i b u t e C a c h e P o r t %
1058 % %
1059 % %
1060 % %
1061 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1062 %
1063 % GetDistributeCachePort() returns the port associated with this
1064 % DistributeCacheInfo structure.
1065 %
1066 % The format of the GetDistributeCachePort method is:
1067 %
1068 % int GetDistributeCachePort(const DistributeCacheInfo *server_info)
1069 %
1070 % A description of each parameter follows:
1071 %
1072 % o server_info: the distributed cache info.
1073 %
1074 */
GetDistributeCachePort(const DistributeCacheInfo * server_info)1075 MagickPrivate int GetDistributeCachePort(const DistributeCacheInfo *server_info)
1076 {
1077 assert(server_info != (DistributeCacheInfo *) NULL);
1078 assert(server_info->signature == MagickCoreSignature);
1079 return(server_info->port);
1080 }
1081
1082 /*
1083 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1084 % %
1085 % %
1086 % %
1087 + O p e n D i s t r i b u t e P i x e l C a c h e %
1088 % %
1089 % %
1090 % %
1091 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1092 %
1093 % OpenDistributePixelCache() opens a pixel cache on a remote server.
1094 %
1095 % The format of the OpenDistributePixelCache method is:
1096 %
1097 % MagickBooleanType *OpenDistributePixelCache(
1098 % DistributeCacheInfo *server_info,Image *image)
1099 %
1100 % A description of each parameter follows:
1101 %
1102 % o server_info: the distributed cache info.
1103 %
1104 % o image: the image.
1105 %
1106 */
OpenDistributePixelCache(DistributeCacheInfo * server_info,Image * image)1107 MagickPrivate MagickBooleanType OpenDistributePixelCache(
1108 DistributeCacheInfo *server_info,Image *image)
1109 {
1110 MagickBooleanType
1111 status;
1112
1113 MagickOffsetType
1114 count;
1115
1116 unsigned char
1117 message[MagickPathExtent],
1118 *p;
1119
1120 /*
1121 Open distributed pixel cache.
1122 */
1123 assert(server_info != (DistributeCacheInfo *) NULL);
1124 assert(server_info->signature == MagickCoreSignature);
1125 assert(image != (Image *) NULL);
1126 assert(image->signature == MagickCoreSignature);
1127 p=message;
1128 *p++='o'; /* open */
1129 /*
1130 Serialize image attributes (see ValidatePixelCacheMorphology()).
1131 */
1132 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1133 p+=sizeof(server_info->session_key);
1134 (void) memcpy(p,&image->storage_class,sizeof(image->storage_class));
1135 p+=sizeof(image->storage_class);
1136 (void) memcpy(p,&image->colorspace,sizeof(image->colorspace));
1137 p+=sizeof(image->colorspace);
1138 (void) memcpy(p,&image->alpha_trait,sizeof(image->alpha_trait));
1139 p+=sizeof(image->alpha_trait);
1140 (void) memcpy(p,&image->channels,sizeof(image->channels));
1141 p+=sizeof(image->channels);
1142 (void) memcpy(p,&image->columns,sizeof(image->columns));
1143 p+=sizeof(image->columns);
1144 (void) memcpy(p,&image->rows,sizeof(image->rows));
1145 p+=sizeof(image->rows);
1146 (void) memcpy(p,&image->number_channels,sizeof(image->number_channels));
1147 p+=sizeof(image->number_channels);
1148 (void) memcpy(p,image->channel_map,MaxPixelChannels*
1149 sizeof(*image->channel_map));
1150 p+=MaxPixelChannels*sizeof(*image->channel_map);
1151 (void) memcpy(p,&image->metacontent_extent,sizeof(image->metacontent_extent));
1152 p+=sizeof(image->metacontent_extent);
1153 count=dpc_send(server_info->file,p-message,message);
1154 if (count != (MagickOffsetType) (p-message))
1155 return(MagickFalse);
1156 status=MagickFalse;
1157 count=dpc_read(server_info->file,sizeof(status),(unsigned char *) &status);
1158 if (count != (MagickOffsetType) sizeof(status))
1159 return(MagickFalse);
1160 return(status);
1161 }
1162
1163 /*
1164 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1165 % %
1166 % %
1167 % %
1168 + R e a d D i s t r i b u t e P i x e l C a c h e M e t a c o n t e n t %
1169 % %
1170 % %
1171 % %
1172 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1173 %
1174 % ReadDistributePixelCacheMetacontents() reads metacontent from the specified
1175 % region of the distributed pixel cache.
1176 %
1177 % The format of the ReadDistributePixelCacheMetacontents method is:
1178 %
1179 % MagickOffsetType ReadDistributePixelCacheMetacontents(
1180 % DistributeCacheInfo *server_info,const RectangleInfo *region,
1181 % const MagickSizeType length,unsigned char *metacontent)
1182 %
1183 % A description of each parameter follows:
1184 %
1185 % o server_info: the distributed cache info.
1186 %
1187 % o image: the image.
1188 %
1189 % o region: read the metacontent from this region of the image.
1190 %
1191 % o length: the length in bytes of the metacontent.
1192 %
1193 % o metacontent: read these metacontent from the pixel cache.
1194 %
1195 */
ReadDistributePixelCacheMetacontent(DistributeCacheInfo * server_info,const RectangleInfo * region,const MagickSizeType length,unsigned char * metacontent)1196 MagickPrivate MagickOffsetType ReadDistributePixelCacheMetacontent(
1197 DistributeCacheInfo *server_info,const RectangleInfo *region,
1198 const MagickSizeType length,unsigned char *metacontent)
1199 {
1200 MagickOffsetType
1201 count;
1202
1203 unsigned char
1204 message[MagickPathExtent],
1205 *p;
1206
1207 /*
1208 Read distributed pixel cache metacontent.
1209 */
1210 assert(server_info != (DistributeCacheInfo *) NULL);
1211 assert(server_info->signature == MagickCoreSignature);
1212 assert(region != (RectangleInfo *) NULL);
1213 assert(metacontent != (unsigned char *) NULL);
1214 if (length > (MagickSizeType) MAGICK_SSIZE_MAX)
1215 return(-1);
1216 p=message;
1217 *p++='R';
1218 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1219 p+=sizeof(server_info->session_key);
1220 (void) memcpy(p,®ion->width,sizeof(region->width));
1221 p+=sizeof(region->width);
1222 (void) memcpy(p,®ion->height,sizeof(region->height));
1223 p+=sizeof(region->height);
1224 (void) memcpy(p,®ion->x,sizeof(region->x));
1225 p+=sizeof(region->x);
1226 (void) memcpy(p,®ion->y,sizeof(region->y));
1227 p+=sizeof(region->y);
1228 (void) memcpy(p,&length,sizeof(length));
1229 p+=sizeof(length);
1230 count=dpc_send(server_info->file,p-message,message);
1231 if (count != (MagickOffsetType) (p-message))
1232 return(-1);
1233 return(dpc_read(server_info->file,length,metacontent));
1234 }
1235
1236 /*
1237 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1238 % %
1239 % %
1240 % %
1241 + R e a d D i s t r i b u t e P i x e l C a c h e P i x e l s %
1242 % %
1243 % %
1244 % %
1245 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1246 %
1247 % ReadDistributePixelCachePixels() reads pixels from the specified region of
1248 % the distributed pixel cache.
1249 %
1250 % The format of the ReadDistributePixelCachePixels method is:
1251 %
1252 % MagickOffsetType ReadDistributePixelCachePixels(
1253 % DistributeCacheInfo *server_info,const RectangleInfo *region,
1254 % const MagickSizeType length,unsigned char *magick_restrict pixels)
1255 %
1256 % A description of each parameter follows:
1257 %
1258 % o server_info: the distributed cache info.
1259 %
1260 % o image: the image.
1261 %
1262 % o region: read the pixels from this region of the image.
1263 %
1264 % o length: the length in bytes of the pixels.
1265 %
1266 % o pixels: read these pixels from the pixel cache.
1267 %
1268 */
ReadDistributePixelCachePixels(DistributeCacheInfo * server_info,const RectangleInfo * region,const MagickSizeType length,unsigned char * magick_restrict pixels)1269 MagickPrivate MagickOffsetType ReadDistributePixelCachePixels(
1270 DistributeCacheInfo *server_info,const RectangleInfo *region,
1271 const MagickSizeType length,unsigned char *magick_restrict pixels)
1272 {
1273 MagickOffsetType
1274 count;
1275
1276 unsigned char
1277 message[MagickPathExtent],
1278 *p;
1279
1280 /*
1281 Read distributed pixel cache pixels.
1282 */
1283 assert(server_info != (DistributeCacheInfo *) NULL);
1284 assert(server_info->signature == MagickCoreSignature);
1285 assert(region != (RectangleInfo *) NULL);
1286 assert(pixels != (unsigned char *) NULL);
1287 if (length > (MagickSizeType) MAGICK_SSIZE_MAX)
1288 return(-1);
1289 p=message;
1290 *p++='r';
1291 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1292 p+=sizeof(server_info->session_key);
1293 (void) memcpy(p,®ion->width,sizeof(region->width));
1294 p+=sizeof(region->width);
1295 (void) memcpy(p,®ion->height,sizeof(region->height));
1296 p+=sizeof(region->height);
1297 (void) memcpy(p,®ion->x,sizeof(region->x));
1298 p+=sizeof(region->x);
1299 (void) memcpy(p,®ion->y,sizeof(region->y));
1300 p+=sizeof(region->y);
1301 (void) memcpy(p,&length,sizeof(length));
1302 p+=sizeof(length);
1303 count=dpc_send(server_info->file,p-message,message);
1304 if (count != (MagickOffsetType) (p-message))
1305 return(-1);
1306 return(dpc_read(server_info->file,length,pixels));
1307 }
1308
1309 /*
1310 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1311 % %
1312 % %
1313 % %
1314 + R e l i n q u i s h D i s t r i b u t e P i x e l C a c h e %
1315 % %
1316 % %
1317 % %
1318 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1319 %
1320 % RelinquishDistributePixelCache() frees resources acquired with
1321 % OpenDistributePixelCache().
1322 %
1323 % The format of the RelinquishDistributePixelCache method is:
1324 %
1325 % MagickBooleanType RelinquishDistributePixelCache(
1326 % DistributeCacheInfo *server_info)
1327 %
1328 % A description of each parameter follows:
1329 %
1330 % o server_info: the distributed cache info.
1331 %
1332 */
RelinquishDistributePixelCache(DistributeCacheInfo * server_info)1333 MagickPrivate MagickBooleanType RelinquishDistributePixelCache(
1334 DistributeCacheInfo *server_info)
1335 {
1336 MagickBooleanType
1337 status;
1338
1339 MagickOffsetType
1340 count;
1341
1342 unsigned char
1343 message[MagickPathExtent],
1344 *p;
1345
1346 /*
1347 Delete distributed pixel cache.
1348 */
1349 assert(server_info != (DistributeCacheInfo *) NULL);
1350 assert(server_info->signature == MagickCoreSignature);
1351 p=message;
1352 *p++='d';
1353 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1354 p+=sizeof(server_info->session_key);
1355 count=dpc_send(server_info->file,p-message,message);
1356 if (count != (MagickOffsetType) (p-message))
1357 return(MagickFalse);
1358 status=MagickFalse;
1359 count=dpc_read(server_info->file,sizeof(status),(unsigned char *) &status);
1360 if (count != (MagickOffsetType) sizeof(status))
1361 return(MagickFalse);
1362 return(status);
1363 }
1364
1365 /*
1366 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1367 % %
1368 % %
1369 % %
1370 + W r i t e D i s t r i b u t e P i x e l C a c h e M e t a c o n t e n t %
1371 % %
1372 % %
1373 % %
1374 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1375 %
1376 % WriteDistributePixelCacheMetacontents() writes image metacontent to the
1377 % specified region of the distributed pixel cache.
1378 %
1379 % The format of the WriteDistributePixelCacheMetacontents method is:
1380 %
1381 % MagickOffsetType WriteDistributePixelCacheMetacontents(
1382 % DistributeCacheInfo *server_info,const RectangleInfo *region,
1383 % const MagickSizeType length,const unsigned char *metacontent)
1384 %
1385 % A description of each parameter follows:
1386 %
1387 % o server_info: the distributed cache info.
1388 %
1389 % o image: the image.
1390 %
1391 % o region: write the metacontent to this region of the image.
1392 %
1393 % o length: the length in bytes of the metacontent.
1394 %
1395 % o metacontent: write these metacontent to the pixel cache.
1396 %
1397 */
WriteDistributePixelCacheMetacontent(DistributeCacheInfo * server_info,const RectangleInfo * region,const MagickSizeType length,const unsigned char * metacontent)1398 MagickPrivate MagickOffsetType WriteDistributePixelCacheMetacontent(
1399 DistributeCacheInfo *server_info,const RectangleInfo *region,
1400 const MagickSizeType length,const unsigned char *metacontent)
1401 {
1402 MagickOffsetType
1403 count;
1404
1405 unsigned char
1406 message[MagickPathExtent],
1407 *p;
1408
1409 /*
1410 Write distributed pixel cache metacontent.
1411 */
1412 assert(server_info != (DistributeCacheInfo *) NULL);
1413 assert(server_info->signature == MagickCoreSignature);
1414 assert(region != (RectangleInfo *) NULL);
1415 assert(metacontent != (unsigned char *) NULL);
1416 if (length > (MagickSizeType) MAGICK_SSIZE_MAX)
1417 return(-1);
1418 p=message;
1419 *p++='W';
1420 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1421 p+=sizeof(server_info->session_key);
1422 (void) memcpy(p,®ion->width,sizeof(region->width));
1423 p+=sizeof(region->width);
1424 (void) memcpy(p,®ion->height,sizeof(region->height));
1425 p+=sizeof(region->height);
1426 (void) memcpy(p,®ion->x,sizeof(region->x));
1427 p+=sizeof(region->x);
1428 (void) memcpy(p,®ion->y,sizeof(region->y));
1429 p+=sizeof(region->y);
1430 (void) memcpy(p,&length,sizeof(length));
1431 p+=sizeof(length);
1432 count=dpc_send(server_info->file,p-message,message);
1433 if (count != (MagickOffsetType) (p-message))
1434 return(-1);
1435 return(dpc_send(server_info->file,length,metacontent));
1436 }
1437
1438 /*
1439 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1440 % %
1441 % %
1442 % %
1443 + W r i t e D i s t r i b u t e P i x e l C a c h e P i x e l s %
1444 % %
1445 % %
1446 % %
1447 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1448 %
1449 % WriteDistributePixelCachePixels() writes image pixels to the specified
1450 % region of the distributed pixel cache.
1451 %
1452 % The format of the WriteDistributePixelCachePixels method is:
1453 %
1454 % MagickBooleanType WriteDistributePixelCachePixels(
1455 % DistributeCacheInfo *server_info,const RectangleInfo *region,
1456 % const MagickSizeType length,
1457 % const unsigned char *magick_restrict pixels)
1458 %
1459 % A description of each parameter follows:
1460 %
1461 % o server_info: the distributed cache info.
1462 %
1463 % o image: the image.
1464 %
1465 % o region: write the pixels to this region of the image.
1466 %
1467 % o length: the length in bytes of the pixels.
1468 %
1469 % o pixels: write these pixels to the pixel cache.
1470 %
1471 */
WriteDistributePixelCachePixels(DistributeCacheInfo * server_info,const RectangleInfo * region,const MagickSizeType length,const unsigned char * magick_restrict pixels)1472 MagickPrivate MagickOffsetType WriteDistributePixelCachePixels(
1473 DistributeCacheInfo *server_info,const RectangleInfo *region,
1474 const MagickSizeType length,const unsigned char *magick_restrict pixels)
1475 {
1476 MagickOffsetType
1477 count;
1478
1479 unsigned char
1480 message[MagickPathExtent],
1481 *p;
1482
1483 /*
1484 Write distributed pixel cache pixels.
1485 */
1486 assert(server_info != (DistributeCacheInfo *) NULL);
1487 assert(server_info->signature == MagickCoreSignature);
1488 assert(region != (RectangleInfo *) NULL);
1489 assert(pixels != (const unsigned char *) NULL);
1490 if (length > (MagickSizeType) MAGICK_SSIZE_MAX)
1491 return(-1);
1492 p=message;
1493 *p++='w';
1494 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1495 p+=sizeof(server_info->session_key);
1496 (void) memcpy(p,®ion->width,sizeof(region->width));
1497 p+=sizeof(region->width);
1498 (void) memcpy(p,®ion->height,sizeof(region->height));
1499 p+=sizeof(region->height);
1500 (void) memcpy(p,®ion->x,sizeof(region->x));
1501 p+=sizeof(region->x);
1502 (void) memcpy(p,®ion->y,sizeof(region->y));
1503 p+=sizeof(region->y);
1504 (void) memcpy(p,&length,sizeof(length));
1505 p+=sizeof(length);
1506 count=dpc_send(server_info->file,p-message,message);
1507 if (count != (MagickOffsetType) (p-message))
1508 return(-1);
1509 return(dpc_send(server_info->file,length,pixels));
1510 }
1511