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-2016 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 % http://www.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
90 #elif defined(MAGICKCORE_WINDOWS_SUPPORT)
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
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 !defined(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 defined(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("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) ResetMagickMemory(&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(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 *) AcquireMagickMemory(sizeof(*server_info));
342 if (server_info == (DistributeCacheInfo *) NULL)
343 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
344 (void) ResetMagickMemory(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->read_mask)+
495 sizeof(image->write_mask)+sizeof(image->columns)+sizeof(image->rows)+
496 sizeof(image->number_channels)+MaxPixelChannels*sizeof(*image->channel_map)+
497 sizeof(image->metacontent_extent);
498 count=dpc_read(file,length,message);
499 if (count != (MagickOffsetType) length)
500 return(MagickFalse);
501 /*
502 Deserialize the image attributes.
503 */
504 p=message;
505 (void) memcpy(&image->storage_class,p,sizeof(image->storage_class));
506 p+=sizeof(image->storage_class);
507 (void) memcpy(&image->colorspace,p,sizeof(image->colorspace));
508 p+=sizeof(image->colorspace);
509 (void) memcpy(&image->alpha_trait,p,sizeof(image->alpha_trait));
510 p+=sizeof(image->alpha_trait);
511 (void) memcpy(&image->read_mask,p,sizeof(image->read_mask));
512 p+=sizeof(image->read_mask);
513 (void) memcpy(&image->write_mask,p,sizeof(image->write_mask));
514 p+=sizeof(image->write_mask);
515 (void) memcpy(&image->columns,p,sizeof(image->columns));
516 p+=sizeof(image->columns);
517 (void) memcpy(&image->rows,p,sizeof(image->rows));
518 p+=sizeof(image->rows);
519 (void) memcpy(&image->number_channels,p,sizeof(image->number_channels));
520 p+=sizeof(image->number_channels);
521 (void) memcpy(image->channel_map,p,MaxPixelChannels*
522 sizeof(*image->channel_map));
523 p+=MaxPixelChannels*sizeof(*image->channel_map);
524 (void) memcpy(&image->metacontent_extent,p,sizeof(image->metacontent_extent));
525 p+=sizeof(image->metacontent_extent);
526 if (SyncImagePixelCache(image,exception) == MagickFalse)
527 return(MagickFalse);
528 status=AddValueToSplayTree(registry,(const void *) session_key,image);
529 return(status);
530 }
531
ReadDistributeCacheMetacontent(SplayTreeInfo * registry,int file,const size_t session_key,ExceptionInfo * exception)532 static MagickBooleanType ReadDistributeCacheMetacontent(SplayTreeInfo *registry,
533 int file,const size_t session_key,ExceptionInfo *exception)
534 {
535 const unsigned char
536 *metacontent;
537
538 Image
539 *image;
540
541 MagickOffsetType
542 count;
543
544 MagickSizeType
545 length;
546
547 RectangleInfo
548 region;
549
550 register const Quantum
551 *p;
552
553 register unsigned char
554 *q;
555
556 unsigned char
557 message[MagickPathExtent];
558
559 /*
560 Read distributed pixel cache metacontent.
561 */
562 image=(Image *) GetValueFromSplayTree(registry,(const void *) session_key);
563 if (image == (Image *) NULL)
564 return(MagickFalse);
565 length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
566 sizeof(region.y)+sizeof(length);
567 count=dpc_read(file,length,message);
568 if (count != (MagickOffsetType) length)
569 return(MagickFalse);
570 q=message;
571 (void) memcpy(®ion.width,q,sizeof(region.width));
572 q+=sizeof(region.width);
573 (void) memcpy(®ion.height,q,sizeof(region.height));
574 q+=sizeof(region.height);
575 (void) memcpy(®ion.x,q,sizeof(region.x));
576 q+=sizeof(region.x);
577 (void) memcpy(®ion.y,q,sizeof(region.y));
578 q+=sizeof(region.y);
579 (void) memcpy(&length,q,sizeof(length));
580 q+=sizeof(length);
581 p=GetVirtualPixels(image,region.x,region.y,region.width,region.height,
582 exception);
583 if (p == (const Quantum *) NULL)
584 return(MagickFalse);
585 metacontent=(const unsigned char *) GetVirtualMetacontent(image);
586 count=dpc_send(file,length,metacontent);
587 if (count != (MagickOffsetType) length)
588 return(MagickFalse);
589 return(MagickTrue);
590 }
591
ReadDistributeCachePixels(SplayTreeInfo * registry,int file,const size_t session_key,ExceptionInfo * exception)592 static MagickBooleanType ReadDistributeCachePixels(SplayTreeInfo *registry,
593 int file,const size_t session_key,ExceptionInfo *exception)
594 {
595 Image
596 *image;
597
598 MagickOffsetType
599 count;
600
601 MagickSizeType
602 length;
603
604 RectangleInfo
605 region;
606
607 register const Quantum
608 *p;
609
610 register unsigned char
611 *q;
612
613 unsigned char
614 message[MagickPathExtent];
615
616 /*
617 Read distributed pixel cache pixels.
618 */
619 image=(Image *) GetValueFromSplayTree(registry,(const void *) session_key);
620 if (image == (Image *) NULL)
621 return(MagickFalse);
622 length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
623 sizeof(region.y)+sizeof(length);
624 count=dpc_read(file,length,message);
625 if (count != (MagickOffsetType) length)
626 return(MagickFalse);
627 q=message;
628 (void) memcpy(®ion.width,q,sizeof(region.width));
629 q+=sizeof(region.width);
630 (void) memcpy(®ion.height,q,sizeof(region.height));
631 q+=sizeof(region.height);
632 (void) memcpy(®ion.x,q,sizeof(region.x));
633 q+=sizeof(region.x);
634 (void) memcpy(®ion.y,q,sizeof(region.y));
635 q+=sizeof(region.y);
636 (void) memcpy(&length,q,sizeof(length));
637 q+=sizeof(length);
638 p=GetVirtualPixels(image,region.x,region.y,region.width,region.height,
639 exception);
640 if (p == (const Quantum *) NULL)
641 return(MagickFalse);
642 count=dpc_send(file,length,(unsigned char *) p);
643 if (count != (MagickOffsetType) length)
644 return(MagickFalse);
645 return(MagickTrue);
646 }
647
RelinquishImageRegistry(void * image)648 static void *RelinquishImageRegistry(void *image)
649 {
650 return((void *) DestroyImageList((Image *) image));
651 }
652
WriteDistributeCacheMetacontent(SplayTreeInfo * registry,int file,const size_t session_key,ExceptionInfo * exception)653 static MagickBooleanType WriteDistributeCacheMetacontent(
654 SplayTreeInfo *registry,int file,const size_t session_key,
655 ExceptionInfo *exception)
656 {
657 Image
658 *image;
659
660 MagickOffsetType
661 count;
662
663 MagickSizeType
664 length;
665
666 RectangleInfo
667 region;
668
669 register Quantum
670 *q;
671
672 register unsigned char
673 *p;
674
675 unsigned char
676 message[MagickPathExtent],
677 *metacontent;
678
679 /*
680 Write distributed pixel cache metacontent.
681 */
682 image=(Image *) GetValueFromSplayTree(registry,(const void *) session_key);
683 if (image == (Image *) NULL)
684 return(MagickFalse);
685 length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
686 sizeof(region.y)+sizeof(length);
687 count=dpc_read(file,length,message);
688 if (count != (MagickOffsetType) length)
689 return(MagickFalse);
690 p=message;
691 (void) memcpy(®ion.width,p,sizeof(region.width));
692 p+=sizeof(region.width);
693 (void) memcpy(®ion.height,p,sizeof(region.height));
694 p+=sizeof(region.height);
695 (void) memcpy(®ion.x,p,sizeof(region.x));
696 p+=sizeof(region.x);
697 (void) memcpy(®ion.y,p,sizeof(region.y));
698 p+=sizeof(region.y);
699 (void) memcpy(&length,p,sizeof(length));
700 p+=sizeof(length);
701 q=GetAuthenticPixels(image,region.x,region.y,region.width,region.height,
702 exception);
703 if (q == (Quantum *) NULL)
704 return(MagickFalse);
705 metacontent=(unsigned char *) GetAuthenticMetacontent(image);
706 count=dpc_read(file,length,metacontent);
707 if (count != (MagickOffsetType) length)
708 return(MagickFalse);
709 return(SyncAuthenticPixels(image,exception));
710 }
711
WriteDistributeCachePixels(SplayTreeInfo * registry,int file,const size_t session_key,ExceptionInfo * exception)712 static MagickBooleanType WriteDistributeCachePixels(SplayTreeInfo *registry,
713 int file,const size_t session_key,ExceptionInfo *exception)
714 {
715 Image
716 *image;
717
718 MagickOffsetType
719 count;
720
721 MagickSizeType
722 length;
723
724 RectangleInfo
725 region;
726
727 register Quantum
728 *q;
729
730 register unsigned char
731 *p;
732
733 unsigned char
734 message[MagickPathExtent];
735
736 /*
737 Write distributed pixel cache pixels.
738 */
739 image=(Image *) GetValueFromSplayTree(registry,(const void *) session_key);
740 if (image == (Image *) NULL)
741 return(MagickFalse);
742 length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
743 sizeof(region.y)+sizeof(length);
744 count=dpc_read(file,length,message);
745 if (count != (MagickOffsetType) length)
746 return(MagickFalse);
747 p=message;
748 (void) memcpy(®ion.width,p,sizeof(region.width));
749 p+=sizeof(region.width);
750 (void) memcpy(®ion.height,p,sizeof(region.height));
751 p+=sizeof(region.height);
752 (void) memcpy(®ion.x,p,sizeof(region.x));
753 p+=sizeof(region.x);
754 (void) memcpy(®ion.y,p,sizeof(region.y));
755 p+=sizeof(region.y);
756 (void) memcpy(&length,p,sizeof(length));
757 p+=sizeof(length);
758 q=GetAuthenticPixels(image,region.x,region.y,region.width,region.height,
759 exception);
760 if (q == (Quantum *) NULL)
761 return(MagickFalse);
762 count=dpc_read(file,length,(unsigned char *) q);
763 if (count != (MagickOffsetType) length)
764 return(MagickFalse);
765 return(SyncAuthenticPixels(image,exception));
766 }
767
DistributePixelCacheClient(void * socket)768 static HANDLER_RETURN_TYPE DistributePixelCacheClient(void *socket)
769 {
770 char
771 *shared_secret;
772
773 ExceptionInfo
774 *exception;
775
776 MagickBooleanType
777 status;
778
779 MagickOffsetType
780 count;
781
782 register unsigned char
783 *p;
784
785 RandomInfo
786 *random_info;
787
788 size_t
789 key,
790 session_key;
791
792 SOCKET_TYPE
793 client_socket;
794
795 SplayTreeInfo
796 *registry;
797
798 StringInfo
799 *secret;
800
801 unsigned char
802 command,
803 session[2*MagickPathExtent];
804
805 /*
806 Distributed pixel cache client.
807 */
808 shared_secret=GetPolicyValue("shared-secret");
809 if (shared_secret == (char *) NULL)
810 ThrowFatalException(CacheFatalError,"shared secret expected");
811 p=session;
812 (void) CopyMagickString((char *) p,shared_secret,MagickPathExtent);
813 p+=strlen(shared_secret);
814 shared_secret=DestroyString(shared_secret);
815 random_info=AcquireRandomInfo();
816 secret=GetRandomKey(random_info,DPCSessionKeyLength);
817 (void) memcpy(p,GetStringInfoDatum(secret),DPCSessionKeyLength);
818 session_key=GetMagickSignature(secret);
819 random_info=DestroyRandomInfo(random_info);
820 exception=AcquireExceptionInfo();
821 registry=NewSplayTree((int (*)(const void *,const void *)) NULL,
822 (void *(*)(void *)) NULL,RelinquishImageRegistry);
823 client_socket=(*(SOCKET_TYPE *) socket);
824 count=dpc_send(client_socket,DPCSessionKeyLength,GetStringInfoDatum(secret));
825 secret=DestroyStringInfo(secret);
826 for ( ; ; )
827 {
828 count=dpc_read(client_socket,1,(unsigned char *) &command);
829 if (count <= 0)
830 break;
831 count=dpc_read(client_socket,sizeof(key),(unsigned char *) &key);
832 if ((count != (MagickOffsetType) sizeof(key)) || (key != session_key))
833 break;
834 status=MagickFalse;
835 switch (command)
836 {
837 case 'o':
838 {
839 status=OpenDistributeCache(registry,client_socket,session_key,
840 exception);
841 count=dpc_send(client_socket,sizeof(status),(unsigned char *) &status);
842 break;
843 }
844 case 'r':
845 {
846 status=ReadDistributeCachePixels(registry,client_socket,session_key,
847 exception);
848 break;
849 }
850 case 'R':
851 {
852 status=ReadDistributeCacheMetacontent(registry,client_socket,
853 session_key,exception);
854 break;
855 }
856 case 'w':
857 {
858 status=WriteDistributeCachePixels(registry,client_socket,session_key,
859 exception);
860 break;
861 }
862 case 'W':
863 {
864 status=WriteDistributeCacheMetacontent(registry,client_socket,
865 session_key,exception);
866 break;
867 }
868 case 'd':
869 {
870 status=DestroyDistributeCache(registry,session_key);
871 break;
872 }
873 default:
874 break;
875 }
876 if (status == MagickFalse)
877 break;
878 if (command == 'd')
879 break;
880 }
881 count=dpc_send(client_socket,sizeof(status),(unsigned char *) &status);
882 CLOSE_SOCKET(client_socket);
883 exception=DestroyExceptionInfo(exception);
884 registry=DestroySplayTree(registry);
885 return(HANDLER_RETURN_VALUE);
886 }
887
DistributePixelCacheServer(const int port,ExceptionInfo * exception)888 MagickExport void DistributePixelCacheServer(const int port,
889 ExceptionInfo *exception)
890 {
891 #if defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
892 char
893 service[MagickPathExtent];
894
895 int
896 status;
897
898 #if defined(MAGICKCORE_THREAD_SUPPORT)
899 pthread_attr_t
900 attributes;
901
902 pthread_t
903 threads;
904 #elif defined(MAGICKCORE_WINDOWS_SUPPORT)
905 DWORD
906 threadID;
907 #else
908 Not implemented!
909 #endif
910
911 register struct addrinfo
912 *p;
913
914 SOCKET_TYPE
915 server_socket;
916
917 struct addrinfo
918 hint,
919 *result;
920
921 struct sockaddr_in
922 address;
923
924 /*
925 Launch distributed pixel cache server.
926 */
927 assert(exception != (ExceptionInfo *) NULL);
928 assert(exception->signature == MagickCoreSignature);
929 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
930 NTInitializeWinsock(MagickFalse);
931 #endif
932 (void) ResetMagickMemory(&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 magick_unreferenced(exception);
1002 ThrowFatalException(MissingDelegateError,"DelegateLibrarySupportNotBuiltIn");
1003 #endif
1004 }
1005
1006 /*
1007 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1008 % %
1009 % %
1010 % %
1011 + G e t D i s t r i b u t e C a c h e F i l e %
1012 % %
1013 % %
1014 % %
1015 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1016 %
1017 % GetDistributeCacheFile() returns the file associated with this
1018 % DistributeCacheInfo structure.
1019 %
1020 % The format of the GetDistributeCacheFile method is:
1021 %
1022 % int GetDistributeCacheFile(const DistributeCacheInfo *server_info)
1023 %
1024 % A description of each parameter follows:
1025 %
1026 % o server_info: the distributed cache info.
1027 %
1028 */
GetDistributeCacheFile(const DistributeCacheInfo * server_info)1029 MagickPrivate int GetDistributeCacheFile(const DistributeCacheInfo *server_info)
1030 {
1031 assert(server_info != (DistributeCacheInfo *) NULL);
1032 assert(server_info->signature == MagickCoreSignature);
1033 return(server_info->file);
1034 }
1035
1036 /*
1037 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1038 % %
1039 % %
1040 % %
1041 + 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 %
1042 % %
1043 % %
1044 % %
1045 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1046 %
1047 % GetDistributeCacheHostname() returns the hostname associated with this
1048 % DistributeCacheInfo structure.
1049 %
1050 % The format of the GetDistributeCacheHostname method is:
1051 %
1052 % const char *GetDistributeCacheHostname(
1053 % const DistributeCacheInfo *server_info)
1054 %
1055 % A description of each parameter follows:
1056 %
1057 % o server_info: the distributed cache info.
1058 %
1059 */
GetDistributeCacheHostname(const DistributeCacheInfo * server_info)1060 MagickPrivate const char *GetDistributeCacheHostname(
1061 const DistributeCacheInfo *server_info)
1062 {
1063 assert(server_info != (DistributeCacheInfo *) NULL);
1064 assert(server_info->signature == MagickCoreSignature);
1065 return(server_info->hostname);
1066 }
1067
1068 /*
1069 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1070 % %
1071 % %
1072 % %
1073 + G e t D i s t r i b u t e C a c h e P o r t %
1074 % %
1075 % %
1076 % %
1077 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1078 %
1079 % GetDistributeCachePort() returns the port associated with this
1080 % DistributeCacheInfo structure.
1081 %
1082 % The format of the GetDistributeCachePort method is:
1083 %
1084 % int GetDistributeCachePort(const DistributeCacheInfo *server_info)
1085 %
1086 % A description of each parameter follows:
1087 %
1088 % o server_info: the distributed cache info.
1089 %
1090 */
GetDistributeCachePort(const DistributeCacheInfo * server_info)1091 MagickPrivate int GetDistributeCachePort(const DistributeCacheInfo *server_info)
1092 {
1093 assert(server_info != (DistributeCacheInfo *) NULL);
1094 assert(server_info->signature == MagickCoreSignature);
1095 return(server_info->port);
1096 }
1097
1098 /*
1099 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1100 % %
1101 % %
1102 % %
1103 + O p e n D i s t r i b u t e P i x e l C a c h e %
1104 % %
1105 % %
1106 % %
1107 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1108 %
1109 % OpenDistributePixelCache() opens a pixel cache on a remote server.
1110 %
1111 % The format of the OpenDistributePixelCache method is:
1112 %
1113 % MagickBooleanType *OpenDistributePixelCache(
1114 % DistributeCacheInfo *server_info,Image *image)
1115 %
1116 % A description of each parameter follows:
1117 %
1118 % o server_info: the distributed cache info.
1119 %
1120 % o image: the image.
1121 %
1122 */
OpenDistributePixelCache(DistributeCacheInfo * server_info,Image * image)1123 MagickPrivate MagickBooleanType OpenDistributePixelCache(
1124 DistributeCacheInfo *server_info,Image *image)
1125 {
1126 MagickBooleanType
1127 #ifdef __VMS
1128 status=MagickTrue;
1129 #else
1130 status;
1131 #endif
1132
1133 MagickOffsetType
1134 count;
1135
1136 register unsigned char
1137 *p;
1138
1139 unsigned char
1140 message[MagickPathExtent];
1141
1142 /*
1143 Open distributed pixel cache.
1144 */
1145 assert(server_info != (DistributeCacheInfo *) NULL);
1146 assert(server_info->signature == MagickCoreSignature);
1147 assert(image != (Image *) NULL);
1148 assert(image->signature == MagickCoreSignature);
1149 p=message;
1150 *p++='o'; /* open */
1151 /*
1152 Serialize image attributes (see ValidatePixelCacheMorphology()).
1153 */
1154 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1155 p+=sizeof(server_info->session_key);
1156 (void) memcpy(p,&image->storage_class,sizeof(image->storage_class));
1157 p+=sizeof(image->storage_class);
1158 (void) memcpy(p,&image->colorspace,sizeof(image->colorspace));
1159 p+=sizeof(image->colorspace);
1160 (void) memcpy(p,&image->alpha_trait,sizeof(image->alpha_trait));
1161 p+=sizeof(image->alpha_trait);
1162 (void) memcpy(p,&image->read_mask,sizeof(image->read_mask));
1163 p+=sizeof(image->read_mask);
1164 (void) memcpy(p,&image->write_mask,sizeof(image->write_mask));
1165 p+=sizeof(image->write_mask);
1166 (void) memcpy(p,&image->columns,sizeof(image->columns));
1167 p+=sizeof(image->columns);
1168 (void) memcpy(p,&image->rows,sizeof(image->rows));
1169 p+=sizeof(image->rows);
1170 (void) memcpy(p,&image->number_channels,sizeof(image->number_channels));
1171 p+=sizeof(image->number_channels);
1172 (void) memcpy(p,image->channel_map,MaxPixelChannels*
1173 sizeof(*image->channel_map));
1174 p+=MaxPixelChannels*sizeof(*image->channel_map);
1175 (void) memcpy(p,&image->metacontent_extent,sizeof(image->metacontent_extent));
1176 p+=sizeof(image->metacontent_extent);
1177 count=dpc_send(server_info->file,p-message,message);
1178 if (count != (MagickOffsetType) (p-message))
1179 return(MagickFalse);
1180 status=MagickFalse;
1181 count=dpc_read(server_info->file,sizeof(status),(unsigned char *) &status);
1182 if (count != (MagickOffsetType) sizeof(status))
1183 return(MagickFalse);
1184 return(status);
1185 }
1186
1187 /*
1188 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1189 % %
1190 % %
1191 % %
1192 + 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 %
1193 % %
1194 % %
1195 % %
1196 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1197 %
1198 % ReadDistributePixelCacheMetacontents() reads metacontent from the specified
1199 % region of the distributed pixel cache.
1200 %
1201 % The format of the ReadDistributePixelCacheMetacontents method is:
1202 %
1203 % MagickOffsetType ReadDistributePixelCacheMetacontents(
1204 % DistributeCacheInfo *server_info,const RectangleInfo *region,
1205 % const MagickSizeType length,unsigned char *metacontent)
1206 %
1207 % A description of each parameter follows:
1208 %
1209 % o server_info: the distributed cache info.
1210 %
1211 % o image: the image.
1212 %
1213 % o region: read the metacontent from this region of the image.
1214 %
1215 % o length: the length in bytes of the metacontent.
1216 %
1217 % o metacontent: read these metacontent from the pixel cache.
1218 %
1219 */
ReadDistributePixelCacheMetacontent(DistributeCacheInfo * server_info,const RectangleInfo * region,const MagickSizeType length,unsigned char * metacontent)1220 MagickPrivate MagickOffsetType ReadDistributePixelCacheMetacontent(
1221 DistributeCacheInfo *server_info,const RectangleInfo *region,
1222 const MagickSizeType length,unsigned char *metacontent)
1223 {
1224 MagickOffsetType
1225 count;
1226
1227 register unsigned char
1228 *p;
1229
1230 unsigned char
1231 message[MagickPathExtent];
1232
1233 /*
1234 Read distributed pixel cache metacontent.
1235 */
1236 assert(server_info != (DistributeCacheInfo *) NULL);
1237 assert(server_info->signature == MagickCoreSignature);
1238 assert(region != (RectangleInfo *) NULL);
1239 assert(metacontent != (unsigned char *) NULL);
1240 if (length > (MagickSizeType) SSIZE_MAX)
1241 return(-1);
1242 p=message;
1243 *p++='R';
1244 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1245 p+=sizeof(server_info->session_key);
1246 (void) memcpy(p,®ion->width,sizeof(region->width));
1247 p+=sizeof(region->width);
1248 (void) memcpy(p,®ion->height,sizeof(region->height));
1249 p+=sizeof(region->height);
1250 (void) memcpy(p,®ion->x,sizeof(region->x));
1251 p+=sizeof(region->x);
1252 (void) memcpy(p,®ion->y,sizeof(region->y));
1253 p+=sizeof(region->y);
1254 (void) memcpy(p,&length,sizeof(length));
1255 p+=sizeof(length);
1256 count=dpc_send(server_info->file,p-message,message);
1257 if (count != (MagickOffsetType) (p-message))
1258 return(-1);
1259 return(dpc_read(server_info->file,length,metacontent));
1260 }
1261
1262 /*
1263 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1264 % %
1265 % %
1266 % %
1267 + 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 %
1268 % %
1269 % %
1270 % %
1271 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1272 %
1273 % ReadDistributePixelCachePixels() reads pixels from the specified region of
1274 % the distributed pixel cache.
1275 %
1276 % The format of the ReadDistributePixelCachePixels method is:
1277 %
1278 % MagickOffsetType ReadDistributePixelCachePixels(
1279 % DistributeCacheInfo *server_info,const RectangleInfo *region,
1280 % const MagickSizeType length,unsigned char *magick_restrict pixels)
1281 %
1282 % A description of each parameter follows:
1283 %
1284 % o server_info: the distributed cache info.
1285 %
1286 % o image: the image.
1287 %
1288 % o region: read the pixels from this region of the image.
1289 %
1290 % o length: the length in bytes of the pixels.
1291 %
1292 % o pixels: read these pixels from the pixel cache.
1293 %
1294 */
ReadDistributePixelCachePixels(DistributeCacheInfo * server_info,const RectangleInfo * region,const MagickSizeType length,unsigned char * magick_restrict pixels)1295 MagickPrivate MagickOffsetType ReadDistributePixelCachePixels(
1296 DistributeCacheInfo *server_info,const RectangleInfo *region,
1297 const MagickSizeType length,unsigned char *magick_restrict pixels)
1298 {
1299 MagickOffsetType
1300 count;
1301
1302 register unsigned char
1303 *p;
1304
1305 unsigned char
1306 message[MagickPathExtent];
1307
1308 /*
1309 Read distributed pixel cache pixels.
1310 */
1311 assert(server_info != (DistributeCacheInfo *) NULL);
1312 assert(server_info->signature == MagickCoreSignature);
1313 assert(region != (RectangleInfo *) NULL);
1314 assert(pixels != (unsigned char *) NULL);
1315 if (length > (MagickSizeType) SSIZE_MAX)
1316 return(-1);
1317 p=message;
1318 *p++='r';
1319 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1320 p+=sizeof(server_info->session_key);
1321 (void) memcpy(p,®ion->width,sizeof(region->width));
1322 p+=sizeof(region->width);
1323 (void) memcpy(p,®ion->height,sizeof(region->height));
1324 p+=sizeof(region->height);
1325 (void) memcpy(p,®ion->x,sizeof(region->x));
1326 p+=sizeof(region->x);
1327 (void) memcpy(p,®ion->y,sizeof(region->y));
1328 p+=sizeof(region->y);
1329 (void) memcpy(p,&length,sizeof(length));
1330 p+=sizeof(length);
1331 count=dpc_send(server_info->file,p-message,message);
1332 if (count != (MagickOffsetType) (p-message))
1333 return(-1);
1334 return(dpc_read(server_info->file,length,pixels));
1335 }
1336
1337 /*
1338 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1339 % %
1340 % %
1341 % %
1342 + 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 %
1343 % %
1344 % %
1345 % %
1346 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1347 %
1348 % RelinquishDistributePixelCache() frees resources acquired with
1349 % OpenDistributePixelCache().
1350 %
1351 % The format of the RelinquishDistributePixelCache method is:
1352 %
1353 % MagickBooleanType RelinquishDistributePixelCache(
1354 % DistributeCacheInfo *server_info)
1355 %
1356 % A description of each parameter follows:
1357 %
1358 % o server_info: the distributed cache info.
1359 %
1360 */
RelinquishDistributePixelCache(DistributeCacheInfo * server_info)1361 MagickPrivate MagickBooleanType RelinquishDistributePixelCache(
1362 DistributeCacheInfo *server_info)
1363 {
1364 MagickBooleanType
1365 #ifdef __VMS
1366 status = MagickTrue;
1367 #else
1368 status;
1369 #endif
1370
1371 MagickOffsetType
1372 count;
1373
1374 register unsigned char
1375 *p;
1376
1377 unsigned char
1378 message[MagickPathExtent];
1379
1380 /*
1381 Delete distributed pixel cache.
1382 */
1383 assert(server_info != (DistributeCacheInfo *) NULL);
1384 assert(server_info->signature == MagickCoreSignature);
1385 p=message;
1386 *p++='d';
1387 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1388 p+=sizeof(server_info->session_key);
1389 count=dpc_send(server_info->file,p-message,message);
1390 if (count != (MagickOffsetType) (p-message))
1391 return(MagickFalse);
1392 count=dpc_read(server_info->file,sizeof(status),(unsigned char *) &status);
1393 if (count != (MagickOffsetType) sizeof(status))
1394 return(MagickFalse);
1395 return(status);
1396 }
1397
1398 /*
1399 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1400 % %
1401 % %
1402 % %
1403 + 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 %
1404 % %
1405 % %
1406 % %
1407 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1408 %
1409 % WriteDistributePixelCacheMetacontents() writes image metacontent to the
1410 % specified region of the distributed pixel cache.
1411 %
1412 % The format of the WriteDistributePixelCacheMetacontents method is:
1413 %
1414 % MagickOffsetType WriteDistributePixelCacheMetacontents(
1415 % DistributeCacheInfo *server_info,const RectangleInfo *region,
1416 % const MagickSizeType length,const unsigned char *metacontent)
1417 %
1418 % A description of each parameter follows:
1419 %
1420 % o server_info: the distributed cache info.
1421 %
1422 % o image: the image.
1423 %
1424 % o region: write the metacontent to this region of the image.
1425 %
1426 % o length: the length in bytes of the metacontent.
1427 %
1428 % o metacontent: write these metacontent to the pixel cache.
1429 %
1430 */
WriteDistributePixelCacheMetacontent(DistributeCacheInfo * server_info,const RectangleInfo * region,const MagickSizeType length,const unsigned char * metacontent)1431 MagickPrivate MagickOffsetType WriteDistributePixelCacheMetacontent(
1432 DistributeCacheInfo *server_info,const RectangleInfo *region,
1433 const MagickSizeType length,const unsigned char *metacontent)
1434 {
1435 MagickOffsetType
1436 count;
1437
1438 register unsigned char
1439 *p;
1440
1441 unsigned char
1442 message[MagickPathExtent];
1443
1444 /*
1445 Write distributed pixel cache metacontent.
1446 */
1447 assert(server_info != (DistributeCacheInfo *) NULL);
1448 assert(server_info->signature == MagickCoreSignature);
1449 assert(region != (RectangleInfo *) NULL);
1450 assert(metacontent != (unsigned char *) NULL);
1451 if (length > (MagickSizeType) SSIZE_MAX)
1452 return(-1);
1453 p=message;
1454 *p++='W';
1455 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1456 p+=sizeof(server_info->session_key);
1457 (void) memcpy(p,®ion->width,sizeof(region->width));
1458 p+=sizeof(region->width);
1459 (void) memcpy(p,®ion->height,sizeof(region->height));
1460 p+=sizeof(region->height);
1461 (void) memcpy(p,®ion->x,sizeof(region->x));
1462 p+=sizeof(region->x);
1463 (void) memcpy(p,®ion->y,sizeof(region->y));
1464 p+=sizeof(region->y);
1465 (void) memcpy(p,&length,sizeof(length));
1466 p+=sizeof(length);
1467 count=dpc_send(server_info->file,p-message,message);
1468 if (count != (MagickOffsetType) (p-message))
1469 return(-1);
1470 return(dpc_send(server_info->file,length,metacontent));
1471 }
1472
1473 /*
1474 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1475 % %
1476 % %
1477 % %
1478 + 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 %
1479 % %
1480 % %
1481 % %
1482 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1483 %
1484 % WriteDistributePixelCachePixels() writes image pixels to the specified
1485 % region of the distributed pixel cache.
1486 %
1487 % The format of the WriteDistributePixelCachePixels method is:
1488 %
1489 % MagickBooleanType WriteDistributePixelCachePixels(
1490 % DistributeCacheInfo *server_info,const RectangleInfo *region,
1491 % const MagickSizeType length,
1492 % const unsigned char *magick_restrict pixels)
1493 %
1494 % A description of each parameter follows:
1495 %
1496 % o server_info: the distributed cache info.
1497 %
1498 % o image: the image.
1499 %
1500 % o region: write the pixels to this region of the image.
1501 %
1502 % o length: the length in bytes of the pixels.
1503 %
1504 % o pixels: write these pixels to the pixel cache.
1505 %
1506 */
WriteDistributePixelCachePixels(DistributeCacheInfo * server_info,const RectangleInfo * region,const MagickSizeType length,const unsigned char * magick_restrict pixels)1507 MagickPrivate MagickOffsetType WriteDistributePixelCachePixels(
1508 DistributeCacheInfo *server_info,const RectangleInfo *region,
1509 const MagickSizeType length,const unsigned char *magick_restrict pixels)
1510 {
1511 MagickOffsetType
1512 count;
1513
1514 register unsigned char
1515 *p;
1516
1517 unsigned char
1518 message[MagickPathExtent];
1519
1520 /*
1521 Write distributed pixel cache pixels.
1522 */
1523 assert(server_info != (DistributeCacheInfo *) NULL);
1524 assert(server_info->signature == MagickCoreSignature);
1525 assert(region != (RectangleInfo *) NULL);
1526 assert(pixels != (const unsigned char *) NULL);
1527 if (length > (MagickSizeType) SSIZE_MAX)
1528 return(-1);
1529 p=message;
1530 *p++='w';
1531 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1532 p+=sizeof(server_info->session_key);
1533 (void) memcpy(p,®ion->width,sizeof(region->width));
1534 p+=sizeof(region->width);
1535 (void) memcpy(p,®ion->height,sizeof(region->height));
1536 p+=sizeof(region->height);
1537 (void) memcpy(p,®ion->x,sizeof(region->x));
1538 p+=sizeof(region->x);
1539 (void) memcpy(p,®ion->y,sizeof(region->y));
1540 p+=sizeof(region->y);
1541 (void) memcpy(p,&length,sizeof(length));
1542 p+=sizeof(length);
1543 count=dpc_send(server_info->file,p-message,message);
1544 if (count != (MagickOffsetType) (p-message))
1545 return(-1);
1546 return(dpc_send(server_info->file,length,pixels));
1547 }
1548