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