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