Logo Search packages:      
Sourcecode: kmess version File versions

P2PApplicationBase Class Reference
[network/applications]

#include <p2papplicationbase.h>

Inheritance diagram for P2PApplicationBase:

Application P2PApplication FileTransferP2P InkTransferP2P MsnObjectTransferP2P UnknownApplication

List of all members.


Detailed Description

An Application subclass implementing MSN6 P2P-style conversations.

This base class aims to hide all complex details of the P2P communication. The derived P2PApplication class adds handling of the MSNSLP protocol to this featureset. To implement a P2P service, create a derived class of P2PApplication which implements the userStarted*, contactStarted* and getAppId() methods.

P2P messages can be received from switchboard or direct connections. The message flow looks like:

The data flow starts with the gotMessage() method, which is called by the ApplicationList class with the incoming P2P message.

A user-started application is initiated with start(), which calls userStarted1_UserInvitesContact() to send the first message.

When a data transfer is active, the methods showTransferMessage(), showTransferProgress(), showTransferComplete() are called to inform the derived class of the status. It can update the GUI from these methods.

--- internals ----

Internally, this code ensures valid P2P messages are sent.

A P2P message consists of a a 48 byte binary header followed by an optional pyload. The payload which can be binary data or plain text MIME data (the MSNSLP messages, which are handled by the derived P2PApplication class).

The messages can be sent over the switchboard, or direct connection. When the P2P messages are sent over the switchboard, they will be wrapped in a standard MIME message and a footer code will be appended.

This is a P2P message with SLP payload sent over the switchboard:

MSG contact@kmessdemo.org Test%20user 465
MIME-Version: 1.0
Content-Type: application/x-msnmsgrp2p
P2P-Dest: user@kmessdemo.org
     (blank line)
00000000 0d6ff300 00000000 00000000
52010000 00000000 52010000 00000000
c08d4900 00000000 00000000 00000000
MSNSLP/1.0 200 OK
To: <msnmsgr:user@kmessdemo.org>
From: <msnmsgr:contact@kmessdemo.org>
Via: MSNSLP/1.0/TLP ;branch={EA820F90-802C-48A3-AE53-F660111220FF}
CSeq: 1
Call-ID: {44AAC3F3-30D7-49B7-9732-AF7D32BD36B3}
Max-Forwards: 0
Content-Type: application/x-msnmsgr-sessionreqbody
Content-Length: 22

SessionID: 114164
00
00000000

The message is built of the following parts:

There is a limit of 1202 bytes for the P2P payload, longer payloads are splitted into multiple P2P messages. In practise, that only happens with the SLP INVITE and file data messages.

The binary P2P header has the following layout:

0    4    8        16        24   28   32   36   40        48
|....|....|....|....|....|....|....|....|....|....|....|....|
|sid |mid |offset   |totalsize|size|flag|uid |auid|a-datasz |
The fields are:

For ACK messages some the fields are used differently:

For direct connection handshake messages, the last 3 fields will be replaced with the Nonce value.

The flag field can be one of these values:

These fields and flags appear to make it utterly complex. However, P2P messages can be divided into three groups:

Each message expects to get some ACK message back, clients actually wait to send more data until an ACK or error message is received. KMess uses timers to detect whether a contact did not sent a message back. The application will be aborted automatically to avoid stale application in the memory.

To match a incoming P2P message with a P2PApplication instance, the following identifiers are used:

The ApplicationList::gotMessage() method uses these identifiers to find the correct P2PApplication instance for a message. Note that the session-id is also transferred in the body of an SLP INVITE message. The P2P packets are only routed by the ApplicationList using the binary header fields and SLP header.

Some third party clients (including KMess 1.4.x) seam to send incorrect message fields. This class is able to handle those not-entirely valid messages as well. The situations where this happens are marked as "HACK" in the code.

Author:
Diederik van der Boor

Definition at line 189 of file p2papplicationbase.h.


Public Types

enum  ApplicationMode { APP_MODE_NORMAL, APP_MODE_ERROR_HANDLER, APP_MODE_DATACAST }

Signals

