/// <summary> /// writes as run log /// </summary> /// <param name="runLog">log message</param> /// <param name="toPrint">log data if any</param> /// <exception cref="ObjectDisposedException"> /// thrown when invoked on disposed object. /// </exception> private void writeAsRunLog( string runLog, DataBlock toPrint) { if (IsDisposed) throw new ObjectDisposedException("IOHandler"); var logger = AsRunLogger; if (null == logger) return; lock (logger) { logger.WriteLine(runLog); logger.WriteLine( toPrint.ToString( ShowByteDisplayInAsRunLog)); logger.WriteLine(); } }
/// <summary> /// inner operation for sending data to PS. /// In this context, locking is handled upward(in calling context), /// so we don't care about synchronization here. /// </summary> /// <param name="toSend">data to be sent to PS</param> /// <returns> /// true, when sending operation succeeded, so we can proceed forward. /// else communication error arised, so we should stop proceeding. /// </returns> /// <exception cref="ObjectDisposedException"> /// thrown when invoking on disposed object /// </exception> private bool sendDataBlock( DataBlock toSend) { // 01. check if disposed if (IsDisposed) throw new ObjectDisposedException("IOHandler"); // 02. prepare data to send var plainBytes = toSend.GetPlainBuffer(); writeAsRunLog( "Bytes to encrypt: " + plainBytes.Length, plainBytes); var encryptedBytes = toSend.GetEncryptedBuffer(_encryptDecrypt); writeAsRunLog( "Bytes encrypted: " + encryptedBytes.Length, encryptedBytes); try { // 03. send data to PS using ( var bwWriter = new BinaryWriter( _netStream, Encoding.UTF8, true)) { // send length value in network order var lengthValue = IPAddress.HostToNetworkOrder( (int)PhotoShopConstants.COMM_LENGTH + encryptedBytes.Length); bwWriter.Write((int)lengthValue); // send status value in network order var statusValue = IPAddress.HostToNetworkOrder( (int)PhotoShopConstants.NO_COMM_ERROR); bwWriter.Write((int)statusValue); // send encrypted data bwWriter.Write( encryptedBytes, 0, encryptedBytes.Length); bwWriter.Flush(); } return true; } catch (Exception e) { var strOut = string.Format( "{0} raised during data sending to PS \n" + "with message \"{1}\"", e.GetType().Name, e.Message); writeAsRunLog(strOut); return false; } }
/// <summary> /// create new <see cref="DataBlock"/> from given encrypted byte array /// </summary> /// <param name="decryptor"> /// used for descryption of given encrypted byte array</param> /// <param name="encryptedBytes"> /// encrypted byte array to decrypt</param> /// <returns> /// new <see cref="DataBlock"/> from given encrypted byte array /// </returns> /// <exception cref="ArgumentNullException"> /// thrown when given "decryptor" parameter is null /// </exception> /// <exception cref="ArgumentNullException"> /// thrown when given "encryptedBytes" parameter is null /// </exception> /// <exception cref="ArgumentOutOfRangeException"> /// thrown when given "encryptedBytes" parameter is shorter than /// <seealso cref="PhotoShopConstants.PROTOCOL_LENGTH"/> /// </exception> public static DataBlock CreateNonErrorDataBlock( EncryptDecrypt decryptor, byte[] encryptedBytes) { // check for required conditions if (null == decryptor) throw new ArgumentNullException("decryptor"); if (null == encryptedBytes) throw new ArgumentNullException("encryptedBytes"); if (encryptedBytes.Length < PhotoShopConstants.PROTOCOL_LENGTH) throw new ArgumentOutOfRangeException("encryptedBytes"); using (var msStream = new MemoryStream(decryptor.Decrypt(encryptedBytes))) { var result = new DataBlock(); using (var brReader = new BinaryReader(msStream)) { // protocol version, transaction id, content type are passed // with Big-Endian byte order // so need to convert to host byte order, ie little-endian result.ProtocolVersion = IPAddress.NetworkToHostOrder( brReader.ReadInt32()); result.TransactionID = IPAddress.NetworkToHostOrder( brReader.ReadInt32()); var contentTypeValue = IPAddress.NetworkToHostOrder( brReader.ReadInt32()); switch (contentTypeValue) { case (int)ContentType.ERRORSTRING: case (int)ContentType.JAVASCRIPT: case (int)ContentType.IMAGE: case (int)ContentType.PROFILE: case (int)ContentType.DATA: result.ContentType = (ContentType)contentTypeValue; break; default: break; } var toRead = (int)(msStream.Length - PhotoShopConstants.PROTOCOL_LENGTH); result.Content = (0 == toRead) ? null : brReader.ReadBytes(toRead); return result; } } }
/// <summary> /// base function for communication with PhotoShop /// </summary> /// <param name="toSend"> /// <see cref="DataBlock"/> containing data to pass to PhotoShop</param> /// <returns>PhotoShop Response w.r.t <paramref name="toSend"/></returns> /// <exception cref="ObjectDisposedException"> /// thrown when invoking on disposed object /// </exception> private PhotoShopResponse SendAndReceive( DataBlock toSend) { // 01. check if object is disposed if (IsDisposed) throw new ObjectDisposedException("IOHandler"); var commError = new PhotoShopResponse() { Status = CommunicationStatus.ERROR_COMMUNICATION }; lock (_netStream) { // 02. send data to PS if (false == sendDataBlock(toSend)) return commError; // 03. receive data from PS for dedicated transaction ID return getPhotoShopResponseUntil(toSend.TransactionID); } }
/// <summary> /// create new <see cref="DataBlock"/> from given error byte array, /// ie plain byte array /// </summary> /// <param name="errorBytes">byte array containing raw data.</param> /// <returns> /// new <see cref="DataBlock"/> from given error byte array /// </returns> /// <exception cref="ArgumentNullException"> /// thrown when given "errorBytes" parameter is null /// </exception> /// <exception cref="ArgumentOutOfRangeException"> /// thrown when given "errorBytes" parameter is shorter than /// <seealso cref="PhotoShopConstants.PROTOCOL_LENGTH"/> /// </exception> public static DataBlock CreateErrorDataBlock( byte[] errorBytes) { // check for required conditions if (null == errorBytes) throw new ArgumentNullException("errorBytes"); if (errorBytes.Length < PhotoShopConstants.PROTOCOL_LENGTH) throw new ArgumentOutOfRangeException("errorBytes"); using (var msStream = new MemoryStream(errorBytes)) { var result = new DataBlock(); using (var brReader = new BinaryReader(msStream)) { // never mind protocol version, transaction id, content type. result.ProtocolVersion = IPAddress.NetworkToHostOrder( brReader.ReadInt32()); result.TransactionID = IPAddress.NetworkToHostOrder( brReader.ReadInt32()); // meaningless operation, just move stream pointer forward. var contentTypeValue = IPAddress.NetworkToHostOrder( brReader.ReadInt32()); // context assumes that comming content is error string type. result.ContentType = ContentType.ERRORSTRING; var toRead = (int)(msStream.Length - PhotoShopConstants.PROTOCOL_LENGTH); result.Content = (0 == toRead) ? null : brReader.ReadBytes(toRead); return result; } } }