1 /*
2  * IP2Location C library is distributed under MIT license
3  * Copyright (c) 2013 IP2Location.com. support at ip2location dot com
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the MIT license
7  * License as published by the Free Software Foundation; either
8  */
9 
10 #ifdef WIN32
11 #include <winsock2.h>
12 #else
13 #include <stdint.h>
14 #include <strings.h>
15 #include <unistd.h>
16 #include <sys/mman.h>
17 #endif
18 
19 
20 #include <stdio.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <fcntl.h>
26 #include <errno.h>
27 
28 
29 #include "IP2Location.h"
30 #include "IP2Loc_DBInterface.h"
31 
32 #define IP2LOCATION_SHM "/IP2location_Shm"
33 #define MAP_ADDR 4194500608
34 
35 //Static variables
36 static enum IP2Location_mem_type DB_access_type = IP2LOCATION_FILE_IO;
37 static void *cache_shm_ptr;
38 #ifndef WIN32
39 static int32_t shm_fd;
40 #else
41 #ifdef WIN32
42 HANDLE shm_fd;
43 #endif
44 #endif
45 
46 //Static functions
47 static int32_t IP2Location_DB_Load_to_mem(FILE *filehandle, void *cache_shm_ptr, int64_t size);
48 
49 //Description: set the DB access method as memory cache and read the file into cache
IP2Location_DB_set_memory_cache(FILE * filehandle)50 int32_t IP2Location_DB_set_memory_cache(FILE *filehandle)
51 {
52     struct stat statbuf;
53     DB_access_type = IP2LOCATION_CACHE_MEMORY;
54     if(fstat(fileno(filehandle), &statbuf) == -1)
55     {
56         DB_access_type = IP2LOCATION_FILE_IO;
57         return -1;
58     }
59 
60     if ( (cache_shm_ptr = malloc(statbuf.st_size + 1)) == NULL )
61     {
62         DB_access_type = IP2LOCATION_FILE_IO;
63         return -1;
64     }
65     if( IP2Location_DB_Load_to_mem(filehandle, cache_shm_ptr, statbuf.st_size) == -1 )
66     {
67         DB_access_type = IP2LOCATION_FILE_IO;
68         free(cache_shm_ptr);
69         return -1;
70     }
71     return 0;
72 }
73 
74 //Description: set the DB access method as shared memory
75 #ifndef WIN32
IP2Location_DB_set_shared_memory(FILE * filehandle)76 int32_t IP2Location_DB_set_shared_memory(FILE *filehandle)
77 {
78     struct stat statbuf;
79     int32_t DB_loaded = 1;
80     void *addr = (void*)MAP_ADDR;
81 
82     DB_access_type = IP2LOCATION_SHARED_MEMORY;
83 
84     if ( ( shm_fd = shm_open(IP2LOCATION_SHM, O_RDWR | O_CREAT | O_EXCL, 0777)) != -1 )
85     {
86         DB_loaded = 0;
87     }
88     else if ((shm_fd = shm_open(IP2LOCATION_SHM, O_RDWR , 0777)) == -1 )
89     {
90         DB_access_type = IP2LOCATION_FILE_IO;
91         return -1;
92     }
93     if(fstat(fileno(filehandle), &statbuf) == -1)
94     {
95         close(shm_fd);
96         if( DB_loaded == 0 )
97             shm_unlink(IP2LOCATION_SHM);
98         DB_access_type = IP2LOCATION_FILE_IO;
99         return -1;
100     }
101 
102     if( DB_loaded == 0 && ftruncate(shm_fd, statbuf.st_size + 1) == -1)
103     {
104         close(shm_fd);
105         shm_unlink(IP2LOCATION_SHM);
106         DB_access_type = IP2LOCATION_FILE_IO;
107         return -1;
108     }
109 
110     cache_shm_ptr = mmap(addr, statbuf.st_size + 1, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
111     if (cache_shm_ptr == (void *) -1)
112     {
113         close(shm_fd);
114         if( DB_loaded == 0 )
115             shm_unlink(IP2LOCATION_SHM);
116         DB_access_type = IP2LOCATION_FILE_IO;
117         return -1;
118     }
119     if( DB_loaded == 0 )
120     {
121         if ( IP2Location_DB_Load_to_mem(filehandle, cache_shm_ptr, statbuf.st_size) == -1 )
122         {
123             munmap(cache_shm_ptr, statbuf.st_size);
124             close(shm_fd);
125             shm_unlink(IP2LOCATION_SHM);
126             DB_access_type = IP2LOCATION_FILE_IO;
127             return -1;
128         }
129     }
130     return 0;
131 }
132 #else
133 #ifdef WIN32
IP2Location_DB_set_shared_memory(FILE * filehandle)134 int32_t IP2Location_DB_set_shared_memory(FILE *filehandle)
135 {
136     struct stat statbuf;
137     int32_t DB_loaded = 1;
138 
139     DB_access_type = IP2LOCATION_SHARED_MEMORY;
140 
141     if(fstat(fileno(filehandle), &statbuf) == -1)
142     {
143         DB_access_type = IP2LOCATION_FILE_IO;
144         return -1;
145     }
146 
147     shm_fd = CreateFileMapping(
148                  INVALID_HANDLE_VALUE,
149                  NULL,
150                  PAGE_READWRITE,
151                  0,
152                  statbuf.st_size + 1,
153                  TEXT(IP2LOCATION_SHM));
154     if(shm_fd == NULL)
155     {
156         DB_access_type = IP2LOCATION_FILE_IO;
157         return -1;
158     }
159 
160     DB_loaded = (GetLastError() == ERROR_ALREADY_EXISTS);
161 
162     cache_shm_ptr = MapViewOfFile(
163                         shm_fd,
164                         FILE_MAP_WRITE,
165                         0,
166                         0,
167                         0);
168 
169     if(cache_shm_ptr == NULL)
170     {
171         UnmapViewOfFile(cache_shm_ptr);
172         DB_access_type = IP2LOCATION_FILE_IO;
173         return -1;
174     }
175 
176     if( DB_loaded == 0 )
177     {
178         if ( IP2Location_DB_Load_to_mem(filehandle, cache_shm_ptr, statbuf.st_size) == -1 )
179         {
180             UnmapViewOfFile(cache_shm_ptr);
181             CloseHandle(shm_fd);
182             DB_access_type = IP2LOCATION_FILE_IO;
183             return -1;
184         }
185     }
186     return 0;
187 }
188 #endif
189 #endif
190 
191 //Load the DB file into shared/cache memory
IP2Location_DB_Load_to_mem(FILE * filehandle,void * memory,int64_t size)192 int32_t IP2Location_DB_Load_to_mem(FILE *filehandle, void *memory, int64_t size)
193 {
194     fseek(filehandle, SEEK_SET, 0);
195     if ( fread(memory, size, 1, filehandle) != 1 )
196         return -1;
197     return 0;
198 }
199 
200 //Close the corresponding memory, based on the opened option.
IP2Location_DB_close(FILE * filehandle)201 int32_t IP2Location_DB_close(FILE *filehandle)
202 {
203     struct stat statbuf;
204 
205 	if ( DB_access_type == IP2LOCATION_CACHE_MEMORY )
206     {
207         if( cache_shm_ptr != NULL )
208             free(cache_shm_ptr);
209     }
210     else if ( DB_access_type == IP2LOCATION_SHARED_MEMORY )
211     {
212         if( cache_shm_ptr != NULL )
213         {
214 #ifndef	WIN32
215             if(fstat(fileno(filehandle), &statbuf) == 0)
216             {
217                 munmap(cache_shm_ptr, statbuf.st_size);
218             }
219             close(shm_fd);
220 #else
221 #ifdef WIN32
222             UnmapViewOfFile(cache_shm_ptr);
223             CloseHandle(shm_fd);
224 #endif
225 #endif
226         }
227     }
228 
229 	if ( filehandle != NULL )
230         fclose(filehandle);
231 
232     DB_access_type = IP2LOCATION_FILE_IO;
233     return 0;
234 }
235 
236 #ifndef	WIN32
IP2Location_DB_del_shm()237 void IP2Location_DB_del_shm()
238 {
239     shm_unlink(IP2LOCATION_SHM);
240 }
241 #else
242 #ifdef WIN32
IP2Location_DB_del_shm()243 void IP2Location_DB_del_shm()
244 {
245 }
246 #endif
247 #endif
248 
IP2Location_readIPv6Address(FILE * handle,uint32_t position)249 struct in6_addr_local IP2Location_readIPv6Address(FILE *handle, uint32_t position)
250 {
251     int i,j;
252     struct in6_addr_local addr6;
253     for( i = 0, j = 15; i < 16; i++, j-- )
254     {
255         addr6.u.addr8[i] = IP2Location_read8(handle, position + j);
256     }
257     return addr6;
258 }
259 
IP2Location_read32(FILE * handle,uint32_t position)260 uint32_t IP2Location_read32(FILE *handle, uint32_t position)
261 {
262     uint8_t byte1 = 0;
263     uint8_t byte2 = 0;
264     uint8_t byte3 = 0;
265     uint8_t byte4 = 0;
266     uint8_t *cache_shm = cache_shm_ptr;
267     size_t temp;
268 
269     //Read from file
270     if (DB_access_type == IP2LOCATION_FILE_IO && handle != NULL)
271     {
272         fseek(handle, position-1, 0);
273         temp = fread(&byte1, 1, 1, handle);
274         temp = fread(&byte2, 1, 1, handle);
275         temp = fread(&byte3, 1, 1, handle);
276         temp = fread(&byte4, 1, 1, handle);
277     }
278     else
279     {
280         byte1 = cache_shm[ position - 1 ];
281         byte2 = cache_shm[ position ];
282         byte3 = cache_shm[ position + 1 ];
283         byte4 = cache_shm[ position + 2 ];
284     }
285     return ((byte4 << 24) | (byte3 << 16) | (byte2 << 8) | (byte1));
286 }
287 
IP2Location_read8(FILE * handle,uint32_t position)288 uint8_t IP2Location_read8(FILE *handle, uint32_t position)
289 {
290     uint8_t ret = 0;
291     uint8_t *cache_shm = cache_shm_ptr;
292     size_t temp;
293 
294     if (DB_access_type == IP2LOCATION_FILE_IO && handle != NULL)
295     {
296         fseek(handle, position-1, 0);
297         temp = fread(&ret, 1, 1, handle);
298     }
299     else
300     {
301         ret = cache_shm[ position - 1 ];
302     }
303     return ret;
304 }
305 
IP2Location_readStr(FILE * handle,uint32_t position)306 char *IP2Location_readStr(FILE *handle, uint32_t position)
307 {
308     uint8_t size = 0;
309     char *str = 0;
310     uint8_t *cache_shm = cache_shm_ptr;
311     size_t temp;
312     if (DB_access_type == IP2LOCATION_FILE_IO && handle != NULL)
313     {
314         fseek(handle, position, 0);
315         temp = fread(&size, 1, 1, handle);
316         str = (char *)malloc(size+1);
317         memset(str, 0, size+1);
318         temp = fread(str, size, 1, handle);
319     }
320     else
321     {
322         size = cache_shm[ position ];
323         str = (char *)malloc(size+1);
324         memset(str, 0, size+1);
325         memcpy((void*) str, (void*)&cache_shm[ position + 1 ], size);
326     }
327     return str;
328 }
329 
IP2Location_readFloat(FILE * handle,uint32_t position)330 float IP2Location_readFloat(FILE *handle, uint32_t position)
331 {
332     float ret = 0.0;
333     uint8_t *cache_shm = cache_shm_ptr;
334     size_t temp;
335 
336 #if defined(_SUN_) || defined(__powerpc__) || defined(__ppc__) || defined(__ppc64__) || defined(__powerpc64__)
337     char * p = (char *) &ret;
338 
339     // for SUN SPARC, have to reverse the byte order
340     if (DB_access_type == IP2LOCATION_FILE_IO && handle != NULL)
341     {
342         fseek(handle, position-1, 0);
343         temp = fread(p+3, 1, 1, handle);
344         temp = fread(p+2, 1, 1, handle);
345         temp = fread(p+1, 1, 1, handle);
346         temp = fread(p,   1, 1, handle);
347     }
348     else
349     {
350         *(p+3) = cache_shm[ position - 1 ];
351         *(p+2) = cache_shm[ position ];
352         *(p+1) = cache_shm[ position + 1 ];
353         *(p)   = cache_shm[ position + 2 ];
354     }
355 #else
356     if (DB_access_type == IP2LOCATION_FILE_IO && handle != NULL)
357     {
358         fseek(handle, position-1, 0);
359         temp = fread(&ret, 4, 1, handle);
360     }
361     else
362     {
363         memcpy((void*) &ret, (void*)&cache_shm[ position - 1 ], 4);
364     }
365 #endif
366     return ret;
367 }
368 
369 
370