added timeout functionality
[my-code/api.git] / network / network.c
1 /* network.c -- network management stuff
2  *
3  * author: hackbard@hackdaworld.dyndns.org
4  *
5  */
6
7 #include "network.h"
8
9 int network_init(t_net *net,int outfd) {
10
11   dprintf(net->outfd,"[network] initializing network api ...\n");
12
13   memset(net->connection,0,MAX_CONNECTIONS*sizeof(t_connection));
14   net->c_count=0;
15   net->sendmask=0;
16   net->outfd=outfd;
17
18   return N_SUCCESS;
19 }
20
21 int network_set_timeout_chan(t_net *net,int chan,int read,int write) {
22
23   struct timeval to;
24   socklen_t len;
25
26   len=sizeof(struct timeval);
27
28   to.tv_usec=0;
29
30   to.tv_sec=read;
31   setsockopt(net->connection[chan].fd,SOL_SOCKET,SO_RCVTIMEO,&to,len);
32   to.tv_sec=write;
33   setsockopt(net->connection[chan].fd,SOL_SOCKET,SO_SNDTIMEO,&to,len);
34
35   return N_SUCCESS;
36 }
37
38 int network_listen(t_net *net) {
39   
40   struct sockaddr_in addr;
41   int true;
42
43   if((net->l_fd=socket(AF_INET,SOCK_STREAM,0))==-1) {
44     perror("[network] socket call");
45     return N_ERROR;
46   }
47
48   memset(&addr,0,sizeof(struct sockaddr));
49   addr.sin_family=AF_INET;
50   addr.sin_port=htons(net->l_port);
51   addr.sin_addr.s_addr=INADDR_ANY;
52
53   if(bind(net->l_fd,(struct sockaddr *)&addr,
54           sizeof(struct sockaddr))==-1) {
55     /* try harder ... */
56     true=1;
57     if(setsockopt(net->l_fd,SOL_SOCKET,SO_REUSEADDR,&true,sizeof(true))==-1) {
58       perror("[network] setsockopt call");
59       return N_ERROR;
60     }
61     dprintf(net->outfd,"[network] reused address\n");
62   }
63
64   if(listen(net->l_fd,MAX_LISTEN_QUEUE)==-1) {
65     perror("[network] listen call");
66     return N_ERROR;
67   }
68
69   dprintf(net->outfd,"[network] listen on %s port %d\n",
70           inet_ntoa(addr.sin_addr),net->l_port);
71
72   return N_SUCCESS;
73 }
74
75 int network_shutdown(t_net *net) {
76
77   int channel;
78
79   for(channel=0;channel<MAX_CONNECTIONS;channel++)
80     if(net->connection[channel].status&C_SOCKET)
81       close(net->connection[channel].fd);
82
83   if(close(net->l_fd)==-1) {
84     perror("[network] close call");
85     return N_ERROR;
86   }
87
88   dprintf(net->outfd,"[network] shutdown\n");
89
90   return N_SUCCESS;
91 }
92
93 int network_set_listen_port(t_net *net,in_port_t port) {
94
95   net->l_port=port;
96
97   return N_SUCCESS;
98 }
99
100 int network_manage_connection(t_net *net) {
101
102   int i;
103   struct sockaddr_in addr;
104   
105   for(i=0;i<MAX_CONNECTIONS;i++) {
106
107     if(net->connection[i].status&C_IN_USE) {
108
109       if(net->connection[i].status&C_HANGUP) {
110         if(close(net->connection[i].fd)==-1) {
111           perror("[network] close call");
112           return N_E_CLOSE;
113         }
114         dprintf(net->outfd,"[network] connection %d closed\n",i);
115         net->connection[i].status=0;
116       }
117
118       if(net->connection[i].status&C_INFO_A) {
119
120         if(!(net->connection[i].status&C_SOCKET)) {
121           if((net->connection[i].fd=socket(AF_INET,SOCK_STREAM,0))==-1) {
122             perror("[network] socket call");
123             return N_ERROR;
124           }
125           net->connection[i].status|=C_SOCKET;
126         }
127
128         if((!(net->connection[i].status&C_ESTABL))&&
129            (net->connection[i].status&C_SOCKET)) {
130
131           memset(&addr,0,sizeof(struct sockaddr));
132           addr.sin_family=AF_INET;
133           addr.sin_port=htons(net->connection[i].port);
134           if(!inet_aton(net->connection[i].ip,&(addr.sin_addr))) {
135             perror("[network] inet_aton call");
136             return N_ERROR;
137           }
138           
139           if(connect(net->connection[i].fd,(struct sockaddr *)&addr,
140                      sizeof(struct sockaddr))==-1) {
141             perror("[network] connect call");
142             return N_E_CONNECT;
143           }
144
145           dprintf(net->outfd,"[network] established connection to ");
146           dprintf(net->outfd,"%s port %d on channel %d\n",
147                   net->connection[i].ip,net->connection[i].port,i);
148           net->connection[i].status|=C_ESTABL;
149
150         }
151
152       }
153
154     }
155
156   }
157
158   return N_SUCCESS;
159 }
160
161 int network_connect(t_net *net,int channel) {
162
163   if(net->connection[channel].status&C_IN_USE) {
164     dprintf(net->outfd,"[network] connect failed, channel %02d in use\n",
165             channel);
166     return N_E_IN_USE;
167   }
168   if(!(net->connection[channel].status&C_INFO_A)) {
169     dprintf(net->outfd,
170             "[network] connect failed, missing config for chan %02d\n",channel);
171     return N_E_NO_INFO;
172   }
173
174   /* try connect & return result */
175   net->connection[channel].status|=C_IN_USE;
176   return(network_manage_connection(net)); /* could be other channel too */
177 }
178
179 int network_close(t_net *net,int channel) {
180
181   if(!(net->connection[channel].status&C_ESTABL)) {
182     dprintf(net->outfd,"[network] close failed, channel %02d not active\n",
183             channel);
184     return N_E_NC;
185   }
186   
187   net->connection[channel].status|=C_HANGUP;
188   return(network_manage_connection(net)); /* could be other channel too */
189 }
190
191 int network_close_all(t_net *net) {
192
193   int channel;
194
195   for(channel=0;channel<MAX_CONNECTIONS;channel++)
196     if(net->connection[channel].status&C_ESTABL) network_close(net,channel);
197
198   return N_SUCCESS;
199 }
200
201 int network_set_connection_info(t_net *net,int channel,char *ip,int port) {
202
203   if(net->connection[channel].status&C_IN_USE) {
204     dprintf(net->outfd,
205             "[network] set connection failed, channel %02d in use\n",channel);
206     return N_E_IN_USE;
207   }
208
209   strncpy(net->connection[channel].ip,ip,IP_DIGITS);
210   net->connection[channel].port=port;
211   net->connection[channel].status|=C_INFO_A;
212
213   return N_SUCCESS;
214 }
215
216 int network_select(t_net *net,int channel) {
217
218   int mask;
219
220   if(channel==MAX_CONNECTIONS) mask=0xffffffff;
221   else mask=(1<<channel);
222   net->sendmask|=mask;
223
224   return N_SUCCESS;
225 }
226
227 int network_deselect(t_net *net,int channel) {
228
229   int mask;
230
231   if(channel==MAX_CONNECTIONS) mask=0;
232   else mask=~(1<<channel);
233   net->sendmask&=mask;
234
235   return N_SUCCESS;
236 }
237
238 int network_manage_incoming(t_net *net) {
239
240   int channel;
241   struct sockaddr_in addr;
242   int len;
243
244   for(channel=0;channel<MAX_CONNECTIONS;channel++) {
245     if(!(net->connection[channel].status&C_IN_USE)) {
246       if((net->connection[channel].fd=accept(net->l_fd,
247                                        (struct sockaddr *)&addr,
248                                        &len))==-1) {
249         perror("[network] accept call");
250         return N_E_ACCEPT;
251       }
252       strncpy(net->connection[channel].ip,inet_ntoa(addr.sin_addr),IP_DIGITS);
253       net->connection[channel].port=ntohs(addr.sin_port);
254       net->connection[channel].status=C_IN_USE|C_INFO_A|C_SOCKET|C_ESTABL;
255       dprintf(net->outfd,
256               "[network] established connection from %s:%d, channel %d\n",
257               net->connection[channel].ip,net->connection[channel].port,
258               channel);
259       return channel;
260     }
261   }
262
263   dprintf(net->outfd,"[network] maximum connections reached\n");
264   return N_E_MAXC;
265 }
266  
267 int network_send(int fd,unsigned char *data,int datasize) {
268
269   int count,left;
270
271   count=0;
272   left=datasize;
273
274   while(left) {
275     if((count=write(fd,data+datasize-left,left))==-1) {
276       perror("[network] write call");
277       return N_ERROR;
278     }
279     left-=count;
280   }
281
282   return N_SUCCESS;
283 }
284
285 int network_send_chan(t_net *net,int chan,unsigned char *data,int datasize) {
286
287   return(network_send(net->connection[chan].fd,data,datasize));
288 }
289
290 int network_receive(int fd,unsigned char *data,int datasize) {
291
292   int count,left;
293
294   count=0;
295   left=datasize;
296
297   while(left) {
298     if((count=read(fd,data,datasize))==-1) {
299       perror("[network] read call");
300       return N_ERROR;
301     }
302     left-=count;
303   }
304
305   return datasize;
306 }
307
308 int network_receive_chan(t_net *net,int chan,unsigned char *data,int datasize) {
309
310   return(network_receive(net->connection[chan].fd,data,datasize));
311 }
312
313 int network_udp_listen_init(t_net *net) {
314
315   struct sockaddr_in addr;
316   int true;
317
318   if((net->l_udp_fd=socket(AF_INET,SOCK_DGRAM,0))==-1) {
319     perror("[network] socket call (udp-receive)");
320     return N_ERROR;
321   }
322
323   memset(&addr,0,sizeof(struct sockaddr));
324   addr.sin_family=AF_INET;
325   addr.sin_port=htons(net->l_udp_port);
326   addr.sin_addr.s_addr=INADDR_ANY;
327   if(bind(net->l_udp_fd,(struct sockaddr *)&addr,sizeof(struct sockaddr))==-1) {
328     /* try harder ... */
329     true=1;
330     if(setsockopt(net->l_udp_fd,SOL_SOCKET,SO_REUSEADDR,
331                   &true,sizeof(true))==-1) {
332       perror("[network] setsockopt call (udp)");
333       return N_ERROR;
334     }
335     dprintf(net->outfd,"[network] reused address (udp)\n");
336   }
337
338   dprintf(net->outfd,"[network] listening on port %d (udp)\n",
339           net->l_udp_port);
340
341   if((net->s_udp_fd=socket(AF_INET,SOCK_DGRAM,0))==-1) {
342     perror("[network] socket call (udp-send)");
343     return N_ERROR;
344   }
345
346   return N_SUCCESS;
347 }
348
349 int network_udp_receive(t_net *net,int channel, unsigned char *data,int count) {
350
351   struct sockaddr_in addr;
352   socklen_t len;
353
354   if((count=recvfrom(net->l_udp_fd,data,count,0,
355                      (struct sockaddr *)&addr,&len))==-1) {
356     perror("[network] recvfrom call");
357     return N_ERROR;
358   }
359
360   if(strncmp(net->connection[channel].ip,inet_ntoa(addr.sin_addr),IP_DIGITS)) {
361     dprintf(net->outfd,"[network] packet from unknown: %s\n",
362             inet_ntoa(addr.sin_addr));
363     return N_UDP_WRONG_SENDER;
364   }
365
366   return N_SUCCESS;
367 }
368
369 int network_udp_send(t_net *net,int channel, unsigned char *data,int size) {
370
371   int count,left;
372   struct sockaddr_in addr;
373
374   count=0;
375   left=count;
376
377   memset(&addr,0,sizeof(struct sockaddr));
378   addr.sin_family=AF_INET;
379   addr.sin_port=htons(net->l_udp_port);
380   inet_aton(net->connection[channel].ip,&(addr.sin_addr));
381
382   while(left) {
383     if((count=sendto(net->s_udp_fd,data+size-left,left,0,
384                      (struct sockaddr *)&addr,sizeof(struct sockaddr)))==-1) {
385       perror("[network] sendto call");
386       return N_ERROR;
387     }
388     left-=count;
389   }
390
391   return N_SUCCESS;
392 }
393
394 int network_udp_shutdown(t_net *net) {
395   
396   if(close(net->l_udp_fd)==-1) {
397     perror("[network] close call (udp-receive)");
398     return N_ERROR;
399   }
400
401   if(close(net->s_udp_fd)==-1) {
402     perror("[network] close call (udp-send)");
403     return N_ERROR;
404   }
405
406   return N_SUCCESS;
407 }