void applicationMessage (const ChatMessage &message)
void deleteMe (Application *object)
void updateApplicationMessage (const QString &messageId, const QString &newMessage)

Public Member Functions

virtual void contactAborted (const QString &message=QString::null)
 The contact aborted the session.
ChatgetChat () const
 Return the chat the application was originally created for (may be null).
const QString & getContactHandle () const
 Return the handle of the other contact.
const QString & getCookie () const
 Return the application's identifying cookie.
unsigned long getLastContactMessageID () const
 Return the message ID used in the previous message from the contact.
int getMode () const
 Return the current mode of the application.
virtual quint32 getSessionID () const =0
void gotCommand (QString command)
 A command for the application was received (i.e. "Accept" or "Reject").
void gotMessage (const P2PMessage &p2pMessage)
 Main entry function for incoming incoming messages.
bool hasUnAckedMessage (const P2PMessage &p2pMessage)
 Returns whether the application can handle the given ACK message.
bool isClosing () const
 Indicate whether the application is closing or not.
virtual bool isPrivateChatRequired () const
 Returns whether the application can operate in a multi-chat session, or requires a private chat.
 P2PApplicationBase (ApplicationList *applicationList)
 Constructor, initializes the P2PApplicationBase instance fields.
bool sendNextDataParts (int preferredFragments)
 Called when the connection is ready to send more file data.
void setChat (Chat *chat)
 Set the chat the application was originally created for.
void setMode (ApplicationMode mode)
 Change the current mode.
void start ()
 Start the application.
virtual void userAborted ()
 You have cancelled the session.
virtual ~P2PApplicationBase ()
 Class destructor.

Protected Types

enum  ApplicationCancelReason {
  CANCEL_INVITATION, CANCEL_ABORT, CANCEL_NOT_INSTALLED, CANCEL_TIMEOUT,
  CANCEL_FAILED, CANCEL_INVALID_SLP_CONTENT_TYPE
}
enum  P2PDataType {
  P2P_TYPE_NEGOTIATION = 0, P2P_TYPE_PICTURE = 1, P2P_TYPE_FILE = 2, P2P_TYPE_INK = 3,
  P2P_TYPE_WEBCAM = 4
}
 The data type being sent. More...
enum  P2PMessageType {
  P2P_MSG_UNKNOWN = 0, P2P_MSG_SESSION_INVITATION = 1, P2P_MSG_SESSION_OK = 2, P2P_MSG_TRANSFER_INVITATION = 9,
  P2P_MSG_TRANSFER_OK = 3, P2P_MSG_DATA_PREPARATION = 4, P2P_MSG_DATA = 5, P2P_MSG_SESSION_BYE = 6,
  P2P_MSG_SESSION_DECLINE = 10, P2P_MSG_TRANSFER_DECLINE = 7, P2P_MSG_SLP_ERROR = 8, P2P_MSG_WEBCAM_SETUP = 11,
  P2P_MSG_WEBCAM_SYN = 12, P2P_MSG_WEBCAM_ACK = 13
}
 The meta type of a P2P message. More...
enum  P2PWaitingState {
  P2P_WAIT_DEFAULT = 0, P2P_WAIT_FOR_SLP_OK_ACK = 1, P2P_WAIT_FOR_FILE_DATA = 2, P2P_WAIT_FOR_WEBCAM_DATA = 19,
  P2P_WAIT_FOR_PREPARE = 3, P2P_WAIT_FOR_PREPARE_ACK = 4, P2P_WAIT_FOR_SLP_BYE = 5, P2P_WAIT_FOR_SLP_BYE_ACK = 6,
  P2P_WAIT_FOR_SLP_ERR_ACK = 7, P2P_WAIT_FOR_INVITE_ACK = 18, P2P_WAIT_CONTACT_ACCEPT = 8, P2P_WAIT_FOR_TRANSFER_ACCEPT = 9,
  P2P_WAIT_FOR_INVITE_TR_ACK = 19, P2P_WAIT_FOR_CONNECTION = 10, P2P_WAIT_FOR_DATA_ACK = 11, P2P_WAIT_FOR_TRANSFER_ACK = 12,
  P2P_WAIT_FOR_HANDSHAKE = 13, P2P_WAIT_FOR_HANDSHAKE_OK = 14, P2P_WAIT_FOR_CONNECTION2 = 15, P2P_WAIT_USER_ACCEPT = 16,
  P2P_WAIT_END_APPLICATION = 17
}
 An indication which message is expected from the contact. More...

