make dm8000 blink pattern a bit nicer
[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
6 #include <lib/network/socket.h>
7
8 void eSocket::close()
9 {
10         if (writebuffer.empty())
11         {
12                 int wasconnected=(mystate==Connection) || (mystate==Closing);
13                 rsn=0;
14                 ::close(socketdesc);
15                 socketdesc=-1;
16                 mystate=Idle;
17                 if (wasconnected)
18                         connectionClosed_();
19         } else
20         {
21                 mystate=Closing;
22                 rsn->setRequested(rsn->getRequested()|eSocketNotifier::Write);
23         }
24 }
25
26 void eSocket::enableRead()
27 {
28         if (rsn)
29                 rsn->setRequested(rsn->getRequested()|eSocketNotifier::Read);
30 }
31
32 void eSocket::disableRead()
33 {
34         if (rsn)
35                 rsn->setRequested(rsn->getRequested()&~eSocketNotifier::Read);
36 }
37
38 void eSocket::inject(const char *data, int len)
39 {
40         readbuffer.write(data, len);
41         if (mystate == Connection)
42                 readyRead_();
43 }
44
45 std::string eSocket::readLine()
46 {
47         int size=readbuffer.searchchr('\n');
48         if (size == -1)
49                 return std::string();
50         size++; // ich will auch das \n
51         char buffer[size+1];
52         buffer[size]=0;
53         readbuffer.read(buffer, size);
54         return std::string(buffer);
55 }
56
57 bool eSocket::canReadLine()
58 {
59         return readbuffer.searchchr('\n') != -1;
60 }
61
62 int eSocket::bytesAvailable()
63 {
64         return readbuffer.size();
65 }
66
67 int eSocket::readBlock(char *data, unsigned int maxlen)
68 {
69         return readbuffer.read(data, maxlen);
70 }
71
72 int eSocket::bytesToWrite()
73 {
74         return writebuffer.size();
75 }
76
77 int eSocket::state()
78 {
79         return mystate;
80 }
81
82 int eSocket::setSocket(int s, int iss, eMainloop *ml)
83 {
84         socketdesc=s;
85         issocket=iss;
86         fcntl(socketdesc, F_SETFL, O_NONBLOCK);
87         last_break = 0xFFFFFFFF;
88
89         rsn = 0;
90         rsn=eSocketNotifier::create(ml, getDescriptor(), 
91                 eSocketNotifier::Read|eSocketNotifier::Hungup);
92         CONNECT(rsn->activated, eSocket::notifier);
93         return 0;
94 }
95
96 void eSocket::notifier(int what)
97 {
98         if ((what & eSocketNotifier::Read) && (mystate == Connection))
99         {
100                 int bytesavail=256;
101                 if (issocket)
102                         if (ioctl(getDescriptor(), FIONREAD, &bytesavail)<0)
103                                 eDebug("FIONREAD failed.\n");
104
105                 {
106                         if (issocket)
107                         {
108                                 if (!bytesavail)  // does the REMOTE END has closed the connection? (no Hungup here!)
109                                 {
110                                         writebuffer.clear();
111                                         close();
112                                         return;
113                                 }
114                         } else          // when operating on terminals, check for break
115                         {
116                                         // where is this struct defined?
117                                 struct async_icount {
118                                         unsigned long cts, dsr, rng, dcd, tx, rx;
119                                         unsigned long frame, parity, overrun, brk;
120                                         unsigned long buf_overrun;
121                                 } icount;
122
123                                 if (!ioctl(getDescriptor(), TIOCGICOUNT, &icount))
124                                 {
125                                         if (last_break == 0xFFFFFFFF)
126                                                 last_break = icount.brk;
127                                         else if (last_break != icount.brk)
128                                         {
129                                                 last_break = icount.brk;
130                                                 readbuffer.fromfile(getDescriptor(), bytesavail);
131                                                 readbuffer.clear();
132                                                 writebuffer.clear();
133                                                 rsn->setRequested(rsn->getRequested()&~eSocketNotifier::Write);
134                                                 write(getDescriptor(), "BREAK!", 6);
135                                                 hangup();
136                                                 return;
137                                         }
138                                 }
139                         }
140                         int r;
141                         if ((r=readbuffer.fromfile(getDescriptor(), bytesavail)) != bytesavail)
142                                 if (issocket)
143                                         eDebug("fromfile failed!");
144                         readyRead_();
145                 }
146         } else if (what & eSocketNotifier::Write)
147         {
148                 if ((mystate == Connection) || (mystate == Closing))
149                 {
150                         if (!writebuffer.empty())
151                         {
152                                 bytesWritten_(writebuffer.tofile(getDescriptor(), 65536));
153                                 if (writebuffer.empty())
154                                 {
155                                         rsn->setRequested(rsn->getRequested()&~eSocketNotifier::Write);
156                                         if (mystate == Closing)
157                                         {
158                                                 close();                // warning, we might get destroyed after close.
159                                                 return;
160                                         }
161                                 }
162                         } else
163                                 eDebug("got ready to write, but nothin in buffer. strange.");
164                         if (mystate == Closing)
165                                 close();
166                 } else if (mystate == Connecting)
167                 {
168                         mystate=Connection;
169                         rsn->setRequested(rsn->getRequested()&~eSocketNotifier::Write);
170                         
171                         int res;
172                         socklen_t size=sizeof(res);
173                         ::getsockopt(getDescriptor(), SOL_SOCKET, SO_ERROR, &res, &size);
174                         if (!res)
175                                 connected_();
176                         else
177                         {
178                                 close();
179                                 error_(res);
180                         }
181                 }
182         } else if (what & eSocketNotifier::Hungup)
183         {
184                 if (mystate == Connection)
185                 {
186                         writebuffer.clear();
187                         close();
188                 } else if (mystate == Connecting)
189                 {
190                         int res;
191                         socklen_t size=sizeof(res);
192                         ::getsockopt(getDescriptor(), SOL_SOCKET, SO_ERROR, &res, &size);
193                         close();
194                         error_(res);
195                 }
196         }
197 }
198
199 int eSocket::writeBlock(const char *data, unsigned int len)
200 {
201         int w=len;
202         if (issocket && writebuffer.empty())
203         {
204                 int tw=::send(getDescriptor(), data, len, MSG_NOSIGNAL);
205                 if ((tw < 0) && (errno != EWOULDBLOCK))
206                         eDebug("write: %m");
207                 
208                 if (tw < 0)
209                         tw = 0;
210                 data+=tw;
211                 len-=tw;
212         }
213         if (len)
214                 writebuffer.write(data, len);
215
216         if (!writebuffer.empty())
217                 rsn->setRequested(rsn->getRequested()|eSocketNotifier::Write);
218         return w;
219 }
220
221 int eSocket::getDescriptor()
222 {
223         return socketdesc;
224 }
225
226 int eSocket::connectToHost(std::string hostname, int port)
227 {
228         struct hostent *server;
229         int res;
230
231         if(!socketdesc){
232                 error_(errno);
233                 return(-1);
234         }
235         server=gethostbyname(hostname.c_str());
236         if(server==NULL)
237         {
238                 eDebug("can't resolve %s", hostname.c_str());
239                 error_(errno);
240                 return(-2);
241         }
242         bzero(  (char*)&serv_addr, sizeof(serv_addr));
243         serv_addr.sin_family=AF_INET;
244         bcopy(  (char*)server->h_addr,
245                 (char*)&serv_addr.sin_addr.s_addr,
246                 server->h_length);
247         serv_addr.sin_port=htons(port);
248         res=::connect(socketdesc, (const sockaddr*)&serv_addr, sizeof(serv_addr));
249         if ((res < 0) && (errno != EINPROGRESS))
250         {
251                 eDebug("can't connect to host: %s", hostname.c_str());
252                 close();
253                 error_(errno);
254                 return(-3);
255         }
256         if (res < 0)    // EINPROGRESS
257         {
258                 rsn->setRequested(rsn->getRequested()|eSocketNotifier::Write);
259                 mystate=Connecting;
260         } else
261         {
262                 mystate=Connection;
263                 connected_();
264         }
265         return(0);
266 }
267
268 eSocket::eSocket(eMainloop *ml): readbuffer(32768), writebuffer(32768), rsn(0)
269 {
270         ASSERT(ml);
271         int s=socket(AF_INET, SOCK_STREAM, 0);
272 #if 0
273         eDebug("[SOCKET]: initalized socket %d", socketdesc);
274 #endif
275         mystate=Idle;
276         setSocket(s, 1, ml);
277 }
278
279 eSocket::eSocket(int socket, int issocket, eMainloop *ml): readbuffer(32768), writebuffer(32768)
280 {
281         setSocket(socket, issocket, ml);
282         mystate=Connection;
283 }
284
285 eSocket::~eSocket()
286 {
287         if(socketdesc>=0)
288         {
289                 ::close(socketdesc);
290         }
291 }