Merge pull request #121 from Dima73/timer
[openblackhole/openblackhole-enigma2.git] / lib / network / socket.cpp
1 #include <sys/ioctl.h>
2 #include <asm/ioctls.h>
3 #include <unistd.h>
4 #include <errno.h>
5 #include <time.h>
6 #include <string.h>
7 #include <linux/serial.h>
8 #include <lib/network/socket.h>
9
10 void eSocket::close()
11 {
12         if (writebuffer.empty())
13         {
14                 int wasconnected = (mystate == Connection) || (mystate == Closing);
15                 rsn = 0;
16                 if (socketdesc >= 0)
17                 {
18                         ::close(socketdesc);
19                         socketdesc = -1;
20                 }
21                 mystate = Invalid;
22                 if (wasconnected)
23                         connectionClosed_();
24         } else
25         {
26                 mystate = Closing;
27                 rsn->setRequested(rsn->getRequested()|eSocketNotifier::Write);
28         }
29 }
30
31 void eSocket::enableRead()
32 {
33         if (rsn)
34                 rsn->setRequested(rsn->getRequested()|eSocketNotifier::Read);
35 }
36
37 void eSocket::disableRead()
38 {
39         if (rsn)
40                 rsn->setRequested(rsn->getRequested()&~eSocketNotifier::Read);
41 }
42
43 void eSocket::inject(const char *data, int len)
44 {
45         readbuffer.write(data, len);
46         if (mystate == Connection)
47                 readyRead_();
48 }
49
50 std::string eSocket::readLine()
51 {
52         int size=readbuffer.searchchr('\n');
53         if (size == -1)
54                 return std::string();
55         size++; // ich will auch das \n
56         char buffer[size+1];
57         buffer[size]=0;
58         readbuffer.read(buffer, size);
59         return std::string(buffer);
60 }
61
62 bool eSocket::canReadLine()
63 {
64         return readbuffer.searchchr('\n') != -1;
65 }
66
67 int eSocket::bytesAvailable()
68 {
69         return readbuffer.size();
70 }
71
72 int eSocket::readBlock(char *data, unsigned int maxlen)
73 {
74         return readbuffer.read(data, maxlen);
75 }
76
77 int eSocket::bytesToWrite()
78 {
79         return writebuffer.size();
80 }
81
82 int eSocket::state()
83 {
84         return mystate;
85 }
86
87 int eSocket::setSocket(int s, int iss)
88 {
89         socketdesc = s;
90         if (socketdesc < 0) return -1;
91         issocket = iss;
92         fcntl(socketdesc, F_SETFL, O_NONBLOCK);
93         last_break = -1;
94
95         rsn = 0;
96         rsn = eSocketNotifier::create(mainloop, getDescriptor(),
97                 eSocketNotifier::Read|eSocketNotifier::Hungup);
98         CONNECT(rsn->activated, eSocket::notifier);
99         return 0;
100 }
101
102 void eSocket::notifier(int what)
103 {
104         if ((what & eSocketNotifier::Read) && (mystate == Connection))
105         {
106                 int bytesavail=256;
107                 if (issocket)
108                         if (ioctl(getDescriptor(), FIONREAD, &bytesavail)<0)
109                                 eDebug("[eSocket] FIONREAD failed.\n");
110
111                 {
112                         if (issocket)
113                         {
114                                 if (!bytesavail)  // does the REMOTE END has closed the connection? (no Hungup here!)
115                                 {
116                                         writebuffer.clear();
117                                         close();
118                                         return;
119                                 }
120                         }
121                         else            // when operating on terminals, check for break
122                         {
123                                 serial_icounter_struct icount;
124                                 memset(&icount, 0, sizeof(icount));
125                                 if (!ioctl(getDescriptor(), TIOCGICOUNT, &icount))
126                                 {
127                                         if (last_break == -1)
128                                                 last_break = icount.brk;
129                                         else if (last_break != icount.brk)
130                                         {
131                                                 last_break = icount.brk;
132                                                 readbuffer.fromfile(getDescriptor(), bytesavail);
133                                                 readbuffer.clear();
134                                                 writebuffer.clear();
135                                                 rsn->setRequested(rsn->getRequested()&~eSocketNotifier::Write);
136                                                 write(getDescriptor(), "BREAK!", 6);
137                                                 hangup();
138                                                 return;
139                                         }
140                                 }
141                                 else
142                                         eDebug("[eSocket] TIOCGICOUNT failed: %m");
143                         }
144                         int r;
145                         if ((r=readbuffer.fromfile(getDescriptor(), bytesavail)) != bytesavail)
146                                 if (issocket)
147                                         eDebug("[eSocket] fromfile failed!");
148                         readyRead_();
149                 }
150         } else if (what & eSocketNotifier::Write)
151         {
152                 if ((mystate == Connection) || (mystate == Closing))
153                 {
154                         if (!writebuffer.empty())
155                         {
156                                 bytesWritten_(writebuffer.tofile(getDescriptor(), 65536));
157                                 if (writebuffer.empty())
158                                 {
159                                         rsn->setRequested(rsn->getRequested()&~eSocketNotifier::Write);
160                                         if (mystate == Closing)
161                                         {
162                                                 close();                // warning, we might get destroyed after close.
163                                                 return;
164                                         }
165                                 }
166                         } else
167                                 eDebug("[eSocket] got ready to write, but nothin in buffer. strange.");
168                         if (mystate == Closing)
169                                 close();
170                 } else if (mystate == Connecting)
171                 {
172                         mystate=Connection;
173                         rsn->setRequested(rsn->getRequested()&~eSocketNotifier::Write);
174
175                         int res;
176                         socklen_t size=sizeof(res);
177                         ::getsockopt(getDescriptor(), SOL_SOCKET, SO_ERROR, &res, &size);
178                         if (!res)
179                                 connected_();
180                         else
181                         {
182                                 close();
183                                 error_(res);
184                         }
185                 }
186         } else if (what & eSocketNotifier::Hungup)
187         {
188                 if (mystate == Connection || (mystate == Closing && issocket) )
189                 {
190                         writebuffer.clear();
191                         close();
192                 } else if (mystate == Connecting)
193                 {
194                         int res;
195                         socklen_t size=sizeof(res);
196                         ::getsockopt(getDescriptor(), SOL_SOCKET, SO_ERROR, &res, &size);
197                         close();
198                         error_(res);
199                 }
200         }
201 }
202
203 int eSocket::writeBlock(const char *data, unsigned int len)
204 {
205         int err=0;
206         int w=len;
207         if (issocket && writebuffer.empty())
208         {
209                 int tw=::send(getDescriptor(), data, len, MSG_NOSIGNAL);
210                 if ((tw < 0) && (errno != EWOULDBLOCK)) {
211         // don't use eDebug here because of a adaptive mutex in the eDebug call..
212         // and eDebug self can cause a call of writeBlock !!
213                         struct timespec tp;
214                         clock_gettime(CLOCK_MONOTONIC, &tp);
215                         fprintf(stderr, "<%6lu.%06lu> [eSocket] write: %m\n", tp.tv_sec, tp.tv_nsec/1000);
216                 }
217                 if (tw < 0)
218                         tw = 0;
219                 data+=tw;
220                 len-=tw;
221         }
222         if (len && !err)
223                 writebuffer.write(data, len);
224
225         if (!writebuffer.empty())
226                 rsn->setRequested(rsn->getRequested()|eSocketNotifier::Write);
227         return w;
228 }
229
230 int eSocket::connect(struct addrinfo *addr)
231 {
232         int res;
233         struct addrinfo *ptr = addr;
234         close();
235         for (ptr = addr; ptr != NULL; ptr = ptr->ai_next)
236         {
237                 if (setSocket(socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol), 1) < 0)
238                 {
239                         /* No need to close, setSocket only fails when socket() already failed */
240                         continue;
241                 }
242                 mystate = Idle;
243
244                 res = ::connect(socketdesc, ptr->ai_addr, ptr->ai_addrlen);
245                 if ((res < 0) && (errno != EINPROGRESS) && (errno != EINTR))
246                 {
247                         error_(errno);
248                         close(); /* Release and disconnect the notifier */
249                         continue;
250                 }
251                 if (res < 0)    // EINPROGRESS or EINTR
252                 {
253                         rsn->setRequested(rsn->getRequested() | eSocketNotifier::Write);
254                         mystate = Connecting;
255                         return 0;
256                 }
257                 else
258                 {
259                         mystate = Connection;
260                         connected_();
261                         return 1;
262                 }
263         }
264         return -1;
265 }
266
267 int eSocket::connectToHost(std::string hostname, int port)
268 {
269         int res;
270         struct addrinfo *addr = NULL;
271         struct addrinfo hints;
272         char portnumber[16];
273
274         memset(&hints, 0, sizeof(hints));
275         hints.ai_family = AF_UNSPEC; /* both ipv4 and ipv6 */
276         hints.ai_socktype = SOCK_STREAM;
277         hints.ai_protocol = 0; /* any */
278 #ifdef AI_ADDRCONFIG
279         hints.ai_flags = AI_NUMERICSERV | AI_ADDRCONFIG; /* only return ipv6 if we have an ipv6 address ourselves, and ipv4 if we have an ipv4 address ourselves */
280 #else
281         hints.ai_flags = AI_NUMERICSERV; /* AI_ADDRCONFIG is not available */
282 #endif
283         snprintf(portnumber, sizeof(portnumber), "%d", port);
284
285         if ((res = getaddrinfo(hostname.c_str(), portnumber, &hints, &addr)) || !addr)
286         {
287                 eDebug("[eSocket] can't resolve %s (getaddrinfo: %s)", hostname.c_str(), gai_strerror(res));
288                 return -2;
289         }
290
291         res = connect(addr);
292         if (res < 0)
293         {
294                 eDebug("[eSocket] can't connect to host: %s", hostname.c_str());
295         }
296         freeaddrinfo(addr);
297         return res;
298 }
299
300 eSocket::eSocket(eMainloop *ml): readbuffer(32768), writebuffer(32768), mainloop(ml)
301 {
302         socketdesc = -1;
303         mystate = Invalid;
304 }
305
306 eSocket::eSocket(int socket, int issocket, eMainloop *ml): readbuffer(32768), writebuffer(32768), mainloop(ml)
307 {
308         setSocket(socket, issocket);
309         mystate = Connection;
310 }
311
312 eSocket::~eSocket()
313 {
314         if (socketdesc >= 0)
315         {
316                 ::close(socketdesc);
317                 socketdesc = -1;
318         }
319 }
320
321 eUnixDomainSocket::eUnixDomainSocket(eMainloop *ml) : eSocket(ml)
322 {
323 }
324
325 eUnixDomainSocket::eUnixDomainSocket(int socket, int issocket, eMainloop *ml) : eSocket(socket, issocket, ml)
326 {
327 }
328
329 eUnixDomainSocket::~eUnixDomainSocket()
330 {
331 }
332
333 int eUnixDomainSocket::connectToPath(std::string path)
334 {
335         int res;
336         struct sockaddr_un serv_addr_un;
337         struct addrinfo addr;
338
339         memset(&serv_addr_un, 0, sizeof(serv_addr_un));
340         serv_addr_un.sun_family = AF_LOCAL;
341         strcpy(serv_addr_un.sun_path, path.c_str());
342
343         memset(&addr, 0, sizeof(addr));
344         addr.ai_family = AF_LOCAL;
345         addr.ai_socktype = SOCK_STREAM;
346         addr.ai_protocol = 0; /* any */
347         addr.ai_addr = (struct sockaddr *)&serv_addr_un;
348         addr.ai_addrlen = sizeof(serv_addr_un);
349
350         res = connect(&addr);
351         return res;
352 }