Ejemplo n.º 1
0
/**
 * Adhoc Emulator PTP Receiver
 * @param id Socket File Descriptor
 * @param buf Data Buffer
 * @param len IN: Buffersize OUT: Received Data (in Bytes)
 * @param timeout Receive Timeout (in Microseconds)
 * @param flag Nonblocking Flag
 * @return 0 on success or... ADHOC_NOT_INITIALIZED, ADHOC_INVALID_ARG, ADHOC_INVALID_SOCKET_ID, ADHOC_SOCKET_DELETED, ADHOC_SOCKET_ALERTED, ADHOC_WOULD_BLOCK, ADHOC_TIMEOUT, ADHOC_THREAD_ABORTED, ADHOC_DISCONNECTED, NET_INTERNAL
 */
int proNetAdhocPtpRecv(int id, void * buf, int * len, uint32_t timeout, int flag)
{
	// Library is initialized
	if(_init)
	{
		// Valid Socket
		if(id > 0 && id <= 255 && _ptp[id - 1] != NULL && _ptp[id - 1]->state == PTP_STATE_ESTABLISHED)
		{
			// Cast Socket
			SceNetAdhocPtpStat * socket = _ptp[id - 1];
			
			// Valid Arguments
			if(buf != NULL && len != NULL && *len > 0)
			{
				// Schedule Timeout Removal
				if(flag) timeout = 0;
				
				// Apply Send Timeout Settings to Socket
				sceNetInetSetsockopt(socket->id, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
				
				// Acquire Network Lock
				_acquireNetworkLock();
				
				// Receive Data
				int received = sceNetInetRecv(socket->id, buf, *len, ((flag) ? (INET_MSG_DONTWAIT) : (0)));
				
				// Free Network Lock
				_freeNetworkLock();
				
				// Received Data
				if(received > 0)
				{
					// Save Length
					*len = received;
					
					// Return Success
					return 0;
				}
				
				// Non-Critical Error
				else if(received == -1 && sceNetInetGetErrno() == EAGAIN)
				{
					// Blocking Situation
					if(flag) return ADHOC_WOULD_BLOCK;
					
					// Timeout
					return ADHOC_TIMEOUT;
				}
				
				// Change Socket State
				socket->state = PTP_STATE_CLOSED;
				
				// Disconnected
				return ADHOC_DISCONNECTED;
			}
			
			// Invalid Arguments
			return ADHOC_INVALID_ARG;
		}
		
		// Invalid Socket
		return ADHOC_INVALID_SOCKET_ID;
	}
	
	// Library is uninitialized
	return ADHOC_NOT_INITIALIZED;
}
Ejemplo n.º 2
0
/**
 * Friend Finder Thread (Receives Peer Information)
 * @param args Length of argp in Bytes (Unused)
 * @param argp Argument (Unused)
 * @return Unused Value - Return 0
 */
int _friendFinder(SceSize args, void * argp)
{
	// Receive Buffer
	int rxpos = 0;
	uint8_t rx[1024];
	
	// Chat Packet
	SceNetAdhocctlChatPacketC2S chat;
	chat.base.opcode = OPCODE_CHAT;
	
	// Last Ping Time
	uint64_t lastping = 0;
	
	// Last Time Reception got updated
	uint64_t lastreceptionupdate = 0;
	
	// Finder Loop
	while(_init == 1)
	{
		// Acquire Network Lock
		_acquireNetworkLock();
		
		// Ping Server
		if((sceKernelGetSystemTimeWide() - lastping) >= ADHOCCTL_PING_TIMEOUT)
		{
			// Update Ping Time
			lastping = sceKernelGetSystemTimeWide();
			
			// Prepare Packet
			uint8_t opcode = OPCODE_PING;
			
			// Send Ping to Server
			sceNetInetSend(_metasocket, &opcode, 1, INET_MSG_DONTWAIT);
		}
		
		// Send Chat Messages
		while(popFromOutbox(chat.message))
		{
			// Send Chat to Server
			sceNetInetSend(_metasocket, &chat, sizeof(chat), INET_MSG_DONTWAIT);
		}
		
		// Wait for Incoming Data
		int received = sceNetInetRecv(_metasocket, rx + rxpos, sizeof(rx) - rxpos, INET_MSG_DONTWAIT);
		
		// Free Network Lock
		_freeNetworkLock();
		
		// Received Data
		if(received > 0)
		{
			// Fix Position
			rxpos += received;
			
			// Log Incoming Traffic
			#ifdef DEBUG
			printk("Received %d Bytes of Data from Server\n", received);
			#endif
		}
		
		// Handle Packets
		if(rxpos > 0)
		{
			// BSSID Packet
			if(rx[0] == OPCODE_CONNECT_BSSID)
			{
				// Enough Data available
				if(rxpos >= sizeof(SceNetAdhocctlConnectBSSIDPacketS2C))
				{
					// Cast Packet
					SceNetAdhocctlConnectBSSIDPacketS2C * packet = (SceNetAdhocctlConnectBSSIDPacketS2C *)rx;
					
					// Update BSSID
					_parameter.bssid.mac_addr = packet->mac;
					
					// Change State
					_thread_status = ADHOCCTL_STATE_CONNECTED;
					
					// Notify Event Handlers
					int i = 0; for(; i < ADHOCCTL_MAX_HANDLER; i++)
					{
						// Active Handler
						if(_event_handler[i] != NULL) _event_handler[i](ADHOCCTL_EVENT_CONNECT, 0, _event_args[i]);
					}
					
					// Move RX Buffer
					memmove(rx, rx + sizeof(SceNetAdhocctlConnectBSSIDPacketS2C), sizeof(rx) - sizeof(SceNetAdhocctlConnectBSSIDPacketS2C));
					
					// Fix RX Buffer Length
					rxpos -= sizeof(SceNetAdhocctlConnectBSSIDPacketS2C);
				}
			}
			
			// Chat Packet
			else if(rx[0] == OPCODE_CHAT)
			{
				// Enough Data available
				if(rxpos >= sizeof(SceNetAdhocctlChatPacketS2C))
				{
					// Cast Packet
					SceNetAdhocctlChatPacketS2C * packet = (SceNetAdhocctlChatPacketS2C *)rx;
					
					// Fix for Idiots that try to troll the "ME" Nametag
					if(stricmp((char *)packet->name.data, "ME") == 0) strcpy((char *)packet->name.data, "NOT ME");
					
					// Add Incoming Chat to HUD
					addChatLog((char *)packet->name.data, packet->base.message);
					
					// Move RX Buffer
					memmove(rx, rx + sizeof(SceNetAdhocctlChatPacketS2C), sizeof(rx) - sizeof(SceNetAdhocctlChatPacketS2C));
					
					// Fix RX Buffer Length
					rxpos -= sizeof(SceNetAdhocctlChatPacketS2C);
				}
			}
			
			// Connect Packet
			else if(rx[0] == OPCODE_CONNECT)
			{
				// Enough Data available
				if(rxpos >= sizeof(SceNetAdhocctlConnectPacketS2C))
				{
					// Log Incoming Peer
					#ifdef DEBUG
					printk("Incoming Peer Data...\n");
					#endif
					
					// Cast Packet
					SceNetAdhocctlConnectPacketS2C * packet = (SceNetAdhocctlConnectPacketS2C *)rx;
					
					// Add User
					_addFriend(packet);
					
					// Update HUD User Count
					#ifdef LOCALHOST_AS_PEER
					setUserCount(_getActivePeerCount());
					#else
					setUserCount(_getActivePeerCount()+1);
					#endif
					
					// Move RX Buffer
					memmove(rx, rx + sizeof(SceNetAdhocctlConnectPacketS2C), sizeof(rx) - sizeof(SceNetAdhocctlConnectPacketS2C));
					
					// Fix RX Buffer Length
					rxpos -= sizeof(SceNetAdhocctlConnectPacketS2C);
				}
			}
			
			// Disconnect Packet
			else if(rx[0] == OPCODE_DISCONNECT)
			{
				// Enough Data available
				if(rxpos >= sizeof(SceNetAdhocctlDisconnectPacketS2C))
				{
					// Log Incoming Peer Delete Request
					#ifdef DEBUG
					printk("Incoming Peer Data Delete Request...\n");
					#endif
					
					// Cast Packet
					SceNetAdhocctlDisconnectPacketS2C * packet = (SceNetAdhocctlDisconnectPacketS2C *)rx;
					
					// Delete User by IP
					_deleteFriendByIP(packet->ip);
					
					// Update HUD User Count
					#ifdef LOCALHOST_AS_PEER
					setUserCount(_getActivePeerCount());
					#else
					setUserCount(_getActivePeerCount()+1);
					#endif
					
					// Move RX Buffer
					memmove(rx, rx + sizeof(SceNetAdhocctlDisconnectPacketS2C), sizeof(rx) - sizeof(SceNetAdhocctlDisconnectPacketS2C));
					
					// Fix RX Buffer Length
					rxpos -= sizeof(SceNetAdhocctlDisconnectPacketS2C);
				}
			}
			
			// Scan Packet
			else if(rx[0] == OPCODE_SCAN)
			{
				// Enough Data available
				if(rxpos >= sizeof(SceNetAdhocctlScanPacketS2C))
				{
					// Log Incoming Network Information
					#ifdef DEBUG
					printk("Incoming Group Information...\n");
					#endif
					
					// Cast Packet
					SceNetAdhocctlScanPacketS2C * packet = (SceNetAdhocctlScanPacketS2C *)rx;
					
					// Allocate Structure Data
					SceNetAdhocctlScanInfo * group = (SceNetAdhocctlScanInfo *)malloc(sizeof(SceNetAdhocctlScanInfo));
					
					// Allocated Structure Data
					if(group != NULL)
					{
						// Clear Memory
						memset(group, 0, sizeof(SceNetAdhocctlScanInfo));
						
						// Link to existing Groups
						group->next = _networks;
						
						// Copy Group Name
						group->group_name = packet->group;
						
						// Set Group Host
						group->bssid.mac_addr = packet->mac;
						
						// Link into Group List
						_networks = group;
					}
					
					// Move RX Buffer
					memmove(rx, rx + sizeof(SceNetAdhocctlScanPacketS2C), sizeof(rx) - sizeof(SceNetAdhocctlScanPacketS2C));
					
					// Fix RX Buffer Length
					rxpos -= sizeof(SceNetAdhocctlScanPacketS2C);
				}
			}
			
			// Scan Complete Packet
			else if(rx[0] == OPCODE_SCAN_COMPLETE)
			{
				// Log Scan Completion
				#ifdef DEBUG
				printk("Incoming Scan complete response...\n");
				#endif
				
				// Change State
				_thread_status = ADHOCCTL_STATE_DISCONNECTED;
				
				// Notify Event Handlers
				int i = 0; for(; i < ADHOCCTL_MAX_HANDLER; i++)
				{
					// Active Handler
					if(_event_handler[i] != NULL) _event_handler[i](ADHOCCTL_EVENT_SCAN, 0, _event_args[i]);
				}
				
				// Move RX Buffer
				memmove(rx, rx + 1, sizeof(rx) - 1);
				
				// Fix RX Buffer Length
				rxpos -= 1;
			}
		}
		
		// Reception Update required
		if((sceKernelGetSystemTimeWide() - lastreceptionupdate) > 5000000)
		{
			// Clone Time into Last Update Field
			lastreceptionupdate = sceKernelGetSystemTimeWide();
			
			// Update Reception Level
			union SceNetApctlInfo info;
			if(sceNetApctlGetInfo(PSP_NET_APCTL_INFO_STRENGTH, &info) >= 0) setReceptionPercentage((int)info.strength);
			else setReceptionPercentage(0);
		}
		
		//	Delay Thread (10ms)
		sceKernelDelayThread(10000);
	}
	
	// Set WLAN HUD Reception to 0% on Shutdown
	setReceptionPercentage(0);
	
	// Notify Caller of Shutdown
	_init = -1;
	
	// Log Shutdown
	printk("End of Friend Finder Thread\n");
	
	// Reset Thread Status
	_thread_status = ADHOCCTL_STATE_DISCONNECTED;
	
	// Kill Thread
	sceKernelExitDeleteThread(0);
	
	// Return Success
	return 0;
}
Ejemplo n.º 3
0
/**
 * Adhoc Emulator PDP Send Call
 * @param id Socket File Descriptor
 * @param daddr Target MAC Address
 * @param dport Target Port
 * @param data Data Payload
 * @param len Payload Length
 * @param timeout Send Timeout
 * @param flag Nonblocking Flag
 * @return 0 on success or... ADHOC_INVALID_ARG, ADHOC_NOT_INITIALIZED, ADHOC_INVALID_SOCKET_ID, ADHOC_SOCKET_DELETED, ADHOC_INVALID_ADDR, ADHOC_INVALID_PORT, ADHOC_INVALID_DATALEN, ADHOC_SOCKET_ALERTED, ADHOC_TIMEOUT, ADHOC_THREAD_ABORTED, ADHOC_WOULD_BLOCK, NET_NO_SPACE, NET_INTERNAL
 */
int proNetAdhocPdpSend(int id, const SceNetEtherAddr * daddr, uint16_t dport, const void * data, int len, uint32_t timeout, int flag)
{
	// Library is initialized
	if(_init)
	{
		// Valid Port
		if(dport != 0)
		{
			// Valid Data Length
			if(len > 0)
			{
				// Valid Socket ID
				if(id > 0 && id <= 255 && _pdp[id - 1] != NULL)
				{
					// Cast Socket
					SceNetAdhocPdpStat * socket = _pdp[id - 1];
					
					// Valid Data Buffer
					if(data != NULL)
					{
						// Valid Destination Address
						if(daddr != NULL)
						{
							// Log Destination
							#ifdef DEBUG
							printk("Attempting PDP Send to %02X:%02X:%02X:%02X:%02X:%02X on Port %u\n", daddr->data[0], daddr->data[1], daddr->data[2], daddr->data[3], daddr->data[4], daddr->data[5], dport);
							#endif
							
							// Schedule Timeout Removal
							if(flag) timeout = 0;
							
							// Apply Send Timeout Settings to Socket
							sceNetInetSetsockopt(socket->id, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
							
							// Single Target
							if(!_isBroadcastMAC(daddr))
							{
								// Fill in Target Structure
								SceNetInetSockaddrIn target;
								target.sin_family = AF_INET;
								target.sin_port = sceNetHtons(dport);
								
								// Get Peer IP
								if(_resolveMAC((SceNetEtherAddr *)daddr, &target.sin_addr) == 0)
								{
									// Acquire Network Lock
									_acquireNetworkLock();
									
									// Send Data
									int sent = sceNetInetSendto(socket->id, data, len, ((flag != 0) ? (INET_MSG_DONTWAIT) : (0)), (SceNetInetSockaddr *)&target, sizeof(target));
									
									// Free Network Lock
									_freeNetworkLock();
									
									// Sent Data
									if(sent == len)
									{
										// Success
										return 0;
									}
									
									// Blocking Situation
									if(flag) return ADHOC_WOULD_BLOCK;
									
									// Timeout
									return ADHOC_TIMEOUT;
								}
							}
							
							// Broadcast Target
							else
							{
								// Acquire Network Lock
								_acquireNetworkLock();
								
								#ifdef BROADCAST_TO_LOCALHOST
								// Get Local IP Address
								union SceNetApctlInfo info; if(sceNetApctlGetInfo(PSP_NET_APCTL_INFO_IP, &info) == 0)
								{
									// Fill in Target Structure
									SceNetInetSockaddrIn target;
									target.sin_family = AF_INET;
									sceNetInetInetAton(info.ip, &target.sin_addr);
									target.sin_port = sceNetHtons(dport);
									
									// Send Data
									sceNetInetSendto(socket->id, data, len, ((flag != 0) ? (INET_MSG_DONTWAIT) : (0)), (SceNetInetSockaddr *)&target, sizeof(target));
								}
								#endif
								
								// Acquire Peer Lock
								_acquirePeerLock();
								
								// Iterate Peers
								SceNetAdhocctlPeerInfo * peer = _getInternalPeerList();
								for(; peer != NULL; peer = peer->next)
								{
									// Fill in Target Structure
									SceNetInetSockaddrIn target;
									target.sin_family = AF_INET;
									target.sin_addr = peer->ip_addr;
									target.sin_port = sceNetHtons(dport);
									
									// Send Data
									sceNetInetSendto(socket->id, data, len, ((flag != 0) ? (INET_MSG_DONTWAIT) : (0)), (SceNetInetSockaddr *)&target, sizeof(target));
								}
								
								// Free Peer Lock
								_freePeerLock();
								
								// Free Network Lock
								_freeNetworkLock();
								
								// Broadcast never fails!
								return 0;
							}
						}
						
						// Invalid Destination Address
						return ADHOC_INVALID_ADDR;
					}
					
					// Invalid Argument
					return ADHOC_INVALID_ARG;
				}
				
				// Invalid Socket ID
				return ADHOC_INVALID_SOCKET_ID;
			}
			
			// Invalid Data Length
			return ADHOC_INVALID_DATALEN;
		}
		
		// Invalid Destination Port
		return ADHOC_INVALID_PORT;
	}
	
	// Library is uninitialized
	return ADHOC_NOT_INITIALIZED;
}
Ejemplo n.º 4
0
/**
 * Initialize Networking Components for Adhocctl Emulator
 * @param adhoc_id Game Product Code
 * @param server_ip Server IP
 * @return 0 on success or... -1
 */
int _initNetwork(const SceNetAdhocctlAdhocId * adhoc_id, const char * server_ip)
{
	// WLAN Switch Check
	if(sceWlanGetSwitchState() == 1)
	{
		// Initialize Access Point Control
		if(sceNetApctlInit(0x1800, 0x30) == 0)
		{
			// Attempt Counter
			int attemptmax = 10;
			
			// Attempt Number
			int attempt = 0;
			
			// Attempt Connection Setup
			for(; attempt < attemptmax; attempt++)
			{
				// Start Connection
				if(sceNetApctlConnect(_hotspot) == 0)
				{
					// Wait for Connection
					int statebefore = 0;
					int state = 0; while(state != 4)
					{
						// Query State
						int getstate = sceNetApctlGetState(&state);
						
						// Log State Change
						if(statebefore != state) printk("New Connection State: %d\n", state);					
						
						// Query Success
						if(getstate == 0 && state != 4)
						{
							// Wait for Retry
							sceKernelDelayThread(1000000);
						}
						
						// Query Error
						else break;
						
						// Save Before State
						statebefore = state;
					}
					
					// Connected
					if(state == 4)
					{
						// Create Friend Finder Socket
						int socket = sceNetInetSocket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
						
						// Created Socket
						if(socket > 0)
						{
							// Enable Port Re-use
							sceNetInetSetsockopt(socket, SOL_SOCKET, SO_REUSEADDR, &_one, sizeof(_one));
							sceNetInetSetsockopt(socket, SOL_SOCKET, SO_REUSEPORT, &_one, sizeof(_one));
							
							// Apply Receive Timeout Settings to Socket
							// uint32_t timeout = ADHOCCTL_RECV_TIMEOUT;
							// sceNetInetSetsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
							
							// Server IP
							uint32_t ip = 0;
							
							// Initialize DNS Resolver
							if(sceNetResolverInit() == 0)
							{
								// Create DNS Resolver
								unsigned char rbuf[512]; int rid = 0;
								if(sceNetResolverCreate(&rid, rbuf, sizeof(rbuf)) == 0)
								{
									// Resolve Domain
									if(sceNetResolverStartNtoA(rid, server_ip, &ip, 500000, 2) != 0)
									{
										// Attempt IP Conversion
										sceNetInetInetAton(server_ip, &ip);
									}
									
									// Delete DNS Resolver
									sceNetResolverDelete(rid);
								}
								
								// Shutdown DNS Resolver
								sceNetResolverTerm();
							}
							
							// Prepare Server Address
							SceNetInetSockaddrIn addr;
							addr.sin_len = sizeof(addr);
							addr.sin_family = AF_INET;
							addr.sin_addr = ip;
							addr.sin_port = sceNetHtons(ADHOCCTL_METAPORT);
							
							// Connect to Server
							if(sceNetInetConnect(socket, (SceNetInetSockaddr *)&addr, sizeof(addr)) == 0)
							{
								// Save Meta Socket
								_metasocket = socket;
								
								// Save Product Code
								_product_code = *adhoc_id;
								
								// Clear Event Handler
								memset(_event_handler, 0, sizeof(_event_handler[0]) * ADHOCCTL_MAX_HANDLER);
								memset(_event_args, 0, sizeof(_event_args[0]) * ADHOCCTL_MAX_HANDLER);
								
								// Clear Internal Control Status
								memset(&_parameter, 0, sizeof(_parameter));
								
								// Read PSP Player Name
								sceUtilityGetSystemParamString(PSP_SYSTEMPARAM_ID_STRING_NICKNAME, (char *)_parameter.nickname.data, ADHOCCTL_NICKNAME_LEN);
								
								// Read Adhoc Channel
								sceUtilityGetSystemParamInt(PSP_SYSTEMPARAM_ID_INT_ADHOC_CHANNEL, &_parameter.channel);
								
								// Fake Channel Number 1 on Automatic Channel
								if(_parameter.channel == 0) _parameter.channel = 1;
								
								// Read PSP MAC Address
								sceWlanGetEtherAddr((void *)&_parameter.bssid.mac_addr.data);
								
								// Prepare Login Packet
								SceNetAdhocctlLoginPacketC2S packet;
								
								// Set Packet Opcode
								packet.base.opcode = OPCODE_LOGIN;
								
								// Set MAC Address
								packet.mac = _parameter.bssid.mac_addr;
								
								// Set Nickname
								packet.name = _parameter.nickname;
								
								// Set Game Product ID
								memcpy(packet.game.data, adhoc_id->data, ADHOCCTL_ADHOCID_LEN);
								
								// Acquire Network Layer Lock
								_acquireNetworkLock();
								
								// Send Login Packet
								sceNetInetSend(_metasocket, &packet, sizeof(packet), INET_MSG_DONTWAIT);
								
								// Free Network Layer Lock
								_freeNetworkLock();
								
								// Load UPNP Library
								_upnp_uid = sceKernelLoadModule("ms0:/kd/pspnet_miniupnc.prx", 0, NULL);
								
								// Start UPNP Library
								int status = 0; sceKernelStartModule(_upnp_uid, 0, NULL, &status, NULL);
								
								// Return Success
								return 0;
							}
							
							// Delete Socket
							sceNetInetClose(socket);
						}
						
						// Close Hotspot Connection
						sceNetApctlDisconnect();
					}
				}
			}
			
			// Terminate Access Point Control
			sceNetApctlTerm();	
		}
	}
	
	// Generic Error
	return -1;
}
Ejemplo n.º 5
0
/**
 * Adhoc Emulator PDP Socket Poller (Select Equivalent)
 * @param sds Poll Socket Descriptor Array
 * @param nsds Array Item Count
 * @param timeout Timeout in Microseconds
 * @param flags Nonblocking Flag
 * @return Number of affected Sockets on success or... ADHOC_NOT_INITIALIZED, ADHOC_INVALID_SOCKET_ID, ADHOC_INVALID_ARG, ADHOC_TIMEOUT, ADHOC_THREAD_ABORTED, ADHOC_EXCEPTION_EVENT, NET_NO_SPACE, NET_INTERNAL
 */
int proNetAdhocPollSocket(SceNetAdhocPollSd * sds, int nsds, uint32_t timeout, int flags)
{
	// Library is initialized
	if(_init)
	{
		// Valid Arguments
		if(sds != NULL && nsds > 0)
		{
			// Socket Check
			int i = 0; for(; i < nsds; i++)
			{
				// Invalid Socket
				if(sds[i].id < 1 || sds[i].id > 255 || _pdp[sds[i].id - 1] == NULL) return ADHOC_INVALID_SOCKET_ID;
			}
			
			// Allocate Infrastructure Memory
			SceNetInetPollfd * isds = (SceNetInetPollfd *)malloc(sizeof(SceNetInetPollfd) * nsds);
			
			// Allocated Memory
			if(isds != NULL)
			{
				// Clear Memory
				memset(isds, 0, sizeof(SceNetInetPollfd) * nsds);
				
				// Translate Polling Flags to Infrastructure
				for(i = 0; i < nsds; i++)
				{
					// Fill in Infrastructure Socket ID
					isds[i].fd = _pdp[sds[i].id - 1]->id;
					
					// Send Event
					if(sds[i].events & ADHOC_EV_SEND) isds[i].events |= INET_POLLWRNORM;
					
					// Receive Event
					if(sds[i].events & ADHOC_EV_RECV) isds[i].events |= INET_POLLRDNORM;
				}
				
				// Nonblocking Mode
				if(flags) timeout = 0;
				
				// Timeout Translation (Micro to Milliseconds)
				else
				{
					// Convert Timeout
					timeout /= 1000;
					
					// Prevent Nonblocking Mode
					if(timeout == 0) timeout = 1;
				}
				
				// Acquire Network Lock
				_acquireNetworkLock();
				
				// Poll Sockets
				int affectedsockets = sceNetInetPoll(isds, nsds, timeout);
				
				// Free Network Lock
				_freeNetworkLock();
				
				// Sockets affected
				if(affectedsockets > 0)
				{
					// Translate Polling Results to Adhoc
					for(i = 0; i < nsds; i++)
					{
						// Send Event
						if(isds[i].revents & INET_POLLWRNORM) sds[i].revents |= ADHOC_EV_SEND;
						
						// Receive Event
						if(isds[i].revents & INET_POLLRDNORM) sds[i].revents |= ADHOC_EV_RECV;
					}
				}
				
				// Free Memory
				free(isds);
				
				// Blocking Mode (Nonblocking Mode returns 0, even on Success)
				if(!flags)
				{
					// Success
					if(affectedsockets > 0) return affectedsockets;
					
					// Timeout
					return ADHOC_TIMEOUT;
				}
			}
			
			// No Events generated
			return 0;
		}
		
		// Invalid Argument
		return ADHOC_INVALID_ARG;
	}
	
	// Library is uninitialized
	return ADHOC_NOT_INITIALIZED;
}