///////////////////////////////////////////////////////////////////// // socks.cpp - socket client and multi-threaded server // // prototype for project #2 // // ver 1.1 // // Language: Visual C++, ver 6.0, SP 5 // // Platform: Dell Dimension 8100, Win 2000 Pro, SP 2 // // Application: CSE691/791 - SWM&A Demonstration // // Author: Jim Fawcett, CST 2-187, Syracuse Univ // // (315) 443-3948, jfawcett@twcny.rr.com // ///////////////////////////////////////////////////////////////////// #include #include #include "socks.h" using namespace std; CRITICAL_SECTION sockSvr::_cs; //----< constructor >------------------------------------------------ sockClt::sockClt() { // load version 1.1 of winsock dll WORD wVersionRequested = MAKEWORD(1,1); // requesting version 1.1 WSAData wData; // startup data filled // by WSAStartup int err = WSAStartup(wVersionRequested, &wData); if(err == SOCKET_ERROR) { int errType = WSAGetLastError(); cout << "\n initialization error type: " << errType << "\n\n"; } // create TCP/IP socket object _client = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); } // //----< attempt to connect to a server >----------------------------- bool sockClt::connectTo(address &addr, int port) { // connect to server on specified address and port // - note the IP address 127.0.0.1 refers to host machine _port = port; // user port struct hostent *serverHostent; serverHostent = gethostbyname("Lusitania"); SOCKADDR_IN tcpAddr; tcpAddr.sin_family = AF_INET; // TCP/IP tcpAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); // host machine tcpAddr.sin_port = htons(port); // server port int err = ::connect(_client, (sockaddr*)&tcpAddr, sizeof(tcpAddr)); if(err == SOCKET_ERROR) { int errType = WSAGetLastError(); cout << "\n connection error type: " << errType << "\n\n"; return false; } return true; } //----< attempt to connect to a server >----------------------------- bool sockClt::connectTo(const char *s, int port) { return connectTo(string(s), port); } //----< destructor >------------------------------------------------- sockClt::~sockClt() { closesocket(_client); WSACleanup(); } // //----< insertion operator >----------------------------------------- sockClt& sockClt::operator<<(std::string &s) { int bytesSent = send(s.c_str()); if(bytesSent != s.size()) throw "transmission error in sockClt::operator<<(std::string &s)"; return *this; } //----< insertion operator >----------------------------------------- sockClt& sockClt::operator<<(const char *s) { return operator<<(string(s)); } //----< extraction operator >---------------------------------------- sockClt& sockClt::operator>>(std::string &s) { const int bufferSize = 5; char buffer[bufferSize]; recv(_client,buffer,bufferSize,0); s = buffer; return *this; } //----< send a block of bytes through socket connection >------------ // // attempts to guarantee that all bytes are sent // int sockClt::send(const char *block) { const int sendRetries = 100; int blockLen = strlen(block); int bytesSent; int bytesLeft = blockLen; int blockIndx = 0; int count = 0; while(bytesLeft > 0) { bytesSent = ::send(_client,&block[blockIndx],bytesLeft,0); if(bytesSent == SOCKET_ERROR) { Sleep(50); ++count; } if(count==sendRetries) throw "send failed after 100 retries",__FILE__,__LINE__; bytesLeft -= bytesSent; blockIndx += bytesSent; } return blockLen; } // //----< constructor >------------------------------------------------ sockSvr::sockSvr(int port) : _port(port) { // load version 1.1 of winsock dll WORD wVersionRequested = MAKEWORD(1,1); // requesting version 1.1 WSAData wData; // startup data filled // by WSAStartup int err = WSAStartup(wVersionRequested, &wData); if(err == SOCKET_ERROR) { int errType = WSAGetLastError(); cout << "\n initialization error type: " << errType << "\n\n"; } InitializeCriticalSection(&_cs); } //----< destructor >------------------------------------------------- sockSvr::~sockSvr() { DeleteCriticalSection(&_cs); closesocket(_listener); WSACleanup(); } // //----< send a block of bytes through socket connection >------------ // // attempts to guarantee that all bytes are sent // int sockSvr::send(SOCKET *pSock, const char *block) { const int sendRetries = 100; int blockLen = strlen(block); int bytesSent; int bytesLeft = blockLen; int blockIndx = 0; int count = 0; while(bytesLeft > 0) { bytesSent = ::send(*pSock,&block[blockIndx],bytesLeft,0); if(bytesSent == SOCKET_ERROR) { Sleep(50); ++count; } if(count==sendRetries) throw "send failed after 100 retries",__FILE__,__LINE__; bytesLeft -= bytesSent; blockIndx += bytesSent; } return blockLen; } //----< start up server >-------------------------------------------- void sockSvr::start() { // create TCP/IP socket object to listen for connection requests _listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // bind listner socket to specific port and network interface SOCKADDR_IN tcpAddr; tcpAddr.sin_family = AF_INET; // TCP/IP tcpAddr.sin_port = htons(_port); // listening port tcpAddr.sin_addr.s_addr = INADDR_ANY; // listen over every network interface int err = bind(_listener, (SOCKADDR*)&tcpAddr, sizeof(tcpAddr)); if(err == SOCKET_ERROR) { int errType = WSAGetLastError(); cout << "\n initialization error type: " << errType << "\n\n"; return; // errType; } // listen for incoming connection requests int backLog = 10; err = ::listen(_listener, backLog); if(err == SOCKET_ERROR) { int errType = WSAGetLastError(); cout << "\n initialization error type: " << errType << "\n\n"; return; //errType; } // cout << "\n waiting for incoming request"; // block until a connection is established int size = sizeof(tcpAddr); while(1) { SOCKET toClient = accept(_listener, (SOCKADDR*)&tcpAddr, &size); if(toClient == INVALID_SOCKET) break; EnterCriticalSection(&_cs); cout << "\n established connection with: " << inet_ntoa(tcpAddr.sin_addr) << ":" << ntohs(tcpAddr.sin_port) << endl; LeaveCriticalSection(&_cs); // got connection so spawn thread to read transferred data unsigned int threadID; HANDLE hThread = (HANDLE)_beginthreadex( NULL, 0, threadProc, &toClient, 0, &threadID ); CloseHandle(hThread); } } //----< attempt to connect to client and receive messages >---------- bool sockSvr::handleConnection(connectionHandler &ch) { return true; } // //----< client connection thread processing >------------------------ unsigned int __stdcall sockSvr::threadProc(void *pArgs) { SOCKET *pSock = (SOCKET*)pArgs; char *msg = "server got your message"; // sockClt _client; // _client.connectTo("127.0.0.1",2048); string save; const int bufSize = 1024; char buffer[bufSize]; int bytes, count=0; do { bytes = recv(*pSock,buffer,bufSize-1,0); buffer[bytes] = '\0'; save = buffer; if(bytes > 0) { EnterCriticalSection(&_cs); cout << save.c_str(); cout.flush(); LeaveCriticalSection(&_cs); } send(pSock,msg); } while(bytes != 0 && bytes != SOCKET_ERROR); if(bytes == SOCKET_ERROR) { int errType = WSAGetLastError(); EnterCriticalSection(&_cs); cout << "\n receive error type: " << errType << "\n\n"; LeaveCriticalSection(&_cs); } closesocket(*pSock); return 0; } // //----< test stub >-------------------------------------------------- #ifdef TEST_SOCKS_CLIENT #include "threads.h" #include "sysUtils.h" class clientThread : public thread { public: clientThread(int port) : _port(port) {} protected: int _port; void run() { sockSvr _clientSvr(_port); _clientSvr.start(); } }; class clientThreadRcvr : public thread { public: clientThreadRcvr(sockClt &client) : _client(client) {} protected: sockClt &_client; void run() { string msg; _client >> msg; cout << msg; cout.flush(); } }; void main(int argc, char *argv[]) { cout << "\n running client\n"; try { sockClt client; if(!client.connectTo("127.0.0.1", 1024)) { sysError err; throw err.getLastMsg(); } // clientThreadRcvr ct(client); // this part is not working yet // ct.start(); if(argc > 1) { int i=1; cout << " "; while(i < argc) client << " " << argv[i++]; } else { client << "this is a string\n"; client << "and another\n"; } // ct.wait(); } catch(const string &msg) { sysError err; cout << "\n " << msg << "\n\n"; } catch(...) { cout << "\n unknown error type\n\n"; } } #endif #ifdef TEST_SOCKS_SERVER void main() { cout << "\n running server\n"; try { sockSvr server(1024); server.start(); } catch(...) { cout << "\n can't create server - is there one already running?\n\n"; } } #endif