]> git.lizzy.rs Git - rudp.git/blob - rudp_punch.c
Switch to CMake
[rudp.git] / rudp_punch.c
1 #include <string.h>
2 #include "rudp_punch.h"
3
4 /*
5  * \param local_port 
6  *      Local port the socket will bind to(but not listen on).
7  * \param listening_peer 
8  *      The address the other side listening on, may be NULL.
9  * \param candidate_peers, n_peer
10  *      The possible addresses the other side can be reached by.
11  */
12 RUDPSOCKET RUDPPunch(unsigned short local_port, 
13                 const struct sockaddr *listening_peer, 
14                 const struct sockaddr_in *candidate_peers, int n_peer, 
15                 CHECKCONNECTIONCB cb, void *cb_data)
16 {
17 #define MAX_CANDIDATES 10
18         RUDPSOCKET rsock_c = INVALID_RUDPSOCKET, rsocks[MAX_CANDIDATES];
19         RUDPSOCKCHNO rset[MAX_CANDIDATES], wset[MAX_CANDIDATES], eset[MAX_CANDIDATES];
20         int n_rset, n_wset, n_eset, nr, nw, ne;
21         struct timeval tv;
22         struct sockaddr_in sai;
23         int i, opt;
24
25         if(n_peer > 9) n_peer = 9;
26         if(listening_peer) n_peer++;
27
28         memset(&sai, 0, sizeof(sai));
29         sai.sin_family = AF_INET;
30         sai.sin_port = htons(local_port);
31         opt = 1;
32         n_rset = n_wset = n_eset = 0;
33         for(i=0; i<n_peer; i++)
34         {
35                 rsocks[i] = RUDPSocket();
36                 RUDPSetSockOpt(rsocks[i], OPT_REUSEADDR, &opt, sizeof(int));
37                 if(RUDPBind(rsocks[i], (struct sockaddr*)&sai, sizeof(sai)) != 0)
38                 {
39                         dbg_msg("RUDPBind failed.\n");
40                 }
41                 RUDPSetSockOpt(rsocks[i], OPT_NBLK, &opt, sizeof(int));
42                 if(i==n_peer-1 && listening_peer)
43                 {
44                         RUDPConnect(rsocks[i], listening_peer, sizeof(struct sockaddr));
45                         rsock_c = rsocks[i];
46                 }
47                 else
48                         RUDPConnect(rsocks[i], (const struct sockaddr*)&candidate_peers[i], sizeof(struct sockaddr));
49
50                 RUDP_SET(rsocks[i], -1, eset, n_eset);
51                 RUDP_SET(rsocks[i], -1, rset, n_rset);
52         }
53
54
55         tv.tv_sec = 1; tv.tv_usec = 0;
56         time_t t0 = time(NULL);
57         do {
58
59                 nr = n_rset; nw = n_wset; ne = n_eset;
60                 if(RUDPSelect(rset, &nr, wset, &nw, eset, &ne, &tv) <= 0)
61                         continue;
62
63                 for(i=0; i<n_peer; i++)
64                         if(rsocks[i] != INVALID_RUDPSOCKET && RUDP_ISSET(rsocks[i], rset, nr))  //data arrived
65                         {
66                                 switch(cb(rsocks[i], CONNSTATUS_READABLE, cb_data))
67                                 {
68                                 case CHECKCONNECTION_OK:
69                                         rsock_c = rsocks[i];
70                                         rsocks[i] = INVALID_RUDPSOCKET;
71                                         goto out;
72
73                                 case CHECKCONNECTION_FAKE:
74                                         RUDPClose(rsocks[i]);
75                                         rsocks[i] = INVALID_RUDPSOCKET;
76                                         break;
77                                 }
78                         }
79
80                 for(i=0; i<n_peer; i++)
81                         if(rsocks[i] != INVALID_RUDPSOCKET && RUDP_ISSET(rsocks[i], wset, nw))  //connected
82                         {
83                                 switch(cb(rsocks[i], (i==n_peer-1)&&listening_peer?CONNSTATUS_ACCEPTED:CONNSTATUS_CONNECTED, cb_data))
84                                 {
85                                 case CHECKCONNECTION_OK:
86                                         rsock_c = rsocks[i];
87                                         rsocks[i] = INVALID_RUDPSOCKET;
88                                         goto out;
89                                         
90                                 case CHECKCONNECTION_CONTINUE:
91                                         RUDP_SET(rsocks[i], 0, rset, n_rset);
92                                         RUDP_CLR(rsocks[i], 0, wset, n_wset);
93                                         break;
94
95                                 case CHECKCONNECTION_FAKE:
96                                         RUDPClose(rsocks[i]);
97                                         rsocks[i] = INVALID_RUDPSOCKET;
98                                         break;
99                                 }
100                         }
101
102                 for(i=0; i<n_peer; i++)
103                         if(rsocks[i] != INVALID_RUDPSOCKET && RUDP_ISSET(rsocks[i], eset, ne))
104                         {
105                                 if(i==n_peer-1 && listening_peer)
106                                 {
107                                         RUDPConnect(rsocks[i], listening_peer, sizeof(struct sockaddr));
108                                 }
109                                 else
110                                         RUDPConnect(rsocks[i], (const struct sockaddr*)&candidate_peers[i], sizeof(struct sockaddr));
111                         }
112
113         } while(time(NULL) - t0 < 8);
114
115 out:
116         for(i=0; i<n_peer; i++)
117                 if(rsocks[i] != INVALID_RUDPSOCKET)
118                         RUDPClose(rsocks[i]);
119         return rsock_c;
120 }
121
122 int _ClientPunchCb(RUDPSOCKET s, int status, void *data)
123 {
124         int len, chno;
125         struct dcs_punch dp;
126
127         switch(status)
128         {
129         case CONNSTATUS_CONNECTED:
130         case CONNSTATUS_ACCEPTED:
131                 if(RUDPSend(s, 0, (char*)data, sizeof(struct dcs_header) + ntohl(((struct dcs_header*)data)->length), 0) < 0)
132                         break;
133                 return CHECKCONNECTION_CONTINUE;
134
135         case CONNSTATUS_READABLE:
136                 len = RUDPRecv(s, 0, &chno, &dp, sizeof(dp));
137                 if(len >= sizeof(struct dcs_header) && check_dcs_header(&dp.dh) && dp.dh.cls == CLS_RESPONSE && dp.dh.st == ST_IPCAM)
138                         return(dp.dh.status == 0)?CHECKCONNECTION_OK:-dp.dh.status;
139                 else
140                         return -1000;
141                 break;
142         }
143
144         return CHECKCONNECTION_CONTINUE;
145 }
146
147 int _CameraPunchCb(RUDPSOCKET s, int status, void *data)
148 {
149         int len;
150         struct dcs_punch dp;
151         switch(status)
152         {
153         case CONNSTATUS_CONNECTED:
154                 ;//if this is client, send confirmation
155                 break;
156         case CONNSTATUS_ACCEPTED:
157                 ;//send confirmation
158                 break;
159         case CONNSTATUS_READABLE:
160                 len = RUDPRecv(s, &chno, &dp, sizeof(dp));
161                 if(len >= sizeof(struct dcs_header) && check_dcs_header(&dp.dh) && dp.dh.cls == CLS_REQUEST && dp.dh.st == ST_CLT)
162                 {
163                         ;//check session and password
164                 }
165                 break;
166         }
167
168         return CHECKCONNECTION_CONTINUE;
169 }
170
171
172 int main()
173 {
174         return 0;
175 }
176