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