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 WRITE_LOG(LOG_DEBUG, "StopWork fdIO:%d", fdIO);
51 uv_fs_close(loop, &reqClose, fdIO, [](uv_fs_t *req) {
52 auto thisClass = (HdcFileDescriptor *)req->data;
53 uv_fs_req_cleanup(req);
54 if (thisClass->callbackCloseFd != nullptr) {
55 thisClass->callbackCloseFd();
56 }
57 --thisClass->refIO;
58 });
59 }
60 };
61
OnFileIO(uv_fs_t * req)62 void HdcFileDescriptor::OnFileIO(uv_fs_t *req)
63 {
64 CtxFileIO *ctxIO = static_cast<CtxFileIO *>(req->data);
65 HdcFileDescriptor *thisClass = ctxIO->thisClass;
66 uint8_t *buf = ctxIO->bufIO;
67 bool bFinish = false;
68 bool fetalFinish = false;
69
70 do {
71 if (req->result > 0) {
72 if (req->fs_type == UV_FS_READ) {
73 if (!thisClass->callbackRead(thisClass->callerContext, buf, req->result)) {
74 bFinish = true;
75 break;
76 }
77 thisClass->LoopRead();
78 } else {
79 // fs_write
80 }
81 } else {
82 if (req->result != 0) {
83 constexpr int bufSize = 1024;
84 char buffer[bufSize] = { 0 };
85 uv_strerror_r((int)req->result, buffer, bufSize);
86 WRITE_LOG(LOG_DEBUG, "OnFileIO fd:%d failed:%s", thisClass->fdIO, buffer);
87 }
88 bFinish = true;
89 fetalFinish = true;
90 break;
91 }
92 } while (false);
93 uv_fs_req_cleanup(req);
94 delete[] buf;
95 delete ctxIO;
96
97 --thisClass->refIO;
98 if (bFinish) {
99 thisClass->callbackFinish(thisClass->callerContext, fetalFinish, STRING_EMPTY);
100 thisClass->workContinue = false;
101 }
102 }
103
LoopRead()104 int HdcFileDescriptor::LoopRead()
105 {
106 uv_buf_t iov;
107 int readMax = Base::GetMaxBufSize() * 1.2;
108 auto contextIO = new CtxFileIO();
109 auto buf = new uint8_t[readMax]();
110 if (!contextIO || !buf) {
111 if (contextIO) {
112 delete contextIO;
113 }
114 if (buf) {
115 delete[] buf;
116 }
117 WRITE_LOG(LOG_FATAL, "Memory alloc failed");
118 callbackFinish(callerContext, true, "Memory alloc failed");
119 return -1;
120 }
121 uv_fs_t *req = &contextIO->fs;
122 contextIO->bufIO = buf;
123 contextIO->thisClass = this;
124 req->data = contextIO;
125 ++refIO;
126 iov = uv_buf_init((char *)buf, readMax);
127 uv_fs_read(loop, req, fdIO, &iov, 1, -1, OnFileIO);
128 return 0;
129 }
130
StartWork()131 bool HdcFileDescriptor::StartWork()
132 {
133 if (LoopRead() < 0) {
134 return false;
135 }
136 return true;
137 }
138
Write(uint8_t * data,int size)139 int HdcFileDescriptor::Write(uint8_t *data, int size)
140 {
141 if (size > static_cast<int>(HDC_BUF_MAX_BYTES - 1)) {
142 size = static_cast<int>(HDC_BUF_MAX_BYTES - 1);
143 }
144 if (size <= 0) {
145 WRITE_LOG(LOG_WARN, "Write failed, size:%d", size);
146 return -1;
147 }
148 auto buf = new uint8_t[size];
149 if (!buf) {
150 return -1;
151 }
152 (void)memcpy_s(buf, size, data, size);
153 return WriteWithMem(buf, size);
154 }
155
156 // Data's memory must be Malloc, and the callback FREE after this function is completed
WriteWithMem(uint8_t * data,int size)157 int HdcFileDescriptor::WriteWithMem(uint8_t *data, int size)
158 {
159 auto contextIO = new CtxFileIO();
160 if (!contextIO) {
161 delete[] data;
162 WRITE_LOG(LOG_FATAL, "Memory alloc failed");
163 callbackFinish(callerContext, true, "Memory alloc failed");
164 return -1;
165 }
166 uv_fs_t *req = &contextIO->fs;
167 contextIO->bufIO = data;
168 contextIO->thisClass = this;
169 req->data = contextIO;
170 ++refIO;
171
172 uv_buf_t iov = uv_buf_init((char *)data, size);
173 uv_fs_write(loop, req, fdIO, &iov, 1, -1, OnFileIO);
174 return size;
175 }
176 } // namespace Hdc
177