Protected Member Functions

void abortDataSending ()
 Make sure no more data will be sent.
void contactRejected (const QString &message=QString::null)
 The contact declined the invitation.
virtual void contactStarted1_ContactInvitesUser (const MimeMessage &message)
 Step 1 of a contact-started chat: the contact invites the user.
virtual void contactStarted2_UserAccepts ()
 Step 2 of a contact-started chat: the user accepts.
virtual void contactStarted3_ContactConfirmsAccept (const MimeMessage &message)
void delayDeletion (bool doDelay)
void endApplication ()
 Request to delete this application.
void endApplicationLater ()
 Scheduelle termination, but wait for last incoming packets.
QString generateCookie () const
 Generate a random cookie value.
virtual QString getContactAbortMessage () const
 Return an abort message to display.
virtual QString getContactRejectMessage () const
 Return a reject message to display.
const QString & getExternalIp () const
 Return the external IP address.
const QString & getLocalIp () const
unsigned long getTransferredBytes () const
 Return the number of transferred bytes.
virtual QString getUserAbortMessage () const
 Return an abort message to display.
virtual QString getUserRejectMessage () const
 Return a reject message to display.
P2PWaitingState getWaitingState () const
 Return the current waiting state.
virtual void gotAck (const P2PMessage &message, const P2PMessageType messageType)=0
virtual void gotData (const P2PMessage &message)=0
virtual void gotDataComplete (const P2PMessage &lastMessage)=0
virtual void gotDataPreparation (const P2PMessage &message)=0
virtual void gotDirectConnectionHandshake (const P2PMessage &message)=0
virtual void gotNegotiationMessage (const MimeMessage &slpMessage, const QString &preamble)=0
bool hasUnAckedMessage (const P2PMessageType messageType)
 Return whether a given message type is still unacked.
bool isFirstMessageSent () const
 Test whether the first message has been sent.
bool isP2PAckSent () const
 Test whether a P2P ack was sent for the current message.
bool isTransferActive () const
 Test whether the transfer is active.
bool isTransferComplete () const
 Verify whether the transfer was initiated and was completed.
bool isUserStartedApp () const
 Return the "user started this app" state.
bool isWaitingForUser () const
 Return true if we're waiting for the user to accept.
bool isWaitingState (P2PWaitingState waitingState) const
 Test whether a given waiting state is set.
void modifyOfferMessage (const QString &newMessage=QString())
 Replace an application's accept/reject/cancel links with another text.
void offerAcceptOrReject (const QString &appHtml)
 Let the user accept or reject the application.
void offerCancel (const QString &appHtml)
 Let the user cancel the application.
virtual void sendCancelMessage (const ApplicationCancelReason cancelReason)=0
 Send a cancel message and terminate the application.
void sendData (QIODevice *dataSource, const P2PDataType dataType)
 Send file data in P2P packets.
void sendDataPreparation ()
 Send the data preparation message.
void sendDataPreparationAck ()
void sendDirectConnectionHandshake (const QString &nonce)
 Send the direct connection handshake.
void sendP2PAbort ()
 Send a low-level control message to terminate the session.
bool sendP2PAck ()
 Send an ACK message if this is needed.
void sendP2PMessage (const QByteArray &messageData, int flagField=0, P2PDataType footerCode=P2P_TYPE_NEGOTIATION, P2PMessageType messageType=P2P_MSG_UNKNOWN)
 Sends a complete P2P message payload.
void sendP2PWaitingError ()
 Send a low-level error message that the application is waiting for a certain message.
void sendSlpMessage (const QString &slpMessage, P2PMessageType messageType)
 Send a complete SLP message in multiple P2P packets.
