1 /*
2 * Copyright (C) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include "file_descriptor.h"
16
17 namespace Hdc {
HdcFileDescriptor(uv_loop_t * loopIn,int fdToRead,void * callerContextIn,CallBackWhenRead callbackReadIn,CmdResultCallback callbackFinishIn)18 HdcFileDescriptor::HdcFileDescriptor(uv_loop_t *loopIn, int fdToRead, void *callerContextIn,
19 CallBackWhenRead callbackReadIn, CmdResultCallback callbackFinishIn)
20 {
21 loop = loopIn;
22 workContinue = true;
23 callbackFinish = callbackFinishIn;
24 callbackRead = callbackReadIn;
25 fdIO = fdToRead;
26 refIO = 0;
27 callerContext = callerContextIn;
28 }
29
~HdcFileDescriptor()30 HdcFileDescriptor::~HdcFileDescriptor()
31 {
32 if (refIO > 0) {
33 WRITE_LOG(LOG_FATAL, "~HdcFileDescriptor refIO > 0");
34 }
35 }
36
ReadyForRelease()37 bool HdcFileDescriptor::ReadyForRelease()
38 {
39 return refIO == 0;
40 }
41
42 // just tryCloseFdIo = true, callback will be effect
StopWork(bool tryCloseFdIo,std::function<void ()> closeFdCallback)43 void HdcFileDescriptor::StopWork(bool tryCloseFdIo, std::function<void()> closeFdCallback)
44 {
45 workContinue = false;
46 callbackCloseFd = closeFdCallback;
47 if (tryCloseFdIo && refIO > 0) {
48 ++refIO;
49 reqClose.data = this;
50 uv_fs_close(loop, &reqClose, fdIO, [](uv_fs_t *req) {
51 auto thisClass = (HdcFileDescriptor *)req->data;
52 uv_fs_req_cleanup(req);
53 if (thisClass->callbackCloseFd != nullptr) {
54 thisClass->callbackCloseFd();
55 }
56 --thisClass->refIO;
57 });
58 }
59 };
60
OnFileIO(uv_fs_t * req)61 void HdcFileDescriptor::OnFileIO(uv_fs_t *req)
62 {
63 CtxFileIO *ctxIO = static_cast<CtxFileIO *>(req->data);
64 HdcFileDescriptor *thisClass = ctxIO->thisClass;
65 uint8_t *buf = ctxIO->bufIO;
66 bool bFinish = false;
67 bool fetalFinish = false;
68
69 do {
70 if (req->result > 0) {
71 if (req->fs_type == UV_FS_READ) {
72 if (!thisClass->callbackRead(thisClass->callerContext, buf, req->result)) {
73 bFinish = true;
74 break;
75 }
76 thisClass->LoopRead();
77 } else {
78 // fs_write
79 }
80 } else {
81 if (req->result != 0) {
82 constexpr int bufSize = 1024;
83 char buf[bufSize] = { 0 };
84 uv_strerror_r((int)req->result, buf, bufSize);
85 WRITE_LOG(LOG_DEBUG, "OnFileIO fd:%d failed:%s", thisClass->fdIO, buf);
86 }
87 bFinish = true;
88 fetalFinish = true;
89 break;
90 }
91 } while (false);
92 uv_fs_req_cleanup(req);
93 delete[] buf;
94 delete ctxIO;
95
96 --thisClass->refIO;
97 if (bFinish) {
98 thisClass->callbackFinish(thisClass->callerContext, fetalFinish, STRING_EMPTY);
99 thisClass->workContinue = false;
100 }
101 }
102
LoopRead()103 int HdcFileDescriptor::LoopRead()
104 {
105 uv_buf_t iov;
106 int readMax = Base::GetMaxBufSize() * 1.2;
107 auto contextIO = new CtxFileIO();
108 auto buf = new uint8_t[readMax]();
109 if (!contextIO || !buf) {
110 if (contextIO) {
111 delete contextIO;
112 }
113 if (buf) {
114 delete[] buf;
115 }
116 WRITE_LOG(LOG_FATAL, "Memory alloc failed");
117 callbackFinish(callerContext, true, "Memory alloc failed");
118 return -1;
119 }
120 uv_fs_t *req = &contextIO->fs;
121 contextIO->bufIO = buf;
122 contextIO->thisClass = this;
123 req->data = contextIO;
124 ++refIO;
125 iov = uv_buf_init((char *)buf, readMax);
126 uv_fs_read(loop, req, fdIO, &iov, 1, -1, OnFileIO);
127 return 0;
128 }
129
StartWork()130 bool HdcFileDescriptor::StartWork()
131 {
132 if (LoopRead() < 0) {
133 return false;
134 }
135 return true;
136 }
137
Write(uint8_t * data,int size)138 int HdcFileDescriptor::Write(uint8_t *data, int size)
139 {
140 if (size > static_cast<int>(HDC_BUF_MAX_BYTES - 1)) {
141 size = static_cast<int>(HDC_BUF_MAX_BYTES - 1);
142 }
143 if (size <= 0) {
144 WRITE_LOG(LOG_WARN, "Write failed, size:%d", size);
145 return -1;
146 }
147 auto buf = new uint8_t[size];
148 if (!buf) {
149 return -1;
150 }
151 (void)memcpy_s(buf, size, data, size);
152 return WriteWithMem(buf, size);
153 }
154
155 // Data's memory must be Malloc, and the callback FREE after this function is completed
WriteWithMem(uint8_t * data,int size)156 int HdcFileDescriptor::WriteWithMem(uint8_t *data, int size)
157 {
158 auto contextIO = new CtxFileIO();
159 if (!contextIO) {
160 delete[] data;
161 WRITE_LOG(LOG_FATAL, "Memory alloc failed");
162 callbackFinish(callerContext, true, "Memory alloc failed");
163 return -1;
164 }
165 uv_fs_t *req = &contextIO->fs;
166 contextIO->bufIO = data;
167 contextIO->thisClass = this;
168 req->data = contextIO;
169 ++refIO;
170
171 uv_buf_t iov = uv_buf_init((char *)data, size);
172 uv_fs_write(loop, req, fdIO, &iov, 1, -1, OnFileIO);
173 return size;
174 }
175 } // namespace Hdc
176