// получает поле с размером данных из канала связи. Возвращает размер данных или 0xFFFFFFFF в случае ошибки static uint32 ReceiveLengthField(int Handle, StreamMethod Method, byte *LengthField, byte *LengthFieldSize, uint32 Timeout) { uint32 Size = 0xFFFFFFFF; *LengthFieldSize = 0; byte b; if (recvByte(Handle, Method, &b, Timeout) > 0) { LengthField[0] = b; if (b < 0x80) { Size = b; *LengthFieldSize = 1; } else { byte datasize = b & 0x0F; uint32 data = 0; // datasize не больше 4 байт tBuffer buf; bufInit(&buf, (byte *)&data, datasize); if (recvBuffer(Handle, Method, buf.ptr, buf.dim, Timeout) > 0) { memcpy(LengthField + 1, &data, datasize); if (IsLittleEndian()) memrev(&data, datasize); Size = data; *LengthFieldSize = datasize + 1; } } } return Size; }
// Try to read data at serial port & pass anything read to processing function void Midi::poll(void) { int c; // Just keep sucking data from serial port until it runs out, processing // MIDI messages as we go while((c = serial_.read()) != -1) { recvByte(c); } }
static void HandleClientConnection(int Socket) { StreamMethod Method = smRecvSend; if (!Socket) return; byte Status = 0; byte cc = 0; #ifdef TCP_DEBUG printf("Wait connection\n"); #endif int ret = recvByte(Socket, Method, &cc, ConnectionTimeoutMSec); #ifdef TCP_DEBUG //printf("recvByte: %d. cc = %d \n", ret, cc); #endif if (ret > 0 && cc == pccENQ) { byte ConnectionBuffer[2]; ret = recvBuffer(Socket, Method, ConnectionBuffer, sizeof(ConnectionBuffer), ConnectionTimeoutMSec); // принимаем данные дл¤ соединени¤ if (ret > 0) { PV = ConnectionBuffer[0]; KSN = ConnectionBuffer[1]; if (sendByte(Socket, Method, pccACK) < 0) goto lblKO; // подтверждаем соединение и переходим в режим ожидани¤ сообщени¤ #ifdef TCP_DEBUG printf("Connected. PV: %d, KSN: %d\n", PV, KSN); #endif int time1 = GetTickCount(); uint32 size; byte *data = NULL; while (/*Status == 0*/1) // –јЅќ“ј≈ћ ƒќ “ј…ћј”“ј »Ћ» ѕќЋ”„≈Ќ»я —»√ЌјЋј Ќј ќ“—ќ≈ƒ»Ќ≈Ќ»≈ { data = tcpReceiveMessage(Socket, &size, &cc, ReceiveTimeoutMSec); #ifdef TCP_DEBUG if (cc != 0) printf("drmReceiveMessage. cc = %d, size = %lu\n", cc, size); #endif if (cc == pccSTX) // в data у мен¤ лежит data { if (data) { Status = 3; // хорошее завершение с приЄмом какого-то пакета ParseClientMessage(Socket, data, size); // в buffer у нас сообщение от клиента time1 = GetTickCount(); } else { printf("Empty package from client\n"); } } else if (cc == pccEOT) { Status = 2; // disconnect query #ifdef TCP_DEBUG printf("Disconnect query received\n"); #endif if (sendByte(Socket, Method, pccEOT) < 0) goto lblKO; break; // exit from the cycle } if (data) // очищаем пам¤ть { free(data); data = NULL; } // check timeout if (GetTickCount() - time1 >= ClientTimeoutMSec) { #ifdef TCP_DEBUG printf("Client timeout occurred\n"); #endif Status = 1; // timeout //sendByte(Socket, pccEOT); break; } } if (Status != 1) { //printf("Send disconnect byte..."); if (sendByte(Socket, Method, pccEOT) < 0) goto lblKO; // disconnect //printf("Done\n"); } } } lblKO: goto lblEnd; lblEnd: #ifdef TCP_DEBUG printf("Closing client socket..."); #endif close(Socket); // закрываем сокет клиента в конце работы Socket = 0; #ifdef TCP_DEBUG printf("Done\n"); #endif #ifdef TCP_DEBUG printf("Client disconnected\n"); #endif }
/** @brief Receive message from the server @param size - return size of data @param decrypt - if TRUE, then decrypt received data by session key @param control - return control character @return data (you MUST free memory after use) */ byte *tcpReceiveMessage(int Handle, uint32 *size, byte *control, uint32 TimeoutMsec) { StreamMethod Method = smRecvSend; byte *data; int ret = 0; byte cc = 0; byte LengthField[MAXLENGTHFIELDSIZE]; byte LengthFieldSize; uint32 AlignedSize; byte AttempsCount = 1; byte MaxAttempsCount = 5; lblWaitAgain: *size = 0; *control = 0; data = NULL; sleepms(100); ret = recvByte(Handle, Method, &cc, 0/*Timeout*/); //printf"recvByte: %d. byte %d\n", ret, cc); if (ret > 0) { *control = cc; switch (cc) { case pccSTX: *size = ReceiveLengthField(Handle, Method, LengthField, &LengthFieldSize, TimeoutMsec); // получаем размер данных if (*size != 0xFFFFFFFF) { AlignedSize = GetAlignedSize(*size); data = malloc(AlignedSize); // allocate data ret = recvBuffer(Handle, Method, data, AlignedSize, TimeoutMsec); #ifdef TCP_DEBUG // PrintHEX(data, *size); #endif //printf"comRecvBufLarge: %d\n", ret); if (ret > 0) { // ok, we have a data - calc CRC uint32 CRCBufferSize = LengthFieldSize + AlignedSize + 1; // datasize + data + ETX byte *CRCBuffer = malloc(CRCBufferSize); memcpy(CRCBuffer, LengthField, LengthFieldSize); // copy length field to checkbuffer memcpy(CRCBuffer+LengthFieldSize, data, AlignedSize); // copy data from checkbuffer CRCBuffer[CRCBufferSize - 1] = pccETX; // last character = ETX uint64 CalculatedCRC = crcCalculate(CRCBuffer, CRCBufferSize); free(CRCBuffer); CRCBuffer = NULL; ret = recvByte(Handle, Method, &cc, TimeoutMsec); // receive ETX character //printf"comRecv: %d. byte %d\n", ret, cc); if (ret > 0 && cc == pccETX) { byte crcfield[crcGetFieldSize(CRCBufferSize)]; ret = recvBuffer(Handle, Method, crcfield, sizeof(crcfield), TimeoutMsec); // get size uint64 ReceivedCRC = crcExtract(crcfield, sizeof(crcfield)); //printf"comRecvBuf: %d\n", ret); if (ret > 0) { if (ReceivedCRC == CalculatedCRC) // check the data ret = sendByte(Handle, Method, pccACK); // good!!! else { if (AttempsCount <= MaxAttempsCount) { AttempsCount++; ret = sendByte(Handle, Method, pccNAK); // and go to wait this packet again goto lblWaitAgain; } else { free(data); data = NULL; } } } else { free(data); data = NULL; } } else { free(data); data = NULL; } } else { free(data); data = NULL; } } break; case pccEOT: // query close connection data = NULL; break; case pccBEL: sendByte(Handle, Method, pccBEL); goto lblWaitAgain; default: data = NULL; break; } } else { *control = 0; data = NULL; } /*if (data) cphDecrypt(data, data, PCSessionKey, AlignedSize, ToServer); // decipher received data*/ return data; }
/** @brief Send message to the server (PC or Retail system) @param size - return size of data @param decrypt - if TRUE, then decrypt received data by session key @param control - return control character @return TRUE if OK, or error code */ Bool tcpSendMessage(int Handle, byte *Data, uint32 DataSize, uint32 TimeoutMSec) { StreamMethod Method = smRecvSend; int ret; Bool result = FALSE; uint32 size = DataSize; uint32 AlignedSize = GetAlignedSize(size); byte LengthField[MAXLENGTHFIELDSIZE]; byte LengthFieldSize; tlvMakeLengthField(size, LengthField, &LengthFieldSize); byte MaxAttempsCount = 5; byte ack; tBuffer sendbuf; byte DataToSend[AlignedSize + MAXLENGTHFIELDSIZE + 1 + MAXCRCBUFFERSIZE]; // + max data size buffer, ETX, max CRC buffer bufInit(&sendbuf, DataToSend, sizeof(DataToSend)); // init buffer for writing (and clear of DataToSend) bufApp(&sendbuf, LengthField, LengthFieldSize); memcpy(DataToSend + sendbuf.pos, Data, DataSize); // просто копирование, без шифрования sendbuf.pos += AlignedSize; // DataToSend уже лежит в буфере на отправку bufAppByte(&sendbuf, pccETX); // append ETX to buffer byte CRCBuffer[MAXCRCBUFFERSIZE]; byte CRCBufferSize = crcMakeField(sendbuf.ptr, (word)sendbuf.pos, CRCBuffer); bufApp(&sendbuf, CRCBuffer, CRCBufferSize); /* printf("CRC Buffer: "); PrintHEX(CRCBuffer, CRCBufferSize);*/ byte AttempsCount = 1; lblSendAgain: ret = sendByte(Handle, Method, pccSTX); // send control char "start of packet" if (ret > 0) { ret = sendBuffer(Handle, Method, bufPtr(&sendbuf), bufLen(&sendbuf)); // send packet if (ret == bufLen(&sendbuf)) { // and wait for acknowledgment lblWaitAskAgain: ack = 0; ret = recvByte(Handle, Method, &ack, TimeoutMSec); if (ret > 0) { switch (ack) { case pccACK: // good result = TRUE; break; case pccBEL: // please, wait sendByte(Handle, Method, pccBEL); goto lblWaitAskAgain; case pccNAK: // send packet again if (AttempsCount <= MaxAttempsCount) { AttempsCount++; goto lblSendAgain; } else result = FALSE; break; default: // unknown state result = FALSE; break; } } else result = FALSE; } else result = FALSE; } else result = FALSE; //ptarr = memFree(ptarr); return result; }