CSIS 440 chat client/server project.

SircClient.cpp 5.5KB

    /* Author: Matt Kava Asmt: CSIS 440, Spring 2010, Assignment 6 :: IRC-Like Client/Server Description: Sirc Client class - A basic text-based (Curses) client */ #include <curses.h> #include "SircClient.h" #include "User.h" #include <curses.h> #include <unistd.h> #include <stdlib.h> #include <sys/types.h> // For data types #include <sys/socket.h> // For socket(), connect(), send(), and recv() #include <netdb.h> // For gethostbyname() #include <arpa/inet.h> // For inet_addr() #include <netinet/in.h> // For sockaddr_in #include <string.h> #include <sstream> // string stream using namespace std; SircClient::SircClient() { _sockfd = -1; _user = new User(); } SircClient::~SircClient() { // close up shop and terminate the window as well _user->CloseSocket(); endwin(); } void SircClient::DrawWindow() { int x, y; char fillChar = '!'; // fill in the screen with the fill character initscr(); for(x = 0; x < COLS-1; x++) { for(y = 0; y < LINES-1; y++) { mvwaddch(stdscr, y, x, fillChar); } } refresh(); // make the send window _sendWindow = newwin(3, COLS - 3, LINES - 5, 1); wclear(_sendWindow); wrefresh(_sendWindow); // make the recv window _recvWindow = newwin(LINES - 7, COLS - 3, 1, 1); wclear(_recvWindow); wrefresh(_recvWindow); wprintw(_recvWindow, " SimpleIRC Client goes \"%s\"\n", "WHEEE!"); // turn on echoing... echo(); // allow the top window (recv window) to scroll scrollok(_recvWindow, 1); } int SircClient::Init(const string address, const unsigned short port) { fd_set readFDset; fd_set activeFDset; int numberFD; char buffer[BUFFER_SIZE]; if( CreateConnection(address, port) != 0 ) { cerr << "An error occured while trying to connect.\n"; return 1; } _user->SockFD(_sockfd); // one for stdin, other for the socket numberFD = 5; FD_ZERO(&activeFDset); FD_SET(0, &activeFDset); FD_SET(_sockfd, &activeFDset); // get some constants ready string msg = ""; // draw the window(s) this->DrawWindow(); // oh, the madness of the tormenting infinate loop! while(1) { // refresh the windows wrefresh(_recvWindow); wclear(_sendWindow); wprintw(_sendWindow, " %s > ", "Msg"); wrefresh(_sendWindow); // start the select train memcpy(&readFDset, &activeFDset, sizeof(readFDset)); if( select(numberFD, &readFDset, (fd_set *)0, (fd_set *)0, (struct timeval *)0) < 0) { endwin(); // select error cout << "Select error.\n"; return 1; } msg = ""; // check the network socket if(FD_ISSET(_user->SockFD(), &readFDset)) { msg = _user->Recv(); wprintw(_recvWindow, " > %s\n", msg.c_str()); wrefresh(_recvWindow); if(!_user->Validated()) { if( msg.find("JOIN:") != string::npos) { _user->Validated(true); } } } // check stdin if(FD_ISSET(0, &readFDset)) { wgetnstr(_sendWindow, buffer, BUFFER_SIZE); msg = buffer; // catch that quit command if(msg == "/quit") { _user->Send("\0"); _user->CloseSocket(); return 0; } _user->Send( (string)buffer ); if(_user->Validated()) { // we have a nickname already wprintw(_recvWindow, " %s > %s\n", _user->Nick().c_str(), buffer); } else { string nick = ""; for(int i = 0; i < MAX_NICK_LENGTH; i++) { // as long as its not a space, keep getting it... if( (int)buffer[i] != 32 ) nick += buffer[i]; } _user->Nick(nick); wprintw(_recvWindow, " Requested nickname: %s\n", nick.c_str()); } } } endwin(); return 1; } int SircClient::CreateConnection(const string address, const unsigned short port) { struct addrinfo hints, *servinfo, *p; int rv; memset(&hints, 0, sizeof hints); hints.ai_family = AF_INET; // use AF_INET6 to force IPv6 hints.ai_socktype = SOCK_STREAM; // if this is running on Windows, Winsock needs to be started #ifdef WINDOWS WSADATA wsaData; int iResult = WSAStartup(MAKEWORD(2,2), &wsaData); if (iResult != NO_ERROR) { cerr << "Error: Running on Windows. Winsock could not be started. Exiting.\n"; return 1; } #endif // convert the PORT (unsigned short) to PORT (string) stringstream ss; ss << port; string portC = ss.str(); // find the hostname information using getaddrinfo, report error and return if fails // using getaddrinfo instead of gethostbyname as gethostbyname is depreciated and can // have spotty results at times. if ((rv = getaddrinfo(address.c_str(), portC.c_str(), &hints, &servinfo)) != 0) { cerr << "Error: On host lookup of \"" << address << ":" << portC << "\", there was an error with getaddrinfo: \"" << gai_strerror(rv) << "\" Exiting.\n"; return 2; } /* loop through all the results and connect to the first we can */ for(p = servinfo; p != NULL; p = p->ai_next) { // attempt to create the socket needed, error if fails if ((_sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0) { cerr << "Error: Could not create socket of defined type. Exiting." << endl; return 2; } // attempt to connect, report error and return if fails if (connect(_sockfd, p->ai_addr, p->ai_addrlen) < 0) { close(_sockfd); cerr << "Error: Could not connect to host \"" << address << ":" << port << "\" Exiting.\n"; return 3; } // if we made it this far, this can terminate now. break; } // all done with this structure freeaddrinfo(servinfo); _user->SockFD(_sockfd); // no error occured, return 0 to show no error // the file descriptor number is set to _sockfd, a class variable so it does not need to be returned return 0; }