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