void CFileConn::_HandleClientFilePullFileReq(CImPdu *pPdu) { if (!_IsAuth()) { return; } IM::File::IMFilePullDataReq msg; CHECK_PB_PARSE_MSG(msg.ParseFromArray(pPdu->GetBodyData(), pPdu->GetBodyLength())); uint32_t user_id = msg.user_id(); string task_id = msg.task_id(); uint32_t mode = msg.trans_mode(); uint32_t offset = msg.offset(); uint32_t datasize = msg.data_size(); IM::File::IMFilePullDataRsp msg2; msg2.set_result_code(1); msg2.set_task_id(task_id); msg2.set_user_id(user_id); msg2.set_offset(offset); msg2.set_data(""); CImPdu pdu; pdu.SetPBMsg(&msg2); pdu.SetServiceId(SID_FILE); pdu.SetCommandId(CID_FILE_PULL_DATA_RSP); pdu.SetSeqNum(pPdu->GetSeqNum()); // since the task had been created when the recver logged-in // we can find task in g_file_task_map here pthread_rwlock_wrlock(&g_file_task_map_lock); TaskMap_t::iterator iter = g_file_task_map.find(task_id.c_str()); if (g_file_task_map.end() == iter) { // invalid task id pthread_rwlock_unlock(&g_file_task_map_lock); log("invalid task id %s ", task_id.c_str()); SendPdu(&pdu); return; } transfer_task_t* t = iter->second; pthread_rwlock_unlock(&g_file_task_map_lock); t->lock(__LINE__); t->create_time = time(NULL); if (t->from_user_id != user_id /*for the realtime recver*/ && t->to_user_id != user_id /*for the offline download*/) { // invalid user log("illieage user %d for task %s", user_id, task_id.c_str()); SendPdu(&pdu); t->unlock(__LINE__); return; } switch (mode) { case IM::BaseDefine::FILE_TYPE_ONLINE: // transfer request to sender { CFileConn* pConn = (CFileConn*)t->GetOpponentConn(user_id); pConn->SendPdu(pPdu); break; } case IM::BaseDefine::FILE_TYPE_OFFLINE: // for the offline download { // find file use task id // send header info to user // send data // save path manager not used // save transfered info into task // like FILE* // transfered size // haven't been opened size_t size = 0; if (NULL == t->fp) { char save_path[BUFSIZ] = {0}; snprintf(save_path, BUFSIZ, "%s/%d", g_current_save_path, user_id); // those who can only get files under their user_id-dir int ret = mkdir(save_path, 0755); if ( (ret != 0) && (errno != EEXIST) ) { log("mkdir failed for path: %s", save_path); SendPdu(&pdu); t->unlock(__LINE__); return; } strncat(save_path, "/", BUFSIZ); strncat(save_path, task_id.c_str(), BUFSIZ); // use task_id as file name, in case of same-name file // open at first time t->fp = fopen(save_path, "rb"); // save fp if (!t->fp) { log("can not open file"); SendPdu(&pdu); t->unlock(__LINE__); return; } // read head at open if (NULL == t->file_head) { t->file_head = new file_header_t; if (NULL == t->file_head) { // close to ensure next time will new file-header again log("read file head failed."); fclose(t->fp); SendPdu(&pdu); t->unlock(__LINE__); return; } } size = fread(t->file_head, 1, sizeof(file_header_t), t->fp); // read header if (sizeof(file_header_t) > size) { // close to ensure next time will read again log("read file head failed."); fclose(t->fp); // error to get header SendPdu(&pdu); t->unlock(__LINE__); return; } // the header won't be sent to recver, because the msg svr had already notified it. // if the recver needs to check it, it could be helpful // or sometime later, the recver needs it in some way. } // read data and send based on offset and datasize. char* tmpbuf = new char[datasize]; if (NULL == tmpbuf) { // alloc mem failed log("alloc mem failed."); SendPdu(&pdu); t->unlock(__LINE__); return; } memset(tmpbuf, 0, datasize); // offset file_header_t int iret = fseek(t->fp, sizeof(file_header_t) + offset, SEEK_SET); // read after file_header_t if (0 != iret) { log("seek offset failed."); SendPdu(&pdu); delete[] tmpbuf; t->unlock(__LINE__); return; // offset failed } size = fread(tmpbuf, 1, datasize, t->fp); msg2.set_data(tmpbuf, size); CImPdu pdu2; pdu2.SetPBMsg(&msg2); pdu2.SetServiceId(SID_FILE); pdu2.SetCommandId(CID_FILE_PULL_DATA_RSP); pdu2.SetSeqNum(pPdu->GetSeqNum()); pdu2.SetSeqNum(pPdu->GetSeqNum()); SendPdu(&pdu2); delete[] tmpbuf; t->transfered_size += size; // record transfered size for next time offset if (0 == size) { fclose(t->fp); t->fp = NULL; _StatesNotify(CLIENT_FILE_DONE, task_id.c_str(), user_id, this); Close(); t->self_destroy = true; t->unlock(__LINE__); return; } break; } default: break; } t->unlock(__LINE__); return; }
void FileTransferSocket::_filePullDataRspResponse(IN std::string& body)//收 { IM::File::IMFilePullDataRsp imFilePullDataRsp; if (!imFilePullDataRsp.ParseFromString(body)) { LOG__(ERR, _T("parse failed,body:%s"), util::stringToCString(body)); return; } UInt32 nRes = imFilePullDataRsp.result_code(); if (0 != nRes) { LOG__(ERR, _T("PullDataRspResponse: error result:%d"),nRes); return; } std::string taskId = imFilePullDataRsp.task_id(); const std::string& strData = imFilePullDataRsp.file_data();//todo ?????要长度 void* pData = (void*)(strData.data()); UInt32 nBlockSize = strData.size(); UInt32 fileOffset = imFilePullDataRsp.offset(); TransferFileEntity fileEntity; if (!TransferFileEntityManager::getInstance()->getFileInfoByTaskId(taskId, fileEntity)) { LOG__(ERR, _T("can't find the fileInfo")); return; } LOG__(DEBG, _T("receive:taskId=%s,filesize=%d,name=%s,BolckSize=%d") , util::stringToCString(fileEntity.sTaskID) , fileEntity.nFileSize , fileEntity.getRealFileName() , nBlockSize); //存文件... if (!fileEntity.pFileObject->writeBlock(fileOffset, nBlockSize, pData)) { LOG__(DEBG, _T("writeBlock failed ")); return; } fileEntity.nProgress = fileOffset + nBlockSize; if (fileEntity.nProgress < fileEntity.nFileSize) { //更新进度条 TransferFileEntityManager::getInstance()->updateFileInfoBysTaskID(fileEntity);//保存当前进度 module::getFileTransferModule()->asynNotifyObserver(module::KEY_FILESEVER_UPDATA_PROGRESSBAR , fileEntity.sTaskID); //继续发file block req... int mode = fileEntity.nClientMode == IM::BaseDefine::ClientFileRole::CLIENT_OFFLINE_DOWNLOAD ? IM::BaseDefine::TransferFileType::FILE_TYPE_OFFLINE : IM::BaseDefine::TransferFileType::FILE_TYPE_ONLINE; IM::File::IMFilePullDataReq imFilePullDataReq; imFilePullDataReq.set_task_id(taskId); imFilePullDataReq.set_user_id(util::stringToInt32(fileEntity.sToID)); imFilePullDataReq.set_trans_mode(static_cast<IM::BaseDefine::TransferFileType>(mode)); imFilePullDataReq.set_offset(fileEntity.nProgress); UInt32 pullSize = fileEntity.nFileSize - fileEntity.nProgress; pullSize > nBlockSize ? imFilePullDataReq.set_data_size(nBlockSize) : imFilePullDataReq.set_data_size(pullSize); // 发包 sendPacket(IM::BaseDefine::ServiceID::SID_FILE, IM::BaseDefine::FileCmdID::CID_FILE_PULL_DATA_REQ, &imFilePullDataReq); } else//传输完成 { if (fileEntity.pFileObject) { delete fileEntity.pFileObject; fileEntity.pFileObject = nullptr; } //告知对方文件传输完成了。 IM::File::IMFileState imFileState; imFileState.set_state(IM::BaseDefine::ClientFileState::CLIENT_FILE_DONE); imFileState.set_task_id(taskId); imFileState.set_user_id(util::stringToInt32(fileEntity.sToID)); sendPacket(IM::BaseDefine::ServiceID::SID_FILE, IM::BaseDefine::FileCmdID::CID_FILE_STATE, &imFileState); TransferFileEntityManager::getInstance()->updateFileInfoBysTaskID(fileEntity); module::getFileTransferModule()->asynNotifyObserver(module::KEY_FILESEVER_PROGRESSBAR_FINISHED, fileEntity.sTaskID); } }
/// yunfan add 2014.8.7 /// offline file upload /// file-svr will send pull-data-req to sender /// then wait for sender's rsp void* _DoUpload(void* lparam) { if (NULL == lparam) { return NULL; } transfer_task_t* t = reinterpret_cast<transfer_task_t*>(lparam); t->create_time = time(NULL); // at begin // send 10 data-pull-req for (uint32_t cnt = 0; cnt < 1; ++cnt) { std::map<uint32_t, upload_package_t*>::iterator iter = t->upload_packages.begin(); if (t->upload_packages.end() != iter) { IM::File::IMFilePullDataReq msg; msg.set_task_id(t->task_id); msg.set_user_id(t->from_user_id); msg.set_trans_mode(::IM::BaseDefine::FILE_TYPE_OFFLINE); msg.set_offset(iter->second->offset); msg.set_data_size(iter->second->size); CImPdu pdu; pdu.SetPBMsg(&msg); pdu.SetServiceId(SID_FILE); pdu.SetCommandId(CID_FILE_PULL_DATA_REQ); CFileConn* pConn = (CFileConn*)t->GetConn(t->from_user_id); pConn->SendPdu(&pdu); log("Pull Data Req"); } ++iter; } // what if there is no rsp? // still send req? // no! // at last, the user will cancel // next ver, do change while (t->transfered_size != t->upload_packages.size()) { if (t->self_destroy) { log("timeout, exit thread, task %s", t->task_id.c_str()); return NULL; } sleep(1); } t->lock(__LINE__); // write head if (NULL == t->file_head) { t->file_head = new file_header_t; } if (NULL == t->file_head) { log("create file header failed %s", t->task_id.c_str()); // beacuse all data in mem // it has to be released /* UserMap_t::iterator ator = g_file_user_map.find(t->from_user_id); if (g_file_user_map.end() != ator) { CFileConn* pConn = (CFileConn*)ator->second; pConn->Close(); } */ CFileConn* pConn = (CFileConn*)t->GetConn(t->from_user_id); pConn->Close(); t->self_destroy = true; t->unlock(__LINE__); return NULL; } t->file_head->set_create_time(time(NULL)); t->file_head->set_task_id(t->task_id.c_str()); t->file_head->set_from_user_id(t->from_user_id); t->file_head->set_to_user_id(t->to_user_id); t->file_head->set_file_name(""); t->file_head->set_file_size(t->file_size); fwrite(t->file_head, 1, sizeof(file_header_t), t->fp); std::map<uint32_t, upload_package_t*>::iterator itor = t->upload_packages.begin(); for ( ; itor != t->upload_packages.end(); ++itor) { fwrite(itor->second->data, 1, itor->second->size, t->fp); } fflush(t->fp); if (t->fp) { fclose(t->fp); t->fp = NULL; } t->unlock(__LINE__); return NULL; }
void FileTransferSocket::_filePullDataReqResponse(IN std::string& body)//发 { IM::File::IMFilePullDataReq imFilePullDataReq; if (!imFilePullDataReq.ParseFromString(body)) { LOG__(ERR, _T("parse failed,body:%s"), util::stringToCString(body)); return; } UInt32 fileSize = imFilePullDataReq.data_size(); UInt32 fileOffset = imFilePullDataReq.offset(); std::string taskId = imFilePullDataReq.task_id(); TransferFileEntity fileEntity; if (!TransferFileEntityManager::getInstance()->getFileInfoByTaskId(taskId, fileEntity)) { LOG__(ERR, _T("PullDataReqResponse: can't find the fileInfo")); return; } LOG__(DEBG, _T("send:taskId=%s,filesize=%d,name=%s,BolckSize=%d") ,util::stringToCString(fileEntity.sTaskID) ,fileEntity.nFileSize ,fileEntity.getRealFileName() ,fileSize); std::string buff; if (nullptr == fileEntity.pFileObject) { LOG__(ERR, _T("PullDataReqResponse: file boject Destoryed!")); return; } fileEntity.pFileObject->readBlock(fileOffset, fileSize, buff);//读取本地文件的数据块 IM::File::IMFilePullDataRsp imFilePullDataRsp;//todo check imFilePullDataRsp.set_result_code(0); imFilePullDataRsp.set_task_id(taskId); imFilePullDataRsp.set_user_id(util::stringToInt32(fileEntity.sFromID)); imFilePullDataRsp.set_offset(fileOffset); imFilePullDataRsp.set_file_data((void*)buff.data(), fileSize); //send packet sendPacket(IM::BaseDefine::ServiceID::SID_FILE, IM::BaseDefine::FileCmdID::CID_FILE_PULL_DATA_RSP , &imFilePullDataRsp); fileEntity.nProgress = fileOffset + fileSize; if (fileEntity.nProgress < fileEntity.nFileSize) { //更新进度条 TransferFileEntityManager::getInstance()->updateFileInfoBysTaskID(fileEntity);//保存当前进度 module::getFileTransferModule()->asynNotifyObserver(module::KEY_FILESEVER_UPDATA_PROGRESSBAR , fileEntity.sTaskID); } else//传输完成 { if (fileEntity.pFileObject) { delete fileEntity.pFileObject; fileEntity.pFileObject = nullptr; } module::getFileTransferModule()->asynNotifyObserver(module::KEY_FILESEVER_PROGRESSBAR_FINISHED , fileEntity.sTaskID); } TransferFileEntityManager::getInstance()->updateFileInfoBysTaskID(fileEntity); }