MagickCore 7.1.2-32
Convert, Edit, Or Compose Bitmap Images
Loading...
Searching...
No Matches
distribute-cache.c
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 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/license/ %
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/utility-private.h"
76#include "MagickCore/version.h"
77#include "MagickCore/version-private.h"
78#define SOCKET_TYPE int
79#undef MAGICKCORE_HAVE_DISTRIBUTE_CACHE
80#if defined(MAGICKCORE_DPC_SUPPORT)
81#if defined(MAGICKCORE_HAVE_SOCKET) && defined(MAGICKCORE_THREAD_SUPPORT)
82#include <netinet/in.h>
83#include <netdb.h>
84#include <sys/socket.h>
85#include <arpa/inet.h>
86#define CLOSE_SOCKET(socket) (void) close_utf8(socket)
87#define HANDLER_RETURN_TYPE void *
88#define HANDLER_RETURN_VALUE (void *) NULL
89#define SOCKET_TYPE int
90#define LENGTH_TYPE size_t
91#define MAGICKCORE_HAVE_DISTRIBUTE_CACHE 1
92#elif defined(_MSC_VER)
93#define CLOSE_SOCKET(socket) (void) closesocket(socket)
94#define HANDLER_RETURN_TYPE DWORD WINAPI
95#define HANDLER_RETURN_VALUE 0
96#define LENGTH_TYPE int
97#define MAGICKCORE_HAVE_DISTRIBUTE_CACHE 1
98#define MAGICKCORE_HAVE_WINSOCK2 1
99#endif
100#endif
101␌
102/*
103 Define declarations.
104*/
105#define DPCHostname "127.0.0.1"
106#define DPCMaxClientWorkers 128
107#define DPCMaxUnauthenticatedClientWorkers 16
108#define DPCPendingConnections 10
109#define DPCPort 6668
110#define DPCSessionKeyLength 16
111#ifndef MSG_NOSIGNAL
112# define MSG_NOSIGNAL 0
113#endif
114␌
115/*
116 Static declarations.
117*/
118#ifdef MAGICKCORE_HAVE_WINSOCK2
119static SemaphoreInfo
120 *winsock_semaphore = (SemaphoreInfo *) NULL;
121
122static WSADATA
123 *wsaData = (WSADATA*) NULL;
124#endif
125
126#if defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
127static SemaphoreInfo
128 *dpc_semaphore = (SemaphoreInfo *) NULL;
129
130static char
131 *dpc_shared_secret = (char *) NULL;
132
133static size_t
134 dpc_clients = 0,
135 dpc_unauthenticated_clients = 0;
136#endif
137␌
138/*
139%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
140% %
141% %
142% %
143+ 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 %
144% %
145% %
146% %
147%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
148%
149% AcquireDistributeCacheInfo() allocates the DistributeCacheInfo structure.
150%
151% The format of the AcquireDistributeCacheInfo method is:
152%
153% DistributeCacheInfo *AcquireDistributeCacheInfo(ExceptionInfo *exception)
154%
155% A description of each parameter follows:
156%
157% o exception: return any errors or warnings in this structure.
158%
159*/
160
161#if !defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
162static inline MagickOffsetType dpc_receive(SOCKET_TYPE magick_unused(file),
163 const MagickSizeType magick_unused(length),
164 unsigned char *magick_restrict magick_unused(message))
165{
166 magick_unreferenced(file);
167 magick_unreferenced(length);
168 magick_unreferenced(message);
169 return(-1);
170}
171
172static inline MagickOffsetType dpc_receive_deadline(SOCKET_TYPE
173 magick_unused(file),const MagickSizeType magick_unused(length),
174 unsigned char *magick_restrict magick_unused(message),
175 double magick_unused(deadline))
176{
177 magick_unreferenced(file);
178 magick_unreferenced(length);
179 magick_unreferenced(message);
180 magick_unreferenced(deadline);
181 return(-1);
182}
183#else
184static void SetSocketReceiveTimeout(SOCKET_TYPE file,double seconds)
185{
186 /*
187 Set a receive timeout.
188 */
189#if defined(MAGICKCORE_HAVE_WINSOCK2)
190 {
191 DWORD timeout = (DWORD) (seconds*1000.0);
192 (void) setsockopt(file,SOL_SOCKET,SO_RCVTIMEO,
193 (const char *) &timeout,sizeof(timeout));
194 }
195#else
196 {
197 struct timeval tv;
198 tv.tv_sec=(int) seconds;
199 tv.tv_usec=(int) ((seconds-(double) tv.tv_sec)*1000000.0);
200 (void) setsockopt(file,SOL_SOCKET,SO_RCVTIMEO,&tv,sizeof(tv));
201 }
202#endif
203}
204
205static inline MagickOffsetType dpc_receive(SOCKET_TYPE file,
206 const MagickSizeType length,unsigned char *magick_restrict message)
207{
208 MagickOffsetType offset = 0;
209 while (offset < (MagickOffsetType) length)
210 {
211 MagickSizeType chunk = MagickMin(length-offset,(MagickSizeType)
212 MagickMaxBufferExtent);
213 ssize_t count = recv(file,(char *) message+offset,(LENGTH_TYPE) chunk,0);
214 if (count > 0)
215 offset+=(MagickOffsetType) count;
216 else
217 if (count == 0)
218 return(0);
219 else
220 {
221#ifdef MAGICKCORE_HAVE_WINSOCK2
222 int wsa_err = WSAGetLastError();
223 if ((wsa_err == WSAEINTR) || (wsa_err == WSAEWOULDBLOCK))
224 continue;
225 if (wsa_err == WSAECONNRESET)
226 return(-2);
227#else
228 if ((errno == EINTR) || (errno == EAGAIN) || (errno == EWOULDBLOCK))
229 continue;
230 if (errno == ECONNRESET)
231 return(-2);
232#endif
233 return(-1);
234 }
235 }
236 return(offset);
237}
238
239static inline MagickOffsetType dpc_receive_deadline(SOCKET_TYPE file,
240 MagickSizeType length,unsigned char *message,double deadline)
241{
242 /*
243 Enforce an absolute deadline for authentication and command reads.
244 */
245 MagickOffsetType offset = 0;
246 while (offset < (MagickOffsetType) length)
247 {
248 double
249 now = (double) time((time_t *) NULL),
250 remaining = deadline-now;
251
252 MagickSizeType
253 chunk;
254
255 ssize_t
256 count;
257
258 if (now >= deadline)
259 return(-1);
260 if (remaining < 0.001)
261 remaining=0.001;
262 SetSocketReceiveTimeout(file,remaining);
263 chunk=MagickMin(length-offset,(MagickSizeType) MagickMaxBufferExtent);
264 count=recv(file,(char *) message+offset,(LENGTH_TYPE) chunk,0);
265 if (count > 0)
266 offset+=(MagickOffsetType) count;
267 else
268 if (count == 0)
269 return(0);
270 else
271 {
272#ifdef MAGICKCORE_HAVE_WINSOCK2
273 int wsa_err = WSAGetLastError();
274 if ((wsa_err == WSAEINTR) || (wsa_err == WSAEWOULDBLOCK))
275 continue;
276 if (wsa_err == WSAECONNRESET)
277 return(-2);
278 return(-1);
279#else
280 if ((errno == EINTR) || (errno == EAGAIN) || (errno == EWOULDBLOCK))
281 continue;
282 if (errno == ECONNRESET)
283 return(-2);
284 return(-1);
285#endif
286 }
287 }
288 return(offset);
289}
290#endif
291
292#if defined(MAGICKCORE_HAVE_WINSOCK2)
293static void InitializeWinsock2(MagickBooleanType use_lock)
294{
295 if (use_lock != MagickFalse)
296 {
297 if (winsock_semaphore == (SemaphoreInfo *) NULL)
298 ActivateSemaphoreInfo(&winsock_semaphore);
299 LockSemaphoreInfo(winsock_semaphore);
300 }
301 if (wsaData == (WSADATA *) NULL)
302 {
303 wsaData=(WSADATA *) AcquireMagickMemory(sizeof(WSADATA));
304 if (WSAStartup(MAKEWORD(2,2),wsaData) != 0)
305 ThrowFatalException(CacheFatalError,"WSAStartup failed");
306 }
307 if (use_lock != MagickFalse)
308 UnlockSemaphoreInfo(winsock_semaphore);
309}
310#endif
311
312#if !defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
313static int ConnectPixelCacheServer(const char *magick_unused(hostname),
314 const int magick_unused(port),uint64_t *magick_unused(session_key),
315 ExceptionInfo *exception)
316{
317 magick_unreferenced(hostname);
318 magick_unreferenced(port);
319 magick_unreferenced(session_key);
320 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
321 "DelegateLibrarySupportNotBuiltIn","distributed pixel cache");
322 return(MagickFalse);
323}
324#else
325static inline uint64_t ROTL(uint64_t x,int b)
326{
327 return((x << b) | (x >> (64-b)));
328}
329
330static inline uint64_t U8TO64_LE(const uint8_t *p)
331{
332 return(((uint64_t) p[0] << 0) | ((uint64_t) p[1] << 8) |
333 ((uint64_t) p[2] << 16) | ((uint64_t) p[3] << 24) |
334 ((uint64_t) p[4] << 32) | ((uint64_t) p[5] << 40) |
335 ((uint64_t) p[6] << 48) | ((uint64_t) p[7] << 56));
336}
337
338static inline uint64_t SIPHash24(const uint8_t key[16],const uint8_t *message,
339 const size_t length)
340{
341 const uint8_t
342 *end = message+length-(length % 8);
343
344 size_t
345 i;
346
347 uint64_t
348 b = ((uint64_t) length) << 56,
349 k0 = U8TO64_LE(key),
350 k1 = U8TO64_LE(key+8),
351 m,
352 v0 = 0x736f6d6570736575ULL ^ k0,
353 v1 = 0x646f72616e646f6dULL ^ k1,
354 v2 = 0x6c7967656e657261ULL ^ k0,
355 v3 = 0x7465646279746573ULL ^ k1;
356
357 for ( ; message != end; message+=8)
358 {
359 m=U8TO64_LE(message);
360 v3^=m;
361 for (i=0; i < 2; i++)
362 {
363 v0+=v1; v1=ROTL(v1,13); v1^=v0; v0=ROTL(v0,32);
364 v2+=v3; v3=ROTL(v3,16); v3^=v2;
365 v0+=v3; v3=ROTL(v3,21); v3^=v0;
366 v2+=v1; v1=ROTL(v1,17); v1^=v2; v2=ROTL(v2,32);
367 }
368 v0^=m;
369 }
370 switch (length & 0x07)
371 {
372 case 7: b|=((uint64_t) message[6]) << 48; magick_fallthrough;
373 case 6: b|=((uint64_t) message[5]) << 40; magick_fallthrough;
374 case 5: b|=((uint64_t) message[4]) << 32; magick_fallthrough;
375 case 4: b|=((uint64_t) message[3]) << 24; magick_fallthrough;
376 case 3: b|=((uint64_t) message[2]) << 16; magick_fallthrough;
377 case 2: b|=((uint64_t) message[1]) << 8; magick_fallthrough;
378 case 1: b|=((uint64_t) message[0]); magick_fallthrough;
379 default: break;
380 }
381 v3^=b;
382 for (i=0; i < 2; i++)
383 {
384 v0+=v1; v1=ROTL(v1,13); v1^=v0; v0=ROTL(v0,32);
385 v2+=v3; v3=ROTL(v3,16); v3^=v2;
386 v0+=v3; v3=ROTL(v3,21); v3^=v0;
387 v2+=v1; v1=ROTL(v1,17); v1^=v2; v2=ROTL(v2,32);
388 }
389 v0^=b;
390 v2^=0xff;
391 for (i=0; i < 4; i++)
392 {
393 v0+=v1; v1=ROTL(v1,13); v1^=v0; v0=ROTL(v0,32);
394 v2+=v3; v3=ROTL(v3,16); v3^=v2;
395 v0+=v3; v3=ROTL(v3,21); v3^=v0;
396 v2+=v1; v1=ROTL(v1,17); v1^=v2; v2=ROTL(v2,32);
397 }
398 return(v0^v1^v2^v3);
399}
400
401static inline void DeriveSIPKeyFromSecret(const char *shared_secret,
402 uint8_t key[16])
403{
404 size_t
405 i,
406 length;
407
408 uint64_t
409 k0 = 0x0706050403020100ULL,
410 k1 = 0x0f0e0d0c0b0a0908ULL;
411
412 length=strlen(shared_secret);
413 for (i=0; i < length; i++)
414 {
415 uint8_t
416 b = (uint8_t) shared_secret[i];
417
418 k0^=b;
419 k0*=0x100000001b3ULL;
420 k1^=(uint64_t) b << ((i & 7)*8);
421 k1=(k1 << 5) | (k1 >> (64-5));
422 }
423 (void) memcpy(key,&k0,8);
424 (void) memcpy(key+8,&k1,8);
425}
426
427static inline uint64_t GenerateSessionKey(const char *shared_secret,
428 const unsigned char *nonce,size_t length)
429{
430 uint8_t
431 key[16];
432
433 DeriveSIPKeyFromSecret(shared_secret,key);
434 return(SIPHash24(key,nonce,length));
435}
436
437static int ConnectPixelCacheServer(const char *hostname,const int port,
438 uint64_t *session_key,ExceptionInfo *exception)
439{
440#if defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
441 char
442 *message,
443 service[MagickPathExtent],
444 *shared_secret;
445
446 int
447 status;
448
449 SOCKET_TYPE
450 client_socket;
451
452 ssize_t
453 count;
454
455 struct addrinfo
456 hints,
457 *result;
458
459 unsigned char
460 nonce[DPCSessionKeyLength];
461
462 /*
463 Connect to distributed pixel cache server and get session key.
464 */
465 *session_key=0;
466#if defined(MAGICKCORE_HAVE_WINSOCK2)
467 InitializeWinsock2(MagickTrue);
468#endif
469 (void) memset(&hints,0,sizeof(hints));
470 hints.ai_family=AF_INET;
471 hints.ai_socktype=SOCK_STREAM;
472 hints.ai_flags=AI_PASSIVE;
473 (void) FormatLocaleString(service,MagickPathExtent,"%d",port);
474 status=getaddrinfo(hostname,service,&hints,&result);
475 if (status != 0)
476 {
477 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
478 "DistributedPixelCache","'%s': %s",hostname,gai_strerror(status));
479 return(-1);
480 }
481 client_socket=(SOCKET_TYPE) socket(result->ai_family,result->ai_socktype,
482 result->ai_protocol);
483 if (client_socket == -1)
484 {
485 freeaddrinfo(result);
486 message=GetExceptionMessage(errno);
487 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
488 "DistributedPixelCache","'%s': %s",hostname,message);
489 message=DestroyString(message);
490 return(-1);
491 }
492 status=connect(client_socket,result->ai_addr,(socklen_t) result->ai_addrlen);
493 freeaddrinfo(result);
494 if (status == -1)
495 {
496 CLOSE_SOCKET(client_socket);
497 message=GetExceptionMessage(errno);
498 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
499 "DistributedPixelCache","'%s': %s",hostname,message);
500 message=DestroyString(message);
501 return(-1);
502 }
503 /*
504 Receive server nonce.
505 */
506 count=recv(client_socket,(char *) nonce,sizeof(nonce),0);
507 if (count != (ssize_t) sizeof(nonce))
508 {
509 CLOSE_SOCKET(client_socket);
510 message=GetExceptionMessage(errno);
511 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
512 "DistributedPixelCache","'%s': %s",hostname,message);
513 message=DestroyString(message);
514 return(-1);
515 }
516 /*
517 Compute keyed hash(shared_secret,nonce).
518 */
519 shared_secret=GetPolicyValue("cache:shared-secret");
520 if (shared_secret == (const char *) NULL)
521 {
522 CLOSE_SOCKET(client_socket);
523 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
524 "DistributedPixelCache","'%s': shared secret required",hostname);
525 return(-1);
526 }
527 *session_key=GenerateSessionKey(shared_secret,nonce,sizeof(nonce));
528 shared_secret=DestroyString(shared_secret);
529 /*
530 Send keyed hash back to client.
531 */
532 count=send(client_socket,(char *) session_key,sizeof(*session_key),
533 MSG_NOSIGNAL);
534 if (count != (ssize_t) sizeof(*session_key))
535 {
536 CLOSE_SOCKET(client_socket);
537 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
538 "DistributedPixelCache","'%s': authentication failed",hostname);
539 return(-1);
540 }
541 return((int) client_socket);
542#else
543 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
544 "DelegateLibrarySupportNotBuiltIn","distributed pixel cache");
545 return(-1);
546#endif
547}
548#endif
549
550static char *GetHostname(int *port,ExceptionInfo *exception)
551{
552 char
553 *host,
554 *hosts,
555 **hostlist;
556
557 int
558 argc;
559
560 ssize_t
561 i;
562
563 static size_t
564 id = 0;
565
566 /*
567 Parse host list (e.g. 192.168.100.1:6668,192.168.100.2:6668).
568 */
569 hosts=(char *) GetImageRegistry(StringRegistryType,"cache:hosts",exception);
570 if (hosts == (char *) NULL)
571 {
572 *port=DPCPort;
573 return(AcquireString(DPCHostname));
574 }
575 (void) SubstituteString(&hosts,","," ");
576 hostlist=StringToArgv(hosts,&argc);
577 hosts=DestroyString(hosts);
578 if ((hostlist == (char **) NULL) || ((argc-1) == 0))
579 {
580 *port=DPCPort;
581 return(AcquireString(DPCHostname));
582 }
583 {
584 size_t host_count = (size_t) argc-1;
585 size_t index = (id++ % host_count)+1;
586 hosts=AcquireString(hostlist[index]);
587 }
588 for (i=0; i < (ssize_t) argc; i++)
589 hostlist[i]=DestroyString(hostlist[i]);
590 hostlist=(char **) RelinquishMagickMemory(hostlist);
591 (void) SubstituteString(&hosts,":"," ");
592 hostlist=StringToArgv(hosts,&argc);
593 if (hostlist == (char **) NULL)
594 {
595 *port=DPCPort;
596 return(AcquireString(DPCHostname));
597 }
598 host=AcquireString(hostlist[1]);
599 if (hostlist[2] == (char *) NULL)
600 *port=DPCPort;
601 else
602 *port=(int) StringToLong(hostlist[2]);
603 for (i=0; i < (ssize_t) argc; i++)
604 hostlist[i]=DestroyString(hostlist[i]);
605 hostlist=(char **) RelinquishMagickMemory(hostlist);
606 return(host);
607}
608
609MagickPrivate DistributeCacheInfo *AcquireDistributeCacheInfo(
610 ExceptionInfo *exception)
611{
612 char
613 *hostname;
614
615 DistributeCacheInfo
616 *server_info;
617
618 uint64_t
619 session_key;
620
621 /*
622 Connect to the distributed pixel cache server.
623 */
624 server_info=(DistributeCacheInfo *) AcquireCriticalMemory(
625 sizeof(*server_info));
626 (void) memset(server_info,0,sizeof(*server_info));
627 server_info->signature=MagickCoreSignature;
628 server_info->port=0;
629 hostname=GetHostname(&server_info->port,exception);
630 session_key=0;
631 server_info->file=ConnectPixelCacheServer(hostname,server_info->port,
632 &session_key,exception);
633 if (server_info->file == -1)
634 server_info=DestroyDistributeCacheInfo(server_info);
635 else
636 {
637 server_info->session_key=session_key;
638 (void) CopyMagickString(server_info->hostname,hostname,MagickPathExtent);
639 server_info->debug=(GetLogEventMask() & CacheEvent) != 0 ? MagickTrue :
640 MagickFalse;
641 }
642 hostname=DestroyString(hostname);
643 return(server_info);
644}
645␌
646/*
647%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
648% %
649% %
650% %
651+ 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 %
652% %
653% %
654% %
655%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
656%
657% DestroyDistributeCacheInfo() deallocates memory associated with an
658% DistributeCacheInfo structure.
659%
660% The format of the DestroyDistributeCacheInfo method is:
661%
662% DistributeCacheInfo *DestroyDistributeCacheInfo(
663% DistributeCacheInfo *server_info)
664%
665% A description of each parameter follows:
666%
667% o server_info: the distributed cache info.
668%
669*/
670MagickPrivate DistributeCacheInfo *DestroyDistributeCacheInfo(
671 DistributeCacheInfo *server_info)
672{
673 assert(server_info != (DistributeCacheInfo *) NULL);
674 assert(server_info->signature == MagickCoreSignature);
675#if defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
676 if (server_info->file >= 0)
677 CLOSE_SOCKET(server_info->file);
678#endif
679 server_info->signature=(~MagickCoreSignature);
680 server_info=(DistributeCacheInfo *) RelinquishMagickMemory(server_info);
681 return(server_info);
682}
683␌
684/*
685%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
686% %
687% %
688% %
689+ 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 %
690% %
691% %
692% %
693%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
694%
695% DistributePixelCacheServer() waits on the specified port for commands to
696% create, read, update, or destroy a pixel cache.
697%
698% The format of the DistributePixelCacheServer() method is:
699%
700% void DistributePixelCacheServer(const int port)
701%
702% A description of each parameter follows:
703%
704% o port: connect the distributed pixel cache at this port.
705%
706% o exception: return any errors or warnings in this structure.
707%
708*/
709
710#if !defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
711static inline MagickOffsetType dpc_send(SOCKET_TYPE magick_unused(file),
712 const MagickSizeType magick_unused(length),
713 const void *magick_restrict magick_unused(message))
714{
715 magick_unreferenced(file);
716 magick_unreferenced(length);
717 magick_unreferenced(message);
718 return(-1);
719}
720#else
721static inline MagickOffsetType dpc_send(SOCKET_TYPE file,
722 const MagickSizeType length,const void *magick_restrict message)
723{
724 MagickOffsetType
725 i;
726
727 ssize_t
728 count;
729
730 /*
731 Ensure a complete message is sent.
732 */
733 count=0;
734 for (i=0; i < (MagickOffsetType) length; i+=count)
735 {
736 count=(ssize_t) send(file,(const char *) message+i,(LENGTH_TYPE) MagickMin(
737 length-(MagickSizeType) i,(MagickSizeType) MagickMaxBufferExtent),
738 MSG_NOSIGNAL);
739 if (count <= 0)
740 {
741 count=0;
742 if (errno != EINTR)
743 break;
744 }
745 }
746 return(i);
747}
748#endif
749
750#if !defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
751MagickExport void DistributePixelCacheServer(const int magick_unused(port),
752 ExceptionInfo *magick_unused(exception))
753{
754 magick_unreferenced(port);
755 magick_unreferenced(exception);
756 ThrowFatalException(MissingDelegateError,"DelegateLibrarySupportNotBuiltIn");
757}
758#else
759static MagickBooleanType DestroyDistributeCache(SplayTreeInfo *registry,
760 const uint64_t session_key)
761{
762 MagickAddressType
763 key = (MagickAddressType) session_key;
764
765 /*
766 Destroy distributed pixel cache.
767 */
768 return(DeleteNodeFromSplayTree(registry,(const void *) key));
769}
770
771static MagickBooleanType OpenDistributeCache(SplayTreeInfo *registry,
772 SOCKET_TYPE file,const uint64_t session_key,ExceptionInfo *exception)
773{
774 Image
775 *image;
776
777 MagickAddressType
778 key = (MagickAddressType) session_key;
779
780 MagickBooleanType
781 status;
782
783 MagickOffsetType
784 count;
785
786 MagickSizeType
787 length;
788
789 unsigned char
790 message[MagickPathExtent],
791 *p;
792
793 /*
794 Open distributed pixel cache.
795 */
796 image=AcquireImage((ImageInfo *) NULL,exception);
797 if (image == (Image *) NULL)
798 return(MagickFalse);
799 length=sizeof(image->storage_class)+sizeof(image->colorspace)+
800 sizeof(image->alpha_trait)+sizeof(image->channels)+sizeof(image->columns)+
801 sizeof(image->rows)+sizeof(image->number_channels)+MaxPixelChannels*
802 sizeof(*image->channel_map)+sizeof(image->metacontent_extent);
803 count=dpc_receive(file,length,message);
804 if (count != (MagickOffsetType) length)
805 {
806 image=DestroyImage(image);
807 return(MagickFalse);
808 }
809 /*
810 Deserialize the image attributes.
811 */
812 p=message;
813 (void) memcpy(&image->storage_class,p,sizeof(image->storage_class));
814 p+=(ptrdiff_t) sizeof(image->storage_class);
815 (void) memcpy(&image->colorspace,p,sizeof(image->colorspace));
816 p+=(ptrdiff_t) sizeof(image->colorspace);
817 (void) memcpy(&image->alpha_trait,p,sizeof(image->alpha_trait));
818 p+=(ptrdiff_t) sizeof(image->alpha_trait);
819 (void) memcpy(&image->channels,p,sizeof(image->channels));
820 p+=(ptrdiff_t) sizeof(image->channels);
821 (void) memcpy(&image->columns,p,sizeof(image->columns));
822 p+=(ptrdiff_t) sizeof(image->columns);
823 (void) memcpy(&image->rows,p,sizeof(image->rows));
824 p+=(ptrdiff_t) sizeof(image->rows);
825 (void) memcpy(&image->number_channels,p,sizeof(image->number_channels));
826 p+=(ptrdiff_t) sizeof(image->number_channels);
827 (void) memcpy(image->channel_map,p,MaxPixelChannels*
828 sizeof(*image->channel_map));
829 p+=(ptrdiff_t) MaxPixelChannels*sizeof(*image->channel_map);
830 (void) memcpy(&image->metacontent_extent,p,sizeof(image->metacontent_extent));
831 p+=(ptrdiff_t) sizeof(image->metacontent_extent);
832 if (SyncImagePixelCache(image,exception) == MagickFalse)
833 {
834 image=DestroyImage(image);
835 return(MagickFalse);
836 }
837 status=AddValueToSplayTree(registry,(const void *) key,image);
838 if (status == MagickFalse)
839 {
840 image=DestroyImage(image);
841 return(MagickFalse);
842 }
843 return(status);
844}
845
846static inline MagickBooleanType ValidateDistributedPixelCache(
847 const RectangleInfo *region,const size_t per_pixel,
848 const MagickSizeType length)
849{
850 size_t
851 extent = 0,
852 pixels = 0;
853
854 if (HeapOverflowSanityCheckGetSize(region->width,region->height,&pixels) != MagickFalse)
855 return(MagickFalse);
856 if (HeapOverflowSanityCheckGetSize(pixels,per_pixel,&extent) != MagickFalse)
857 return(MagickFalse);
858 if (length > (MagickSizeType) extent)
859 return(MagickFalse);
860 return(MagickTrue);
861}
862
863static MagickBooleanType ReadDistributeCacheMetacontent(SplayTreeInfo *registry,
864 SOCKET_TYPE file,const uint64_t session_key,ExceptionInfo *exception)
865{
866 const Quantum
867 *p;
868
869 const unsigned char
870 *metacontent;
871
872 Image
873 *image;
874
875 MagickAddressType
876 key = (MagickAddressType) session_key;
877
878 MagickOffsetType
879 count;
880
881 MagickSizeType
882 length;
883
884 RectangleInfo
885 region;
886
887 size_t
888 per_pixel;
889
890 unsigned char
891 message[MagickPathExtent],
892 *q;
893
894 /*
895 Read distributed pixel cache metacontent.
896 */
897 image=(Image *) GetValueFromSplayTree(registry,(const void *) key);
898 if (image == (Image *) NULL)
899 return(MagickFalse);
900 length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
901 sizeof(region.y)+sizeof(length);
902 count=dpc_receive(file,length,message);
903 if (count != (MagickOffsetType) length)
904 return(MagickFalse);
905 q=message;
906 (void) memcpy(&region.width,q,sizeof(region.width));
907 q+=(ptrdiff_t) sizeof(region.width);
908 (void) memcpy(&region.height,q,sizeof(region.height));
909 q+=(ptrdiff_t) sizeof(region.height);
910 (void) memcpy(&region.x,q,sizeof(region.x));
911 q+=(ptrdiff_t) sizeof(region.x);
912 (void) memcpy(&region.y,q,sizeof(region.y));
913 q+=(ptrdiff_t) sizeof(region.y);
914 (void) memcpy(&length,q,sizeof(length));
915 q+=(ptrdiff_t) sizeof(length);
916 per_pixel=image->number_meta_channels*sizeof(Quantum);
917 if (ValidateDistributedPixelCache(&region,per_pixel,length) == MagickFalse)
918 return(MagickFalse);
919 p=GetVirtualPixels(image,region.x,region.y,region.width,region.height,
920 exception);
921 if (p == (const Quantum *) NULL)
922 return(MagickFalse);
923 metacontent=(const unsigned char *) GetVirtualMetacontent(image);
924 count=dpc_send(file,length,metacontent);
925 if (count != (MagickOffsetType) length)
926 return(MagickFalse);
927 return(MagickTrue);
928}
929
930static MagickBooleanType ReadDistributeCachePixels(SplayTreeInfo *registry,
931 SOCKET_TYPE file,const uint64_t session_key,ExceptionInfo *exception)
932{
933 const Quantum
934 *p;
935
936 Image
937 *image;
938
939 MagickAddressType
940 key = (MagickAddressType) session_key;
941
942 MagickOffsetType
943 count;
944
945 MagickSizeType
946 length;
947
948 RectangleInfo
949 region;
950
951 size_t
952 per_pixel;
953
954 unsigned char
955 message[MagickPathExtent],
956 *q;
957
958 /*
959 Read distributed pixel cache pixels.
960 */
961 image=(Image *) GetValueFromSplayTree(registry,(const void *) key);
962 if (image == (Image *) NULL)
963 return(MagickFalse);
964 length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
965 sizeof(region.y)+sizeof(length);
966 count=dpc_receive(file,length,message);
967 if (count != (MagickOffsetType) length)
968 return(MagickFalse);
969 q=message;
970 (void) memcpy(&region.width,q,sizeof(region.width));
971 q+=(ptrdiff_t) sizeof(region.width);
972 (void) memcpy(&region.height,q,sizeof(region.height));
973 q+=(ptrdiff_t) sizeof(region.height);
974 (void) memcpy(&region.x,q,sizeof(region.x));
975 q+=(ptrdiff_t) sizeof(region.x);
976 (void) memcpy(&region.y,q,sizeof(region.y));
977 q+=(ptrdiff_t) sizeof(region.y);
978 (void) memcpy(&length,q,sizeof(length));
979 per_pixel=image->number_channels*sizeof(Quantum);
980 if (ValidateDistributedPixelCache(&region,per_pixel,length) == MagickFalse)
981 return(MagickFalse);
982 q+=(ptrdiff_t) sizeof(length);
983 p=GetVirtualPixels(image,region.x,region.y,region.width,region.height,
984 exception);
985 if (p == (const Quantum *) NULL)
986 return(MagickFalse);
987 count=dpc_send(file,length,p);
988 if (count != (MagickOffsetType) length)
989 return(MagickFalse);
990 return(MagickTrue);
991}
992
993static void *RelinquishImageRegistry(void *image)
994{
995 return((void *) DestroyImageList((Image *) image));
996}
997
998static MagickBooleanType WriteDistributeCacheMetacontent(
999 SplayTreeInfo *registry,SOCKET_TYPE file,const uint64_t session_key,
1000 ExceptionInfo *exception)
1001{
1002 Image
1003 *image;
1004
1005 MagickAddressType
1006 key = (MagickAddressType) session_key;
1007
1008 MagickOffsetType
1009 count;
1010
1011 MagickSizeType
1012 length;
1013
1014 Quantum
1015 *q;
1016
1017 RectangleInfo
1018 region;
1019
1020 size_t
1021 per_pixel;
1022
1023 unsigned char
1024 message[MagickPathExtent],
1025 *metacontent,
1026 *p;
1027
1028 /*
1029 Write distributed pixel cache metacontent.
1030 */
1031 image=(Image *) GetValueFromSplayTree(registry,(const void *) key);
1032 if (image == (Image *) NULL)
1033 return(MagickFalse);
1034 length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
1035 sizeof(region.y)+sizeof(length);
1036 count=dpc_receive(file,length,message);
1037 if (count != (MagickOffsetType) length)
1038 return(MagickFalse);
1039 p=message;
1040 (void) memcpy(&region.width,p,sizeof(region.width));
1041 p+=(ptrdiff_t) sizeof(region.width);
1042 (void) memcpy(&region.height,p,sizeof(region.height));
1043 p+=(ptrdiff_t) sizeof(region.height);
1044 (void) memcpy(&region.x,p,sizeof(region.x));
1045 p+=(ptrdiff_t) sizeof(region.x);
1046 (void) memcpy(&region.y,p,sizeof(region.y));
1047 p+=(ptrdiff_t) sizeof(region.y);
1048 (void) memcpy(&length,p,sizeof(length));
1049 per_pixel=image->number_meta_channels*sizeof(Quantum);
1050 if (ValidateDistributedPixelCache(&region,per_pixel,length) == MagickFalse)
1051 return(MagickFalse);
1052 p+=(ptrdiff_t) sizeof(length);
1053 q=GetAuthenticPixels(image,region.x,region.y,region.width,region.height,
1054 exception);
1055 if (q == (Quantum *) NULL)
1056 return(MagickFalse);
1057 metacontent=(unsigned char *) GetAuthenticMetacontent(image);
1058 count=dpc_receive(file,length,metacontent);
1059 if (count != (MagickOffsetType) length)
1060 return(MagickFalse);
1061 return(SyncAuthenticPixels(image,exception));
1062}
1063
1064static MagickBooleanType WriteDistributeCachePixels(SplayTreeInfo *registry,
1065 SOCKET_TYPE file,const uint64_t session_key,ExceptionInfo *exception)
1066{
1067 Image
1068 *image;
1069
1070 MagickAddressType
1071 key = (MagickAddressType) session_key;
1072
1073 MagickOffsetType
1074 count;
1075
1076 MagickSizeType
1077 length;
1078
1079 Quantum
1080 *q;
1081
1082 RectangleInfo
1083 region;
1084
1085 size_t
1086 per_pixel;
1087
1088 unsigned char
1089 message[MagickPathExtent],
1090 *p;
1091
1092 /*
1093 Write distributed pixel cache pixels.
1094 */
1095 image=(Image *) GetValueFromSplayTree(registry,(const void *) key);
1096 if (image == (Image *) NULL)
1097 return(MagickFalse);
1098 length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
1099 sizeof(region.y)+sizeof(length);
1100 count=dpc_receive(file,length,message);
1101 if (count != (MagickOffsetType) length)
1102 return(MagickFalse);
1103 p=message;
1104 (void) memcpy(&region.width,p,sizeof(region.width));
1105 p+=(ptrdiff_t) sizeof(region.width);
1106 (void) memcpy(&region.height,p,sizeof(region.height));
1107 p+=(ptrdiff_t) sizeof(region.height);
1108 (void) memcpy(&region.x,p,sizeof(region.x));
1109 p+=(ptrdiff_t) sizeof(region.x);
1110 (void) memcpy(&region.y,p,sizeof(region.y));
1111 p+=(ptrdiff_t) sizeof(region.y);
1112 (void) memcpy(&length,p,sizeof(length));
1113 per_pixel=image->number_channels*sizeof(Quantum);
1114 if (ValidateDistributedPixelCache(&region,per_pixel,length) == MagickFalse)
1115 return(MagickFalse);
1116 p+=(ptrdiff_t) sizeof(length);
1117 q=GetAuthenticPixels(image,region.x,region.y,region.width,region.height,
1118 exception);
1119 if (q == (Quantum *) NULL)
1120 return(MagickFalse);
1121 count=dpc_receive(file,length,(unsigned char *) q);
1122 if (count != (MagickOffsetType) length)
1123 return(MagickFalse);
1124 return(SyncAuthenticPixels(image,exception));
1125}
1126
1127static void LockDPCSemaphore(void)
1128{
1129 if (dpc_semaphore == (SemaphoreInfo *) NULL)
1130 ActivateSemaphoreInfo(&dpc_semaphore);
1131 LockSemaphoreInfo(dpc_semaphore);
1132}
1133
1134static void AuthenticateDPCClient(void)
1135{
1136 LockDPCSemaphore();
1137 if (dpc_unauthenticated_clients != 0)
1138 dpc_unauthenticated_clients--;
1139 UnlockSemaphoreInfo(dpc_semaphore);
1140}
1141
1142static void RelinquishDPCClient(const MagickBooleanType unauthenticated)
1143{
1144 LockDPCSemaphore();
1145 if ((unauthenticated != MagickFalse) && (dpc_unauthenticated_clients != 0))
1146 dpc_unauthenticated_clients--;
1147 if (dpc_clients != 0)
1148 dpc_clients--;
1149 UnlockSemaphoreInfo(dpc_semaphore);
1150}
1151
1152static HANDLER_RETURN_TYPE DistributePixelCacheConnectionHandler(void *socket_arg)
1153{
1154 ExceptionInfo
1155 *exception;
1156
1157 MagickBooleanType
1158 authenticated = MagickFalse,
1159 status = MagickFalse;
1160
1161 MagickOffsetType
1162 count;
1163
1164 RandomInfo
1165 *random_info;
1166
1167 SOCKET_TYPE
1168 client_socket,
1169 *client_socket_ptr = (SOCKET_TYPE *) socket_arg;
1170
1171 SplayTreeInfo
1172 *registry;
1173
1174 StringInfo
1175 *entropy;
1176
1177 uint64_t
1178 key,
1179 session_key;
1180
1181 unsigned char
1182 command,
1183 nonce[DPCSessionKeyLength];
1184
1185 client_socket=(*client_socket_ptr);
1186 client_socket_ptr=(SOCKET_TYPE *) RelinquishMagickMemory(client_socket_ptr);
1187 /*
1188 Generate random nonce.
1189 */
1190 random_info=AcquireRandomInfo();
1191 entropy=GetRandomKey(random_info,sizeof(nonce));
1192 (void) memcpy(nonce,GetStringInfoDatum(entropy),sizeof(nonce));
1193 entropy=DestroyStringInfo(entropy);
1194 random_info=DestroyRandomInfo(random_info);
1195 /*
1196 Derive session key.
1197 */
1198 session_key=GenerateSessionKey(dpc_shared_secret,nonce,sizeof(nonce));
1199 /*
1200 Send nonce to client.
1201 */
1202 count=dpc_send(client_socket,sizeof(nonce),nonce);
1203 if (count != (MagickOffsetType) sizeof(nonce))
1204 {
1205 CLOSE_SOCKET(client_socket);
1206 RelinquishDPCClient(MagickTrue);
1207 return(HANDLER_RETURN_VALUE);
1208 }
1209 /*
1210 Receive client's keyed hash.
1211 */
1212 count=dpc_receive_deadline(client_socket,sizeof(key),(unsigned char *) &key,
1213 (double) time((time_t *) NULL)+5.0);
1214 if ((count != (MagickOffsetType) sizeof(key)) || (key != session_key))
1215 {
1216 CLOSE_SOCKET(client_socket);
1217 RelinquishDPCClient(MagickTrue);
1218 return(HANDLER_RETURN_VALUE);
1219 }
1220 AuthenticateDPCClient();
1221 authenticated=MagickTrue;
1222 exception=AcquireExceptionInfo();
1223 registry=NewSplayTree((int (*)(const void *,const void *)) NULL,
1224 (void *(*)(void *)) NULL,RelinquishImageRegistry);
1225 /*
1226 Command loop.
1227 */
1228 for (status=MagickFalse; ; )
1229 {
1230 /*
1231 Each command must echo the authenticated session key.
1232 */
1233 count=dpc_receive_deadline(client_socket,1,(unsigned char *) &command,
1234 (double) time((time_t *) NULL)+5.0);
1235 if (count <= 0)
1236 break;
1237 count=dpc_receive_deadline(client_socket,sizeof(key),(unsigned char *) &key,
1238 (double) time((time_t *) NULL)+5.0);
1239 if ((count != (MagickOffsetType) sizeof(key)) || (key != session_key))
1240 break;
1241 switch (command)
1242 {
1243 case 'o':
1244 {
1245 status=OpenDistributeCache(registry,client_socket,session_key,
1246 exception);
1247 dpc_send(client_socket,sizeof(status),&status);
1248 break;
1249 }
1250 case 'r':
1251 {
1252 status=ReadDistributeCachePixels(registry,client_socket,session_key,
1253 exception);
1254 break;
1255 }
1256 case 'R':
1257 {
1258 status=ReadDistributeCacheMetacontent(registry,client_socket,
1259 session_key,exception);
1260 break;
1261 }
1262 case 'w':
1263 {
1264 status=WriteDistributeCachePixels(registry,client_socket,session_key,
1265 exception);
1266 break;
1267 }
1268 case 'W':
1269 {
1270 status=WriteDistributeCacheMetacontent(registry,client_socket,
1271 session_key,exception);
1272 break;
1273 }
1274 case 'd':
1275 {
1276 status=DestroyDistributeCache(registry,session_key);
1277 break;
1278 }
1279 default:
1280 break;
1281 }
1282 if ((status == MagickFalse) || (command == 'd'))
1283 break;
1284 }
1285 count=dpc_send(client_socket,sizeof(status),&status);
1286 CLOSE_SOCKET(client_socket);
1287 exception=DestroyExceptionInfo(exception);
1288 registry=DestroySplayTree(registry);
1289 RelinquishDPCClient(authenticated == MagickFalse ? MagickTrue :
1290 MagickFalse);
1291 return(HANDLER_RETURN_VALUE);
1292}
1293
1294static size_t GetDPCPolicyLimit(const char *name,const size_t default_limit)
1295{
1296 char
1297 policy_name[MagickPathExtent],
1298 *policy_value;
1299
1300 size_t
1301 limit;
1302
1303 limit=default_limit;
1304 (void) FormatLocaleString(policy_name,MagickPathExtent,"cache:%s",name);
1305 policy_value=GetPolicyValue(policy_name);
1306 if (policy_value != (char *) NULL)
1307 {
1308 char
1309 *q;
1310
1311 unsigned long
1312 policy_limit;
1313
1314 errno=0;
1315 policy_limit=strtoul(policy_value,&q,10);
1316 if ((errno == 0) && (q != policy_value) && (policy_limit != 0))
1317 limit=(size_t) policy_limit;
1318 policy_value=DestroyString(policy_value);
1319 }
1320 return(limit);
1321}
1322
1323static size_t GetMaxDPCClients(void)
1324{
1325 return(GetDPCPolicyLimit("max-dpc-clients",DPCMaxClientWorkers));
1326}
1327
1328static size_t GetMaxDPCUnauthenticatedClients(void)
1329{
1330 size_t
1331 client_workers,
1332 unauthenticated_workers;
1333
1334 client_workers=GetMaxDPCClients();
1335 unauthenticated_workers=GetDPCPolicyLimit("max-dpc-unauthenticated-clients",
1336 DPCMaxUnauthenticatedClientWorkers);
1337 return(MagickMin(unauthenticated_workers,client_workers));
1338}
1339
1340static MagickBooleanType AcquireDPCClientWorker(void)
1341{
1342 MagickBooleanType
1343 status;
1344
1345 size_t
1346 max_dpc_clients,
1347 unauthenticated_worker_limit;
1348
1349 status=MagickFalse;
1350 max_dpc_clients=GetMaxDPCClients();
1351 unauthenticated_worker_limit=GetMaxDPCUnauthenticatedClients();
1352 LockDPCSemaphore();
1353 if ((dpc_clients < max_dpc_clients) &&
1354 (dpc_unauthenticated_clients < unauthenticated_worker_limit))
1355 {
1356 dpc_clients++;
1357 dpc_unauthenticated_clients++;
1358 status=MagickTrue;
1359 }
1360 UnlockSemaphoreInfo(dpc_semaphore);
1361 return(status);
1362}
1363
1364MagickExport void DistributePixelCacheServer(const int port,
1365 ExceptionInfo *exception)
1366{
1367 char
1368 service[MagickPathExtent];
1369
1370 int
1371 status;
1372
1373#if defined(MAGICKCORE_THREAD_SUPPORT)
1374 pthread_attr_t
1375 attributes;
1376
1377 pthread_t
1378 thread_id;
1379#elif defined(_MSC_VER)
1380 DWORD
1381 threadID;
1382#else
1383 Not implemented!
1384#endif
1385
1386 SOCKET_TYPE
1387 server_socket;
1388
1389 struct addrinfo
1390 *p;
1391
1392 struct addrinfo
1393 hint,
1394 *result;
1395
1396 struct sockaddr_in
1397 address;
1398
1399 /*
1400 Launch distributed pixel cache server.
1401 */
1402 assert(exception != (ExceptionInfo *) NULL);
1403 assert(exception->signature == MagickCoreSignature);
1404 magick_unreferenced(exception);
1405 dpc_shared_secret=GetPolicyValue("cache:shared-secret");
1406 if (dpc_shared_secret == (char *) NULL)
1407 ThrowFatalException(CacheFatalError,"no shared secret");
1408#if defined(MAGICKCORE_HAVE_WINSOCK2)
1409 InitializeWinsock2(MagickFalse);
1410#endif
1411 (void) memset(&hint,0,sizeof(hint));
1412 hint.ai_family=AF_INET;
1413 hint.ai_socktype=SOCK_STREAM;
1414 hint.ai_flags=AI_PASSIVE;
1415 FormatLocaleString(service,MagickPathExtent,"%d",port);
1416 status=getaddrinfo(NULL,service,&hint,&result);
1417 if (status != 0)
1418 ThrowFatalException(CacheFatalError,"UnableToListen");
1419 server_socket=(SOCKET_TYPE) 0;
1420 for (p=result; p != NULL; p=p->ai_next)
1421 {
1422 int
1423 one = 1;
1424
1425 server_socket=(SOCKET_TYPE) socket(p->ai_family,p->ai_socktype,
1426 p->ai_protocol);
1427 if (server_socket == -1)
1428 continue;
1429 status=setsockopt(server_socket,SOL_SOCKET,SO_REUSEADDR,(char *) &one,
1430 (socklen_t) sizeof(one));
1431 if (status == -1)
1432 {
1433 CLOSE_SOCKET(server_socket);
1434 continue;
1435 }
1436 SetSocketReceiveTimeout(server_socket,5.0);
1437 status=bind(server_socket,p->ai_addr,(socklen_t) p->ai_addrlen);
1438 if (status == -1)
1439 {
1440 CLOSE_SOCKET(server_socket);
1441 continue;
1442 }
1443 break;
1444 }
1445 if (p == (struct addrinfo *) NULL)
1446 ThrowFatalException(CacheFatalError,"UnableToBind");
1447 freeaddrinfo(result);
1448 status=listen(server_socket,DPCPendingConnections);
1449 if (status != 0)
1450 ThrowFatalException(CacheFatalError,"UnableToListen");
1451#if defined(MAGICKCORE_THREAD_SUPPORT)
1452 pthread_attr_init(&attributes);
1453 pthread_attr_setdetachstate(&attributes,PTHREAD_CREATE_DETACHED);
1454#endif
1455 for ( ; ; )
1456 {
1457 SOCKET_TYPE
1458 *client_socket_ptr;
1459
1460 socklen_t
1461 length = (socklen_t) sizeof(address);
1462
1463 client_socket_ptr=(SOCKET_TYPE *) AcquireMagickMemory(sizeof(SOCKET_TYPE));
1464 if (client_socket_ptr == NULL)
1465 continue; /* skip connection */
1466 *client_socket_ptr=(SOCKET_TYPE) accept(server_socket,(struct sockaddr *)
1467 &address,&length);
1468 if (*client_socket_ptr == -1)
1469 {
1470 client_socket_ptr=(SOCKET_TYPE *) RelinquishMagickMemory(
1471 client_socket_ptr);
1472 continue;
1473 }
1474 if (AcquireDPCClientWorker() == MagickFalse)
1475 {
1476 CLOSE_SOCKET(*client_socket_ptr);
1477 client_socket_ptr=(SOCKET_TYPE *) RelinquishMagickMemory(
1478 client_socket_ptr);
1479 continue;
1480 }
1481 SetSocketReceiveTimeout(*client_socket_ptr,5.0);
1482 if (status == -1)
1483 {
1484 CLOSE_SOCKET(*client_socket_ptr);
1485 RelinquishDPCClient(MagickTrue);
1486 client_socket_ptr=(SOCKET_TYPE *) RelinquishMagickMemory(
1487 client_socket_ptr);
1488 continue;
1489 }
1490#if defined(MAGICKCORE_THREAD_SUPPORT)
1491 status=pthread_create(&thread_id,&attributes,DistributePixelCacheConnectionHandler,
1492 (void *) client_socket_ptr);
1493 if (status != 0)
1494 {
1495 CLOSE_SOCKET(*client_socket_ptr);
1496 RelinquishDPCClient(MagickTrue);
1497 RelinquishMagickMemory(client_socket_ptr);
1498 continue;
1499 }
1500#elif defined(_MSC_VER)
1501 if (CreateThread(0,0,DistributePixelCacheConnectionHandler,(void*) client_socket_ptr,
1502 0,&threadID) == (HANDLE) NULL)
1503 {
1504 CLOSE_SOCKET(*client_socket_ptr);
1505 RelinquishDPCClient(MagickTrue);
1506 RelinquishMagickMemory(client_socket_ptr);
1507 continue;
1508 }
1509#else
1510 Not implemented!
1511#endif
1512 }
1513}
1514#endif
1515␌
1516/*
1517%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1518% %
1519% %
1520% %
1521+ D i s t r i b u t e C a c h e T e r m i n u s %
1522% %
1523% %
1524% %
1525%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1526%
1527% DistributeCacheTerminus() destroys the Distributed Cache.
1528%
1529*/
1530MagickPrivate void DistributeCacheTerminus(void)
1531{
1532#ifdef MAGICKCORE_HAVE_WINSOCK2
1533 if (winsock_semaphore == (SemaphoreInfo *) NULL)
1534 ActivateSemaphoreInfo(&winsock_semaphore);
1535 LockSemaphoreInfo(winsock_semaphore);
1536 if (wsaData != (WSADATA *) NULL)
1537 {
1538 WSACleanup();
1539 wsaData=(WSADATA *) RelinquishMagickMemory((void *) wsaData);
1540 }
1541 UnlockSemaphoreInfo(winsock_semaphore);
1542 RelinquishSemaphoreInfo(&winsock_semaphore);
1543#endif
1544#if defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
1545 if (dpc_shared_secret != (char *) NULL)
1546 dpc_shared_secret=DestroyString(dpc_shared_secret);
1547 if (dpc_semaphore != (SemaphoreInfo *) NULL)
1548 RelinquishSemaphoreInfo(&dpc_semaphore);
1549#endif
1550}
1551
1552/*
1553%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1554% %
1555% %
1556% %
1557+ G e t D i s t r i b u t e C a c h e F i l e %
1558% %
1559% %
1560% %
1561%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1562%
1563% GetDistributeCacheFile() returns the file associated with this
1564% DistributeCacheInfo structure.
1565%
1566% The format of the GetDistributeCacheFile method is:
1567%
1568% int GetDistributeCacheFile(const DistributeCacheInfo *server_info)
1569%
1570% A description of each parameter follows:
1571%
1572% o server_info: the distributed cache info.
1573%
1574*/
1575MagickPrivate int GetDistributeCacheFile(const DistributeCacheInfo *server_info)
1576{
1577 assert(server_info != (DistributeCacheInfo *) NULL);
1578 assert(server_info->signature == MagickCoreSignature);
1579 return(server_info->file);
1580}
1581␌
1582/*
1583%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1584% %
1585% %
1586% %
1587+ 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 %
1588% %
1589% %
1590% %
1591%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1592%
1593% GetDistributeCacheHostname() returns the hostname associated with this
1594% DistributeCacheInfo structure.
1595%
1596% The format of the GetDistributeCacheHostname method is:
1597%
1598% const char *GetDistributeCacheHostname(
1599% const DistributeCacheInfo *server_info)
1600%
1601% A description of each parameter follows:
1602%
1603% o server_info: the distributed cache info.
1604%
1605*/
1606MagickPrivate const char *GetDistributeCacheHostname(
1607 const DistributeCacheInfo *server_info)
1608{
1609 assert(server_info != (DistributeCacheInfo *) NULL);
1610 assert(server_info->signature == MagickCoreSignature);
1611 return(server_info->hostname);
1612}
1613␌
1614/*
1615%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1616% %
1617% %
1618% %
1619+ G e t D i s t r i b u t e C a c h e P o r t %
1620% %
1621% %
1622% %
1623%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1624%
1625% GetDistributeCachePort() returns the port associated with this
1626% DistributeCacheInfo structure.
1627%
1628% The format of the GetDistributeCachePort method is:
1629%
1630% int GetDistributeCachePort(const DistributeCacheInfo *server_info)
1631%
1632% A description of each parameter follows:
1633%
1634% o server_info: the distributed cache info.
1635%
1636*/
1637MagickPrivate int GetDistributeCachePort(const DistributeCacheInfo *server_info)
1638{
1639 assert(server_info != (DistributeCacheInfo *) NULL);
1640 assert(server_info->signature == MagickCoreSignature);
1641 return(server_info->port);
1642}
1643␌
1644/*
1645%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1646% %
1647% %
1648% %
1649+ O p e n D i s t r i b u t e P i x e l C a c h e %
1650% %
1651% %
1652% %
1653%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1654%
1655% OpenDistributePixelCache() opens a pixel cache on a remote server.
1656%
1657% The format of the OpenDistributePixelCache method is:
1658%
1659% MagickBooleanType *OpenDistributePixelCache(
1660% DistributeCacheInfo *server_info,Image *image)
1661%
1662% A description of each parameter follows:
1663%
1664% o server_info: the distributed cache info.
1665%
1666% o image: the image.
1667%
1668*/
1669MagickPrivate MagickBooleanType OpenDistributePixelCache(
1670 DistributeCacheInfo *server_info,Image *image)
1671{
1672 MagickBooleanType
1673 status;
1674
1675 MagickOffsetType
1676 count;
1677
1678 unsigned char
1679 message[MagickPathExtent],
1680 *p;
1681
1682 /*
1683 Open distributed pixel cache.
1684 */
1685 assert(server_info != (DistributeCacheInfo *) NULL);
1686 assert(server_info->signature == MagickCoreSignature);
1687 assert(image != (Image *) NULL);
1688 assert(image->signature == MagickCoreSignature);
1689 p=message;
1690 *p++='o'; /* open */
1691 /*
1692 Serialize image attributes (see ValidatePixelCacheMorphology()).
1693 */
1694 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1695 p+=(ptrdiff_t) sizeof(server_info->session_key);
1696 (void) memcpy(p,&image->storage_class,sizeof(image->storage_class));
1697 p+=(ptrdiff_t) sizeof(image->storage_class);
1698 (void) memcpy(p,&image->colorspace,sizeof(image->colorspace));
1699 p+=(ptrdiff_t) sizeof(image->colorspace);
1700 (void) memcpy(p,&image->alpha_trait,sizeof(image->alpha_trait));
1701 p+=(ptrdiff_t) sizeof(image->alpha_trait);
1702 (void) memcpy(p,&image->channels,sizeof(image->channels));
1703 p+=(ptrdiff_t) sizeof(image->channels);
1704 (void) memcpy(p,&image->columns,sizeof(image->columns));
1705 p+=(ptrdiff_t) sizeof(image->columns);
1706 (void) memcpy(p,&image->rows,sizeof(image->rows));
1707 p+=(ptrdiff_t) sizeof(image->rows);
1708 (void) memcpy(p,&image->number_channels,sizeof(image->number_channels));
1709 p+=(ptrdiff_t) sizeof(image->number_channels);
1710 (void) memcpy(p,image->channel_map,MaxPixelChannels*
1711 sizeof(*image->channel_map));
1712 p+=(ptrdiff_t) MaxPixelChannels*sizeof(*image->channel_map);
1713 (void) memcpy(p,&image->metacontent_extent,sizeof(image->metacontent_extent));
1714 p+=(ptrdiff_t) sizeof(image->metacontent_extent);
1715 count=dpc_send(server_info->file,(MagickSizeType) (p-message),message);
1716 if (count != (MagickOffsetType) (p-message))
1717 return(MagickFalse);
1718 status=MagickFalse;
1719 count=dpc_receive(server_info->file,sizeof(status),(unsigned char *) &status);
1720 if (count != (MagickOffsetType) sizeof(status))
1721 return(MagickFalse);
1722 return(status);
1723}
1724␌
1725/*
1726%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1727% %
1728% %
1729% %
1730+ 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 %
1731% %
1732% %
1733% %
1734%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1735%
1736% ReadDistributePixelCacheMetacontents() reads metacontent from the specified
1737% region of the distributed pixel cache.
1738%
1739% The format of the ReadDistributePixelCacheMetacontents method is:
1740%
1741% MagickOffsetType ReadDistributePixelCacheMetacontents(
1742% DistributeCacheInfo *server_info,const RectangleInfo *region,
1743% const MagickSizeType length,unsigned char *metacontent)
1744%
1745% A description of each parameter follows:
1746%
1747% o server_info: the distributed cache info.
1748%
1749% o image: the image.
1750%
1751% o region: read the metacontent from this region of the image.
1752%
1753% o length: the length in bytes of the metacontent.
1754%
1755% o metacontent: read these metacontent from the pixel cache.
1756%
1757*/
1758MagickPrivate MagickOffsetType ReadDistributePixelCacheMetacontent(
1759 DistributeCacheInfo *server_info,const RectangleInfo *region,
1760 const MagickSizeType length,unsigned char *metacontent)
1761{
1762 MagickOffsetType
1763 count;
1764
1765 unsigned char
1766 message[MagickPathExtent],
1767 *p;
1768
1769 /*
1770 Read distributed pixel cache metacontent.
1771 */
1772 assert(server_info != (DistributeCacheInfo *) NULL);
1773 assert(server_info->signature == MagickCoreSignature);
1774 assert(region != (RectangleInfo *) NULL);
1775 assert(metacontent != (unsigned char *) NULL);
1776 if (length > (MagickSizeType) MAGICK_SSIZE_MAX)
1777 return(-1);
1778 p=message;
1779 *p++='R';
1780 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1781 p+=(ptrdiff_t) sizeof(server_info->session_key);
1782 (void) memcpy(p,&region->width,sizeof(region->width));
1783 p+=(ptrdiff_t) sizeof(region->width);
1784 (void) memcpy(p,&region->height,sizeof(region->height));
1785 p+=(ptrdiff_t) sizeof(region->height);
1786 (void) memcpy(p,&region->x,sizeof(region->x));
1787 p+=(ptrdiff_t) sizeof(region->x);
1788 (void) memcpy(p,&region->y,sizeof(region->y));
1789 p+=(ptrdiff_t) sizeof(region->y);
1790 (void) memcpy(p,&length,sizeof(length));
1791 p+=(ptrdiff_t) sizeof(length);
1792 count=dpc_send(server_info->file,(MagickSizeType) (p-message),message);
1793 if (count != (MagickOffsetType) (p-message))
1794 return(-1);
1795 return(dpc_receive(server_info->file,length,metacontent));
1796}
1797␌
1798/*
1799%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1800% %
1801% %
1802% %
1803+ 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 %
1804% %
1805% %
1806% %
1807%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1808%
1809% ReadDistributePixelCachePixels() reads pixels from the specified region of
1810% the distributed pixel cache.
1811%
1812% The format of the ReadDistributePixelCachePixels method is:
1813%
1814% MagickOffsetType ReadDistributePixelCachePixels(
1815% DistributeCacheInfo *server_info,const RectangleInfo *region,
1816% const MagickSizeType length,unsigned char *magick_restrict pixels)
1817%
1818% A description of each parameter follows:
1819%
1820% o server_info: the distributed cache info.
1821%
1822% o image: the image.
1823%
1824% o region: read the pixels from this region of the image.
1825%
1826% o length: the length in bytes of the pixels.
1827%
1828% o pixels: read these pixels from the pixel cache.
1829%
1830*/
1831MagickPrivate MagickOffsetType ReadDistributePixelCachePixels(
1832 DistributeCacheInfo *server_info,const RectangleInfo *region,
1833 const MagickSizeType length,unsigned char *magick_restrict pixels)
1834{
1835 MagickOffsetType
1836 count;
1837
1838 unsigned char
1839 message[MagickPathExtent],
1840 *p;
1841
1842 /*
1843 Read distributed pixel cache pixels.
1844 */
1845 assert(server_info != (DistributeCacheInfo *) NULL);
1846 assert(server_info->signature == MagickCoreSignature);
1847 assert(region != (RectangleInfo *) NULL);
1848 assert(pixels != (unsigned char *) NULL);
1849 if (length > (MagickSizeType) MAGICK_SSIZE_MAX)
1850 return(-1);
1851 p=message;
1852 *p++='r';
1853 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1854 p+=(ptrdiff_t) sizeof(server_info->session_key);
1855 (void) memcpy(p,&region->width,sizeof(region->width));
1856 p+=(ptrdiff_t) sizeof(region->width);
1857 (void) memcpy(p,&region->height,sizeof(region->height));
1858 p+=(ptrdiff_t) sizeof(region->height);
1859 (void) memcpy(p,&region->x,sizeof(region->x));
1860 p+=(ptrdiff_t) sizeof(region->x);
1861 (void) memcpy(p,&region->y,sizeof(region->y));
1862 p+=(ptrdiff_t) sizeof(region->y);
1863 (void) memcpy(p,&length,sizeof(length));
1864 p+=(ptrdiff_t) sizeof(length);
1865 count=dpc_send(server_info->file,(MagickSizeType) (p-message),message);
1866 if (count != (MagickOffsetType) (p-message))
1867 return(-1);
1868 return(dpc_receive(server_info->file,length,pixels));
1869}
1870␌
1871/*
1872%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1873% %
1874% %
1875% %
1876+ 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 %
1877% %
1878% %
1879% %
1880%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1881%
1882% RelinquishDistributePixelCache() frees resources acquired with
1883% OpenDistributePixelCache().
1884%
1885% The format of the RelinquishDistributePixelCache method is:
1886%
1887% MagickBooleanType RelinquishDistributePixelCache(
1888% DistributeCacheInfo *server_info)
1889%
1890% A description of each parameter follows:
1891%
1892% o server_info: the distributed cache info.
1893%
1894*/
1895MagickPrivate MagickBooleanType RelinquishDistributePixelCache(
1896 DistributeCacheInfo *server_info)
1897{
1898 MagickBooleanType
1899 status;
1900
1901 MagickOffsetType
1902 count;
1903
1904 unsigned char
1905 message[MagickPathExtent],
1906 *p;
1907
1908 /*
1909 Delete distributed pixel cache.
1910 */
1911 assert(server_info != (DistributeCacheInfo *) NULL);
1912 assert(server_info->signature == MagickCoreSignature);
1913 p=message;
1914 *p++='d';
1915 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1916 p+=(ptrdiff_t) sizeof(server_info->session_key);
1917 count=dpc_send(server_info->file,(MagickSizeType) (p-message),message);
1918 if (count != (MagickOffsetType) (p-message))
1919 return(MagickFalse);
1920 status=MagickFalse;
1921 count=dpc_receive(server_info->file,sizeof(status),(unsigned char *) &status);
1922 if (count != (MagickOffsetType) sizeof(status))
1923 return(MagickFalse);
1924 return(status);
1925}
1926␌
1927/*
1928%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1929% %
1930% %
1931% %
1932+ 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 %
1933% %
1934% %
1935% %
1936%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1937%
1938% WriteDistributePixelCacheMetacontents() writes image metacontent to the
1939% specified region of the distributed pixel cache.
1940%
1941% The format of the WriteDistributePixelCacheMetacontents method is:
1942%
1943% MagickOffsetType WriteDistributePixelCacheMetacontents(
1944% DistributeCacheInfo *server_info,const RectangleInfo *region,
1945% const MagickSizeType length,const unsigned char *metacontent)
1946%
1947% A description of each parameter follows:
1948%
1949% o server_info: the distributed cache info.
1950%
1951% o image: the image.
1952%
1953% o region: write the metacontent to this region of the image.
1954%
1955% o length: the length in bytes of the metacontent.
1956%
1957% o metacontent: write these metacontent to the pixel cache.
1958%
1959*/
1960MagickPrivate MagickOffsetType WriteDistributePixelCacheMetacontent(
1961 DistributeCacheInfo *server_info,const RectangleInfo *region,
1962 const MagickSizeType length,const unsigned char *metacontent)
1963{
1964 MagickOffsetType
1965 count;
1966
1967 unsigned char
1968 message[MagickPathExtent],
1969 *p;
1970
1971 /*
1972 Write distributed pixel cache metacontent.
1973 */
1974 assert(server_info != (DistributeCacheInfo *) NULL);
1975 assert(server_info->signature == MagickCoreSignature);
1976 assert(region != (RectangleInfo *) NULL);
1977 assert(metacontent != (unsigned char *) NULL);
1978 if (length > (MagickSizeType) MAGICK_SSIZE_MAX)
1979 return(-1);
1980 p=message;
1981 *p++='W';
1982 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1983 p+=(ptrdiff_t) sizeof(server_info->session_key);
1984 (void) memcpy(p,&region->width,sizeof(region->width));
1985 p+=(ptrdiff_t) sizeof(region->width);
1986 (void) memcpy(p,&region->height,sizeof(region->height));
1987 p+=(ptrdiff_t) sizeof(region->height);
1988 (void) memcpy(p,&region->x,sizeof(region->x));
1989 p+=(ptrdiff_t) sizeof(region->x);
1990 (void) memcpy(p,&region->y,sizeof(region->y));
1991 p+=(ptrdiff_t) sizeof(region->y);
1992 (void) memcpy(p,&length,sizeof(length));
1993 p+=(ptrdiff_t) sizeof(length);
1994 count=dpc_send(server_info->file,(MagickSizeType) (p-message),message);
1995 if (count != (MagickOffsetType) (p-message))
1996 return(-1);
1997 return(dpc_send(server_info->file,length,metacontent));
1998}
1999␌
2000/*
2001%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2002% %
2003% %
2004% %
2005+ 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 %
2006% %
2007% %
2008% %
2009%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2010%
2011% WriteDistributePixelCachePixels() writes image pixels to the specified
2012% region of the distributed pixel cache.
2013%
2014% The format of the WriteDistributePixelCachePixels method is:
2015%
2016% MagickBooleanType WriteDistributePixelCachePixels(
2017% DistributeCacheInfo *server_info,const RectangleInfo *region,
2018% const MagickSizeType length,
2019% const unsigned char *magick_restrict pixels)
2020%
2021% A description of each parameter follows:
2022%
2023% o server_info: the distributed cache info.
2024%
2025% o image: the image.
2026%
2027% o region: write the pixels to this region of the image.
2028%
2029% o length: the length in bytes of the pixels.
2030%
2031% o pixels: write these pixels to the pixel cache.
2032%
2033*/
2034MagickPrivate MagickOffsetType WriteDistributePixelCachePixels(
2035 DistributeCacheInfo *server_info,const RectangleInfo *region,
2036 const MagickSizeType length,const unsigned char *magick_restrict pixels)
2037{
2038 MagickOffsetType
2039 count;
2040
2041 unsigned char
2042 message[MagickPathExtent],
2043 *p;
2044
2045 /*
2046 Write distributed pixel cache pixels.
2047 */
2048 assert(server_info != (DistributeCacheInfo *) NULL);
2049 assert(server_info->signature == MagickCoreSignature);
2050 assert(region != (RectangleInfo *) NULL);
2051 assert(pixels != (const unsigned char *) NULL);
2052 if (length > (MagickSizeType) MAGICK_SSIZE_MAX)
2053 return(-1);
2054 p=message;
2055 *p++='w';
2056 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
2057 p+=(ptrdiff_t) sizeof(server_info->session_key);
2058 (void) memcpy(p,&region->width,sizeof(region->width));
2059 p+=(ptrdiff_t) sizeof(region->width);
2060 (void) memcpy(p,&region->height,sizeof(region->height));
2061 p+=(ptrdiff_t) sizeof(region->height);
2062 (void) memcpy(p,&region->x,sizeof(region->x));
2063 p+=(ptrdiff_t) sizeof(region->x);
2064 (void) memcpy(p,&region->y,sizeof(region->y));
2065 p+=(ptrdiff_t) sizeof(region->y);
2066 (void) memcpy(p,&length,sizeof(length));
2067 p+=(ptrdiff_t) sizeof(length);
2068 count=dpc_send(server_info->file,(MagickSizeType) (p-message),message);
2069 if (count != (MagickOffsetType) (p-message))
2070 return(-1);
2071 return(dpc_send(server_info->file,length,pixels));
2072}