📄 plugs.c
字号:
next_plug:
plug++;
} // for (i), each plug
#if PLUGS_TCP
// |
// | If it was a tcp packet to this IP address, and
// | nobody handled it, reply with an incisive RST
// |
if(sub_protocol[ne_plugs_tcp].header
&& ip_address_equal(ip_packet->destination_ip_address,a->settings.ip_address)
&& !got_tcp)
{
int tcp_flags;
ns_plugs_tcp_packet *tcp_packet;
// |
// | Make sure we have the ethernet address
// | for this packet before we try to send
// |
tcp_packet = sub_protocol[ne_plugs_tcp].header;
tcp_flags = nr_n2h16(tcp_packet->header_length_flags);
if(!(tcp_flags & ne_plugs_flag_tcp_rst))
{
// |
// | But, don't respond to rst with rst!
// |
r_add_to_arp_cache_from_ip_packet(a,packet);
r_tcp_send(0,0,
ne_plugs_flag_tcp_rst | ne_plugs_flag_tcp_ack,
sub_protocol,0);
}
}
//MR #endif PLUGS_TCP
#endif
// If any plug_bitmask, and queing enabled, queue the packet
//HB Removed to get rid of warning message go_home:
g->in_dispatch--;
return 0;
}
int nr_plugs_create(int *plugHandleOut,
int protocol,
host_16 port,
nr_plugs_receive_callback_proc callback,
void *callback_context,
long flags)
{
s_plugs_globals *g = &ng_plugs_globals;
int i;
s_plugs_plug *plug;
if(!g->running)
return ne_plugs_error_not_initialized; // uninitialized error
port = nr_h2n16(port);
// port number zero means "give me a fresh port number"
if(port == 0)
port = get_port_number(g);
plug = g->plug;
for(i = 0; i < PLUGS_PLUG_COUNT; i++)
{
if(plug->protocol == 0)
{
//
// We found an unused plug, lets use it.
// (??? how to mark it until its connected?)
//
// zero out all fields?
plug->protocol = protocol;
plug->local_port = port;
plug->callback_proc = callback;
plug->callback_context = callback_context;
plug->flags = flags;
#if PLUGS_TCP
plug->tcp_state = e_plugs_tcp_inert;
#endif
*plugHandleOut = i + nk_plugs_plug_number_base;
return 0;
}
plug++;
}
return ne_plugs_error_too_many_plugs;
}
int nr_plugs_destroy(int plug_handle)
{
// s_plugs_globals *g = &ng_plugs_globals;
s_plugs_plug *plug = r_plug_from_handle(plug_handle);
// | "Destroying" a plug is easy: just
// | mark it as unused, and everyone
// | will ignore it.
plug->protocol = 0;
return 0;
}
//
// nr_plugs_connect
//
// Some kinds of port _must_ be connected
// before they can send or receive packets.
int nr_plugs_connect(int plug_handle,
char *remote_name,
host_32 remote_ip_address,
host_16 remote_port)
{
s_plugs_globals *g = &ng_plugs_globals;
s_plugs_plug *plug;
int result = 0;
plug = r_plug_from_handle(plug_handle);
if(remote_name)
{
result = nr_plugs_name_to_ip(remote_name,&remote_ip_address);
if(result)
goto go_home;
remote_ip_address = nr_n2h32(remote_ip_address);
}
#if PLUGS_TCP
// |
// | Any existing TCP connection?
// | Close it. We do a partial
// | close: we send a FIN and pretend
// | we're completely done. When they
// | send their ACK and FIN, we'll just
// | slam them with a RST. This is
// | impolite, but happens to be what
// | Windows NT does, too, so I don't
// | feel too bad, actually. -- dvb
// |
if((plug->protocol == ne_plugs_tcp)
&& (plug->tcp_state > e_plugs_tcp_listening))
{
result = r_tcp_send
(
plug_handle,
plug,
ne_plugs_flag_tcp_ack | ne_plugs_flag_tcp_fin,
0,
0
);
if(result)
goto go_home;
plug->tcp_state = e_plugs_tcp_inert;
}
#endif // PLUGS_TCP
plug->remote_ip_address = nr_h2n32(remote_ip_address);
plug->remote_port = nm_h2n16(remote_port);
#if PLUGS_TCP
// |
// | Open a new connection?
// | They may have said connect to 0.0.0.0/0,
// | which just means "hang up and forget it."
// | If not, well, initiate connection.
// |
if((plug->protocol == ne_plugs_tcp) && plug->remote_ip_address)
{
int retry_count;
long t0;
plug->tcp_sn_local = nr_h2n32(get_port_number(g));
for(retry_count = 0; retry_count < nk_plugs_tcp_retry_count; retry_count++)
{
t0 = nr_timer_milliseconds();
result = r_tcp_send(plug_handle,plug,ne_plugs_flag_tcp_syn,0,0);
if(result)
goto go_home;
plug->tcp_state = e_plugs_tcp_connecting;
while(nr_timer_milliseconds() - t0 < nk_plugs_tcp_retry_interval)
{
nr_plugs_idle();
if(plug->tcp_state == e_plugs_tcp_connected)
goto done_trying_to_connect;
if(plug->tcp_state == e_plugs_tcp_inert)
{
result = ne_plugs_error_tcp_connection_refused;
goto done_trying_to_connect;
}
}
}
result = ne_plugs_error_tcp_timed_out;
done_trying_to_connect:
;
}
#endif // PLUGS_TCP
go_home:
return result;
}
// +--------
// | Bracketing the tcp-specific routines...
#if PLUGS_TCP
// +---------------------------------------
// | Listen -- let a tcp port wait for a connection
int nr_plugs_listen(
int plug_handle,
nr_plugs_listen_callback_proc listen_proc,
void *listen_proc_context
)
{
//HB Removed to get rid of warning message s_plugs_globals *g = &ng_plugs_globals;
s_plugs_plug *plug;
plug = r_plug_from_handle(plug_handle);
if(plug->tcp_state != e_plugs_tcp_inert)
nr_plugs_connect(plug_handle,0,0,0);
//return ne_plugs_error;
plug->tcp_listen_proc = listen_proc;
plug->tcp_listen_proc_context = listen_proc_context;
plug->tcp_state = e_plugs_tcp_listening;
plug->remote_ip_address = -1;
plug->remote_port = -1; // accept from anyone...
return 0;
}
// +--------------------------------------------
// | Utility routine for composing and sending
// | tcp packets. Mostly it can figure out
// | what to do just from the flags.
// |
// | Exceptions:
// | if plug is 0, then payload is actually the
// | sub_protocol array.
// |
int r_tcp_send(int plug_handle,s_plugs_plug *plug,int tcp_flags,void *payload,long payload_length)
{
int result;
unsigned char x[1500];
ns_plugs_tcp_packet *tcp_reply; // reply
net_32 destination_ip_address;
int send_to_flags = 0;
tcp_reply = (ns_plugs_tcp_packet *)x;
//MR nr_zerorange((char *)tcp_reply,sizeof(ns_plugs_tcp_packet));
nr_zerorange((char *)tcp_reply,sizeof(ns_plugs_tcp_packet) - 1);
if(!plug)
{
// |
// | If plug is 0, the *only* thing we can
// | do is send an RST to the sender, presumed
// | to be the source of an ip_packet overloading
// | the input parameter "payload"
// |
ns_plugs_packet *sub_protocol = payload;
ns_plugs_ip_packet *ipp = sub_protocol[ne_plugs_ip].header; // what we reply to
ns_plugs_tcp_packet *tcpp = sub_protocol[ne_plugs_tcp].header;
destination_ip_address = ipp->source_ip_address;
tcp_reply->source_port = tcpp->destination_port;
tcp_reply->destination_port = tcpp->source_port;
tcp_reply->sequence_number = tcpp->acknowledgement_number;
tcp_reply->acknowledgement_number = nr_h2n32(nr_n2h32(tcpp->sequence_number) + 1);
tcp_reply->header_length_flags =
nr_h2n16(0x5000 | ne_plugs_flag_tcp_rst | ne_plugs_flag_tcp_ack);
payload = 0;
payload_length = 0;
send_to_flags = nk_plugs_default_debug;
}
else
{
destination_ip_address = plug->remote_ip_address;
tcp_reply->source_port = plug->local_port;
tcp_reply->destination_port = plug->remote_port;
tcp_reply->window_size = nm_h2n16(1024); // always room for another packet!
// | Always send ack & seq numbers...
tcp_reply->acknowledgement_number = nr_h2n32(plug->tcp_sn_remote);
tcp_reply->sequence_number = nr_h2n32(plug->tcp_sn_local);
tcp_reply->header_length_flags =
nr_h2n16(0x5000 | (tcp_flags & ne_plugs_flag_tcp_mask));
// | If SYN or FIN, bump our local seq by 1,
// | else, if PSH, put payload bump local seq by payload size
if(tcp_flags & (ne_plugs_flag_tcp_syn | ne_plugs_flag_tcp_fin))
plug->tcp_sn_local++;
else if(tcp_flags & ne_plugs_flag_tcp_psh)
{
// |
// | Copy (byte by byte) the payload)
// |
int i;
plug->tcp_sn_local += payload_length;
for(i = 0; i < payload_length; i++)
tcp_reply->payload[i] = ((char *)payload)[i];
}
if(tcp_flags & ne_plugs_flag_tcp_rst) // reset? window is zero, thank you.
tcp_reply->window_size = 0;
}
// |
// | Use the overload-feature of nr_plugs_send, and treat
// | our carefully constructed packet as an ip packet,
// | since we're giving it the payload already all
// | put together.
// |
// | (payload_length now includes tcp header + tcp payload)
//MR payload_length += sizeof(ns_plugs_tcp_packet);
payload_length += sizeof(ns_plugs_tcp_packet) - 1;
//MR result = nr_plugs_send_to(ne_plugs_ip,tcp_reply,payload_length,
result = nr_plugs_send_to(ne_plugs_ip,(void *)tcp_reply,payload_length,
ne_plugs_flag_tcp_checksum | send_to_flags,
destination_ip_address,tcp_reply->destination_port);
return result;
}
// +-----------------------------------------
// | Routine for handling non-raw tcp connections
// | Return 0 if the packet is handled by this
// | port, else return -1. Whoever calls this
// | routine may decide to send a tcp RST to
// | the sender if no plug handles the tcp connection.
int r_tcp_dispatch(
s_plugs_adapter_entry *a,
int plug_handle,
s_plugs_plug *plug,
ns_plugs_packet *sub_protocol,
void *payload,
int payload_length)
{
int result = 0;
host_32 seq;
host_32 ack;
host_16 tcp_flags;
ns_plugs_ip_packet *ipp = sub_protocol[ne_plugs_ip].header;
ns_plugs_tcp_packet *tcpp = sub_protocol[ne_plugs_tcp].header;
// |
// | Ensure that we can respond to this
// | packet, mac-address-wise...
// |
r_add_to_arp_cache_from_ip_packet(a,sub_protocol[ne_plugs_ethernet].header);
// |
// | Extract some basic info from the incoming packet
// |
seq = nr_n2h32(tcpp->sequence_number);
ack = nr_n2h32(tcpp->acknowledgement_number);
tcp_flags = nr_n2h16(tcpp->header_length_flags);
// |
// | Handle the various tcp packet kinds in
// | an exploded if{do and go home} list
// |
if(tcp_flags & ne_plugs_flag_tcp_syn) // | connection request or confirm
{
int x = nr_timer_milliseconds();
if(plug->tcp_state == e_plugs_tcp_connecting)
{
// |
// | We initiated a connection, and
// | our remote target has, apparently,
// | responded.
// | Swell, we are connected.
// |
plug->tcp_sn_remote = seq + 1;
result = r_tcp_send(plug_handle,plug,ne_plugs_flag_tcp_ack,0,0);
if(!result)
plug->tcp_state = e_plugs_tcp_connected;
} // if connecting & got syn
else if(plug->tcp_state == e_plugs_tcp_listening)
{
// |
// | Listening -- call application acceptance routine
// | (Really, it's an application rejection routine,
// | since if there isn't one, we automatically accept.
// |
if(plug->tcp_listen_proc)
{
result = (plug->tcp_listen_proc)
(plug_handle,
plug->tcp_listen_proc_context,
nr_n2h32(ipp->source_ip_address),
nr_n2h16(tcpp->source_port));
if(result)
goto go_home;
}
plug->tcp_connection_time = x;
plug->remote_ip_address = ipp->source_ip_address;
plug->remote_port = tcpp->source_port;
plug->tcp_sn_remote = seq + 1;
// |
// | Send ACK & SYN in return, to accept the connection
// |
result = r_tcp_send(plug_handle,plug,ne_plugs_flag_tcp_ack | ne_plugs_flag_tcp_syn,0,0);
if(!result)
plug->tcp_state = e_plugs_tcp_connected;
} // if listening & got syn
else
{
// |
// | Not listening or connecting? Then
// | a SYN has no business with us.
// | Return an error code, we cannot accept.
// |
return_error:
result = ne_plugs_error;
}
goto go_home;
} // if syn
// +---------------------------------
// | If we're not connected, no other packet is interesting
if(plug->tcp_state <= e_plugs_tcp_listening)
{
goto return_error;
}
// +-------------------------------------------
// | If the packet has an ACK in it, we'll check
// | it against our own numbers, and maybe resent
// | an ack to get back into phase...
// |
// | We do this before checking the payload,
// | because the remote count in the packet
// | does not include the current payload.
// |
if(tcp_flags & ne_plugs_flag_tcp_ack)
{
// |
// | Just sending us an ack?
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -