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