1 /*
2  *  TCPProtoSocketAgent.cpp
3  *
4  */
5 
6 #include "nsTCPProtoSocketAgent.h"
7 
8 /////////////////////////////////////////////////////////////////////////
9 // NsProtoSimAgent::UdpSocketAgent implementation
10 //
11 static class ProtoSocketTcpAgentClass : public TclClass {
12 public:
ProtoSocketTcpAgentClass()13 	ProtoSocketTcpAgentClass() : TclClass("Agent/ProtoSocket/TCP") {}
create(int,const char * const *)14 	TclObject* create(int, const char*const*) {
15 		return (new NsTCPProtoSocketAgent());
16 	}
17 } class_proto_socket_tcp_agent;
18 
NsTCPProtoSocketAgent()19 NsTCPProtoSocketAgent::NsTCPProtoSocketAgent()
20  : Agent(PT_TCP)
21 {
22 	socketType_=NotInitialised;
23 	outputNotification=false; // by default
24 	// printf("NsTCPProtoSocketAgent: Created ok\n");
25 	//SetDebugLevel(7);
26 }
27 
Listen(UINT16 thePort)28 bool NsTCPProtoSocketAgent::Listen(UINT16 thePort) {
29 	if (socketType_==NotInitialised) { // must be a server socket, port is set from the NsProtoSimAgent bind operation
30 
31 		PLOG(PL_DEBUG, "TCPProtoSocketAgent: Listening on %i\n", thePort);
32 
33 		Agent* simAgent = dynamic_cast<Agent*>(proto_socket->GetNotifier());
34 
35 		serverSocket = TCPSocketFactory::createServerSocketAgent(simAgent);
36 
37 		if (serverSocket==NULL) return FALSE;
38 
39 		serverSocket->setTCPAgentProtocol(TCPSocketAgent::FULLTCP);
40 
41 		serverSocket->bind(thePort);
42 		socketType_=TcpServerSocket;
43 
44 //		printf("TCPProtoSocketAgent: Calling listen on server socket\n");
45 
46 		isOpen=true;
47 
48 		// start listening for connections
49 		serverSocket->listen();
50 
51 		serverSocket->setListener(this);
52 
53 
54 //		printf("TCPProtoSocketAgent: Server initialsed and listening\n");
55 
56 		}
57 	else {
58 		return false;
59 	}
60 
61 	return true;
62 	}
63 
64 /**
65  *
66  * Enables the output notification for a socket i.e. whether SEND events are generated in trigger mode.
67  */
SetOutputNotification(bool outputnotify)68 bool NsTCPProtoSocketAgent::SetOutputNotification(bool outputnotify) {
69 	outputNotification=outputnotify;
70 	if (socketType_==TcpSocket)
71 		tcpPipe->setOutputNotification(outputnotify);
72 	return outputnotify;
73 	}
74 
Connect(const ProtoAddress & theAddress)75 bool NsTCPProtoSocketAgent::Connect(const ProtoAddress& theAddress) {
76 	PLOG(PL_DEBUG, "TCPProtoSocketAgent: Connect Entering\n");
77 
78 	if (socketType_==NotInitialised) { // must be a client socket, port is set from the NsProtoSimAgent bind operation
79 		PLOG(PL_DETAIL, "TCPProtoSocketAgent: Creating a new socket on %i, port %i\n", addr(), port());
80 		Agent* simAgent = dynamic_cast<Agent*>(proto_socket->GetNotifier());
81 		tcpPipe = TCPSocketFactory::createSocketAgent(simAgent); // sets simAgent as agent to bind to
82 		if (tcpPipe==NULL) return FALSE;
83 		tcpPipe->setTCPAgentProtocol(TCPSocketAgent::FULLTCP);
84 
85 		tcpPipe->bind(port());
86 		tcpPipe->setListener(this); // notifications sent here
87 
88 		socketType_=TcpSocket;
89 		isOpen=true;
90 
91 		PLOG(PL_DETAIL, "TCPProtoSocketAgent: Conencting now to address %u, port %i\n", theAddress.SimGetAddress(), theAddress.GetPort());
92 		// connect to server
93 
94 		tcpPipe->setOutputNotification(outputNotification);
95 		tcpPipe->connect(theAddress.SimGetAddress(), theAddress.GetPort());
96 		}
97 	else {
98 		return false;
99 	}
100 
101 	return true;
102 	}
103 
104  /**
105   * Here, we create a new protosocket to
106   * deal with the new connection and tell this TCPProtoSocketAgent to reply to the requesting
107   * client. This allows us to spwan off new agents to deal with multiple clients.
108   * NOTE that this assumes that the user provides a socket to deal with the connection !
109   */
Accept(ProtoSocket * theSocket)110 bool NsTCPProtoSocketAgent::Accept(ProtoSocket* theSocket) {
111 	PLOG(PL_DEBUG, "TCPProtoSocketAgent::Accept Entering \n");
112 
113 	if (socketType_==NotInitialised) return FALSE;
114 
115 	theSocket->SetNotifier(proto_socket->GetNotifier());
116 
117     // Note that the first argument does not matter because the third is false i.e. bindOnCreate is false
118 	// so port is not used in Open
119 	theSocket->Open(0, ProtoAddress::SIM, FALSE); //creates a new nsTCPProtoSocketAgent
120 
121 	NsTCPProtoSocketAgent *theProtoSocket = (NsTCPProtoSocketAgent *) static_cast<ProtoSimAgent::SocketProxy*>(theSocket->GetHandle());
122 
123 	TCPSocketAgent* socket = serverSocket->accept(); // create new socket agent for this connection
124 
125  	socket->setListener(theProtoSocket); // set the listener for RECEIVE events to this class
126 
127 	theProtoSocket->setTCPSocketAgent(socket);  // set the socket agent in the new TCPProtoSocketAgent to be
128 
129 	// Need to set the destination...
130 
131 	ProtoAddress destination;
132 	destination.SimSetAddress(socket->getDestinationAddress());
133 	destination.SetPort(socket->getDestinationPort());
134 	theSocket->SetDestination(destination);
135 
136 	PLOG(PL_DEBUG, "TCPProtoSocketAgent::Accept Exiting \n");
137 
138 	return true;
139 	}
140 
141 
SendTo(const char * buffer,unsigned int & numBytes,const ProtoAddress & dstAddr)142 bool NsTCPProtoSocketAgent::SendTo(const char* buffer, unsigned int& numBytes, const ProtoAddress& dstAddr) {
143 	PLOG(PL_DEBUG, "NsTCPPrototSocketAgent: Sending Data\n");
144 
145 	if (socketType_==NotInitialised) return FALSE;
146 
147 	unsigned int bytesSent = tcpPipe->send(numBytes,buffer);
148 	numBytes=bytesSent;
149 	PLOG(PL_DEBUG, "NsTCPPrototSocketAgent: Completed send\n");
150 	return true;
151 }
152 
153 
154 /**
155  * Catches events thrown from the underlying TCP agents.
156  */
tcpEventReceived(TCPEvent * event)157 bool NsTCPProtoSocketAgent::tcpEventReceived(TCPEvent *event) {
158 
159 	// check how these map ...
160 
161 	PLOG(PL_DEBUG, "NsTCPPrototSocketAgent: Getting Callback\n");
162 
163 	if (event->getType()==TCPEvent::ACCEPT)
164     {
165         if (proto_socket)
166 			proto_socket->OnNotify(ProtoSocket::NOTIFY_INPUT);
167 	}
168     else if (event->getType()==TCPEvent::CONNECTED)
169     {
170 	    //	printf("Connected event in ProtoSocketAgent\n");
171 		if (proto_socket)
172 			proto_socket->OnNotify(ProtoSocket::NOTIFY_OUTPUT);
173 
174 	}
175     else if (event->getType()==TCPEvent::SEND)
176     {
177 		if (proto_socket)
178 			proto_socket->OnNotify(ProtoSocket::NOTIFY_OUTPUT);
179 	}
180     else if (event->getType()==TCPEvent::RECEIVE)
181     {
182 
183 		recv_data = (char *)event->getData();
184 		recv_data_len = event->getDataSize();
185 		recv_data_offset=0; // reset offset to 0
186 
187 		PLOG(PL_DEBUG,"NsTCPProtoSocketAgent::tcpEventReceived: Got data of length %i\n", recv_data_len);
188 		PLOG(PL_DETAIL, "NsTCPProtoSocketAgent::tcpEventReceived: Destination port and Address are %i and %i\n", tcpPipe->getDestinationPort(),
189 							tcpPipe->getDestinationAddress());
190 
191 		src_addr.SimSetAddress(tcpPipe->getDestinationAddress());
192 		src_addr.SetPort(tcpPipe->getDestinationPort());
193 
194 		PLOG(PL_DETAIL, "NsTCPProtoSocketAgent::tcpEventReceived event being sent to socket ...\n ");
195 
196 		if (proto_socket)
197 			proto_socket->OnNotify(ProtoSocket::NOTIFY_INPUT);
198 		PLOG(PL_DETAIL, "NsTCPProtoSocketAgent::tcpEventReceived event processed ... \n");
199 
200 	}
201     else if (event->getType()==TCPEvent::DISCONNECTED)
202     {
203 		if (proto_socket)
204 			proto_socket->OnNotify(ProtoSocket::NOTIFY_NONE);
205 	}
206     else
207     {
208 		PLOG(PL_ERROR, "NsTCPProtoSocketAgent::tcpEventReceived UNKNOWN Event on node %i\n", addr());
209 		return false;
210 	}
211 
212 	PLOG(PL_DEBUG, "NsTCPProtoSocketAgent::tcpEventReceived finished Callback\n");
213 
214 	delete event;
215 	return true;
216 }
217 
218 /**
219  * Close and detach the relevant agents from the sockets that have been created by this
220  * NS TCP Proto Sokcet Agent.  This agent is NOT attached but others it communicates with are...
221  */
Shutdown()222 bool NsTCPProtoSocketAgent::Shutdown() {
223 	PLOG(PL_DEBUG, "NsTCPPrototSocketAgent: Shutdown\n");
224 
225 	if (!isOpen) return false;
226 
227 	if (socketType_==NotInitialised) return TRUE;
228 
229 	if (socketType_==TcpSocket)
230 		tcpPipe->shutdown();
231 	else
232 		serverSocket->shutdown();
233 
234 	PLOG(PL_DEBUG, "NsTCPPrototSocketAgent: Socket shutdown initiated\n");
235 
236 	return true;
237 }  // end NsProtoSimAgent::UdpSocketAgent::Close()
238 
239 
240 /**
241  * Close and detach the relevant agents from the sockets that have been created by this
242  * NS TCP Proto Sokcet Agent.  This agent is NOT attached but others it communicates with are...
243  */
Close()244 bool NsTCPProtoSocketAgent::Close() {
245 	PLOG(PL_DEBUG, "NsTCPPrototSocketAgent: Closing\n");
246 	bool state=false;
247 	if (!isOpen) return true;
248 
249 	if (socketType_==NotInitialised) return TRUE; // is closed already
250 
251 	if (socketType_==TcpSocket)
252 		state=tcpPipe->closeSocket();
253 	else
254 		state=serverSocket->closeSocket();
255 
256 	PLOG(PL_DEBUG, "NsTCPPrototSocketAgent: Socket Closed\n");
257 
258 	isOpen=false;
259 
260 	return state;
261 }  // end NsProtoSimAgent::UdpSocketAgent::Close()
262 
263