1 /*
2  *
3  *  C++ Portable Types Library (PTypes)
4  *  Version 2.1.1  Released 27-Jun-2007
5  *
6  *  Copyright (C) 2001-2007 Hovik Melikyan
7  *
8  *  http://www.melikyan.com/ptypes/
9  *
10  */
11 
12 #ifdef WIN32
13 #  include <winsock2.h>
14 #else
15 #  include <sys/time.h>
16 #  include <sys/types.h>
17 #  include <sys/socket.h>
18 #  include <netinet/in.h>
19 #  include <arpa/inet.h>
20 #  include <netdb.h>
21 #  include <unistd.h>
22 #  include <time.h>
23 #endif
24 
25 #include "pinet.h"
26 
27 
28 PTYPES_BEGIN
29 
30 
31 //
32 // ipbindinfo
33 //
34 
35 
ipbindinfo(ipaddress iip,const string & ihost,int iport)36 ipbindinfo::ipbindinfo(ipaddress iip, const string& ihost, int iport)
37     : unknown(), ippeerinfo(iip, ihost, iport), handle(invhandle)
38 {
39 }
40 
41 
~ipbindinfo()42 ipbindinfo::~ipbindinfo()
43 {
44 }
45 
46 
47 //
48 // ipsvbase
49 //
50 
51 
ipsvbase(int isocktype)52 ipsvbase::ipsvbase(int isocktype)
53     : socktype(isocktype), active(false), addrlist(true)  {}
54 
55 
~ipsvbase()56 ipsvbase::~ipsvbase()
57 {
58     close();
59 }
60 
61 
error(ippeerinfo & p,int code,const char * defmsg)62 void ipsvbase::error(ippeerinfo& p, int code, const char* defmsg)
63 {
64     string msg = usockerrmsg(code);
65     if (isempty(msg))
66         msg = defmsg;
67     msg += " [" + p.asstring(true) + ']';
68     throw new estream(nil, code, msg);
69 }
70 
71 
bind(ipaddress ip,int port)72 int ipsvbase::bind(ipaddress ip, int port)
73 {
74     close();
75     addrlist.add(new ipbindinfo(ip, nullstring, port));
76     return addrlist.get_count() - 1;
77 }
78 
79 
bindall(int port)80 int ipsvbase::bindall(int port)
81 {
82     close();
83     return bind(ipany, port);
84 }
85 
86 
clear()87 void ipsvbase::clear()
88 {
89     close();
90     addrlist.clear();
91 }
92 
93 
open()94 void ipsvbase::open()
95 {
96     close();
97     if (addrlist.get_count() == 0)
98         fatal(CRIT_FIRST + 52, "No addresses specified to bind to");
99     active = true;
100     for (int i = 0; i < addrlist.get_count(); i++)
101     {
102         ipbindinfo* b = addrlist[i];
103         b->handle = ::socket(AF_INET, socktype, 0);
104         if (b->handle < 0)
105             error(*b, usockerrno(), "Couldn't create socket");
106         sockopt(b->handle);
107         dobind(b);
108     }
109 }
110 
111 
close()112 void ipsvbase::close()
113 {
114     if (!active)
115         return;
116     for (int i = 0; i < addrlist.get_count(); i++)
117     {
118         ipbindinfo* b = addrlist[i];
119         ::closesocket(pexchange(&b->handle, invhandle));
120     }
121     active = false;
122 }
123 
124 
dopoll(int * i,int timeout)125 bool ipsvbase::dopoll(int* i, int timeout)
126 {
127     fd_set set;
128     setupfds(&set, *i);
129     timeval t;
130     t.tv_sec = timeout / 1000;
131     t.tv_usec = (timeout % 1000) * 1000;
132     if (::select(FD_SETSIZE, &set, nil, nil, (timeout < 0) ? nil : &t) > 0)
133     {
134         if (*i >= 0)
135             return true;
136         // if the user selected -1 (all), find the socket which has a pending connection
137         // and assign it to i
138         for (int j = 0; j < addrlist.get_count(); j++)
139             if (FD_ISSET(uint(addrlist[j]->handle), &set))
140             {
141                 *i = j;
142                 return true;
143             }
144     }
145     return false;
146 }
147 
148 
setupfds(void * set,int i)149 void ipsvbase::setupfds(void* set, int i)
150 {
151 #ifdef _MSC_VER
152 // disable "condition always true" warning caused by Microsoft's FD_SET macro
153 #  pragma warning (disable: 4127)
154 #endif
155     FD_ZERO((fd_set*)set);
156     if (i >= 0)
157     {
158         int h = get_addr(i).handle;
159         if (h >= 0)
160             FD_SET((uint)h, (fd_set*)set);
161     }
162     else
163         for (i = 0; i < addrlist.get_count(); i++)
164         {
165             int h = addrlist[i]->handle;
166             if (h >= 0)
167                 FD_SET((uint)h, (fd_set*)set);
168         }
169 }
170 
171 
sockopt(int)172 void ipsvbase::sockopt(int)
173 {
174 }
175 
176 
177 PTYPES_END
178