ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/cf.schmorp.de/dclient/src/backend/communicator/communicator.cpp
Revision: 1.1
Committed: Sun Oct 24 20:31:49 2010 UTC (15 years, 11 months ago) by sf-pippijn
Branch: MAIN
Log Message:
use EV and plain sockets instead of asio

File Contents

# User Rev Content
1 sf-pippijn 1.1 #include "deliantra/communicator.h"
2    
3     #include "adt/logs.h"
4    
5     #include <boost/lexical_cast.hpp>
6    
7     #include <fcntl.h>
8     #include <netdb.h>
9     #include <netinet/in.h>
10     #include <sys/socket.h>
11     #include <unistd.h>
12    
13     static std::string
14     strerror ()
15     {
16     return strerror (errno);
17     }
18    
19     communicator::communicator (std::string const &server, std::string const &port)
20     : response_len (0)
21     , response { 0 }
22     {
23     LOG ("net") << "creating socket\n";
24     int sockfd = socket (AF_INET, SOCK_STREAM, 0);
25     if (sockfd == -1)
26     throw "socket: " + strerror ();
27    
28     int portno = boost::lexical_cast<int> (port);
29    
30     LOG ("net") << "resolving hostname: " << server << "\n";
31     hostent *serverent = gethostbyname (server.c_str ());
32     if (!serverent)
33     throw "gethostbyname: " + strerror ();
34    
35     LOG ("net") << "connecting to: " << server << ":" << portno << "\n";
36     sockaddr_in addr = { 0 };
37     addr.sin_family = AF_INET;
38     memcpy (&addr.sin_addr.s_addr, serverent->h_addr, serverent->h_length);
39     addr.sin_port = htons (portno);
40     if (connect (sockfd, reinterpret_cast<sockaddr const *> (&addr), sizeof addr) == -1)
41     throw "connect: " + strerror ();
42    
43     LOG ("net") << "setting socket to non-blocking\n";
44     int flags = fcntl (sockfd, F_GETFL, 0);
45     if (flags == -1)
46     flags = 0;
47     if (fcntl (sockfd, F_SETFL, flags | O_NONBLOCK) == -1)
48     throw "fcntl: " + strerror ();
49    
50     LOG ("net") << "setting up read callback\n";
51     sock.set (sockfd, ev::READ);
52     sock.set<communicator, &communicator::read_cb> (this);
53     sock.start ();
54     }
55    
56     void
57     communicator::set_packet_handler (interface::packet_handler &handler)
58     {
59     on = &handler;
60     }
61    
62     void
63     communicator::read_cb (ev::io &w, int revents)
64     {
65     LOG ("net") << "data is ready\n";
66    
67     ssize_t readlen = read (w.fd, response + response_len, sizeof response - response_len);
68     if (readlen < 0)
69     throw "read: " + strerror ();
70     if (readlen == 0)
71     throw "connection reset by peer";
72     response_len += readlen;
73    
74     for (;;)
75     {
76     if (response_len < 2)
77     break;
78    
79     unsigned int cmd_len = response[0] << 8 | response[1];
80    
81     LOG ("net") << "command length is ready: " << cmd_len << "\n";
82     if (response_len < cmd_len + 2)
83     break;
84    
85     LOG ("net") << "command is ready; processing\n";
86     on->receive (std::string (response + 2, response + 2 + cmd_len));
87     memmove (response, response + 2 + cmd_len, response_len - 2 - cmd_len);
88     response_len -= 2 + cmd_len;
89     LOG ("net") << response_len << " bytes left\n";
90     }
91     }
92    
93     void
94     communicator::send (std::string const &command)
95     {
96     LOG ("net") << "sending command: " << command << "\n";
97     write (sock.fd, &static_cast<uint16_t const &> (htons (command.length ())), 2);
98     if (write (sock.fd, command.data (), command.length ()) == -1)
99     throw "write: " + strerror ();
100     }