/** * Creates a client transaction * @param providerCallback the provider that created us. * @param request the request that we are living for. * @param requestDestination the destination of the request. * @param apDescriptor the access point through which we are supposed to * @param responseCollector the instance that should receive this request's * response. * retransmit. */ public StunClientTransaction(StunProvider providerCallback, Request request, StunAddress requestDestination, NetAccessPointDescriptor apDescriptor, ResponseCollector responseCollector) { this.providerCallback = providerCallback; this.request = request; this.apDescriptor = apDescriptor; this.responseCollector = responseCollector; this.requestDestination = requestDestination; this.transactionID = TransactionID.CreateTransactionID(); request.SetTransactionID(transactionID.GetTransactionID()); runningThread = new Thread(new ThreadStart(this.Run)); }
/** * Creates a default binding request. The request contains a ChangeReqeust * attribute with zero change ip and change port flags. * @return a default binding request. */ public static Request CreateBindingRequest() { Request bindingRequest = new Request(); try { bindingRequest.SetMessageType(Message.BINDING_REQUEST); } catch (StunException ex) { //there should be no exc here since we're the creators. Console.WriteLine("Exception {0} {1}", ex.Message, ex.StackTrace); } //add a change request attribute ChangeRequestAttribute attribute = AttributeFactory.CreateChangeRequestAttribute(); bindingRequest.AddAttribute(attribute); return bindingRequest; }
/** * Sends the specified request through the specified access point, and * registers the specified ResponseCollector for later notification. * @param request the request to send * @param sendTo the destination address of the request. * @param sendThrough the access point to use when sending the request * @param collector the instance to notify when a response arrives or the * the transaction timeouts * @throws StunException * ILLEGAL_STATE if the stun stack is not started. <br/> * ILLEGAL_ARGUMENT if the apDescriptor references an access point that had * not been installed <br/> * NETWORK_ERROR if an error occurs while sending message bytes through the * network socket. <br/> */ public virtual void SendRequest( Request request, StunAddress sendTo, NetAccessPointDescriptor sendThrough, ResponseCollector collector ) { stunStack.CheckStarted(); StunClientTransaction clientTransaction = new StunClientTransaction(this, request, sendTo, sendThrough, collector); clientTransactions[clientTransaction.GetTransactionID()] = clientTransaction; clientTransaction.SendRequest(); }
/** * Sends the specified request and blocks until a response has been * received or the request transaction has timed out. * @param request the reuqest to send * @param serverAddress the request destination address * @return the event encapsulating the response or null if no response * has been received. * @throws StunException NETWORK_ERROR or other if we fail to send * the message */ public virtual StunMessageEvent SendRequestAndWaitForResponse( Request request, StunAddress serverAddress) { Monitor.Enter(this); try { stunProvider.SendRequest(request, serverAddress, apDescriptor, this); Monitor.Wait(this); StunMessageEvent res = responseEvent; responseEvent = null; //prepare for next message return res; } finally { Monitor.Exit(this); } }
/** * Constructs a message from its binary representation. * @param binMessage the binary array that contains the encoded message * @param offset the index where the message starts. * @param arrayLen the length of the message * @return a Message object constructed from the binMessage array * @throws StunException ILLEGAL_ARGUMENT if one or more of the arguments * have invalid values. */ public static Message Decode(byte[] binMessage, int offset, int arrayLen) { arrayLen = Math.Min(binMessage.Length, arrayLen); if(binMessage == null || arrayLen - offset < Message.HEADER_LENGTH) throw new StunException(StunException.ILLEGAL_ARGUMENT, "The given binary array is not a valid StunMessage"); int messageType = (int)(((binMessage[offset++]<<8) & 0xff00) | (binMessage[offset++]&0xFF)); int mti = (int) messageType; Message message; if (Message.IsResponseType(messageType)) { message = new Response(); } else { message = new Request(); } message.SetMessageType(messageType); int length = (int)(((binMessage[offset++]<<8) & 0xff00) | (binMessage[offset++]&0xFF)); if(arrayLen - offset - TRANSACTION_ID_LENGTH < length) throw new StunException(StunException.ILLEGAL_ARGUMENT, "The given binary array does not seem to " +"contain a whole StunMessage"); byte[] tranID = new byte[TRANSACTION_ID_LENGTH]; for (int x = 0; x < TRANSACTION_ID_LENGTH; x++) { tranID[x] = binMessage[offset + x]; } message.SetTransactionID(tranID); offset+=TRANSACTION_ID_LENGTH; while(offset - Message.HEADER_LENGTH< length) { Attribute att = AttributeDecoder.decode(binMessage, offset, (length - offset)); if (att != null) { message.AddAttribute(att); offset += att.GetDataLength() + Attribute.HEADER_LENGTH; } else { offset += Attribute.HEADER_LENGTH; } } return message; }