void setApplicationType (ChatMessage::MessageType type)
 Set the type of application we're starting.
void setClosing (bool closing)
 Indicate the application is closing or not.
void setCurrentMessageType (P2PMessageType messageType)
 Set the current message type, for debugging.
void setUserAborted (bool userAborted)
 Notify this base class the user is aborting the session.
void setWaitingState (P2PWaitingState waitingState, int timeout)
 Indicate which packet is expected next.
virtual void showEventMessage (const QString &message, const ChatMessage::ContentsClass contents, bool isIncoming=true)
 Show a message to notify the user of an event.
virtual void showSystemMessage (const QString &message, const ChatMessage::ContentsClass contents, bool isIncoming=true)
 Show a message to notify about a system error.
virtual void showTimeoutMessage (P2PWaitingState waitingState)=0
virtual void showTransferComplete ()
 Called when the transfer is complete.
virtual void showTransferMessage (const QString &message)
 Show a message to inform about a transfer event.
virtual void showTransferProgress (const ulong bytesTransferred)
 Show the progress made during a transfer.
void startByInvite (const QString &invitationCookie)
 Start the application internally (from an invite message).
bool stopWaitingTimer ()
 Stop the waiting timer.
void testDataSendingAborted ()
 Test if the contact aborted the sending of data.
virtual void userRejected ()
 You have rejected the invitation.
virtual void userStarted1_UserInvitesContact ()
 Step 1 of a user-started chat: the user invites the contact.
virtual void userStarted2_ContactAccepts (const MimeMessage &message)
 Step 2 of a user-started chat: the contact accepts.
virtual void userStarted3_UserPrepares ()
 Step 3 of a user-started chat: the user prepares for the session.
bool writeP2PDataToFile (const P2PMessage &message, QIODevice *file)
 Utility function to write P2P data to a file, also deals with message offsets.

Private Slots

void slotApplicationListDeleted ()
 Crash prevention method.
void slotCleanup ()
 Cleanup function, is used to handle timeout events.

Private Member Functions

UnAckedMessagegetUnAckedMessage (const P2PMessageType messageType) const
 Find the unacked message which corresponds with given message type.
UnAckedMessagegetUnAckedMessage (const P2PMessage &ackMessage) const
 Find the unacked message which corresponds with the received P2P ACK message.
void gotDataFragment (const P2PMessage &message)
 Called internally when data is received, this eventually calls gotData().
void gotErrorAck (const P2PMessage &message)
 Called when a P2P message was received with the error-flag set.
void gotNegotiationFragment (const P2PMessage &message)
 Called when a SLP message fragment was received.
void gotTimeoutAck (const P2PMessage &message)
 Called when a P2P message with timeout-flag was received.
void gotTransferAbortedAck (const P2PMessage &message)
 Got a transfer aborted ack.
void sendP2PAckImpl (int ackType=P2PMessage::MSN_FLAG_ACK, UnAckedMessage *originalMessageData=0)
 Internal function to send a P2P ACK message.
bool sendP2PMessageImpl (const QByteArray &messageData, int flagField=0, P2PDataType footerCode=P2P_TYPE_NEGOTIATION, P2PMessageType messageType=P2P_MSG_UNKNOWN, quint32 messageID=0)
 Internal function to send a single P2P message.
void testUnAckedMessages (bool sendError)
 Test if there are still unacked messages.

Private Attributes

ApplicationListapplicationList_
QBuffer * buffer_
QPointer< QIODevice > dataSource_
P2PDataType dataType_
quint32 fragmentMessageID_
quint32 fragmentOffset_
quint32 fragmentTotalSize_
P2PFragmentTracker fragmentTracker_
UnAckedMessage lastIncomingMessage_
quint32 nextMessageID_
QList< UnAckedMessage * > outgoingMessages_
bool shouldSendAck_
bool userAborted_
P2PWaitingState waitingState_
QTimer * waitingTimer_

Classes

struct  UnAckedMessage
 Meta data on an unacked message. More...

The documentation for this class was generated from the following files:

Generated by  Doxygen 1.6.0   Back to index