#include "gpsPub.h" #include #include #include #include #include #include // for permissions flags #include // for unlink() static const char* GPS_DEFAULT_KEY_FILE = "/tmp/gpskey"; // Upon success, this returns a pointer for // storage of published GPS position extern "C" char* GPSMemoryInit(const char* keyFile, unsigned int size) { if (!keyFile) keyFile = GPS_DEFAULT_KEY_FILE; char* posPtr = ((char*)-1); int id = -1; // First read file to see if shared memory already active // If active, try to use it FILE* filePtr = fopen(keyFile, "r"); if (filePtr) { if (1 == fscanf(filePtr, "%d", &id)) { if (((char*)-1) != (posPtr = (char*)shmat(id, 0, 0))) { // Make sure pre-existing shared memory is right size unsigned int theSize; memcpy(&theSize, posPtr, sizeof(unsigned int)); if (size != theSize) { GPSPublishShutdown((GPSHandle)posPtr, keyFile); posPtr = (char*)-1; } } else { perror("GPSPublishInit(): shmat() warning"); } } fclose(filePtr); } if (((char*)-1) == posPtr) { // Create new shared memory segment // and advertise its "id" in the keyFile id = shmget(0, (int)(size+sizeof(unsigned int)), IPC_CREAT | SHM_R| S_IRGRP | S_IROTH | SHM_W); if (-1 == id) { perror("GPSPublishInit(): shmget() error"); return NULL; } if (((char*)-1) ==(posPtr = (char*)shmat(id, 0, 0))) { perror("GPSPublishInit(): shmat() error"); struct shmid_ds ds; if (-1 == shmctl(id, IPC_RMID, &ds)) { perror("GPSPublishInit(): shmctl(IPC_RMID) error"); } return NULL; } // Write "id" to "keyFile" if ((filePtr = fopen(keyFile, "w+"))) { if (fprintf(filePtr, "%d", id) <= 0) perror("GPSPublishInit() fprintf() error"); fclose(filePtr); memset(posPtr+sizeof(unsigned int), 0, size); memcpy(posPtr, &size, sizeof(unsigned int)); return (posPtr + sizeof(unsigned int)); } else { perror("GPSPublishInit() fopen() error"); } if (-1 == shmdt(posPtr)) perror("GPSPublishInit() shmdt() error"); struct shmid_ds ds; if (-1 == shmctl(id, IPC_RMID, &ds)) perror("GPSPublishInit(): shmctl(IPC_RMID) error"); return NULL; } if (((char*)-1) == posPtr) return NULL; else return (posPtr + sizeof(unsigned int)); } // end GPSPublishInit() extern "C" void GPSPublishShutdown(GPSHandle gpsHandle, const char* keyFile) { char* ptr = (char*)gpsHandle - sizeof(unsigned int); if (!keyFile) keyFile = GPS_DEFAULT_KEY_FILE; if (-1 == shmdt(ptr)) perror("GPSPublishShutdown() shmdt() error"); FILE* filePtr = fopen(keyFile, "r"); if (filePtr) { int id; if (1 == fscanf(filePtr, "%d", &id)) { struct shmid_ds ds; if (-1 == shmctl(id, IPC_RMID, &ds)) perror("GPSPublishShutdown(): shmctl(IPC_RMID) error"); } fclose(filePtr); if (unlink(keyFile)) perror("GPSPublishShutdown(): unlink() error"); } else { perror("GPSPublishShutdown(): fopen() error"); } } // end GPSPublishShutdown(); // Upon success, this returns a pointer for // storage of published GPS position extern "C" GPSHandle GPSSubscribe(const char* keyFile) { if (!keyFile) keyFile = GPS_DEFAULT_KEY_FILE; char* posPtr = ((char*)-1); int id = -1; // First read file to see if shared memory already active // If active, try to use it FILE* filePtr = fopen(keyFile, "r"); if (filePtr) { if (1 == fscanf(filePtr, "%d", &id)) { if (((char*)-1) == (posPtr = (char*)shmat(id, 0, SHM_RDONLY))) { perror("GPSSubscribe(): shmat() error"); fclose(filePtr); return NULL; } else { fclose(filePtr); return (posPtr + sizeof(unsigned int)); } } else { perror("GPSSubscribe(): fscanf() error"); fclose(filePtr); return NULL; } } else { //fprintf(stderr, "GPSSubscribe(): Error opening %s.\n", keyFile); //perror("GPSSubscribe(): fopen() error"); return NULL; } } // end GPSSubscribe() extern "C" void GPSUnsubscribe(GPSHandle gpsHandle) { char* ptr = (char*)gpsHandle - sizeof(unsigned int); if (-1 == shmdt(ptr)) perror("GPSUnsubscribe() shmdt() error"); } // end GPSUnsubscribe() extern "C" void GPSPublishUpdate(GPSHandle gpsHandle, const GPSPosition* currentPosition) { memcpy((char*)gpsHandle, (char*)currentPosition, sizeof(GPSPosition)); } // end GPSPublishUpdate() extern "C" void GPSGetCurrentPosition(GPSHandle gpsHandle, GPSPosition* currentPosition) { memcpy((char*)currentPosition, (char*)gpsHandle, sizeof(GPSPosition)); } // end GPSGetCurrentPosition() extern "C" unsigned int GPSSetMemory(GPSHandle gpsHandle, unsigned int offset, const char* buffer, unsigned int len) { char* ptr = (char*)gpsHandle - sizeof(unsigned int); unsigned int size; memcpy(&size, ptr, sizeof(unsigned int)); // Make sure request fits into available shared memory if ((offset+len) > size) { fprintf(stderr, "GPSSetMemory() Request exceeds allocated shared memory!\n"); unsigned int delta = offset + len - size; if (delta > len) return 0; else len -= delta; } ptr = (char*)gpsHandle + offset; memcpy(ptr, buffer, len); return len; } // end GPSSetMemory() extern "C" unsigned int GPSGetMemorySize(GPSHandle gpsHandle) { char* ptr = (char*)gpsHandle - sizeof(unsigned int); unsigned int size; memcpy(&size, ptr, sizeof(unsigned int)); return size; } extern "C" const char* GPSGetMemoryPtr(GPSHandle gpsHandle, unsigned int offset) { char* ptr = (char*)gpsHandle - sizeof(unsigned int); unsigned int size; memcpy(&size, ptr, sizeof(unsigned int)); if (offset < size) { return (char*)gpsHandle + offset; } else { fprintf(stderr, "GPSGetMemory() Invalid request!\n"); return (const char*)NULL; } } // end GPSGetMemoryPtr() extern "C" unsigned int GPSGetMemory(GPSHandle gpsHandle, unsigned int offset, char* buffer, unsigned int len) { char* ptr = (char*)gpsHandle - sizeof(unsigned int); unsigned int size; memcpy(&size, ptr, sizeof(unsigned int)); if (size < (offset+len)) { unsigned int delta = offset + len - size; if (delta > len) { fprintf(stderr, "GPSGetMemory() Invalid request!\n"); return 0; } else { len -= delta; } } ptr = (char*)gpsHandle + offset; memcpy(buffer, ptr, len); return len; } // end GPSGetMemory()