1 // Copyright (c) 1999-2018 David Muse
2 // See the COPYING file for more information
3
4 #include <rudiments/protocolentry.h>
5 #include <rudiments/charstring.h>
6 #include <rudiments/bytestring.h>
7 #include <rudiments/error.h>
8 #include <rudiments/stdio.h>
9
10 #include <rudiments/private/winsock.h>
11
12 // for protoent, functions
13 #ifdef RUDIMENTS_HAVE_NETDB_H
14 #include <netdb.h>
15 #endif
16
17 #ifdef RUDIMENTS_HAVE_STDLIB_H
18 #include <stdlib.h>
19 #endif
20
21 #define MAXBUFFER (32*1024)
22
23 class protocolentryprivate {
24 friend class protocolentry;
25 private:
26 protoent *_pe;
27 #if defined(RUDIMENTS_HAVE_GETPROTOBYNAME_R) || \
28 defined(RUDIMENTS_HAVE_GETPROTOBYNUMBER_R)
29 protoent _pebuffer;
30 char *_buffer;
31 #endif
32 };
33
34 // LAME: not in the class
35 #if (!defined(RUDIMENTS_HAVE_GETPROTOBYNAME_R) || \
36 !defined(RUDIMENTS_HAVE_GETPROTOBYNUMBER_R))
37 static threadmutex *_pemutex;
38 #endif
39
protocolentry()40 protocolentry::protocolentry() {
41 pvt=new protocolentryprivate;
42 winsock::initWinsock();
43 pvt->_pe=NULL;
44 #if defined(RUDIMENTS_HAVE_GETPROTOBYNAME_R) && \
45 defined(RUDIMENTS_HAVE_GETPROTOBYNUMBER_R)
46 bytestring::zero(&pvt->_pebuffer,sizeof(pvt->_pebuffer));
47 pvt->_buffer=NULL;
48 #endif
49 }
50
protocolentry(const protocolentry & p)51 protocolentry::protocolentry(const protocolentry &p) {
52 pvt=new protocolentryprivate;
53 winsock::initWinsock();
54 initialize(p.getName());
55 }
56
operator =(const protocolentry & p)57 protocolentry &protocolentry::operator=(const protocolentry &p) {
58 if (this!=&p) {
59 initialize(p.getName());
60 }
61 return *this;
62 }
63
~protocolentry()64 protocolentry::~protocolentry() {
65 #if defined(RUDIMENTS_HAVE_GETPROTOBYNAME_R) && \
66 defined(RUDIMENTS_HAVE_GETPROTOBYNUMBER_R)
67 delete[] pvt->_buffer;
68 #endif
69 delete pvt;
70 }
71
getName() const72 const char *protocolentry::getName() const {
73 return (pvt->_pe)?pvt->_pe->p_name:NULL;
74 }
75
getAliasList() const76 const char * const *protocolentry::getAliasList() const {
77 return (pvt->_pe &&
78 pvt->_pe->p_aliases &&
79 pvt->_pe->p_aliases[0])?
80 pvt->_pe->p_aliases:NULL;
81 }
82
getNumber() const83 int32_t protocolentry::getNumber() const {
84 return (pvt->_pe)?pvt->_pe->p_proto:-1;
85 }
86
needsMutex()87 bool protocolentry::needsMutex() {
88 #if !defined(RUDIMENTS_HAVE_GETPROTOBYNAME_R) || \
89 !defined(RUDIMENTS_HAVE_GETPROTOBYNUMBER_R)
90 return true;
91 #else
92 return false;
93 #endif
94 }
95
setMutex(threadmutex * mtx)96 void protocolentry::setMutex(threadmutex *mtx) {
97 #if !defined(RUDIMENTS_HAVE_GETPROTOBYNAME_R) || \
98 !defined(RUDIMENTS_HAVE_GETPROTOBYNUMBER_R)
99 _pemutex=mtx;
100 #endif
101 }
102
initialize(const char * protocolname)103 bool protocolentry::initialize(const char *protocolname) {
104 return initialize(protocolname,-1);
105 }
106
initialize(int32_t number)107 bool protocolentry::initialize(int32_t number) {
108 return initialize(NULL,number);
109 }
110
initialize(const char * protocolname,int32_t number)111 bool protocolentry::initialize(const char *protocolname, int32_t number) {
112
113 pvt->_pe=NULL;
114 if (!protocolname && number==-1) {
115 return false;
116 }
117
118 #if defined(RUDIMENTS_HAVE_GETPROTOBYNAME_R) && \
119 defined(RUDIMENTS_HAVE_GETPROTOBYNUMBER_R)
120 delete[] pvt->_buffer;
121 pvt->_buffer=NULL;
122 // getprotobyname_r is goofy.
123 // It will retrieve an arbitrarily large amount of data, but
124 // requires that you pass it a pre-allocated buffer. If the
125 // buffer is too small, it returns an ENOMEM and you have to
126 // just make the buffer bigger and try again.
127 for (int32_t size=1024; size<MAXBUFFER; size=size+1024) {
128 pvt->_buffer=new char[size];
129 #if defined(RUDIMENTS_HAVE_GETPROTOBYNAME_R_5) && \
130 defined(RUDIMENTS_HAVE_GETPROTOBYNUMBER_R_5)
131 if (!((protocolname)
132 ?(getprotobyname_r(protocolname,
133 &pvt->_pebuffer,
134 pvt->_buffer,size,
135 &pvt->_pe))
136 :(getprotobynumber_r(number,
137 &pvt->_pebuffer,
138 pvt->_buffer,size,
139 &pvt->_pe)))) {
140 return (pvt->_pe!=NULL);
141 }
142 #elif defined(RUDIMENTS_HAVE_GETPROTOBYNAME_R_4) && \
143 defined(RUDIMENTS_HAVE_GETPROTOBYNUMBER_R_4)
144 if ((protocolname)
145 ?(pvt->_pe=getprotobyname_r(protocolname,
146 &pvt->_pebuffer,
147 pvt->_buffer,size))
148 :(pvt->_pe=getprotobynumber_r(number,
149 &pvt->_pebuffer,
150 pvt->_buffer,size))) {
151 return true;
152 }
153 #endif
154 delete[] pvt->_buffer;
155 pvt->_buffer=NULL;
156 pvt->_pe=NULL;
157 if (error::getErrorNumber()!=ENOMEM) {
158 return false;
159 }
160 }
161 return false;
162 #else
163 return (!(_pemutex && !_pemutex->lock())) &&
164 ((pvt->_pe=((protocolname)
165 ?getprotobyname(protocolname)
166 :getprotobynumber(number)))!=NULL) &&
167 !(_pemutex && !_pemutex->unlock());
168 #endif
169 }
170
getNumber(const char * protocolname)171 int32_t protocolentry::getNumber(const char *protocolname) {
172 protocolentry pe;
173 return (pe.initialize(protocolname))?pe.getNumber():-1;
174 }
175
getName(int32_t number)176 char *protocolentry::getName(int32_t number) {
177 protocolentry pe;
178 return (pe.initialize(number))?
179 charstring::duplicate(pe.getName()):NULL;
180 }
181