• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 * Copyright (c) 2025 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 
16 #include <thread>
17 #include <cups/ipp.h>
18 #include <cups/cups-private.h>
19 #include <securec.h>
20 #include <fstream>
21 #include <algorithm>
22 #include <sstream>
23 #include "usb_manager.h"
24 #include "usb_errors.h"
25 #include "usb_ipp_manager.h"
26 
27 namespace OHOS::CUPS {
28 constexpr int32_t errorReasonCount = 19;
29 static constexpr std::array<const char*, errorReasonCount> ippPrinterErrorReason = {
30     "other",
31     "cover-open",
32     "input-tray-missing",
33     "marker-supply-empty",
34     "marker-supply-low",
35     "marker-waste-almost-full",
36     "marker-waste-full",
37     "media-empty",
38     "media-jam",
39     "media-low",
40     "media-needed",
41     "moving-to-paused",
42     "paused",
43     "spool-area-full",
44     "toner-empty",
45     "toner-low",
46     "offline",
47     "marker-ink-almost-empty",
48     "door-open"
49 };
50 static auto &usbSrvClient = UsbSrvClient::GetInstance();
IppUsbManager()51 IppUsbManager::IppUsbManager()
52 {
53     isTerminated_.store(false);
54 }
55 
~IppUsbManager()56 IppUsbManager::~IppUsbManager()
57 {
58     std::lock_guard<std::mutex> autoLock(lock_);
59     for (auto [uri, ippPrinter] : ippPrinterMap_) {
60         if (ippPrinter.isOpened) {
61             usbSrvClient.Close(ippPrinter.ippPipe);
62         }
63     }
64     ippPrinterMap_.clear();
65 }
66 
GetInstance()67 IppUsbManager& IppUsbManager::GetInstance()
68 {
69     static IppUsbManager instance;
70     return instance;
71 }
72 
FindUsbPrinter(UsbDevice & device,const std::string & uri)73 bool IppUsbManager::FindUsbPrinter(UsbDevice& device, const std::string& uri)
74 {
75     std::vector<UsbDevice> devlist;
76     auto getDevRet = usbSrvClient.GetDevices(devlist);
77     if (getDevRet != OHOS::ERR_OK) {
78         fprintf(stderr, "DEBUG: USB_MONITOR GetDevices fail, ret = %d\n", getDevRet);
79         return false;
80     }
81     if (devlist.empty()) {
82         fprintf(stderr, "DEBUG: USB_MONITOR No usb devices\n");
83         return false;
84     }
85     for (size_t i = 0; i < devlist.size(); i++) {
86         ohusb_pipe pipe;
87         pipe.busNum = devlist[i].GetBusNum();
88         pipe.devAddr = devlist[i].GetDevAddr();
89         constexpr int32_t MAX_SN_LENGTH = 256;
90         char tempsern[MAX_SN_LENGTH] = {};
91         int32_t length = OH_GetStringDescriptor(&pipe, devlist[i].GetiSerialNumber(),
92             reinterpret_cast<unsigned char *>(tempsern), sizeof(tempsern) - 1);
93         std::string sn;
94         if (length <= 0) {
95             fprintf(stderr, "DEBUG: USB_MONITOR Not find sn\n");
96             continue;
97         }
98         sn = std::string(tempsern);
99         if (uri.find(sn) == std::string::npos) {
100             continue;
101         }
102         device = devlist[i];
103         fprintf(stderr, "DEBUG: USB_MONITOR find printer\n");
104         return true;
105     }
106     fprintf(stderr, "DEBUG: USB_MONITOR not find sn\n");
107     return false;
108 }
109 
IsSupportIppOverUsb(const std::string & uri)110 bool IppUsbManager::IsSupportIppOverUsb(const std::string& uri)
111 {
112     {
113         std::lock_guard<std::mutex> autoLock(lock_);
114         auto it = ippPrinterMap_.find(uri);
115         if (it != ippPrinterMap_.end() && it->second.isSupportIpp) {
116             fprintf(stderr, "DEBUG: USB_MONITOR Support has been checked\n");
117             return true;
118         }
119     }
120     UsbDevice usbDevice;
121     if (!FindUsbPrinter(usbDevice, uri)) {
122         fprintf(stderr, "DEBUG: USB_MONITOR FindUsbPrinter fail\n");
123         return false;
124     }
125     int32_t configCount = usbDevice.GetConfigCount();
126     std::vector<PrinterTranIndex> indexVec;
127     for (int32_t configIndex = 0; configIndex < configCount; configIndex++) {
128         int32_t interfaceCount = static_cast<int32_t>(usbDevice.GetConfigs()[configIndex].GetInterfaceCount());
129         for (int32_t interfaceIndex = 0; interfaceIndex < interfaceCount; interfaceIndex++) {
130             UsbInterface usbInterface = usbDevice.GetConfigs()[configIndex].GetInterfaces()[interfaceIndex];
131             bool isSupportIpp = (usbInterface.GetClass() == USB_DEVICE_CLASS_PRINT &&
132                 usbInterface.GetSubClass() == USB_DEVICE_SUBCLASS_PRINT &&
133                 usbInterface.GetProtocol() == USB_DEVICE_PROTOCOL_PRINT);
134             if (isSupportIpp) {
135                 PrinterTranIndex indexPair;
136                 indexPair.configIndex = configIndex;
137                 indexPair.interfaceIndex = interfaceIndex;
138                 indexVec.push_back(indexPair);
139             }
140         }
141     }
142     constexpr int32_t USB_INTERFACE_MIN_COUNT = 1;
143     if (indexVec.size() >= USB_INTERFACE_MIN_COUNT) {
144         std::lock_guard<std::mutex> autoLock(lock_);
145         auto& printer =  ippPrinterMap_[uri];
146         printer.device = usbDevice;
147         printer.isSupportIpp = true;
148         printer.indexVec = std::move(indexVec);
149         fprintf(stderr, "DEBUG: USB_MONITOR printer support ipp-over-usb\n");
150         return true;
151     }
152     fprintf(stderr, "DEBUG: USB_MONITOR printer is not support ipp-over-usb\n");
153     return false;
154 }
155 
ConnectUsbPinter(const std::string & uri)156 bool IppUsbManager::ConnectUsbPinter(const std::string &uri)
157 {
158     if (uri.empty()) {
159         fprintf(stderr, "DEBUG: USB_MONITOR uri is empty\n");
160         return false;
161     }
162     UsbDevice usbdevice;
163     {
164         std::lock_guard<std::mutex> autoLock(lock_);
165         auto it = ippPrinterMap_.find(uri);
166         if (it == ippPrinterMap_.end()) {
167             fprintf(stderr, "DEBUG: USB_MONITOR not find uri in ippPrinterMap_\n");
168             return false;
169         }
170         if (it->second.isOpened) {
171             fprintf(stderr, "DEBUG: USB_MONITOR printer is opened\n");
172             return true;
173         } else {
174             usbdevice = it->second.device;
175         }
176     }
177     USBDevicePipe usbDevicePipe;
178     int32_t openDeviceRet = usbSrvClient.OpenDevice(usbdevice, usbDevicePipe);
179     if (openDeviceRet == UEC_OK) {
180         return AllocateInterface(uri, usbdevice, usbDevicePipe);
181     }
182     fprintf(stderr, "DEBUG: USB_MONITOR OpenDevice fail, ret = %d\n", openDeviceRet);
183     return false;
184 }
185 
DisConnectUsbPinter(const std::string & uri)186 bool IppUsbManager::DisConnectUsbPinter(const std::string& uri)
187 {
188     if (uri.empty()) {
189         fprintf(stderr, "DEBUG: USB_MONITOR uri is empty\n");
190         return false;
191     }
192     std::lock_guard<std::mutex> autoLock(lock_);
193     auto it = ippPrinterMap_.find(uri);
194     if (it == ippPrinterMap_.end()) {
195         fprintf(stderr, "DEBUG: USB_MONITOR uri is not in ippPrinterMap_\n");
196         return false;
197     }
198     usbSrvClient.Close(it->second.ippPipe);
199     ippPrinterMap_.erase(uri);
200     return true;
201 }
202 
SetPrinterStateReasons(PrinterStatus & printerStatus)203 void IppUsbManager::SetPrinterStateReasons(PrinterStatus& printerStatus)
204 {
205     std::vector<int> errorReasonIndex;
206     for (size_t i = 0; i < ippPrinterErrorReason.size(); i++) {
207         if (strstr(printerStatus.printerStateReasons, ippPrinterErrorReason[i]) != nullptr) {
208             errorReasonIndex.push_back(i);
209         }
210     }
211 
212     std::ostringstream errorReasonStream;
213     bool first = true;
214     for (const auto index : errorReasonIndex) {
215         if (!first) {
216             errorReasonStream << ",";
217         }
218         errorReasonStream << ippPrinterErrorReason[index] << "-error";
219         first = false;
220     }
221 
222     const std::string errorReason = errorReasonStream.str();
223     if (!errorReason.empty()) {
224         int ret = snprintf_s(
225             printerStatus.printerStateReasons,
226             sizeof(printerStatus.printerStateReasons),
227             sizeof(printerStatus.printerStateReasons) - 1,
228             "%s",
229             errorReason.c_str());
230         if (ret < 0) {
231             fprintf(stderr, "DEBUG: USB_MONITOR snprintf_s printerStateReasons error\n");
232         }
233     }
234 }
235 
ReportPrinterState(bool & isPrinterStarted,PrinterStatus & printerStatus,MonitorPrinterCallback callback)236 void IppUsbManager::ReportPrinterState(bool& isPrinterStarted, PrinterStatus& printerStatus,
237     MonitorPrinterCallback callback)
238 {
239     if (callback == nullptr) {
240         fprintf(stderr, "DEBUG: USB_MONITOR callback is nullptr\n");
241         return;
242     }
243     SetPrinterStateReasons(printerStatus);
244     ipp_pstate_t printerState = printerStatus.printerState;
245     if (!isPrinterStarted && printerState == IPP_PSTATE_IDLE &&
246         strcmp(printerStatus.printerStateReasons, "none") != 0) {
247         callback(&printerStatus); // report faults before the printer is started
248         return;
249     }
250     if (!isPrinterStarted && printerState != IPP_PSTATE_IDLE) {
251         isPrinterStarted = true;
252     }
253     constexpr int32_t bufferSize = PRINTER_STATE_REASONS_SIZE;
254     if (isPrinterStarted && printerState == IPP_PSTATE_IDLE &&
255         strcmp(printerStatus.printerStateReasons, "none") != 0 &&
256         memset_s(printerStatus.printerStateReasons, bufferSize, 0, bufferSize) == 0 &&
257         sprintf_s(printerStatus.printerStateReasons, bufferSize, "none") < 0) {
258             fprintf(stderr, "DEBUG: USB_MONITOR memset_s printerStateReasons fail\n");
259     }
260     if (isPrinterStarted) {
261         callback(&printerStatus); // report processing or stopped state
262     }
263 }
264 
ProcessMonitorPrinter(const std::string & uri,MonitorPrinterCallback callback)265 bool IppUsbManager::ProcessMonitorPrinter(const std::string& uri, MonitorPrinterCallback callback)
266 {
267     int32_t ret = 0;
268     constexpr uint32_t MAX_LOOP_TIME = 60 * 60 * 24 * 30; // 30 days
269     bool isPrinterStarted = false;
270     for (uint32_t loopCount = 0; loopCount < MAX_LOOP_TIME && !isTerminated_.load(); loopCount++) {
271         std::this_thread::sleep_for(std::chrono::seconds(INDEX_1));
272         int32_t writeDataRetryCount = 0;
273         do {
274             auto ippdata = BuildIppRequest();
275             ret = BulkTransferWrite(uri, ippdata);
276             if (ret == EORROR_HDF_DEV_ERR_TIME_OUT) {
277                 std::this_thread::sleep_for(std::chrono::milliseconds(USB_WRITE_INTERVAL));
278                 writeDataRetryCount++;
279                 fprintf(stderr, "DEBUG: USB_MONITOR retrwriteDataRetryCounty = %d fail\n", writeDataRetryCount);
280             }
281         } while (ret == EORROR_HDF_DEV_ERR_TIME_OUT && writeDataRetryCount < WRITE_RETRY_MAX_TIMES);
282         if (ret != UEC_OK) {
283             fprintf(stderr, "DEBUG: USB_MONITOR BulkTransferWrite fail, ret = %d\n", ret);
284             break;
285         }
286         PrinterStatus printerStatus;
287         if (!ProcessDataFromDevice(uri, printerStatus)) {
288             fprintf(stderr, "DEBUG: USB_MONITOR ProcessDataFromDevice false\n");
289             break;
290         }
291         ReportPrinterState(isPrinterStarted, printerStatus, callback);
292         if (isPrinterStarted && printerStatus.printerState == IPP_PSTATE_IDLE) {
293             fprintf(stderr, "DEBUG: USB_MONITOR ProcessMonitorPrinter job is completed\n");
294             return true;
295         }
296     }
297     fprintf(stderr, "DEBUG: USB_MONITOR endtWriteDataToPrinterLooper\n");
298     return false;
299 }
300 
SetTerminalSingal()301 void IppUsbManager::SetTerminalSingal()
302 {
303     isTerminated_.store(true);
304 }
305 
RemoveHttpHeader(std::vector<uint8_t> & readTempBuffer)306 void IppUsbManager::RemoveHttpHeader(std::vector<uint8_t>& readTempBuffer)
307 {
308     auto it = std::search(
309         readTempBuffer.begin(), readTempBuffer.end(),
310         reinterpret_cast<const uint8_t*>("\r\n\r\n"),
311         reinterpret_cast<const uint8_t*>("\r\n\r\n") + 4
312     );
313     if (it != readTempBuffer.end()) {
314         readTempBuffer.erase(readTempBuffer.begin(), it + INDEX_4);
315     }
316 }
317 
ProcessDataFromDevice(const std::string & uri,PrinterStatus & printerStatus)318 bool IppUsbManager::ProcessDataFromDevice(const std::string& uri, PrinterStatus& printerStatus)
319 {
320     constexpr int32_t MAX_TIME = 50;
321     for (int32_t readCount = 0; readCount < MAX_TIME; readCount++) {
322         std::this_thread::sleep_for(std::chrono::milliseconds(USB_WRITE_INTERVAL));
323         std::vector<uint8_t> readTempBuffer;
324         int32_t readFromUsbRes = BulkTransferRead(uri, readTempBuffer);
325         if (readFromUsbRes != UEC_OK && readFromUsbRes != EORROR_HDF_DEV_ERR_TIME_OUT) {
326             fprintf(stderr, "DEBUG: USB_MONITOR BulkTransferRead fail, ret = %d\n", readFromUsbRes);
327             break;
328         }
329         RemoveHttpHeader(readTempBuffer);
330         if (readTempBuffer.empty()) {
331             continue;
332         }
333         if (ParseIppResponse(readTempBuffer, printerStatus)) {
334             fprintf(stderr, "DEBUG: USB_MONITOR ProcessDataFromDevice success\n");
335             return true;
336         }
337     }
338     fprintf(stderr, "DEBUG: USB_MONITOR ProcessDataFromDevice fail\n");
339     return false;
340 }
341 
BulkTransferRead(const std::string & uri,std::vector<uint8_t> & readTempBuffer)342 int32_t IppUsbManager::BulkTransferRead(const std::string& uri, std::vector<uint8_t>& readTempBuffer)
343 {
344     std::lock_guard<std::mutex> autoLock(lock_);
345     auto it = ippPrinterMap_.find(uri);
346     if (it == ippPrinterMap_.end()) {
347         fprintf(stderr, "DEBUG: USB_MONITOR not found uri in ippPrinterMap_\n");
348         return INVAILD_VALUE;
349     }
350     UsbDevice usbdevice = it->second.device;
351     PrinterTranIndex tranIndex = it->second.tranIndex;
352     int32_t currentConfigIndex = tranIndex.configIndex;
353     int32_t currentInterfaceIndex = tranIndex.interfaceIndex;
354     UsbInterface useInterface = usbdevice.GetConfigs()[currentConfigIndex].GetInterfaces()[currentInterfaceIndex];
355     USBEndpoint pointRead;
356     std::vector<USBEndpoint>& endPoints = useInterface.GetEndpoints();
357     for (auto& point : endPoints) {
358         if (point.GetDirection() != 0) {
359             pointRead = point;
360             break;
361         }
362     }
363     USBDevicePipe usbDevicePipe = it->second.ippPipe;
364     int32_t readFromUsbRes = 0;
365     int32_t claimRetryCount = 0;
366     do {
367         readFromUsbRes = usbSrvClient.BulkTransfer(usbDevicePipe, pointRead, readTempBuffer,
368             USB_BULKTRANSFER_READ_TIMEOUT);
369         if (readFromUsbRes == EORROR_HDF_DEV_ERR_IO_FAILURE) {
370             int claimRes = usbSrvClient.ClaimInterface(usbDevicePipe, useInterface, true);
371             if (claimRes < 0 || ++claimRetryCount >= CLAIM_INTERFACE_RETRY_MAX_TIMES) {
372                 break;
373             }
374         }
375     } while (readFromUsbRes == EORROR_HDF_DEV_ERR_IO_FAILURE);
376     return readFromUsbRes;
377 }
378 
BulkTransferWrite(const std::string & uri,std::vector<uint8_t> & vectorRequestBuffer)379 int32_t IppUsbManager::BulkTransferWrite(const std::string& uri, std::vector<uint8_t>& vectorRequestBuffer)
380 {
381     std::lock_guard<std::mutex> autoLock(lock_);
382     auto it = ippPrinterMap_.find(uri);
383     if (it == ippPrinterMap_.end()) {
384         fprintf(stderr, "DEBUG: USB_MONITOR not found uri in ippPrinterMap_\n");
385         return INVAILD_VALUE;
386     }
387     UsbDevice& usbdevice = it->second.device;
388     PrinterTranIndex& tranIndex = it->second.tranIndex;
389     int32_t currentConfigIndex = tranIndex.configIndex;
390     int32_t currentInterfaceIndex = tranIndex.interfaceIndex;
391     UsbInterface useInterface = usbdevice.GetConfigs()[currentConfigIndex].GetInterfaces()[currentInterfaceIndex];
392     USBEndpoint pointWrite;
393     std::vector<USBEndpoint>& endPoints = useInterface.GetEndpoints();
394     for (auto& point : endPoints) {
395         if (point.GetDirection() == 0) {
396             pointWrite = point;
397             break;
398         }
399     }
400     USBDevicePipe usbDevicePipe = it->second.ippPipe;
401     int32_t writeRet = 0;
402     int32_t claimRetryCount = 0;
403     do {
404         writeRet = usbSrvClient.BulkTransfer(usbDevicePipe, pointWrite, vectorRequestBuffer,
405             USB_BULKTRANSFER_WRITE_TIMEOUT);
406         if (writeRet == EORROR_HDF_DEV_ERR_IO_FAILURE) {
407             int claimRes = usbSrvClient.ClaimInterface(usbDevicePipe, useInterface, true);
408             if (claimRes < 0 || ++claimRetryCount >= CLAIM_INTERFACE_RETRY_MAX_TIMES) {
409                 break;
410             }
411         }
412     } while (writeRet == EORROR_HDF_DEV_ERR_IO_FAILURE);
413     return writeRet;
414 }
415 
AllocateInterface(const std::string & uri,UsbDevice & usbdevice,USBDevicePipe & usbDevicePipe)416 bool IppUsbManager::AllocateInterface(const std::string &uri, UsbDevice& usbdevice,
417     USBDevicePipe &usbDevicePipe)
418 {
419     PrinterTranIndex tranIndex;
420     std::lock_guard<std::mutex> autoLock(lock_);
421     auto it = ippPrinterMap_.find(uri);
422     if (it == ippPrinterMap_.end()) {
423         fprintf(stderr, "DEBUG: USB_MONITOR AllocateInterface, cannot find uri in ippPrinterMap_\n");
424         usbSrvClient.Close(usbDevicePipe);
425         return false;
426     }
427     std::vector<PrinterTranIndex>& indexVec = it->second.indexVec;
428     for (auto indexVecIt = indexVec.rbegin(); indexVecIt != indexVec.rend(); it++) {
429         int32_t configIndex = indexVecIt->configIndex;
430         int32_t interfaceIndex = indexVecIt->interfaceIndex;
431         UsbInterface ippInterface =
432             usbdevice.GetConfigs()[configIndex].GetInterfaces()[interfaceIndex];
433         int32_t ret = usbSrvClient.ClaimInterface(usbDevicePipe, ippInterface, true);
434         if (ret != UEC_OK) {
435             fprintf(stderr, "DEBUG: USB_MONITOR ClaimInterface fail, ret = %d\n", ret);
436             continue;
437         }
438         if (ippInterface.GetAlternateSetting() != 0) {
439             ret = usbSrvClient.SetInterface(usbDevicePipe, ippInterface);
440             if (ret != UEC_OK) {
441                 fprintf(stderr, "DEBUG: USB_MONITOR SetInterface fail, ret = %d\n", ret);
442                 continue;
443             }
444         }
445         tranIndex.configIndex = configIndex;
446         tranIndex.interfaceIndex = interfaceIndex;
447         break;
448     }
449     if (tranIndex.configIndex == INVAILD_VALUE) {
450         fprintf(stderr, "DEBUG: USB_MONITOR connect usb fail");
451         usbSrvClient.Close(usbDevicePipe);
452         return false;
453     }
454     auto& printer = it->second;
455     printer.isOpened = true;
456     printer.ippPipe = usbDevicePipe;
457     printer.tranIndex = tranIndex;
458     return true;
459 }
460 
BuildIppRequest()461 std::vector<uint8_t> IppUsbManager::BuildIppRequest()
462 {
463     ipp_t* request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES);
464     if (request == nullptr) {
465         fprintf(stderr, "DEBUG: USB_MONITOR request is a nullptr.\n");
466         return {};
467     }
468     static const char * const jattrs[] = {
469         "printer-state",
470         "printer-state-reasons"
471     };
472     static const std::string DEFAULT_USER = "default";
473     static const std::string LOCAL_URI = "ipp://127.0.0.1:60000/ipp/print";
474     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", nullptr, LOCAL_URI.c_str());
475     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", nullptr, DEFAULT_USER.c_str());
476     ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes",
477         sizeof(jattrs) / sizeof(jattrs[0]), nullptr, jattrs);
478 
479     std::vector<uint8_t> ippdata;
480     ippWriteIO(&ippdata, (ipp_iocb_t)IppUsbManager::WriteToBuffer, true, nullptr, request);
481     ippDelete(request);
482     if (ippdata.empty()) {
483         fprintf(stderr, "DEBUG: USB_MONITOR ippWriteIO fail.\n");
484         return {};
485     }
486     std::string httpHeader = "POST /ipp/print HTTP/1.1\r\n"
487                             "Host: localhost:60000\r\n"
488                             "Content-Type: application/ipp\r\n"
489                             "Content-Length: " + std::to_string(ippdata.size()) + "\r\n\r\n";
490 
491     std::vector<uint8_t> fullData(ippdata.size() + httpHeader.size());
492     if (memcpy_s(fullData.data(), fullData.size(), httpHeader.data(), httpHeader.size()) != 0) {
493         fprintf(stderr, "DEBUG: USB_MONITOR memcpy_s httpHeader fail.\n");
494         return {};
495     }
496     if (memcpy_s(fullData.data() + httpHeader.size(), fullData.size(), ippdata.data(), ippdata.size()) != 0) {
497         fprintf(stderr, "DEBUG: USB_MONITOR memcpy_s ippdata fail.\n");
498         return {};
499     }
500     return fullData;
501 }
502 
WriteToBuffer(void * ctx,const void * data,size_t len)503 ssize_t IppUsbManager::WriteToBuffer(void* ctx, const void* data, size_t len)
504 {
505     auto *buffer = static_cast<std::vector<uint8_t> *>(ctx);
506     if (buffer == nullptr) {
507         fprintf(stderr, "DEBUG: USB_MONITOR buffer is a nullptr.\n");
508         return IPP_STATE_ERROR;
509     }
510     size_t oldSize = buffer->size();
511     buffer->resize(oldSize + len);
512     if (memcpy_s(buffer->data() + oldSize, buffer->size(), data, len) != 0) {
513         fprintf(stderr, "DEBUG: USB_MONITOR WriteToBuffer memcpy_s fail.\n");
514         return IPP_STATE_ERROR;
515     }
516     return static_cast<ssize_t>(len);
517 }
518 
ReadFromBuffer(void * ctx,void * data,size_t len)519 ssize_t IppUsbManager::ReadFromBuffer(void *ctx, void *data, size_t len)
520 {
521     if (ctx == nullptr || data == nullptr) {
522         fprintf(stderr, "DEBUG: USB_MONITOR ctx or data is a nullptr.\n");
523         return IPP_STATE_ERROR;
524     }
525     auto* context = static_cast<BufferContext*>(ctx);
526     size_t remainSize = context->size - context->pos;
527     if (remainSize == INDEX_0) {
528         fprintf(stderr, "DEBUG: USB_MONITOR Read completed.\n");
529         return INDEX_0;
530     }
531     size_t toRead = std::min(len, remainSize);
532     if (memcpy_s(data, len, context->data + context->pos, toRead) != 0) {
533         fprintf(stderr, "DEBUG: USB_MONITOR ReadFromBuffer memcpy_s fail.\n");
534         return IPP_STATE_ERROR;
535     }
536     context->pos += toRead;
537     return static_cast<ssize_t>(toRead);
538 }
539 
ParseIppResponse(std::vector<uint8_t> & responseData,PrinterStatus & printerStatus)540 bool IppUsbManager::ParseIppResponse(std::vector<uint8_t>& responseData, PrinterStatus& printerStatus)
541 {
542     ipp_t *response = ippNew();
543     if (response == nullptr) {
544         fprintf(stderr, "DEBUG: USB_MONITOR response is nullptr.\n");
545         return false;
546     }
547     BufferContext context { responseData.data(), responseData.size(), 0};
548     ipp_state_t state = ippReadIO(&context, (ipp_iocb_t)IppUsbManager::ReadFromBuffer, true, nullptr, response);
549     if (state != IPP_STATE_DATA) {
550         fprintf(stderr, "DEBUG: USB_MONITOR Failed to parse IPP response.\n");
551         ippDelete(response);
552         return false;
553     }
554     ipp_attribute_t *attr = nullptr;
555     constexpr int32_t bufferSize = PRINTER_STATE_REASONS_SIZE;
556     printerStatus.printerState = IPP_PSTATE_IDLE;
557     if (memset_s(printerStatus.printerStateReasons, bufferSize, 0, bufferSize) != 0) {
558         fprintf(stderr, "DEBUG: USB_MONITOR memset_s printerStateReasons fail\n");
559         ippDelete(response);
560         return false;
561     }
562     if ((attr = ippFindAttribute(response, "printer-state", IPP_TAG_ENUM)) != nullptr) {
563         printerStatus.printerState = (ipp_pstate_e)ippGetInteger(attr, 0);
564     }
565     if ((attr = ippFindAttribute(response, "printer-state-reasons", IPP_TAG_KEYWORD)) != nullptr) {
566         ippAttributeString(attr, printerStatus.printerStateReasons, sizeof(printerStatus.printerStateReasons));
567     }
568     fprintf(stderr, "DEBUG: USB_MONITOR printerStateReasons = %s, printerState = %d\n",
569         printerStatus.printerStateReasons, static_cast<int32_t>(printerStatus.printerState));
570     ippDelete(response);
571     return true;
572 }
573 }  // namespace OHOS::CUPS