📄 plugs.c
字号:
// | eh, ok, great. But if we're out of sync, resend
// | our own ack. (This also ignores a FIN if we're
// | out of phase.)
// |
if(seq != plug->tcp_sn_remote)
{
r_tcp_send(plug_handle,plug,ne_plugs_flag_tcp_ack,0,0);
goto go_home;
}
}
// +---------------------------------
// | Second things second: if there's any
// | data with the packet -- and there could
// | be, even with a FIN packet! -- we must
// | pass it straight to the plug's
// | callback.
if(payload_length)
{
// |
// | They're sending us some bytes!
// | (By the way, the "PSH" flag is
// | irrelevant, it's used to indicate
// | that the bytes are special or something.)
// |
if(seq == plug->tcp_sn_remote)
{
// |
// | We got some legit bytes, let's acknoweldge
// | them and pass the data on to the application.
// |
plug->tcp_sn_remote += payload_length;
(plug->callback_proc)
(plug_handle,
plug->callback_context,
sub_protocol,
payload,
payload_length);
}
else
{
// |
// | Something bad has happened: they have a
// | sequence number that is not what we expect.
// |
// | The best we can do is send an ACK for the
// | sequence number we think we do want.
// |
// | (actually, this "else" clause is just a
// | comment, to fall to the ack below.)
}
r_tcp_send(plug_handle,plug,ne_plugs_flag_tcp_ack,0,0);
} // payload present
// +---------------------------------
// | FIN
// | If they wish to close connection, then do it.
if(tcp_flags & ne_plugs_flag_tcp_fin)
{
// |
// | Close a connection by sending an ack for the fin,
// | and then our own fin. (We won't wait for their ack,
// | though.)
// |
plug->tcp_sn_remote++; // | Bump the ack
r_tcp_send(plug_handle,plug,ne_plugs_flag_tcp_ack,0,0);
if(plug->tcp_state == e_plugs_tcp_connected)
r_tcp_send(plug_handle,plug,ne_plugs_flag_tcp_fin,0,0);
connection_done:
// |
// | Set the plugs disconnected state
// | here, so that the callback proc
// | can, if it wishes, tell the plug
// | to listen.
// |
plug->remote_ip_address = 0;
plug->remote_port = 0;
plug->tcp_state = e_plugs_tcp_inert;
// |
// | Notify the application that the
// | tcp connection has been closed
// | by sending a payload size of 0.
//
(plug->callback_proc)
(plug_handle,
plug->callback_context,
sub_protocol,
0,
0);
goto go_home;
}
if(tcp_flags & ne_plugs_flag_tcp_rst)
{
// |
// | They want an immediate disconnect. Fine.
// |
goto connection_done;
}
go_home:
return result;
}
#endif // PLUGS_TCP
// --------------------------
// DNS lookup
#if PLUGS_DNS
// support routines for parsing those
// troublesome unaligned dns queries
// Given a pointer to some bytes to emit to,
// and an int, emit the two bytes bigendian.
// This is done byte-by-byte, so is ok
// to be unaligned.
static void p16(unsigned char **wp,int v)
{
unsigned char *w;
w = *wp;
*w++ = (v & 0x0000ff00) >> 8;
*w++ = (v & 0x000000ff);
*wp = w;
}
// Given a pointer to some bytes to emit to,
// and a host name, put in the host name
// in the weird form required by dns.
// Advance the pointerpointer.
static void pn(unsigned char **wp,char *name)
{
unsigned char *w;
unsigned char *label_begin;
unsigned char label_len;
int c;
// | Hey man, sorry about the gotos. -- dvb 2001.03.23
w = *wp;
do_label:
label_begin = w++;
label_len = 0;
do_label_char:
c = *name++;
if(c == 0 || c == '.')
{
*label_begin = label_len;
if(c)
goto do_label;
else
{
*w++ = 0;
*wp = w;
return;
}
}
label_len++;
*w++ = c;
goto do_label_char;
}
int g16(unsigned char **wp)
{
unsigned char *w = *wp;
int v;
v = *w++;
v = (v << 8) + *w++;
*wp = w;
return v;
}
// Skip over strange length-delimited dns "label"
void skip_label(unsigned char **wp)
{
unsigned char *w = *wp;
int label_length;
while((label_length = *w++) != 0)
if(label_length > 64)
{
w++;
goto go_home;
}
else
w += label_length;
go_home:
*wp = w;
}
static int r_plugs_dns_proc
(
int plug_handle,
void *context,
ns_plugs_packet *p,
void *payload,
int payload_length
)
{
unsigned char *w = payload;
unsigned char **wp = &w;
int v;
int questions;
int answers;
int result = 0;
s_plugs_globals *g = &ng_plugs_globals;
// identifier... is it the one we sent out?
v = g16(wp);
if(v != g->dns_identifier) // not for us, just ignore
goto go_home;
// flags... did we get an answer?
v = g16(wp);
if(
(!(v & 0x8000)) // it's not an answer?
||
((v & 0x000f) == 3) // it's an error?
)
{
failure:
g->dns_query_state = 3;
goto go_home;
}
// questions & answers
questions = g16(wp);
answers = g16(wp);
if(!answers)
goto failure;
w += 4; // skip over authorities & additional
// skip over questions
while(questions--)
{
skip_label(wp);
// skip over query type & class
w += 4;
}
// take first answer of type 1 as the answer!
while(answers--)
{
skip_label(wp);
v = g16(wp); // query type
if(v == 1) // 'A' (ip address)
{
long vl;
w += 8; // skip type, class, & ttl, and assume lenght = 4...
vl = g16(wp);
vl = (vl << 16) + g16(wp);
g->dns_query_state = 2; // answered ok
g->dns_query_result = nr_h2n32(vl);
goto go_home;
}
else
{
// some query type we dont care about...
w += 6;
v = g16(wp); // resource length
w += v;
}
}
// got to here? No answers with our IP address?? aww.
result = ne_plugs_error_unwanted_reply;
go_home:
return result;
}
#endif
int nr_plugs_name_to_ip(char *host_name,net_32 *host_ip_address_out)
{
#if PLUGS_DNS
unsigned char p[256]; // arbitrary upper bound on query size
int len; // length of constructed query
unsigned char *w;
unsigned char **wp;
s_plugs_globals *g = &ng_plugs_globals;
//HB Removed to get rid of warning message int id;
long t1,ti; // current time, last req time
int retry_count;
//HB Removed to get rid of warning message net_32 host_ip_address;
int result = 0;
w = p;
wp = &w;
g->dns_identifier = g->ip_identifier++;
// Build the dns message, and then possibly reuse it several times
// dns header
p16(wp,g->dns_identifier); // dns id, to recognize answer
p16(wp,0x0100); // dns flags: recursion desired
p16(wp,1); // 1 question
p16(wp,0); // 0 answers
p16(wp,0); // 0 authorities
p16(wp,0); // 0 additional
// dns question
pn(wp,host_name); // host name to look up
p16(wp,1); // query type: 'A' IP address
p16(wp,1); // query class: 1 = internet, blah blah
w = *wp;
len = w - p;
ti = nr_timer_milliseconds() - nk_plugs_dns_retry_interval; // so first timeout always true
g->dns_query_state = 0; // so we can wait for it to change...
g->dns_query_result = 0;
retry_count = nk_plugs_dns_retry_count;
dns_query_loop:
// Time to send another query?
t1 = nr_timer_milliseconds();
if(t1 - ti > nk_plugs_dns_retry_interval)
{
retry_count--;
if(retry_count < 0)
{
result = ne_plugs_error_dns_timed_out;
goto go_home;
}
nr_plugs_send(g->dns_plug,p,len,0);
ti = t1;
}
// Idle the system, and wait for godot.
nr_plugs_idle();
if(g->dns_query_state) // godot here already?
{
if(g->dns_query_state == 3) // failure?
result = ne_plugs_error_dns_not_found;
goto go_home; // we are done, in any case.
}
goto dns_query_loop;
go_home:
*host_ip_address_out = g->dns_query_result;
return result;
#else
*host_ip_address_out = 0;
return ne_plugs_error_feature_disabled;
#endif
}
// ----------------------------
// r_add_to_arp_cache
//
// insert an entry to the cache (at extant spot, if possible)
static void r_add_to_arp_cache(s_plugs_adapter_entry *a,net_32 ip_address,net_32 ethu32,net_16 ethl16)
{
s_plugs_arp_cache_entry *w;
int i;
w = a->arp_cache;
for(i = 0; i < nk_plugs_arp_cache_count; i++)
{
if(w->ip_address == ip_address)
goto found_a_spot;
w++;
}
// no existing ip entry? choose the next one
w = &a->arp_cache[a->arp_cache_walker];
a->arp_cache_walker++;
if(a->arp_cache_walker == nk_plugs_arp_cache_count)
a->arp_cache_walker = 0;
found_a_spot:
w->ip_address = ip_address;
w->ethernet_address.u32 = ethu32;
w->ethernet_address.l16 = ethl16;
}
// --------------------------
// r_add_to_arp_cache_from_ip_packet
//
// Given an ethernet packet known to contain an IP header,
// add the source's address to the cache.
// This is great for imminent replies to packets.
static void r_add_to_arp_cache_from_ip_packet(s_plugs_adapter_entry *a,ns_plugs_ethernet_packet *p)
{
net_32 ip_address;
net_48 ethernet_address;
// pull the info from the packet
ip_address = ((ns_plugs_ip_packet *)(&p->payload))->source_ip_address;
ethernet_address = p->source_address;
// Is it outside our LAN? If so, any ethernet
// address actually refers to the router.
if((ip_address ^ a->settings.ip_address) & a->settings.subnet_mask)
ip_address = a->settings.gateway_ip_address;
// And put in cache!
r_add_to_arp_cache(a,ip_address,ethernet_address.u32,ethernet_address.l16);
}
// --------------------------
// nr_plugs_ip_to_ethernet:
// invokes arp if necessary, but ONLY if we're not in_dispatch. Reentrant, doncha know.
// The "flags" parameter is taken from the plug that's calling
// us, and the routine prints errors if ne_plugs_flag_debug_tx is set.
//
int nr_plugs_ip_to_ethernet(int adapter_index,net_32 ip_address,net_48 *ethernet_address_out,long flags)
{
s_plugs_globals *g = &ng_plugs_globals;
int result = 0;
int i;
s_plugs_arp_cache_entry *w;
//HB Removed to get rid of warning message int requests_sent;
long t0,t1; // time we started, current time
long ti; // time of last arp-request
long retry_count; // how many times we've polled
s_plugs_adapter_entry *a = &g->adapter[adapter_index];
// Is it outside our LAN? If so, we must
// send to the router, not direct
if((ip_address ^ a->settings.ip_address) & a->settings.subnet_mask)
ip_address = a->settings.gateway_ip_address;
t0 = nr_timer_milliseconds();
ti = t0 - nk_plugs_arp_retry_interval; // so first timeout test always does it
retry_count = 0;
scan_cache:
// Already in the cache?
//
// Receive it right now if possible!
nr_plugs_idle();
w = a->arp_cache;
for(i = 0; i < nk_plugs_arp_cache_count; i++)
{
if(w->ip_address == ip_address)
{
// entry there, but no arp-response yet?
if(!(w->ethernet_address.u32 || w->ethernet_address.l16))
goto present_but_unresolved;
*ethernet_address_out = w->ethernet_address;
goto go_home;
}
w++;
}
// Add a spot in the ARP cache, with zeroed ethernet
r_add_to_arp_cache(a,ip_address,0,0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -