Fixed filetransfer to use shm status for flow control.
[profile/ivi/dlt-daemon.git] / src / lib / dlt_filetransfer.c
1 #include "dlt_filetransfer.h"
2
3 //!Defines the buffer size of a single file package which will be logged to dlt
4 #define BUFFER_SIZE 1024
5
6 //!Defines the minimum timeout between two dlt logs. This is important because dlt should not be flooded with too many logs in a short period of time.
7 #define MIN_TIMEOUT 20
8
9
10 #define ERROR_FILE_COMPLETE -300
11 #define ERROR_FILE_COMPLETE1 -301
12 #define ERROR_FILE_COMPLETE2 -302
13 #define ERROR_FILE_COMPLETE3 -303
14 #define ERROR_FILE_HEAD -400
15 #define ERROR_FILE_DATA -500
16 #define ERROR_FILE_END -600
17 #define ERROR_INFO_ABOUT -700
18 #define ERROR_PACKAGE_COUNT -800
19
20
21 //!Buffer for dlt file transfer. The size is defined by BUFFER_SIZE
22 unsigned char buffer[BUFFER_SIZE];
23
24
25 //!Get some information about the file size of a file
26 /**See stat(2) for more informations.
27  * @param file Absolute file path
28  * @return Returns the size of the file (if it is a regular file or a symbolic link) in bytes.
29  */
30 unsigned long getFilesize(const char* file){
31         struct stat st;
32         stat(file, &st);
33         return (unsigned long)st.st_size;
34 }
35
36 //!Get some information about the file serial number of a file
37 /** See stat(2) for more informations.
38  * @param file Absolute file path
39  * @return Returns a unique number associated with each filename
40  */
41 unsigned long getFileSerialNumber(const char* file){
42         struct stat st;
43         stat(file, &st);
44         return (unsigned long)st.st_ino;
45 }
46
47 //!Returns the creation date of a file
48 /** See stat(2) for more informations.
49  * @param file Absolute file path
50  * @return Returns the creation date of a file
51 */
52 time_t getFileCreationDate(const char* file){
53         struct stat st;
54         stat(file, &st);
55         return st.st_ctime;
56 }
57 char* getFileCreationDate2(const char* file){
58         struct stat st;
59         stat(file, &st);
60         
61         struct tm  *ts= localtime(&st.st_ctime);
62         //char       buf[80];
63         /* Format and print the time, "ddd yyyy-mm-dd hh:mm:ss zzz" */
64         //strftime(buf, sizeof(buf), "%a %Y-%m-%d %H:%M:%S %Z", ts);
65         return asctime(ts);
66 }
67
68
69
70
71 //void sighandler(int sig)
72 //{
73 //      
74 //      fprintf(stderr, "Signal handler called with %d\n", sig);
75 //      signal(sig, &sighandler);
76 //      exit(1); 
77 //      
78 //}
79
80
81
82 //!Checks if the file exists
83 /**@param file Absolute file path
84  * @return Returns 1 if the file exists, 0 if the file does not exist
85  */
86 int isFile (const char* file)
87 {
88         struct stat   st;   
89         return (stat (file, &st) == 0);
90 }
91
92 //!Waits a period of time
93 /**Waits a period of time. The minimal time to wait is MIN_TIMEOUT. This makes sure that the FIFO of dlt is not flooded.
94  * @param timeout Timeout to wait in seconds in ms but can not be smaller as MIN_TIMEOUT
95  */
96 void doTimeout(int timeout)
97 {
98         int total_size, used_size;
99         
100         dlt_user_check_buffer(&total_size, &used_size);
101         
102         /* sleep only if more than 50% of buffer used */
103         if((total_size - used_size) < (total_size/2))
104         {
105                 printf("Wait %d of %d already used\n",used_size,total_size);
106
107                 if(timeout>MIN_TIMEOUT)
108                 {       
109                         usleep(timeout * 1000);
110                 }
111                 else
112                 {
113                         usleep(MIN_TIMEOUT * 1000);
114                 }                               
115         }
116 }
117
118 //!Deletes the given file
119 /**
120  * @param filename Absolute file path
121  * @return If the file is successfully deleted, a zero value is returned.If the file can not be deleted a nonzero value is returned.
122  */
123 int doRemoveFile(const char*filename){
124         return remove( filename); 
125 }
126
127 void dlt_user_log_file_errorMessage(DltContext *fileContext, const char *filename, int errorCode){
128
129         if(-errno != -2)
130         {
131                 DLT_LOG(*fileContext,DLT_LOG_ERROR,
132                         DLT_STRING("FLER"),
133                         DLT_INT(errorCode),
134                         DLT_INT(-errno),
135                         DLT_UINT(getFileSerialNumber(filename)),
136                         DLT_STRING(filename),
137                         DLT_UINT(getFilesize(filename)),
138                         DLT_STRING(getFileCreationDate2(filename)),
139                         DLT_UINT(dlt_user_log_file_packagesCount(fileContext,filename)),
140                         DLT_UINT(BUFFER_SIZE),
141                         DLT_STRING("FLER")
142                 );              
143         } else {
144                 DLT_LOG(*fileContext,DLT_LOG_ERROR,
145                         DLT_STRING("FLER"),
146                         DLT_INT(errorCode),
147                         DLT_INT(-errno),
148                         DLT_STRING(filename),
149                         DLT_STRING("FLER")
150                 );
151         }
152 }
153
154
155
156 //!Logs specific file inforamtions to dlt
157 /**The filename, file size, file serial number and the number of packages will be logged to dlt.
158  * @param fileContext Specific context
159  * @param filename Absolute file path
160  * @return Returns 0 if everything was okey.If there was a failure a value < 0 will be returned.
161  */
162 int dlt_user_log_file_infoAbout(DltContext *fileContext, const char *filename){
163         
164         if(isFile(filename))
165         {
166                 DLT_LOG(*fileContext,DLT_LOG_INFO,
167                         DLT_STRING("FLIF"),
168                         DLT_STRING("file serialnumber"),DLT_UINT(getFileSerialNumber(filename)),
169                         DLT_STRING("filename"),DLT_STRING(filename),
170                         DLT_STRING("file size in bytes"),DLT_UINT(getFilesize(filename)),
171                         DLT_STRING("file creation date"),DLT_STRING(getFileCreationDate2(filename)),
172                         DLT_STRING("number of packages"),DLT_UINT(dlt_user_log_file_packagesCount(fileContext, filename)),
173                         DLT_STRING("FLIF")
174                 );
175                 return 0;
176         } else {
177         
178                 dlt_user_log_file_errorMessage(fileContext,filename,ERROR_INFO_ABOUT);
179                 return ERROR_INFO_ABOUT;
180         }
181 }
182
183 //!Transfer the complete file as several dlt logs.
184 /**This method transfer the complete file as several dlt logs. At first it will be checked that the file exist.
185  * In the next step some generic informations about the file will be logged to dlt.
186  * Now the header will be logged to dlt. See the method dlt_user_log_file_header for more informations.
187  * Then the method dlt_user_log_data will be called with the parameter to log all packages in a loop with some timeout.
188  * At last dlt_user_log_end is called to signal that the complete file transfer was okey. This is important for the plugin of the dlt viewer. 
189  * @param fileContext Specific context to log the file to dlt
190  * @param filename Absolute file path
191  * @param deleteFlag Flag if the file will be deleted after transfer. 1->delete, 0->notDelete
192  * @param timeout Timeout in ms to wait between some logs. Important that the FIFO of dlt will not be flooded with to many messages in a short period of time.
193  * @return Returns 0 if everything was okey. If there was a failure a value < 0 will be returned.
194  */
195 int dlt_user_log_file_complete(DltContext *fileContext, const char *filename, int deleteFlag, int timeout)
196 {       
197         //No signal handling in library - part of the main program!
198         //signal(SIGABRT, &sighandler);
199         //signal(SIGTERM, &sighandler);
200         //signal(SIGINT, &sighandler);
201
202         if(!isFile(filename))
203         {
204                 dlt_user_log_file_errorMessage(fileContext,filename, ERROR_FILE_COMPLETE);
205                 return ERROR_FILE_COMPLETE;
206         }
207         
208         //dlt_user_log_file_infoAbout(fileContext,filename);
209         
210         if(dlt_user_log_file_header(fileContext,filename) != 0)
211         {
212                 return ERROR_FILE_COMPLETE1;
213         }
214                 
215         if(dlt_user_log_file_data(fileContext, filename,LONG_MAX,timeout) != 0)
216         {
217                 return ERROR_FILE_COMPLETE2;
218         }
219                 
220         if(dlt_user_log_file_end(fileContext,filename, deleteFlag) != 0)
221         {
222                 return ERROR_FILE_COMPLETE3;
223         }               
224                         
225         return 0;
226 }
227
228 //!This method gives information about the number of packages the file have
229 /**Every file will be divided into several packages. Every package will be logged as a single dlt log.
230  * The number of packages depends on the BUFFER_SIZE.
231  * At first it will be checked if the file exist. Then the file will be divided into
232  * several packages depending on the buffer size.
233  * @param fileContext Specific context to log the file to dlt
234  * @param filename Absolute file path
235  * @return Returns the number of packages if everything was okey. If there was a failure a value < 0 will be returned.
236  */
237 int dlt_user_log_file_packagesCount(DltContext *fileContext, const char *filename){
238         int packages;
239         long filesize;
240         
241         if(isFile(filename))
242         {
243                 packages = 1;
244                 filesize = getFilesize(filename);
245                 if(filesize < BUFFER_SIZE)
246                 {       
247                         return packages;
248                 } 
249                 else 
250                 {
251                         packages = filesize/BUFFER_SIZE;
252                         
253                         if(filesize%BUFFER_SIZE == 0)
254                         {       
255                                 return packages;
256                         }
257                         else
258                         {
259                                 return packages+1;
260                         }
261                 }
262         } else {
263                 dlt_user_log_file_errorMessage(fileContext,filename,ERROR_PACKAGE_COUNT);
264                 return -1;
265         }
266 }
267
268 //!Transfer the head of the file as a dlt logs.
269 /**The head of the file must be logged to dlt because the head contains inforamtion about the file serial number,
270  * the file name, the file size, package number the file have and the buffer size.
271  * All these informations are needed from the plugin of the dlt viewer.
272  * See the Mainpages.c for more informations.
273  * @param fileContext Specific context to log the file to dlt
274  * @param filename Absolute file path
275  * @return Returns 0 if everything was okey. If there was a failure a value < 0 will be returned.
276  */
277 int dlt_user_log_file_header(DltContext *fileContext,const char *filename){
278
279         if(isFile(filename))
280         {
281                 DLT_LOG(*fileContext,DLT_LOG_INFO,
282                                         DLT_STRING("FLST"),
283                                         DLT_UINT(getFileSerialNumber(filename)),
284                                         DLT_STRING(filename),
285                                         DLT_UINT(getFilesize(filename)),
286                                         DLT_STRING(getFileCreationDate2(filename));
287                                         DLT_UINT(dlt_user_log_file_packagesCount(fileContext,filename)),
288                                         DLT_UINT(BUFFER_SIZE),
289                                         DLT_STRING("FLST")              
290                                 );
291
292                 return 0;
293         }
294         else
295         {
296                 dlt_user_log_file_errorMessage(fileContext,filename, ERROR_FILE_HEAD);
297                 return ERROR_FILE_HEAD;
298         }
299 }
300
301 //!Transfer the content data of a file.
302 /**See the Mainpages.c for more informations.
303  * @param fileContext Specific context to log the file to dlt
304  * @param filename Absolute file path
305  * @param packageToTransfer Package number to transfer. If this param is LONG_MAX, the whole file will be transferred with a specific timeout
306  * @param timeout Timeout to wait between dlt logs. Important because the dlt FIFO should not be flooded. Default is defined by MIN_TIMEOUT. The given timeout in ms can not be smaller than MIN_TIMEOUT.
307  * @return Returns 0 if everything was okey. If there was a failure a value < 0 will be returned.
308  */
309 int dlt_user_log_file_data(DltContext *fileContext,const char *filename, int packageToTransfer, int timeout){
310         FILE *file;
311         int pkgNumber;
312         long readBytes;
313                 
314         if(isFile(filename))
315         {
316         
317                 file = fopen (filename,"rb");
318                 if (file == NULL)
319                 {
320                         dlt_user_log_file_errorMessage(fileContext,filename,ERROR_FILE_DATA);
321                         return ERROR_FILE_DATA;
322                 }
323                 
324                 if( (packageToTransfer != LONG_MAX && packageToTransfer > dlt_user_log_file_packagesCount(fileContext,filename)) || packageToTransfer <= 0)
325                 {
326                         DLT_LOG(*fileContext,DLT_LOG_ERROR,
327                                 DLT_STRING("Error at dlt_user_log_file_data: packageToTransfer out of scope"),
328                                 DLT_STRING("packageToTransfer:"),
329                                 DLT_UINT(packageToTransfer),
330                                 DLT_STRING("numberOfMaximalPackages:"),
331                                 DLT_UINT(dlt_user_log_file_packagesCount(fileContext,filename)),
332                                 DLT_STRING("for File:"),
333                                 DLT_STRING(filename)
334                         );
335                         return ERROR_FILE_DATA;
336                 }
337
338                 readBytes = 0;
339                 
340                 if(packageToTransfer != LONG_MAX)
341                 {
342                                 fseek ( file , (packageToTransfer-1)*BUFFER_SIZE , SEEK_SET );
343                                 readBytes = fread(buffer, sizeof(char), BUFFER_SIZE, file);
344                                 
345                                 DLT_LOG(*fileContext,DLT_LOG_INFO,
346                                         DLT_STRING("FLDA"),
347                                         DLT_UINT(getFileSerialNumber(filename)),
348                                         DLT_UINT(packageToTransfer),
349                                         DLT_RAW(buffer,readBytes),
350                                         DLT_STRING("FLDA")      
351                                 );
352                                 
353                                 doTimeout(timeout);
354                                         
355                 } else {
356                         pkgNumber = 0;
357                         while( !feof( file ) )
358                         {
359                                 pkgNumber++;
360                                 readBytes = fread(buffer, sizeof(char), BUFFER_SIZE, file);     
361                                 
362                                 DLT_LOG(*fileContext,DLT_LOG_INFO,
363                                         DLT_STRING("FLDA"),
364                                         DLT_UINT(getFileSerialNumber(filename)),
365                                         DLT_UINT(pkgNumber),
366                                         DLT_RAW(buffer,readBytes),
367                                         DLT_STRING("FLDA")              
368                                 );
369                                 
370                                 doTimeout(timeout); 
371                         }
372                 }
373                 
374                 fclose(file);
375                 
376                 return 0;
377                 
378         } else {
379                 dlt_user_log_file_errorMessage(fileContext,filename,ERROR_FILE_DATA);
380                 return ERROR_FILE_DATA;
381         }
382         
383 }
384 //!Transfer the end of the file as a dlt logs.
385 /**The end of the file must be logged to dlt because the end contains inforamtion about the file serial number.
386  * This informations is needed from the plugin of the dlt viewer.
387  * See the Mainpages.c for more informations.
388  * @param fileContext Specific context to log the file to dlt
389  * @param filename Absolute file path
390  * @param deleteFlag Flag to delete the file after the whole file is transferred (logged to dlt).1->delete,0->NotDelete
391  * @return Returns 0 if everything was okey. If there was a failure a value < 0 will be returned.
392  */
393 int dlt_user_log_file_end(DltContext *fileContext,const char *filename,int deleteFlag){
394
395         if(isFile(filename))
396         {
397
398                 DLT_LOG(*fileContext,DLT_LOG_INFO,
399                                 DLT_STRING("FLFI"),
400                                 DLT_UINT(getFileSerialNumber(filename)),
401                                 DLT_STRING("FLFI")
402                 );
403                 
404                 if(deleteFlag){
405                                 if( doRemoveFile(filename) != 0 ){
406                                         dlt_user_log_file_errorMessage(fileContext,filename,ERROR_FILE_END);
407                                         return -1;
408                                 }
409                 }
410         
411                 return 0;
412         }else{
413                 dlt_user_log_file_errorMessage(fileContext,filename,ERROR_FILE_END);
414                 return ERROR_FILE_END;
415         }
416 }