/* * Copyright (c) 2003 INRIA - All rights reserved * main authors: Christoph Neumann - christoph.neumann@inrialpes.fr * Vincent Roca - vincent.roca@inrialpes.fr * Julien Laboure - julien.laboure@inrialpes.fr * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ /* * fsend.c * * flute sender side functions */ #include "flute.h" /* * Local variables */ int fec_code = MCL_FEC_CODE_NULL; /* FEC code that will be used by the sender */ /* XXX: The current version uses a single FEC code for the whole */ /* session even if FEC can be specified on a per-object basis. */ int max_fragment_size; /* Big files are fragmented into fragments of this size */ unsigned int toiindex=0; GdomeDocument* fdtinstance; void FluteSend (void) { int mcl_max_block_size; /* maximum size of a source block in bytes; */ /* depends on the FEC codec used and its */ /* limitations on the "k" parameter */ int Bytes_sent = 0; #if defined(ALC) int mcl_option; #endif /* RM_PROTOCOL */ pthread_mutex_lock(&flutemutex); fdtinstance = createNewFDTinstance(); pthread_mutex_unlock(&flutemutex); if (fec_ratio > 1.0) { #if defined(ALC) /* * The user asked for FEC, so choose the codec. * Try LDGM first, and if not applicable, revert to RSE * NB: not supported by NORM currently... */ #if 0 #else /* comment #else to test with RSE */ fec_code = MCL_FEC_CODE_LDGM; if (mcl_ctl(id, MCL_OPT_SET_FEC_CODE, (void*)&fec_code, sizeof(fec_code))) #endif { fec_code = MCL_FEC_CODE_RSE; if (mcl_ctl(id, MCL_OPT_SET_FEC_CODE, (void*)&fec_code, sizeof(fec_code))) { EXIT(("Flute: ERROR, no FEC codec available\n")) } } #endif /* RM_PROTOCOL */ if (mcl_ctl(id, MCL_OPT_FEC_RATIO, (void*)&fec_ratio, sizeof(fec_ratio))) EXIT(("Flute: ERROR, mcl_ctl failed for FEC_RATIO\n")) } else { /* * No FEC packet, so set the FEC code to NULL. */ fec_code = MCL_FEC_CODE_NULL; if (mcl_ctl(id, MCL_OPT_SET_FEC_CODE, (void*)&fec_code, sizeof(fec_code))) { EXIT(("Flute: ERROR, FEC codec NULL not available\n")) } } /* * Determine the maximum block size. * This maximum is defined by the MCL library, depending on * the FEC code in use, but it must not exceed the value * specified in the * XXX_MAX_FRAGMENT_SIZE constant. */ if (mcl_ctl(id, MCL_OPT_GET_MAX_BLOCK_SIZE_FOR_CURRENT_FEC, (void*)&mcl_max_block_size, sizeof(mcl_max_block_size))) { EXIT(("Flute: ERROR, mcl_ctl failed for MCL_OPT_GET_MAX_BLOCK_SIZE_FOR_CURRENT_FEC\n")) } ASSERT(mcl_max_block_size > 0); switch (fec_code) { case MCL_FEC_CODE_RSE: max_fragment_size = min(RSE_MAX_FRAGMENT_SIZE, mcl_max_block_size - MAX_TRAILER_SIZE); break; #ifdef ALC case MCL_FEC_CODE_LDGM: max_fragment_size = min(LDPC_MAX_FRAGMENT_SIZE, mcl_max_block_size - MAX_TRAILER_SIZE); break; #endif /* RM_PROTOCOL */ default: /* no FEC encoding... */ max_fragment_size = min(NO_FEC_MAX_FRAGMENT_SIZE, mcl_max_block_size - MAX_TRAILER_SIZE); break; } #if defined(ALC) /* * NB: always use LCT1 now, in all cases... */ mcl_option = MCL_SCHED_LCT1; if (mcl_ctl(id, MCL_OPT_SCHED, (void*)&mcl_option, sizeof(mcl_option))) { EXIT(("Fcast: mcl_ctl MCL_OPT_SCHED failed for LCT1\n")) } #if 0 if (tx_huge_file > 0) mcl_option = MCL_SCHED_LCT3; else mcl_option = MCL_SCHED_LCT2; if (single_layer == 0) { /* * set the scheduling mode, except for single layer where * LCT1 is required */ if (mcl_ctl(id, MCL_OPT_SCHED, (void*)&mcl_option, sizeof(mcl_option))) EXIT(("Flute: mcl_ctl MCL_OPT_SCHED failed\n")) } #endif if (optimode == OPTIMIZE_SPACE) { mcl_option = MCL_SCHED_PARTIALLY_MIXED_ORDER; if (mcl_ctl(id, MCL_OPT_OBJ_SCHED, (void*)&mcl_option, sizeof(mcl_option))) EXIT(("Flute: mcl_ctl MCL_OPT_SCHED failed\n")) } else if (optimode == OPTIMIZE_SPEED) { mcl_option = MCL_SCHED_MIXED_ORDER; if (mcl_ctl(id, MCL_OPT_OBJ_SCHED, (void*)&mcl_option, sizeof(mcl_option))) EXIT(("Flute: mcl_ctl MCL_OPT_OBJ_SCHED failed\n")) } else if (optimode == OPTIMIZE_CPU) { mcl_option = MCL_SCHED_MIXED_ORDER; if (mcl_ctl(id, MCL_OPT_OBJ_SCHED, (void*)&mcl_option, sizeof(mcl_option))) EXIT(("Flute: mcl_ctl MCL_OPT_OBJ_SCHED failed\n")) } else { EXIT(("Flute: ERROR, invalid optimization mode!")) } #elif defined(NORM) /* no equivalent */ #endif /* RM_PROTOCOL */ if (mcl_ctl(id, MCL_OPT_NO_NONEWADU,NULL, 0)) EXIT(("Flute: mcl_ctl MCL_OPT_NO_NONEWADU failed\n")) /* mcl_option = 1; mcl_ctl(id, MCL_OPT_REUSE_APPLI_TX_BUFFER, (void*)&mcl_option, sizeof(mcl_option)); */ if (recursive) { int fdtsize=0; char *fdtbuffer; max_fragment_size = RSE_MAX_FRAGMENT_SIZE; #ifdef ALC max_fragment_size = max(max_fragment_size, LDPC_MAX_FRAGMENT_SIZE); #endif /* RM_PROTOCOL */ max_fragment_size = max(max_fragment_size, NO_FEC_MAX_FRAGMENT_SIZE); if(!(fdtbuffer = (char*)malloc(max_fragment_size))) { EXIT(("Error: Cannot alloc memory!\n")) } #if defined(ALC) if(mcl_ctl(id, MCL_OPT_KEEP_DATA, NULL, 0)) EXIT(("Flute: mcl_ctl KEEP_DATA failed\n")) #endif /* RM_PROTOCOL */ Bytes_sent = RecursiveSend(fileparam); { unsigned int mcl_option_temp=0; if (mcl_ctl(id, MCL_OPT_SET_NEXT_TOI, (void*)&mcl_option_temp, sizeof(mcl_option_temp))) EXIT(("Flute: mcl_ctl MCL_OPT_SET_NEXT_TOI failed\n")) } pthread_mutex_lock(&flutemutex); fdtsize=getFinalFDTInstance(fdtinstance, &fdtbuffer); if (mcl_send(id, fdtbuffer , fdtsize) < 0) EXIT((": mcl_send failed\n")) pthread_mutex_unlock(&flutemutex); #if defined(ALC) if(mcl_ctl(id, MCL_OPT_PUSH_DATA, NULL, 0)) EXIT(("Flute: mcl_ctl PUSH_DATA failed\n")) #endif /* RM_PROTOCOL */ } else { int fdtsize=0; char *fdtbuffer; max_fragment_size = RSE_MAX_FRAGMENT_SIZE; #ifdef ALC max_fragment_size = max(max_fragment_size, LDPC_MAX_FRAGMENT_SIZE); #endif /* RM_PROTOCOL */ max_fragment_size = max(max_fragment_size, NO_FEC_MAX_FRAGMENT_SIZE); if(!(fdtbuffer = (char*)malloc(max_fragment_size))) { EXIT(("Error: Cannot alloc memory!\n")) } #if defined(ALC) if(mcl_ctl(id, MCL_OPT_KEEP_DATA, NULL, 0)) EXIT(("Flute: mcl_ctl KEEP_DATA returned an error\n")) #endif /* RM_PROTOCOL */ Bytes_sent = SendThisFile(fileparam, max_fragment_size); { unsigned int mcl_option_temp=0; if (mcl_ctl(id, MCL_OPT_SET_NEXT_TOI, (void*)&mcl_option_temp, sizeof(mcl_option_temp))) EXIT(("Flute: mcl_ctl MCL_OPT_SET_NEXT_TOI failed\n")) } pthread_mutex_lock(&flutemutex); fdtsize=getFinalFDTInstance(fdtinstance, &fdtbuffer); if (mcl_send(id, fdtbuffer, fdtsize) < 0) EXIT((": mcl_send failed\n")) pthread_mutex_unlock(&flutemutex); #if defined(ALC) if(mcl_ctl(id, MCL_OPT_PUSH_DATA, NULL, 0)) EXIT(("Flute: mcl_ctl PUSH_DATA returned an error\n")) #endif /* RM_PROTOCOL */ } mcl_close(id); PRINT(("\nFluteSend complete. %d bytes sent\n", Bytes_sent)) } #ifdef WIN32 int RecursiveSend (char* Path) { HANDLE dirp = NULL; WIN32_FIND_DATA entry; unsigned int total_sent = 0; char FullName[MAX_PATH + MAX_FILENAME]; char FindString[MAX_PATH]; strcpy(FindString, Path); strcat(FindString, "\\*"); dirp = FindFirstFile(FindString, &entry); if (dirp == INVALID_HANDLE_VALUE) { EXIT(("Flute: ERROR, in recursive mode, the given parameter MUST BE a valid directory name\nAborting...\n")) } if (!IsDirDots (entry.cFileName)) { strcpy(FullName, Path); if(FullName[strlen(FullName)-1] == '\\') FullName[strlen(FullName)-1] = '/'; if(FullName[strlen(FullName)-1] != '/') strcat(FullName,"/"); strcat(FullName, entry.cFileName); if( entry.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { ASSERT((strcmp(Path,FullName))) PRINT(("Entering Directory %s\n", FullName)) total_sent+= RecursiveSend (FullName); } else { PRINT(("\nSending File %s\n", FullName)) total_sent += SendThisFile (FullName, max_fragment_size); } } while ( FindNextFile(dirp, &entry) ) { if (IsDirDots (entry.cFileName)) continue; strcpy(FullName, Path); if(FullName[strlen(FullName)-1] == '\\') FullName[strlen(FullName)-1] = '/'; if(FullName[strlen(FullName)-1] != '/') strcat(FullName,"/"); strcat(FullName, entry.cFileName); if( entry.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { ASSERT((strcmp(Path,FullName))) PRINT(("Entering Directory %s\n", FullName)) total_sent+= RecursiveSend (FullName); } else { PRINT(("\nSending File %s\n", FullName)) total_sent += SendThisFile (FullName, max_fragment_size); } } FindClose(dirp); return total_sent; } #else int RecursiveSend (char* Path) { unsigned int total_sent = 0; struct dirent *entry; struct stat stats; char FullName[MAX_PATH + MAX_FILENAME]; DIR *dirp; if ((dirp = opendir (Path)) == NULL) { perror(Path); EXIT(("RecursiveSend: ERROR, opendir failed\n")) } /* For SOLARIS users: Why doesn't readdir work? It chops the first two characters of all filenames. You're probably linking with libucb and didn't read question 6.18. (Readdir in libucb.so wants you to include sys/dir.h, but many SunOS 4.1.x programs included , consequently, you're mixing native struct dirent with libucb readdir(). The symptom of this mixup is that the first two characters of each filename are missing. Make sure you use a native compiler (default /opt/SUNWspro/bin/cc, which may not be in your PATH), and not /usr/ucb/cc. */ while ((entry = readdir(dirp)) != NULL) { if (IsDirDots (entry->d_name)) continue; strcpy(FullName, Path); if (FullName[strlen(FullName)-1] != '/') strcat(FullName, "/"); strcat(FullName, entry->d_name); if (stat(FullName, &stats) == -1) { perror("RecursiveSend: ERROR, stat failed"); PRINT(("RecursiveSend: FullName=%s\nentry->d_name=%s\nPath=%s\n", FullName, entry->d_name, Path)) EXIT(("RecursiveSend: ERROR, stat() failed\n")) } if (S_ISDIR(stats.st_mode)) { ASSERT((strcmp(Path,FullName))) PRINT(("Entering Directory %s\n", FullName)) total_sent+= RecursiveSend (FullName); } else { PRINT(("Sending File %s\n", FullName)) total_sent += SendThisFile (FullName, max_fragment_size); } } closedir (dirp); return total_sent; } #endif int SendThisFile (char *file_path, int fragment_len) { struct stat file_stats; FILE *file_to_send = NULL; char *buf_file = NULL; int sent = 0; int ObjectLength = 0; char *toistring=(char*)malloc(10); GdomeElement *el; toiindex++; if (mcl_ctl(id, MCL_OPT_SET_NEXT_TOI, (void*)&toiindex, sizeof(toiindex))) EXIT(("Flute: mcl_ctl MCL_OPT_SET_NEXT_TOI failed\n")) if(FileExist(file_path)) { if(stat(file_path, &file_stats) == -1) { PRINT(("Error: stat()\n")) goto end; } file_to_send = fopen(file_path, "rb"); } else { PRINT(("Error: %s, no such file!\n", file_path)) goto end; } if( !(file_stats.st_mode & S_IFREG) ) EXIT(("Error: %s is not a regular file\n", file_path)) if(!(buf_file = (char*)malloc(file_stats.st_size))) { EXIT(("Error: Cannot alloc memory!\n")) } if( (ObjectLength = fread(buf_file, 1, file_stats.st_size, file_to_send)) < 0) EXIT(("Error FluteSend: fread failed, returned %d\n", ObjectLength)) if (mcl_send(id, buf_file, ObjectLength) < 0) EXIT((": mcl_send failed\n")) sent+= ObjectLength; if(buf_file) free(buf_file); fclose(file_to_send); pthread_mutex_lock(&flutemutex); /* Updating FDT*/ el=createNewFile(); sprintf(toistring,"%u",toiindex); el=setFileAttritbute(el, "TOI", toistring); el=setFileAttritbute(el, "Content-Location", file_path); appendFile(el); /* Adding to fdt-instance*/ AddFileToFDTinstance(fdtinstance, toiindex); pthread_mutex_unlock(&flutemutex); end: return sent; }