[10134] MaNGOS 0.16 release.
[getmangos.git] / src / realmd / BufferedSocket.cpp
blob993547811981941643556e4f0ce0a54fa06f7a0b
1 /*
2 * Copyright (C) 2005-2010 MaNGOS <http://getmangos.com/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 /** \file
20 \ingroup realmd
23 #include "BufferedSocket.h"
25 #include <ace/OS_NS_string.h>
26 #include <ace/INET_Addr.h>
27 #include <ace/SString.h>
29 #ifndef MSG_NOSIGNAL
30 #define MSG_NOSIGNAL 0
31 #endif
33 BufferedSocket::BufferedSocket(void):
34 input_buffer_(4096),
35 remote_address_("<unknown>")
39 /*virtual*/ BufferedSocket::~BufferedSocket(void)
43 /*virtual*/ int BufferedSocket::open(void * arg)
45 if(Base::open(arg) == -1)
46 return -1;
48 ACE_INET_Addr addr;
50 if(peer().get_remote_addr(addr) == -1)
51 return -1;
53 char address[1024];
55 addr.get_host_addr(address, 1024);
57 this->remote_address_ = address;
59 this->OnAccept();
61 return 0;
64 const std::string& BufferedSocket::get_remote_address(void) const
66 return this->remote_address_;
69 size_t BufferedSocket::recv_len(void) const
71 return this->input_buffer_.length();
74 bool BufferedSocket::recv_soft(char *buf, size_t len)
76 if(this->input_buffer_.length() < len)
77 return false;
79 ACE_OS::memcpy(buf, this->input_buffer_.rd_ptr(), len);
81 return true;
84 bool BufferedSocket::recv(char *buf, size_t len)
86 bool ret = this->recv_soft(buf, len);
88 if(ret)
89 this->recv_skip(len);
91 return ret;
94 void BufferedSocket::recv_skip(size_t len)
96 this->input_buffer_.rd_ptr(len);
99 ssize_t BufferedSocket::noblk_send(ACE_Message_Block &message_block)
101 const size_t len = message_block.length();
103 if(len == 0)
104 return -1;
106 // Try to send the message directly.
107 ssize_t n = this->peer().send(message_block.rd_ptr(), len, MSG_NOSIGNAL);
109 if(n < 0)
111 if(errno == EWOULDBLOCK)
112 // Blocking signal
113 return 0;
114 else
115 // Error
116 return -1;
118 else if(n == 0)
120 // Can this happen ?
121 return -1;
124 // return bytes transmitted
125 return n;
128 bool BufferedSocket::send(const char *buf, size_t len)
130 if(buf == NULL || len == 0)
131 return true;
133 ACE_Data_Block db(
134 len,
135 ACE_Message_Block::MB_DATA,
136 (const char*)buf,
139 ACE_Message_Block::DONT_DELETE,
142 ACE_Message_Block message_block(
143 &db,
144 ACE_Message_Block::DONT_DELETE,
147 message_block.wr_ptr(len);
149 if(this->msg_queue()->is_empty())
151 // Try to send it directly.
152 ssize_t n = this->noblk_send(message_block);
154 if(n < 0)
155 return false;
156 else if(n == len)
157 return true;
159 // adjust how much bytes we sent
160 message_block.rd_ptr((size_t)n);
162 // fall down
165 // enqueue the message, note: clone is needed cause we cant enqueue stuff on the stack
166 ACE_Message_Block *mb = message_block.clone();
168 if(this->msg_queue()->enqueue_tail(mb, (ACE_Time_Value *) &ACE_Time_Value::zero) == -1)
170 mb->release();
171 return false;
174 // tell reactor to call handle_output() when we can send more data
175 if(this->reactor()->schedule_wakeup(this, ACE_Event_Handler::WRITE_MASK) == -1)
176 return false;
178 return true;
181 /*virtual*/ int BufferedSocket::handle_output(ACE_HANDLE /*= ACE_INVALID_HANDLE*/)
183 ACE_Message_Block *mb = 0;
185 if(this->msg_queue()->is_empty())
187 // if no more data to send, then cancel notification
188 this->reactor()->cancel_wakeup(this, ACE_Event_Handler::WRITE_MASK);
189 return 0;
192 if(this->msg_queue()->dequeue_head(mb, (ACE_Time_Value *) &ACE_Time_Value::zero) == -1)
193 return -1;
195 ssize_t n = this->noblk_send(*mb);
197 if(n < 0)
199 mb->release();
200 return -1;
202 else if(n == mb->length())
204 mb->release();
205 return 1;
207 else
209 mb->rd_ptr(n);
211 if(this->msg_queue()->enqueue_head(mb, (ACE_Time_Value *) &ACE_Time_Value::zero) == -1)
213 mb->release();
214 return -1;
217 return 0;
220 ACE_NOTREACHED(return -1);
223 /*virtual*/ int BufferedSocket::handle_input(ACE_HANDLE /*= ACE_INVALID_HANDLE*/)
225 const ssize_t space = this->input_buffer_.space();
227 ssize_t n = this->peer().recv(this->input_buffer_.wr_ptr(), space);
229 if(n < 0)
231 // blocking signal or error
232 return errno == EWOULDBLOCK ? 0 : -1;
234 else if(n == 0)
236 // EOF
237 return -1;
240 this->input_buffer_.wr_ptr((size_t)n);
242 this->OnRead();
244 // move data in the buffer to the beginning of the buffer
245 this->input_buffer_.crunch();
247 // return 1 in case there might be more data to read from OS
248 return n == space ? 1 : 0;
251 /*virtual*/ int BufferedSocket::handle_close(ACE_HANDLE h, ACE_Reactor_Mask m)
253 this->OnClose();
255 Base::handle_close();
257 return 0;
260 void BufferedSocket::close_connection(void)
262 this->peer().close_reader();
263 this->peer().close_writer();