00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "socket.h"
00017 #include "inspstring.h"
00018 #include "socketengine.h"
00019 #include "inspircd.h"
00020
00021 using irc::sockets::OpenTCPSocket;
00022
00023 bool BufferedSocket::Readable()
00024 {
00025 return ((this->state != I_CONNECTING) && (this->WaitingForWriteEvent == false));
00026 }
00027
00028 BufferedSocket::BufferedSocket(InspIRCd* SI)
00029 {
00030 this->Timeout = NULL;
00031 this->state = I_DISCONNECTED;
00032 this->fd = -1;
00033 this->WaitingForWriteEvent = false;
00034 this->Instance = SI;
00035 this->IsIOHooked = false;
00036 }
00037
00038 BufferedSocket::BufferedSocket(InspIRCd* SI, int newfd, const char* ip)
00039 {
00040 this->Timeout = NULL;
00041 this->fd = newfd;
00042 this->state = I_CONNECTED;
00043 strlcpy(this->IP,ip,MAXBUF);
00044 this->WaitingForWriteEvent = false;
00045 this->Instance = SI;
00046 this->IsIOHooked = false;
00047 if (this->fd > -1)
00048 this->Instance->SE->AddFd(this);
00049 }
00050
00051 BufferedSocket::BufferedSocket(InspIRCd* SI, const std::string &ipaddr, int aport, bool listening, unsigned long maxtime, const std::string &connectbindip)
00052 {
00053 this->cbindip = connectbindip;
00054 this->fd = -1;
00055 this->Instance = SI;
00056 strlcpy(host,ipaddr.c_str(),MAXBUF);
00057 this->WaitingForWriteEvent = false;
00058 this->IsIOHooked = false;
00059 this->Timeout = NULL;
00060 if (listening)
00061 {
00062 if ((this->fd = OpenTCPSocket(host)) == ERROR)
00063 {
00064 this->fd = -1;
00065 this->state = I_ERROR;
00066 this->OnError(I_ERR_SOCKET);
00067 return;
00068 }
00069 else
00070 {
00071 if (!SI->BindSocket(this->fd,aport,(char*)ipaddr.c_str()))
00072 {
00073 this->Close();
00074 this->fd = -1;
00075 this->state = I_ERROR;
00076 this->OnError(I_ERR_BIND);
00077 this->ClosePending = true;
00078 return;
00079 }
00080 else
00081 {
00082 this->state = I_LISTENING;
00083 this->port = aport;
00084 if (this->fd > -1)
00085 {
00086 if (!this->Instance->SE->AddFd(this))
00087 {
00088 this->Close();
00089 this->state = I_ERROR;
00090 this->OnError(I_ERR_NOMOREFDS);
00091 }
00092 }
00093 return;
00094 }
00095 }
00096 }
00097 else
00098 {
00099 strlcpy(this->host,ipaddr.c_str(),MAXBUF);
00100 this->port = aport;
00101
00102 bool ipvalid = true;
00103 #ifdef IPV6
00104 if (strchr(host,':'))
00105 {
00106 in6_addr n;
00107 if (inet_pton(AF_INET6, host, &n) < 1)
00108 ipvalid = false;
00109 }
00110 else
00111 #endif
00112 {
00113 in_addr n;
00114 if (inet_aton(host,&n) < 1)
00115 ipvalid = false;
00116 }
00117 if (!ipvalid)
00118 {
00119 this->Instance->Logs->Log("SOCKET", DEBUG,"BUG: Hostname passed to BufferedSocket, rather than an IP address!");
00120 this->OnError(I_ERR_CONNECT);
00121 this->Close();
00122 this->fd = -1;
00123 this->state = I_ERROR;
00124 return;
00125 }
00126 else
00127 {
00128 strlcpy(this->IP,host,MAXBUF);
00129 timeout_val = maxtime;
00130 if (!this->DoConnect())
00131 {
00132 this->OnError(I_ERR_CONNECT);
00133 this->Close();
00134 this->fd = -1;
00135 this->state = I_ERROR;
00136 return;
00137 }
00138 }
00139 }
00140 }
00141
00142 void BufferedSocket::WantWrite()
00143 {
00144 this->Instance->SE->WantWrite(this);
00145 this->WaitingForWriteEvent = true;
00146 }
00147
00148 void BufferedSocket::SetQueues(int nfd)
00149 {
00150
00151 int sendbuf = 32768;
00152 int recvbuf = 32768;
00153 if(setsockopt(nfd,SOL_SOCKET,SO_SNDBUF,(const char *)&sendbuf,sizeof(sendbuf)) || setsockopt(nfd,SOL_SOCKET,SO_RCVBUF,(const char *)&recvbuf,sizeof(sendbuf)))
00154 {
00155
00156 ;
00157 }
00158 }
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168 bool BufferedSocket::BindAddr(const std::string &ip)
00169 {
00170 ConfigReader Conf(this->Instance);
00171 socklen_t size = sizeof(sockaddr_in);
00172 #ifdef IPV6
00173 bool v6 = false;
00174
00175 if ((ip.empty()) || (ip.find(':') != std::string::npos))
00176 v6 = true;
00177 #endif
00178 int j = 0;
00179 while (j < Conf.Enumerate("bind") || (!ip.empty()))
00180 {
00181 std::string sIP = ip.empty() ? Conf.ReadValue("bind","address",j) : ip;
00182 if (!ip.empty() || Conf.ReadValue("bind","type",j) == "servers")
00183 {
00184 if (!ip.empty() || ((sIP != "*") && (sIP != "127.0.0.1") && (!sIP.empty()) && (sIP != "::1")))
00185 {
00186
00187 sockaddr* s = new sockaddr[2];
00188 #ifdef IPV6
00189 if (v6)
00190 {
00191 in6_addr n;
00192 if (inet_pton(AF_INET6, sIP.c_str(), &n) > 0)
00193 {
00194 memcpy(&((sockaddr_in6*)s)->sin6_addr, &n, sizeof(sockaddr_in6));
00195 ((sockaddr_in6*)s)->sin6_port = 0;
00196 ((sockaddr_in6*)s)->sin6_family = AF_INET6;
00197 size = sizeof(sockaddr_in6);
00198 }
00199 else
00200 {
00201 delete[] s;
00202 j++;
00203 continue;
00204 }
00205 }
00206 else
00207 #endif
00208 {
00209 in_addr n;
00210 if (inet_aton(sIP.c_str(), &n) > 0)
00211 {
00212 ((sockaddr_in*)s)->sin_addr = n;
00213 ((sockaddr_in*)s)->sin_port = 0;
00214 ((sockaddr_in*)s)->sin_family = AF_INET;
00215 }
00216 else
00217 {
00218 delete[] s;
00219 j++;
00220 continue;
00221 }
00222 }
00223
00224 if (Instance->SE->Bind(this->fd, s, size) < 0)
00225 {
00226 this->state = I_ERROR;
00227 this->OnError(I_ERR_BIND);
00228 this->fd = -1;
00229 delete[] s;
00230 return false;
00231 }
00232
00233 delete[] s;
00234 return true;
00235 }
00236 }
00237 j++;
00238 }
00239 Instance->Logs->Log("SOCKET", DEBUG,"nothing in the config to bind()!");
00240 return true;
00241 }
00242
00243 bool BufferedSocket::DoConnect()
00244 {
00245
00246 sockaddr* addr = new sockaddr[2];
00247 socklen_t size = sizeof(sockaddr_in);
00248 #ifdef IPV6
00249 bool v6 = false;
00250 if ((!*this->host) || strchr(this->host, ':'))
00251 v6 = true;
00252
00253 if (v6)
00254 {
00255 this->fd = socket(AF_INET6, SOCK_STREAM, 0);
00256 if ((this->fd > -1) && ((strstr(this->IP,"::ffff:") != (char*)&this->IP) && (strstr(this->IP,"::FFFF:") != (char*)&this->IP)))
00257 {
00258 if (!this->BindAddr(this->cbindip))
00259 {
00260 delete[] addr;
00261 return false;
00262 }
00263 }
00264 }
00265 else
00266 #endif
00267 {
00268 this->fd = socket(AF_INET, SOCK_STREAM, 0);
00269 if (this->fd > -1)
00270 {
00271 if (!this->BindAddr(this->cbindip))
00272 {
00273 delete[] addr;
00274 return false;
00275 }
00276 }
00277 }
00278
00279 if (this->fd == -1)
00280 {
00281 this->state = I_ERROR;
00282 this->OnError(I_ERR_SOCKET);
00283 delete[] addr;
00284 return false;
00285 }
00286
00287 #ifdef IPV6
00288 if (v6)
00289 {
00290 in6_addr addy;
00291 if (inet_pton(AF_INET6, this->host, &addy) > 0)
00292 {
00293 ((sockaddr_in6*)addr)->sin6_family = AF_INET6;
00294 memcpy(&((sockaddr_in6*)addr)->sin6_addr, &addy, sizeof(addy));
00295 ((sockaddr_in6*)addr)->sin6_port = htons(this->port);
00296 size = sizeof(sockaddr_in6);
00297 }
00298 }
00299 else
00300 #endif
00301 {
00302 in_addr addy;
00303 if (inet_aton(this->host, &addy) > 0)
00304 {
00305 ((sockaddr_in*)addr)->sin_family = AF_INET;
00306 ((sockaddr_in*)addr)->sin_addr = addy;
00307 ((sockaddr_in*)addr)->sin_port = htons(this->port);
00308 }
00309 }
00310
00311 Instance->SE->NonBlocking(this->fd);
00312
00313 #ifdef WIN32
00314
00315 Instance->SE->Blocking(this->fd);
00316 #endif
00317
00318 if (Instance->SE->Connect(this, (sockaddr*)addr, size) == -1)
00319 {
00320 if (errno != EINPROGRESS)
00321 {
00322 this->OnError(I_ERR_CONNECT);
00323 this->Close();
00324 this->state = I_ERROR;
00325 return false;
00326 }
00327
00328 this->Timeout = new SocketTimeout(this->GetFd(), this->Instance, this, timeout_val, this->Instance->Time());
00329 this->Instance->Timers->AddTimer(this->Timeout);
00330 }
00331 #ifdef WIN32
00332
00333 Instance->SE->NonBlocking(this->fd);
00334 #endif
00335 this->state = I_CONNECTING;
00336 if (this->fd > -1)
00337 {
00338 if (!this->Instance->SE->AddFd(this))
00339 {
00340 this->OnError(I_ERR_NOMOREFDS);
00341 this->Close();
00342 this->state = I_ERROR;
00343 return false;
00344 }
00345 this->SetQueues(this->fd);
00346 }
00347
00348 Instance->Logs->Log("SOCKET", DEBUG,"BufferedSocket::DoConnect success");
00349 return true;
00350 }
00351
00352
00353 void BufferedSocket::Close()
00354 {
00355
00356
00357
00358
00359 int save = errno;
00360 if (this->fd > -1)
00361 {
00362 if (this->IsIOHooked && Instance->Config->GetIOHook(this))
00363 {
00364 try
00365 {
00366 if (this->state != I_LISTENING)
00367 Instance->Config->GetIOHook(this)->OnRawSocketClose(this->fd);
00368 }
00369 catch (CoreException& modexcept)
00370 {
00371 Instance->Logs->Log("SOCKET", DEFAULT,"%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason());
00372 }
00373 }
00374 Instance->SE->Shutdown(this, 2);
00375 if (Instance->SE->Close(this) != -1)
00376 this->OnClose();
00377
00378 if (Instance->SocketCull.find(this) == Instance->SocketCull.end())
00379 Instance->SocketCull[this] = this;
00380 }
00381 errno = save;
00382 }
00383
00384 std::string BufferedSocket::GetIP()
00385 {
00386 return this->IP;
00387 }
00388
00389 const char* BufferedSocket::Read()
00390 {
00391 if (!Instance->SE->BoundsCheckFd(this))
00392 return NULL;
00393
00394 int n = 0;
00395 char* ReadBuffer = Instance->GetReadBuffer();
00396
00397 if (this->IsIOHooked)
00398 {
00399 int result2 = 0;
00400 int MOD_RESULT = 0;
00401 try
00402 {
00403 MOD_RESULT = Instance->Config->GetIOHook(this)->OnRawSocketRead(this->fd, ReadBuffer, Instance->Config->NetBufferSize, result2);
00404 }
00405 catch (CoreException& modexcept)
00406 {
00407 Instance->Logs->Log("SOCKET", DEFAULT,"%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason());
00408 }
00409 if (MOD_RESULT < 0)
00410 {
00411 n = -1;
00412 errno = EAGAIN;
00413 }
00414 else
00415 {
00416 n = result2;
00417 }
00418 }
00419 else
00420 {
00421 n = recv(this->fd, ReadBuffer, Instance->Config->NetBufferSize, 0);
00422 }
00423
00424
00425
00426
00427
00428
00429
00430 if (n > 0)
00431 {
00432 ReadBuffer[n] = 0;
00433 return ReadBuffer;
00434 }
00435 else
00436 {
00437 int err = errno;
00438 if (err == EAGAIN)
00439 return "";
00440 else
00441 return NULL;
00442 }
00443 }
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457 void BufferedSocket::Write(const std::string &data)
00458 {
00459
00460 outbuffer.push_back(data);
00461
00462
00463 this->Instance->SE->WantWrite(this);
00464 }
00465
00466 bool BufferedSocket::FlushWriteBuffer()
00467 {
00468 errno = 0;
00469 if ((this->fd > -1) && (this->state == I_CONNECTED))
00470 {
00471 if (this->IsIOHooked)
00472 {
00473 while (outbuffer.size() && (errno != EAGAIN))
00474 {
00475 try
00476 {
00477
00478
00479
00480 Instance->Config->GetIOHook(this)->OnRawSocketWrite(this->fd, outbuffer[0].c_str(), outbuffer[0].length());
00481 outbuffer.pop_front();
00482 }
00483 catch (CoreException& modexcept)
00484 {
00485 Instance->Logs->Log("SOCKET", DEBUG,"%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason());
00486 return true;
00487 }
00488 }
00489 }
00490 else
00491 {
00492
00493
00494
00495 while (outbuffer.size() && (errno != EAGAIN))
00496 {
00497
00498 int result = Instance->SE->Send(this, outbuffer[0].c_str(), outbuffer[0].length(), 0);
00499
00500 if (result > 0)
00501 {
00502 if ((unsigned int)result >= outbuffer[0].length())
00503 {
00504
00505
00506
00507
00508
00509 outbuffer.pop_front();
00510 }
00511 else
00512 {
00513 std::string temp = outbuffer[0].substr(result);
00514 outbuffer[0] = temp;
00515
00516
00517
00518
00519
00520 errno = EAGAIN;
00521 }
00522 }
00523 else if (result == 0)
00524 {
00525 this->Instance->SE->DelFd(this);
00526 this->Close();
00527 return true;
00528 }
00529 else if ((result == -1) && (errno != EAGAIN))
00530 {
00531 this->OnError(I_ERR_WRITE);
00532 this->state = I_ERROR;
00533 this->Instance->SE->DelFd(this);
00534 this->Close();
00535 return true;
00536 }
00537 }
00538 }
00539 }
00540
00541 if ((errno == EAGAIN) && (fd > -1))
00542 {
00543 this->Instance->SE->WantWrite(this);
00544 }
00545
00546 return (fd < 0);
00547 }
00548
00549 void SocketTimeout::Tick(time_t)
00550 {
00551 ServerInstance->Logs->Log("SOCKET", DEBUG,"SocketTimeout::Tick");
00552
00553 if (ServerInstance->SE->GetRef(this->sfd) != this->sock)
00554 return;
00555
00556 if (this->sock->state == I_CONNECTING)
00557 {
00558
00559
00560
00561
00562 this->sock->OnTimeout();
00563 this->sock->OnError(I_ERR_TIMEOUT);
00564 this->sock->timeout = true;
00565
00566
00567
00568
00569
00570 this->sock->state = I_ERROR;
00571
00572 if (ServerInstance->SocketCull.find(this->sock) == ServerInstance->SocketCull.end())
00573 ServerInstance->SocketCull[this->sock] = this->sock;
00574 }
00575
00576 this->sock->Timeout = NULL;
00577 }
00578
00579 bool BufferedSocket::Poll()
00580 {
00581 int incoming = -1;
00582
00583 #ifndef WINDOWS
00584 if (!Instance->SE->BoundsCheckFd(this))
00585 return false;
00586 #endif
00587
00588 if (Instance->SE->GetRef(this->fd) != this)
00589 return false;
00590
00591 switch (this->state)
00592 {
00593 case I_CONNECTING:
00594
00595
00596
00597 #ifndef WINDOWS
00598 if (this->fd > -1)
00599 {
00600 this->Instance->SE->DelFd(this);
00601 if (!this->Instance->SE->AddFd(this))
00602 return false;
00603 }
00604 #endif
00605 this->SetState(I_CONNECTED);
00606
00607 if (Instance->Config->GetIOHook(this))
00608 {
00609 Instance->Logs->Log("SOCKET",DEBUG,"Hook for raw connect");
00610 try
00611 {
00612 Instance->Config->GetIOHook(this)->OnRawSocketConnect(this->fd);
00613 }
00614 catch (CoreException& modexcept)
00615 {
00616 Instance->Logs->Log("SOCKET",DEBUG,"%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason());
00617 }
00618 }
00619 return this->OnConnected();
00620 break;
00621 case I_LISTENING:
00622 {
00623
00624 sockaddr* client = new sockaddr[2];
00625 length = sizeof (sockaddr_in);
00626 std::string recvip;
00627 #ifdef IPV6
00628 if ((!*this->host) || strchr(this->host, ':'))
00629 length = sizeof(sockaddr_in6);
00630 #endif
00631 incoming = Instance->SE->Accept(this, client, &length);
00632 #ifdef IPV6
00633 if ((!*this->host) || strchr(this->host, ':'))
00634 {
00635 char buf[1024];
00636 recvip = inet_ntop(AF_INET6, &((sockaddr_in6*)client)->sin6_addr, buf, sizeof(buf));
00637 }
00638 else
00639 #endif
00640 {
00641
00642
00643 recvip = inet_ntoa(((sockaddr_in*)client)->sin_addr);
00644 }
00645
00646 Instance->SE->NonBlocking(incoming);
00647
00648 this->OnIncomingConnection(incoming, (char*)recvip.c_str());
00649
00650 if (this->IsIOHooked)
00651 {
00652 try
00653 {
00654 Instance->Config->GetIOHook(this)->OnRawSocketAccept(incoming, recvip.c_str(), this->port);
00655 }
00656 catch (CoreException& modexcept)
00657 {
00658 Instance->Logs->Log("SOCKET",DEBUG,"%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason());
00659 }
00660 }
00661
00662 this->SetQueues(incoming);
00663
00664 delete[] client;
00665 return true;
00666 }
00667 break;
00668 case I_CONNECTED:
00669
00670 return this->OnDataReady();
00671 break;
00672 default:
00673 break;
00674 }
00675 return true;
00676 }
00677
00678 void BufferedSocket::SetState(BufferedSocketState s)
00679 {
00680 this->state = s;
00681 }
00682
00683 BufferedSocketState BufferedSocket::GetState()
00684 {
00685 return this->state;
00686 }
00687
00688 int BufferedSocket::GetFd()
00689 {
00690 return this->fd;
00691 }
00692
00693 bool BufferedSocket::OnConnected() { return true; }
00694 void BufferedSocket::OnError(BufferedSocketError) { return; }
00695 int BufferedSocket::OnDisconnect() { return 0; }
00696 int BufferedSocket::OnIncomingConnection(int, char*) { return 0; }
00697 bool BufferedSocket::OnDataReady() { return true; }
00698 bool BufferedSocket::OnWriteReady() { return true; }
00699 void BufferedSocket::OnTimeout() { return; }
00700 void BufferedSocket::OnClose() { return; }
00701
00702 BufferedSocket::~BufferedSocket()
00703 {
00704 this->Close();
00705 if (Timeout)
00706 {
00707 Instance->Timers->DelTimer(Timeout);
00708 Timeout = NULL;
00709 }
00710 }
00711
00712 void BufferedSocket::HandleEvent(EventType et, int errornum)
00713 {
00714 switch (et)
00715 {
00716 case EVENT_ERROR:
00717 switch (errornum)
00718 {
00719 case ETIMEDOUT:
00720 this->OnError(I_ERR_TIMEOUT);
00721 break;
00722 case ECONNREFUSED:
00723 case 0:
00724 this->OnError(this->state == I_CONNECTING ? I_ERR_CONNECT : I_ERR_WRITE);
00725 break;
00726 case EADDRINUSE:
00727 this->OnError(I_ERR_BIND);
00728 break;
00729 case EPIPE:
00730 case EIO:
00731 this->OnError(I_ERR_WRITE);
00732 break;
00733 }
00734 if (this->Instance->SocketCull.find(this) == this->Instance->SocketCull.end())
00735 this->Instance->SocketCull[this] = this;
00736 return;
00737 break;
00738 case EVENT_READ:
00739 if (!this->Poll())
00740 {
00741 if (this->Instance->SocketCull.find(this) == this->Instance->SocketCull.end())
00742 this->Instance->SocketCull[this] = this;
00743 return;
00744 }
00745 break;
00746 case EVENT_WRITE:
00747 if (this->WaitingForWriteEvent)
00748 {
00749 this->WaitingForWriteEvent = false;
00750 if (!this->OnWriteReady())
00751 {
00752 if (this->Instance->SocketCull.find(this) == this->Instance->SocketCull.end())
00753 this->Instance->SocketCull[this] = this;
00754 return;
00755 }
00756 }
00757 if (this->state == I_CONNECTING)
00758 {
00759
00760
00761
00762
00763
00764
00765 this->HandleEvent(EVENT_READ);
00766 return;
00767 }
00768 else
00769 {
00770 if (this->FlushWriteBuffer())
00771 {
00772 if (this->Instance->SocketCull.find(this) == this->Instance->SocketCull.end())
00773 this->Instance->SocketCull[this] = this;
00774 return;
00775 }
00776 }
00777 break;
00778 }
00779 }
00780