00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041 #include <sys/confnet.h>
00042 #include <sys/confos.h>
00043 #include <sys/thread.h>
00044 #include <sys/timer.h>
00045 #include <sys/socket.h>
00046
00047 #include <netinet/in.h>
00048 #include <net/if_var.h>
00049
00050 #include <stdlib.h>
00051 #include <string.h>
00052
00053 #include <pro/discover.h>
00054
00059
00060 #ifndef NUT_THREAD_DISTSTACK
00061 #if defined(__AVR__)
00062 #define NUT_THREAD_DISTSTACK 384
00063 #else
00064 #define NUT_THREAD_DISTSTACK 512
00065 #endif
00066 #endif
00067
00068 #ifndef DISCOVERY_PORT
00069 #define DISCOVERY_PORT 9806
00070 #endif
00071
00072 typedef struct {
00073 u_long disopt_ipmask;
00074 u_short disopt_port;
00075 u_int disopt_flags;
00076 } DISCOVERY_OPTIONS;
00077
00078 static DISCOVERY_OPTIONS disopt;
00079 static u_long xid;
00080
00081 static int NutDiscoveryHandler(u_long ip, u_short port, DISCOVERY_TELE * dist, int len);
00082 static NutDiscoveryCallback discovery_callback = NutDiscoveryHandler;
00083
00091 int NutDiscoveryAnnTele(DISCOVERY_TELE * dist)
00092 {
00093 memset(dist, 0, sizeof(DISCOVERY_TELE));
00094 dist->dist_xid = xid;
00095 dist->dist_type = DIST_ANNOUNCE;
00096 dist->dist_ver = DISCOVERY_VERSION;
00097 memcpy(dist->dist_mac, confnet.cdn_mac, sizeof(dist->dist_mac));
00098 dist->dist_ip_addr = confnet.cdn_ip_addr;
00099 dist->dist_ip_mask = confnet.cdn_ip_mask;
00100 dist->dist_gateway = confnet.cdn_gateway;
00101 dist->dist_cip_addr = confnet.cdn_cip_addr;
00102 memcpy(dist->dist_hostname, confos.hostname, sizeof(dist->dist_hostname));
00103
00104 return sizeof(DISCOVERY_TELE) - sizeof(dist->dist_custom);
00105 }
00106
00114 int NutDiscoveryAppConf(DISCOVERY_TELE * dist)
00115 {
00116 memcpy(confos.hostname, dist->dist_hostname, sizeof(confos.hostname));
00117 NutSaveConfig();
00118
00119 memcpy(confnet.cdn_mac, dist->dist_mac, sizeof(confnet.cdn_mac));
00120 confnet.cdn_ip_addr = dist->dist_ip_addr;
00121 confnet.cdn_ip_mask = dist->dist_ip_mask;
00122 confnet.cdn_gateway = dist->dist_gateway;
00123 confnet.cdn_cip_addr = dist->dist_cip_addr;
00124
00125 return NutNetSaveConfig();
00126 }
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136 static int NutDiscoveryHandler(u_long ip, u_short port, DISCOVERY_TELE * dist, int len)
00137 {
00138 int rc = -1;
00139
00140
00141 if (len >= sizeof(DISCOVERY_TELE) - sizeof(dist->dist_custom)) {
00142 if (dist->dist_type == DIST_REQUEST) {
00143
00144 rc = NutDiscoveryAnnTele(dist);
00145 } else if (dist->dist_type == DIST_APPLY
00146 && dist->dist_xid == xid
00147 && dist->dist_ver >= DISCOVERY_VERSION) {
00148 xid += NutGetTickCount();
00149
00150 rc = NutDiscoveryAppConf(dist);
00151 }
00152 }
00153 return rc;
00154 }
00155
00156 THREAD(DiscoveryResponder, arg)
00157 {
00158 UDPSOCKET *sock;
00159 DISCOVERY_TELE *dist;
00160 u_long raddr;
00161 u_short rport;
00162 int len;
00163
00164
00165 while ((dist = malloc(sizeof(DISCOVERY_TELE))) == NULL) {
00166 NutSleep(1000);
00167 }
00168
00169
00170 while ((sock = NutUdpCreateSocket(disopt.disopt_port)) == NULL) {
00171 NutSleep(1000);
00172 }
00173
00174
00175 {
00176 u_short max_ms = sizeof(DISCOVERY_TELE) * 3;
00177
00178 NutUdpSetSockOpt(sock, SO_RCVBUF, &max_ms, sizeof(max_ms));
00179 }
00180
00181
00182 memcpy(&xid, &confnet.cdn_mac[2], sizeof(xid));
00183 xid += NutGetTickCount();
00184
00185
00186 if (disopt.disopt_flags & DISF_INITAL_ANN) {
00187
00188 NutSleep(500 + (xid & 0x7FF));
00189 if ((len = NutDiscoveryAnnTele(dist)) > 0) {
00190 NutUdpSendTo(sock, INADDR_BROADCAST, disopt.disopt_port, dist, len);
00191 }
00192 }
00193
00194
00195 for (;;) {
00196 len = NutUdpReceiveFrom(sock, &raddr, &rport, dist, sizeof(DISCOVERY_TELE), 0);
00197
00198 if ((raddr & disopt.disopt_ipmask) == raddr && len > 0 && discovery_callback) {
00199 if ((len = discovery_callback(raddr, rport, dist, len)) > 0) {
00200
00201 if ((raddr & confnet.cdn_ip_mask) != (confnet.cdn_ip_addr & confnet.cdn_ip_mask)) {
00202 raddr = INADDR_BROADCAST;
00203 }
00204 NutUdpSendTo(sock, raddr, disopt.disopt_port, dist, len);
00205 }
00206 }
00207
00208 NutSleep(100);
00209 }
00210 }
00211
00226 NutDiscoveryCallback NutRegisterDiscoveryCallback(NutDiscoveryCallback func)
00227 {
00228 NutDiscoveryCallback rc = discovery_callback;
00229
00230 discovery_callback = func;
00231
00232 return rc;
00233 }
00234
00252 int NutRegisterDiscovery(u_long ipmask, u_short port, u_int flags)
00253 {
00254 static HANDLE tid = NULL;
00255
00256 if (tid == NULL) {
00257 disopt.disopt_ipmask = ipmask;
00258 disopt.disopt_port = port ? port : DISCOVERY_PORT;
00259 disopt.disopt_flags = flags;
00260 tid = NutThreadCreate("udisc", DiscoveryResponder, NULL, NUT_THREAD_DISTSTACK);
00261 if (tid) {
00262 return 0;
00263 }
00264 }
00265 return -1;
00266 }
00267