⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 plugs.c

📁 altera epxa1的例子程序
💻 C
📖 第 1 页 / 共 5 页
字号:
		// | 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 + -