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