1#include "SharedMemoryServer.h" 2#include <stdlib.h> 3#include <sys/mman.h> 4#include <fcntl.h> 5#include <machine/byte_order.h> 6#include <string> 7#include <sys/stat.h> 8#include <security_utilities/crc.h> 9#include <unistd.h> 10 11static const char* kPrefix = "/private/var/db/mds/messages/se_"; 12 13SharedMemoryServer::SharedMemoryServer (const char* segmentName, SegmentOffsetType segmentSize) : 14 mSegmentName (segmentName), mSegmentSize (segmentSize) 15{ 16 mFileName = kPrefix; 17 mFileName += segmentName; 18 19 // make the mds directory, just in case it doesn't exist 20 mkdir("/var/db/mds", 1777); 21 mkdir("/var/db/mds/messages", 0755); 22 23 // make the file name 24 // clean any old file away 25 unlink (mFileName.c_str ()); 26 27 // open the file 28 int segmentDescriptor = open (mFileName.c_str (), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); 29 if (segmentDescriptor < 0) 30 { 31 return; 32 } 33 34 // set the segment size 35 ftruncate (segmentDescriptor, segmentSize); 36 37 // map it into memory 38 mSegment = (u_int8_t*) mmap (NULL, mSegmentSize, PROT_READ | PROT_WRITE, MAP_SHARED, segmentDescriptor, 0); 39 close (segmentDescriptor); 40 41 if (mSegment == (u_int8_t*) -1) // can't map the memory? 42 { 43 mSegment = NULL; 44 unlink (mFileName.c_str()); 45 } 46 47 mDataPtr = mDataArea = mSegment + sizeof(SegmentOffsetType); 48 mDataMax = mSegment + segmentSize;; 49 50 SetProducerOffset (0); 51} 52 53 54 55SharedMemoryServer::~SharedMemoryServer () 56{ 57 // go away 58 if (mSegment == NULL) 59 { 60 return; 61 } 62 63 // get out of memory 64 munmap (mSegment, mSegmentSize); 65 66 // mark the segment for deletion 67 unlink (mFileName.c_str ()); 68} 69 70 71 72const SegmentOffsetType 73 kSegmentLength = 0, 74 kCRCOffset = kSegmentLength + sizeof(SegmentOffsetType), 75 kDomainOffset = kCRCOffset + sizeof(SegmentOffsetType), 76 kEventTypeOffset = kDomainOffset + sizeof(SegmentOffsetType), 77 kHeaderLength = kEventTypeOffset + sizeof(SegmentOffsetType) - kCRCOffset; 78 79void SharedMemoryServer::WriteMessage (SegmentOffsetType domain, SegmentOffsetType event, const void *message, SegmentOffsetType messageLength) 80{ 81 // assemble the final message 82 ssize_t messageSize = kHeaderLength + messageLength; 83 u_int8_t finalMessage[messageSize]; 84 SegmentOffsetType *fm = (SegmentOffsetType*) finalMessage; 85 fm[0] = OSSwapHostToBigInt32(domain); 86 fm[1] = OSSwapHostToBigInt32(event); 87 memcpy(&fm[2], message, messageLength); 88 89 SegmentOffsetType crc = CalculateCRC(finalMessage, messageSize); 90 91 // write the length 92 WriteOffset(messageSize); 93 94 // write the crc 95 WriteOffset(crc); 96 97 // write the data 98 WriteData (finalMessage, messageSize); 99 100 // write the data count 101 SetProducerOffset(mDataPtr - mDataArea); 102} 103 104 105 106const char* SharedMemoryServer::GetSegmentName () 107{ 108 return mSegmentName.c_str (); 109} 110 111 112 113size_t SharedMemoryServer::GetSegmentSize () 114{ 115 return mSegmentSize; 116} 117 118 119 120SegmentOffsetType SharedMemoryServer::GetProducerOffset () 121{ 122 // the data is stored in the buffer in network byte order 123 u_int32_t pCount = OSSwapBigToHostInt32 (*(u_int32_t*) mSegment); 124 return OSSwapHostToBigInt32 (pCount); 125} 126 127 128 129void SharedMemoryServer::SetProducerOffset (SegmentOffsetType producerCount) 130{ 131 *((SegmentOffsetType*) mSegment) = OSSwapHostToBigInt32 (producerCount); 132} 133 134 135 136void SharedMemoryServer::WriteOffset(SegmentOffsetType offset) 137{ 138 u_int8_t buffer[4]; 139 *((u_int32_t*) buffer) = OSSwapHostToBigInt32(offset); 140 WriteData(buffer, 4); 141} 142 143 144 145void SharedMemoryServer::WriteData(const void* data, SegmentOffsetType length) 146{ 147 // figure out where in the buffer we actually need to write the data 148 // figure out how many bytes we can write without overflowing the buffer 149 const u_int8_t* dp = (const u_int8_t*) data; 150 SegmentOffsetType bytesToEnd = mDataMax - mDataPtr; 151 152 // figure out how many bytes we can write 153 SegmentOffsetType bytesToWrite = (length <= bytesToEnd) ? length : bytesToEnd; 154 155 // move the first part of the data, making sure to skip the producer pointer 156 memcpy (mDataPtr, dp, bytesToWrite); 157 mDataPtr += bytesToWrite; 158 dp += bytesToWrite; 159 160 // deduct the bytes just written 161 length -= bytesToWrite; 162 163 if (length != 0) // did we wrap around? 164 { 165 mDataPtr = mDataArea; 166 memcpy (mDataPtr, dp, length); 167 mDataPtr += length; 168 } 169} 170