/* * $Id: commandcontrol.cpp,v 1.7 2007/06/25 06:19:21 ozawa Exp $ * * Copyright 2003- ONGS Inc. All rights reserved. * * author: Masanori OZAWA (ozawa@ongs.co.jp) * version: $Revision: 1.7 $ * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY ONGS INC ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL ONGS INC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * The views and conclusions contained in the software and documentation are * those of the authors and should not be interpreted as representing official * policies, either expressed or implied, of the ONGS Inc. * */ #include "../include/fusenshi.h" #include "../include/commandcontrol.h" #include //_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ /* static bool read_8bit(int fd, u_int8_t *pBuf) { return (sizeof(u_int8_t) == read(fd, pBuf, sizeof(u_int8_t))); } static bool read_bool(int fd, bool *pBuf) { u_int8_t data; if (read_8bit(fd, &data)) { *pBuf = (data != 0); return true; } return false; } */ static bool read_32bit(int fd, u_int32_t *pBuf) { return (sizeof(u_int32_t) == read(fd, pBuf, sizeof(u_int32_t))); } static bool read_bytes(int fd, u_char **pBuf, ssize_t length) { int nread = 0; *pBuf = (u_char*)g_malloc0(length); if (!(*pBuf)) return false; nread = read(fd, *pBuf, length); if (nread != length) { g_free(*pBuf); *pBuf = NULL; } return (nread == length); } //_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ /* static bool write_8bit(int fd, u_int8_t buf) { return (sizeof(u_int8_t) == write(fd, &buf, sizeof(u_int8_t))); } static bool write_bool(int fd, bool buf) { return (write_8bit(fd, (buf ? 1 : 0))); } */ static bool write_32bit(int fd, u_int32_t buf) { #if 0 fprintf(stdout, "write_32bit: %d <= 0x%X\n", fd, buf); ssize_t wlen = write(fd, &buf, sizeof(u_int32_t)); fprintf(stdout, "write_32bit: write: %ld bytes\n", wlen); return (sizeof(u_int32_t) == wlen); #else return (sizeof(u_int32_t) == write(fd, &buf, sizeof(u_int32_t))); #endif } static bool write_bytes(int fd, const u_char *pBuf, ssize_t length) { #if 0 fprintf(stdout, "write_bytes: %d <= 0x%X\n", fd, length); ssize_t wlen = write(fd, pBuf, length); fprintf(stdout, "write_bytes: write: %ld bytes\n", wlen); return (length == wlen); #else return (length == write(fd, pBuf, length)); #endif } //_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ static LP_COMMAND receiveCommandCore(int fd, char **pErrorMsg) { u_int32_t commandid = 0; u_int32_t fileid = 0; u_int32_t extraflag = 0; u_int32_t datalen = 0; u_char *pdata = NULL; LP_COMMAND result = (LP_COMMAND)g_malloc0(sizeof(COMMAND)); if (!result) { *pErrorMsg = "Out of memory error!"; return NULL; } if (!read_32bit(fd, &commandid) || !read_32bit(fd, &fileid) || !read_32bit(fd, &extraflag) || !read_32bit(fd, &datalen)) { g_free(result); *pErrorMsg = "Internal communication error! (read failed.)"; return NULL; } commandid = ntohl(commandid); fileid = ntohl(fileid); extraflag = ntohl(extraflag); datalen = ntohl(datalen); result->nCommandID = commandid; result->nFileID = fileid; result->nExtraFlag = extraflag; result->nDataLen = datalen; if (0 < datalen) { if (!read_bytes(fd, &pdata, datalen)) { g_free(result); *pErrorMsg = "Unable to read command data."; return NULL; } result->pData = pdata; } switch (result->nCommandID) { case CREATE_NEW_FUSENSHI_WINDOW: case SAVE_FUSENSHI: case VERIFY_RECEIVE_DATA: case PRINT_FUSENSHI: case PROPERTY_CHANGED: if (!pdata) { g_free(result); result = NULL; *pErrorMsg = "Unable to read command data."; break; } case CALL_WND_SERVICE_COMMAND: pdata = NULL; break; case CREATE_NEW_FUSENSHI: case DELETE_FUSENSHI: case EXIT_APP: default: result->pData = NULL; result->nDataLen = 0; break; } if (pdata) { g_free(pdata); } return result; } static bool sendCommandCore(int fd, const LP_COMMAND lpCommand) { if (!lpCommand) return false; u_int32_t commandid = 0; u_int32_t fileid = 0; u_int32_t extraflag = 0; u_int32_t datalen = 0; u_char *pdata = NULL; switch (lpCommand->nCommandID) { case CREATE_NEW_FUSENSHI_WINDOW: case SAVE_FUSENSHI: case VERIFY_RECEIVE_DATA: case PRINT_FUSENSHI: case PROPERTY_CHANGED: case CALL_WND_SERVICE_COMMAND: if (lpCommand->pData) { pdata = (u_char*)lpCommand->pData; datalen = lpCommand->nDataLen; } break; case CREATE_NEW_FUSENSHI: case DELETE_FUSENSHI: case EXIT_APP: default: break; } commandid = htonl(lpCommand->nCommandID); fileid = htonl(lpCommand->nFileID); extraflag = htonl(lpCommand->nExtraFlag); datalen = htonl(lpCommand->nDataLen); if (!write_32bit(fd, commandid) || !write_32bit(fd, fileid) || !write_32bit(fd, extraflag) || !write_32bit(fd, datalen) || (0 < datalen && !write_bytes(fd, pdata, lpCommand->nDataLen))) { return false; } return true; } static void destroyCommandCore(LP_COMMAND lpCommand) { if (lpCommand->pData) { g_free(lpCommand->pData); } g_free(lpCommand); } //_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ /** * コンストラクタ */ CommandControl::CommandControl() { m_pCommands = g_queue_new(); if (!m_pCommands) { throw "Out of Memory Error!"; } m_pMutex = g_mutex_new(); if (!m_pMutex) { throw "Can't create mutex!"; } } /** * デストラクタ */ CommandControl::~CommandControl() { if (m_pMutex) { g_mutex_free(m_pMutex); } if (m_pCommands) { gpointer pData = NULL; while (pData = g_queue_pop_head(m_pCommands), pData) { destroyCommand((LP_COMMAND)pData); } } } /** * コマンドをキューに追加します。 * * @param nCommandID コマンドID * @param nFileID 操作対象のファイルID * @param nExtraFlag 拡張情報 * @param nDataLen pData の長さ(byte) * @param pData コマンドに固有のデータ */ void CommandControl::addCommand(u_int32_t nCommandID, u_int32_t nFileID, u_int32_t nExtraFlag, u_int32_t nDataLen, void *pData) { LP_COMMAND lpCommand = (LP_COMMAND)g_malloc0(sizeof(COMMAND)); if (!lpCommand) { throw "Out of Memory Error!"; } lpCommand->nCommandID = nCommandID; lpCommand->nFileID = nFileID; lpCommand->nExtraFlag = nExtraFlag; lpCommand->nDataLen = nDataLen; lpCommand->pData = pData; // it will be destroy by destroyCommandCore(). g_mutex_lock(m_pMutex); g_queue_push_tail(m_pCommands, (gpointer)lpCommand); g_mutex_unlock(m_pMutex); } /** * コマンドを破棄します。 * * @param lpCommand コマンド */ void CommandControl::destroyCommand(LP_COMMAND lpCommand) { if (!lpCommand) return; destroyCommandCore(lpCommand); } /** * 先頭のコマンドを1つキューから取り出します。 * * @return コマンド */ LP_COMMAND CommandControl::getCommand() { LP_COMMAND result = NULL; g_mutex_lock(m_pMutex); result = (LP_COMMAND)g_queue_pop_head(m_pCommands); g_mutex_unlock(m_pMutex); return result; } /** * コマンドを受信します。 * * @return 受信したコマンド。コマンドができない場合は NULL。 */ LP_COMMAND CommandControl::receiveCommand(int nIn) { LP_COMMAND result = NULL; char *pErrorMsg = NULL; fd_set fdset; struct timeval waitTime = {0, 0}; // 即時応答 FD_ZERO(&fdset); FD_SET(nIn, &fdset); switch (select(nIn +1, &fdset, NULL, NULL, &waitTime)) { case -1: pErrorMsg = "Pipe read error!"; break; default: break; case 1: result = receiveCommandCore(nIn, &pErrorMsg); break; } if (pErrorMsg) { // 読み取りエラーを通知します。 throw pErrorMsg; } return result; } /** * コマンドを送信します。 * * @param lpCommand コマンド */ void CommandControl::sendCommand(int nOut, const LP_COMMAND lpCommand) { if (!lpCommand) return; if (!sendCommandCore(nOut, lpCommand)) { throw "Internal communication error! (write failed.)"; } } /** * 送信コマンドおよび、受信コマンドが発生するまで待機します。 * * @param nIn 入力用デスクリプタ * @param utime 最大待機時間をマイクロ秒単位で指定します。 * 0を指定するとコマンドが発生するまで待機します。 * @return コマンドが発生した場合は true を戻します。 */ #define MIN_TIME (50 * 1000 /* 50ms */) bool CommandControl::wait(int nIn, unsigned long utime) { bool result = false; if (MIN_TIME > utime) { utime = MIN_TIME; } fd_set fdset; struct timeval waitTime = {0, MIN_TIME}; unsigned long totalTime = 0; FD_ZERO(&fdset); FD_SET(nIn, &fdset); while (!result) { switch (select(nIn +1, &fdset, NULL, NULL, &waitTime)) { case -1: // Error happen! throw "pipe closed!"; break; default: g_mutex_lock(m_pMutex); if (0 < g_queue_get_length(m_pCommands)) { result = true; } g_mutex_unlock(m_pMutex); break; case 1: result = true; break; } if (utime) { totalTime += MIN_TIME; if (utime <= totalTime) { break; } } } return result; }