/* This file is part of SLC. Copyright (C) 2008 Sebastien LUTTRINGER SLC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. SLC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with SLC; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include "slc.hh" #include "options.hh" #include "connection.hh" #include "screen.hh" #include "error.hh" pthread_mutex_t mtx_socket = PTHREAD_MUTEX_INITIALIZER; Connection::Connection() : socket_(0) {} bool Connection::connected() const { return socket_ > 0; } void Connection::start() { if (connected()) return; // make connection connect_(O.server.c_str(), O.port); // send login info // send pass info // Start reader thread pthread_create(&g_thread_reader, 0, thread_reader, 0); } void Connection::stop() { if (!connected()) return; disconnect_(); } void Connection::connect_(const char *addr, int port) { struct sockaddr_in daddr; struct hostent *h; // Check no existing connexion assert(socket_ == 0); // retrieve remote host info h = gethostbyname(addr); if (h == 0) { S << "Unable to resolve: " << addr << ": " << hstrerror(h_errno) << ".\n"; return; } // create socket pthread_mutex_lock(&mtx_socket); socket_ = socket(PF_INET, SOCK_STREAM, 0); if (socket_ == -1) { S << "Unable to create socket: " << strerror(errno) << ".\n"; socket_ = 0; pthread_mutex_unlock(&mtx_socket); return; } pthread_mutex_unlock(&mtx_socket); daddr.sin_family = AF_INET; daddr.sin_port = htons(port); daddr.sin_addr = *((struct in_addr *) h->h_addr); memset(daddr.sin_zero, '\0', sizeof daddr.sin_zero); S << "Connecting to " << h->h_name << " (" << inet_ntoa(*(struct in_addr*)h->h_addr) << ") on port " << port << "...\n"; // connect pthread_mutex_lock(&mtx_socket); int con = connect(socket_, (struct sockaddr *) &daddr, sizeof daddr); pthread_mutex_unlock(&mtx_socket); if (con == -1) { disconnect_(); S << "Unable to connect: " << strerror(errno) << ".\n"; return; } S << "Connected to " << h->h_name << " (" << inet_ntoa(*(struct in_addr*)h->h_addr) << ") on port " << port << ".\n"; } void Connection::disconnect_() { assert(socket_ > 0); pthread_mutex_lock(&mtx_socket); close(socket_); socket_ = 0; pthread_mutex_unlock(&mtx_socket); } void Connection::send(const string &data) { send(data.c_str(), data.length()); } void Connection::send(const char* buf, size_t len) { assert(socket_ > 0); pthread_mutex_lock(&mtx_socket); write(socket_, buf, len); pthread_mutex_unlock(&mtx_socket); } void Connection::sendln(const string &data) { sendln(data.c_str(), data.length()); } void Connection::sendln(const char* buf, size_t len) { assert(socket_ > 0); pthread_mutex_lock(&mtx_socket); write(socket_, buf, len); write(socket_, "\n", 1); pthread_mutex_unlock(&mtx_socket); } string Connection::recvln() { assert(socket > 0); do { // check EOL char size_t offset = rbuf_.find('\n'); if (offset != string::npos) { string s = rbuf_.substr(0, offset); rbuf_.erase(0, offset + 1); return s; } // wait incoming data static struct pollfd spfd[1] = {{socket_, POLLIN|POLLPRI|POLLHUP|POLLERR, 0}}; poll(spfd, 1, -1); // lock before read pthread_mutex_lock(&mtx_socket); // read data static char local_buf[MAX_LINE_SIZE]; int ret = ::recv(socket_, local_buf, MAX_LINE_SIZE, MSG_DONTWAIT); // unlock pthread_mutex_unlock(&mtx_socket); if (ret == -1) { disconnect_(); *local_buf = 0; } else local_buf[ret] = 0; // add read data in buffer rbuf_ += local_buf; } while (1); assert(1); }