................... ...::: phearless zine #6 :::... .....................>---[ Symbian Networking ]---<...................... ...........................>---[ by argv ]---<........................... argv.cpp[at]gmail[dot]com Sadrzaj: [0] Intro [1] Basics - Intro to Symbian TCP/IP [2] TCP/IP - RSocket [3] TCP/IP - Example [4] Outro //////////////////////////////////////////////////////////////////////////// --==<[ 0. Intro \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ U ovome tekstu cemo se bazirati na to kako da nas Symbian uredjaj spojimo na racunalo preko TCP/IP sucelja koristeci Symbianove sockete. Mogucnosti su velike - preko tih socketa mozemo kontrolirati odredjene radnje na racunalu, mozemo ih koristiti za transfer fileova, etc. Da bi vidjeli to u praksi, ubacio sam jedan jednostavni client/server program koji ce demonstrirati neke stvari poput trazenja hosta preko IP-a ili hostnamea i transfer .sis fajlova. //////////////////////////////////////////////////////////////////////////// --==<[ 1. Basics - Intro to Symbian TCP/IP \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ TCP/IP komunikacija se obavlja preko Symbianovog TCP/IP protokol modula - tcpip.prt. Ovaj modul nam daje 4 protokola: -IP (RFC791 Protokol) -ICMP (RFC792, RFC950 Protokoli) -TCP (RFC793 Protokol) -UDP (RFC768 Protokol) Protokolima se ne pristupa direktno vec kroz Symbian Socket API-je. Modul takodjer daje DNS servis kojemu se takodjer moze pristupiti preko API interfacea RHostResolver. Vjerujem da se sjecate ove klase iz prijasnjih tekstova. Iako nije izlistano u protokolima gore, Symbian socket takodjer moze pristupiti Dial-up i PPP protokolima: ali to cemo ostaviti za neki drugi put jer nam ne treba ovdje. //////////////////////////////////////////////////////////////////////////// --==<[ 2. TCP/IP - RSocket \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ Ovaj cu dio posvetit RSocketu i vecinom mogucnosti koje posjeduje. RSocket nam daje podrsku za kreiranje socketa, pisanje, citanje, koristenje pasivne ili aktivne konekcije, namjestanje adresa, etc... Sa RSocketom se uvijek koristi RSubSessionBase koji nam daje "handle" za RSocket funkcije. RSocket sadrzi slijedece: Accept(), Bind(), CancelAccept(), CancelAll(), CancelConnect(), CancelIoctl(), CancelRead(), CancelRecv(), CancelSend(), CancelWrite(), Close(), Connect(), EImmediate, ENormal, EStopInput, EStopOutput, GetDisconnectData(), GetOpt(), Info(), Ioctl(), Listen(), LocalName(), LocalPort(), Name(), Open(), Read(), Recv(), RecvFrom(), RecvOneOrMore(), RemoteName(), Send(), SendTo(), SetLocalPort(), SetOpt(), Shutdown(), TShutdown, Transfer(), Write() dok od RSubSessionBase nasljedjuje: CloseSubSession(), CreateSubSession(), SendReceive(), SubSessionHandle() -- Otvaranje i zatvaranje socketa: Open() TInt Open(RSocketServ& aServer,TUint addrFamily,TUint sockType, TUint protocol); TInt Open(RSocketServ& aServer,const TDesC& aName); TInt Open(RSocketServ& aServer); Close() void Close(); -- Dobivanje lokalne adrese i porta: Bind() TInt Bind(TSockAddr& anAddr); SetLocalPort() TInt SetLocalPort(TInt aPort); LocalName() void LocalName(TSockAddr& anAddr); LocalPort() TUint LocalPort(); -- Spajanje na drugi uredjaj: Connect() void Connect(TSockAddr& anAddr,TRequestStatus& aStatus); void Connect(TSockAddr& anAddr,const TDesC8& aDataOut,TDes8& aDataIn, TRequestStatus& aStatus); CancelConnect() void CancelConnect(); -- Slusanje i primanje konekcija: Listen() TInt Listen(TUint qSize); TInt Listen(TUint qSize,const TDesC8& aDataOut); Accept() void Accept(RSocket& aBlankSocket,TRequestStatus& aStatus); void Accept(RSocket& aBlankSocket,TDes8& aConnectData, TRequestStatus& aStatus); CancelAccept() void CancelAccept() -- Dobivanje imena drugog uredjaja: RemoteName() void RemoteName(TSockAddr& anAddr); -- Informacije o socketu Info() TInt Info(TProtocolDesc& aProtocol); -- Opcije socketa SetOpt() TInt SetOpt(TUint anOptionName,TUint anOptionLevel, const TDesC8& anOption=TPtrC8(NULL,0)); TInt SetOpt(TUint anOptionName,TUint anOptionLevel,TInt anOption); GetOpt() TInt GetOpt(TUint anOptionName,TUint anOptionLevel,TDes8& anOption); TInt GetOpt(TUint anOptionName,TUint anOptionLevel,TInt& anOption); -- Slanje podataka Write() void Write(const TDesC8& aDesc,TRequestStatus& aStatus); Send() void Send(const TDesC8& aDesc,TUint someFlags,TRequestStatus& aStatus); void Send(const TDesC8& aDesc,TUint someFlags,TRequestStatus& aStatus, TSockXfrLength& aLen); SendTo() void SendTo(const TDesC8& aDesc,TSockAddr& anAddr,TUint flags, TRequestStatus& aStatus); void SendTo(const TDesC8& aDesc,TSockAddr& anAddr,TUint flags, TRequestStatus& aStatus,TSockXfrLength& aLen); CancelWrite() void CancelWrite(); CancelSend() void CancelSend(); -- Primanje podataka Read() void Read(TDes8& aDesc,TRequestStatus& aStatus); Recv() void Recv(TDes8& aDesc,TUint flags,TRequestStatus& aStatus); void Recv(TDes8& aDesc,TUint flags,TRequestStatus& aStatus,TSockXfrLength& aLen); RecvOneOrMore() void RecvOneOrMore(TDes8& aDesc,TUint flags,TRequestStatus& aStatus, TSockXfrLength& aLen); RecvFrom() void RecvFrom(TDes8& aDesc,TSockAddr& anAddr,TUint flags, TRequestStatus& aStatus); void RecvFrom(TDes8& aDesc,TSockAddr& anAddr,TUint flags, TRequestStatus& aStatus,TSockXfrLength& aLen); CancelRead() void CancelRead(); CancelRecv() void CancelRecv(); -- Transfer Socketa Name() TInt Name(TName& aName); Transfer() TInt Transfer(RSocketServ& aServer, const TDesC& aName); -- Prekidanje veze Shutdown() void Shutdown(TShutdown aHow,TRequestStatus& aStatus); void Shutdown(TShutdown aHow,const TDesC8& aDataOut,TDes8& aDataIn, TRequestStatus& aStatus); GetDisconnectData() TInt GetDisconnectData(TDes8& aDesc); -- Prekidanje veze sa RSocket CancelAll() void CancelAll(); //////////////////////////////////////////////////////////////////////////// --==<[ 3. TCP/IP - Example \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ Evo jedan primjer koji ce u sebi objediniti vecinu funkcija iz prijasnjeg poglavlja: ///////////////// // Example.cpp // ///////////////// #include "example.h" const TInt KTimeOut = 30000000; // 30sec timeout EXPORT_C CExample::CExample() : CActive(EPriorityStandard) { } EXPORT_C CExample* CExample::NewL(MUINotify* aConsole) { CExample* self = NewLC(aConsole); CleanupStack::Pop(); return self; } EXPORT_C CExample* CExample::NewLC(MUINotify* aConsole) { CExample* self = new(ELeave) CExample; CleanupStack::PushL(self); self->ConstructL(aConsole); return self; } EXPORT_C void CExample::ConstructL(MUINotify* aConsole) // otvaranje socketa { iConsole = aConsole; iEngineStatus = EComplete; iTimeOut = KTimeOut; iTimer = CTimeOutTimer::NewL(EPriorityHigh, *this); CActiveScheduler::Add(this); // otvaranje kanala na socket server User::LeaveIfError(iSocketServ.Connect()); // otvaranje TCP socketa User::LeaveIfError(iEchoSocket.Open(iSocketServ, KAfInet, KSockStream, KProtocolInetTcp)); iEchoRead = CEchoRead::NewL(&iEchoSocket, aConsole); iEchoWrite = CEchoWrite::NewL(&iEchoSocket, aConsole); } void CExample::DoCancel() { iTimer->Cancel(); switch (iEngineStatus) { case EConnecting: iEchoSocket.CancelConnect(); break; case ELookingUp: iResolver.Cancel(); iResolver.Close(); break; default:; } } EXPORT_C void CExample::ConnectL(TUint32 aAddr) // spajanje na Echo socket preko IPa { iAddress.SetPort(7); iAddress.SetAddress(aAddr); iEchoSocket.Connect(iAddress, iStatus); iEngineStatus = EConnecting; SetActive(); iTimer->After(iTimeOut); } EXPORT_C void CExample::ConnectL(const TDesC& aServerName) // spajanje na Echo socket preko hostnamea { // DNS User::LeaveIfError(iResolver.Open(iSocketServ, KAfInet, KProtocolInetUdp)); // DNS ime iResolver.GetByName(aServerName, iNameEntry, iStatus); iEngineStatus=ELookingUp; // timeout ako nema imena iTimer->After(iTimeOut); SetActive(); } EXPORT_C void CExample::TestGetByAddr(TUint32 aAddr) // trazenje hostnamea i zatim spajanje (ovo je proto, nece bit koristeno) { // DNS User::LeaveIfError(iResolver.Open(iSocketServ, KAfInet, KProtocolInetUdp)); // DNS ime iAddress.SetAddress(aAddr); iResolver.GetByAddress(iAddress, iNameEntry, iStatus); iEngineStatus=ELookingUp; // time out iTimer->After(iTimeOut); SetActive(); } EXPORT_C void CExample::Write(TChar aChar) // pisanje { if ((iEngineStatus == EConnected) && !iEchoWrite->IsActive()) iEchoWrite->IssueWrite(aChar); } EXPORT_C void CExample::Read() // citanje { if ((iEngineStatus == EConnected)&&(!iEchoRead->IsActive())) iEchoRead->IssueRead(); } void CExample::RunL() // Aplikacija { iTimer->Cancel(); _LIT(KConnecting,"\n Spajanje neuspjelo"); _LIT(KDNSFailed,"\n DNS trazenje neuspjelo"); _LIT(KTimedOut,"\n Timeout\n"); _LIT(KDomainName,"\nIme domene = "); _LIT(KIPAddress,"\nIP adresa = "); TBuf<15> ipAddr; switch(iEngineStatus) { case EConnecting: // spajanje preko IPa if (iStatus == KErrNone) // spojeno { iConsole->PrintNotify(KConnecting); iEngineStatus = EConnected; Read(); } else { iEngineStatus = EConnectFailed; iConsole->ErrorNotify(KConnectionFailed, iStatus.Int()); } break; case ETimedOut: iConsole->ErrorNotify(KTimedOut, KErrTimedOut); break; case ELookingUp: iResolver.Close(); if (iStatus == KErrNone) // DNS lookup uspjelo { iNameRecord = iNameEntry(); iConsole->PrintNotify(KDomainName); iConsole->PrintNotify(iNameRecord.iName); TInetAddr::Cast(iNameRecord.iAddr).Output(ipAddr); iConsole->PrintNotify(KIPAddress); iConsole->PrintNotify(ipAddr); ConnectL(TInetAddr::Cast(iNameRecord.iAddr).Address()); } else { iStatus = ELookUpFailed; iConsole->ErrorNotify(KDNSFailed, iStatus.Int()); } break; default:; }; } CExample::~CExample() { delete iEchoRead; delete iEchoWrite; delete iTimer; iEchoSocket.Close(); iSocketServ.Close(); } void CExample::TimerExpired() { Cancel(); iEngineStatus = ETimedOut; TRequestStatus* p=&iStatus; SetActive(); User::RequestComplete(p, ETimedOut); } EXPORT_C void CExample::Stop() // Shutdown { _LIT(KETerminate,"\n Gasenje...\n"); iConsole->PrintNotify(KETerminate); switch (iEngineStatus) { case EConnected: iEchoRead->Cancel(); iEchoWrite->Cancel(); break; case EConnecting: case ELookingUp: Cancel(); break; default:; } } CEchoRead::CEchoRead() : CActive(EPriorityStandard) { } CEchoRead* CEchoRead::NewL(RSocket* aSocket, MUINotify* aConsole) { CEchoRead* self = NewLC(aSocket, aConsole); CleanupStack::Pop(); return self; } CEchoRead* CEchoRead::NewLC(RSocket* aSocket, MUINotify* aConsole) { CEchoRead* self = new(ELeave) CEchoRead; CleanupStack::PushL(self); self->ConstructL(aSocket, aConsole); return self; } void CEchoRead::ConstructL(RSocket* aSocket, MUINotify* aConsole) { iEchoSocket = aSocket; iConsole = aConsole; CActiveScheduler::Add(this); } void CEchoRead::DoCancel() { iEchoSocket->CancelRead(); } void CEchoRead::RunL() { if (iStatus == KErrNone) { _LIT(KDot,"."); iConsole->PrintNotify(KDot); TBuf16<1> Buffer; Buffer.Copy(iBuffer); iConsole->PrintNotify(Buffer); IssueRead(); } else { _LIT(KCEchoReadError,"\nCEchoRead Error"); iConsole->ErrorNotify(KCEchoReadError, iStatus.Int()); } } void CEchoRead::IssueRead() { if (!IsActive()) { iEchoSocket->Recv(iBuffer, 0, iStatus); SetActive(); } } void CEchoRead::IssueRecvFrom(TInetAddr &aAddr) { iEchoSocket->RecvFrom(iBuffer,aAddr,NULL,iStatus); SetActive(); }; CEchoWrite::CEchoWrite() : CActive(EPriorityStandard) { }; CEchoWrite* CEchoWrite::NewL(RSocket* aSocket, MUINotify* aConsole) { CEchoWrite* self = NewLC(aSocket, aConsole); CleanupStack::Pop(); return self; }; CEchoWrite* CEchoWrite::NewLC(RSocket* aSocket, MUINotify* aConsole) { CEchoWrite* self = new(ELeave) CEchoWrite; CleanupStack::PushL(self); self->ConstructL(aSocket, aConsole); return self; }; void CEchoWrite::ConstructL(RSocket* aSocket, MUINotify* aConsole) { iEchoSocket = aSocket; iConsole = aConsole; CActiveScheduler::Add(this); iTimeOut = KTimeOut; iTimer = CTimeOutTimer::NewL(10, *this); iWriteStatus = EWaiting; }; CEchoWrite::~CEchoWrite() { delete iTimer; } void CEchoWrite::DoCancel() { iEchoSocket->CancelWrite(); }; void CEchoWrite::TimerExpired() { Cancel(); iWriteStatus = ETimedOut; TRequestStatus* p=&iStatus; SetActive(); User::RequestComplete(p, ETimedOut); } void CEchoWrite::RunL() { if (iStatus == KErrNone) { _LIT(KWriteOperationTimedOut,"\nTimeout"); switch(iWriteStatus) { case ESending: iTimer->Cancel(); iWriteStatus = EWaiting; break; case ETimedOut: iConsole->ErrorNotify(KWriteOperationTimedOut, KErrTimedOut); break; default:; }; } else { _LIT(KCEchoWriteError,"\nCEchoWrite Error"); iConsole->ErrorNotify(KCEchoWriteError, iStatus.Int()); } } void CEchoWrite::IssueWrite(const TChar &aChar) // pisanje po streamu { // buffer iBuffer.SetLength(0); iBuffer.Append(aChar); iEchoSocket->Write(iBuffer, iStatus); iTimer->After(iTimeOut); SetActive(); iWriteStatus = ESending; }; CTimeOutTimer::CTimeOutTimer(const TInt aPriority) : CTimer(aPriority) { } CTimeOutTimer::~CTimeOutTimer() { Cancel(); } CTimeOutTimer* CTimeOutTimer::NewL(const TInt aPriority, MTimeOutNotify& aTimeOutNotify) { CTimeOutTimer *p = new (ELeave) CTimeOutTimer(aPriority); CleanupStack::PushL(p); p->ConstructL(aTimeOutNotify); CleanupStack::Pop(); return p; } void CTimeOutTimer::ConstructL(MTimeOutNotify &aTimeOutNotify) { iNotify=&aTimeOutNotify; CTimer::ConstructL(); CActiveScheduler::Add(this); } void CTimeOutTimer::RunL() { iNotify->TimerExpired(); } // Entry point GLDEF_C TInt E32Dll() { return(KErrNone); } /////////////// // Example.h // /////////////// #ifndef _EXAMPLE_H_ #define _EXAMPLE_H_ #include #include #include class MTimeOutNotify { public: virtual void TimerExpired() = 0; }; class MUINotify { public: virtual void PrintNotify(const TDesC& aMessage) = 0; virtual void PrintNotify(TInt aMessage) = 0; virtual void ErrorNotify(const TDesC& aErrMessage, TInt aErrCode) = 0; }; class CTimeOutTimer: public CTimer { public: static CTimeOutTimer* NewL(const TInt aPriority, MTimeOutNotify& aTimeOutNotify); ~CTimeOutTimer(); protected: CTimeOutTimer(const TInt aPriority); void ConstructL(MTimeOutNotify& aTimeOutNotify); virtual void RunL(); private: MTimeOutNotify* iNotify; }; class CEchoRead : public CActive { public: static CEchoRead* NewL(RSocket* aSocket, MUINotify* aConsole); static CEchoRead* NewLC(RSocket* aSocket, MUINotify* aConsole); void ConstructL(RSocket* aSocket, MUINotify* aConsole); void IssueRead(); void IssueRecvFrom(TInetAddr &aAddr); void DoCancel(); void RunL(); protected: CEchoRead(); private: MUINotify* iConsole; RSocket* iEchoSocket; TBuf8<1> iBuffer; }; class CEchoWrite : public CActive, public MTimeOutNotify { public: enum TWriteState { ESending, EWaiting ,ETimedOut }; public: static CEchoWrite* NewL(RSocket* aSocket, MUINotify* aConsole); static CEchoWrite* NewLC(RSocket* aSocket, MUINotify* aConsole); ~CEchoWrite(); void ConstructL(RSocket* aSocket, MUINotify* aConsole); void IssueWrite(const TChar &aChar); void IssueSendTo(TInetAddr &aAddr, const TChar &aChar); void DoCancel(); void RunL(); void TimerExpired(); protected: CEchoWrite(); private: MUINotify* iConsole; RSocket* iEchoSocket; TBuf8<1> iBuffer; CTimeOutTimer* iTimer; TInt iTimeOut; TWriteState iWriteStatus; }; class CExampleine : public CActive, public MTimeOutNotify { public: enum TExampleineState { EComplete, EConnecting, EConnected, ETimedOut, ELookingUp, ELookUpFailed, EConnectFailed, }; public: IMPORT_C CExampleine(); IMPORT_C static CExampleine* NewL(MUINotify* aConsole); IMPORT_C static CExampleine* NewLC(MUINotify* aConsole); IMPORT_C void ConstructL(MUINotify* aConsole); IMPORT_C void Stop(); IMPORT_C void ConnectL(TUint32 aAddr); IMPORT_C void ConnectL(const TDesC& aServerName); IMPORT_C void Write(TChar aChar); IMPORT_C void Read(); IMPORT_C void TestGetByAddr(TUint32 aAddr); void TimerExpired(); void DoCancel(); void RunL(); ~CExampleine(); private: TExampleineState iEngineStatus; MUINotify* iConsole; CEchoRead* iEchoRead; CEchoWrite* iEchoWrite; RSocket iEchoSocket; RSocketServ iSocketServ; RHostResolver iResolver; TNameEntry iNameEntry; TNameRecord iNameRecord; CTimeOutTimer* iTimer; TInt iTimeOut; TInetAddr iAddress; }; #endif //////////////////////////////////////////////////////////////////////////// --==<[ 4. Outro \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ Nazalost ovaj tekst nije uspio kako sam se nadao ponajvise zbog toga jer sam u velikoj vremenskoj krizi tijekom ljeta. Za slijedeci broj vam obecavam pravu poslasticu, ali zato dobro proucite ovaj dio jer ce vam trebati ukoliko zelite shvatiti slijedeci tekst. Materija nije velika, jedna klasa i njene funkcije, ali zato su mogucnosti velike. Pozdrav svima.