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