mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
According to http://msdn.microsoft.com/en-us/library/windows/desktop/ms737625%28v=vs.85%29.aspx "[...] it is not recommended that applications use multiple calls to connect to detect connection completion. If they do, they must be prepared to handle WSAEINVAL and WSAEWOULDBLOCK error values the same way that they handle WSAEALREADY, to assure robust operation." Ideally socket->state should be set to a different state and select() used to poll sockets until state can be switched to closed or established. Changes to socket->state are visible to games as so probably should not be done without testing.
599 lines
13 KiB
C++
599 lines
13 KiB
C++
#pragma once
|
|
|
|
#include "base/timeutil.h"
|
|
#include "base/mutex.h"
|
|
#include "thread/thread.h"
|
|
#include "net/resolve.h"
|
|
|
|
#include "Core/Config.h"
|
|
#include "Core/CoreTiming.h"
|
|
#include "Core/HLE/HLE.h"
|
|
#include "Core/HLE/sceNetAdhoc.h"
|
|
#include "Core/HLE/sceKernel.h"
|
|
#include "Core/HLE/sceKernelMutex.h"
|
|
#include "Core/HLE/sceUtility.h"
|
|
|
|
class PointerWrap;
|
|
|
|
// Net stuff
|
|
#ifdef _XBOX
|
|
#include <winsockx.h>
|
|
typedef int socklen_t;
|
|
#elif defined(_MSC_VER)
|
|
#include <WS2tcpip.h>
|
|
#else
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <netinet/in.h>
|
|
#include <netdb.h>
|
|
#include <arpa/inet.h>
|
|
#include <fcntl.h>
|
|
#include <errno.h>
|
|
#endif
|
|
#ifdef _MSC_VER
|
|
#define PACK
|
|
#undef errno
|
|
#undef EAGAIN
|
|
#undef EINPROGRESS
|
|
#undef EISCONN
|
|
#define errno WSAGetLastError()
|
|
#define EAGAIN WSAEWOULDBLOCK
|
|
#define EINPROGRESS WSAEWOULDBLOCK
|
|
#define EISCONN WSAEISCONN
|
|
inline bool connectInProgress(int errcode){ return (errcode == WSAEWOULDBLOCK || errcode == WSAEINVAL || errcode == WSAEALREADY); }
|
|
#else
|
|
#define INVALID_SOCKET -1
|
|
#define SOCKET_ERROR -1
|
|
#define closesocket close
|
|
#define PACK __attribute__((packed))
|
|
inline bool connectInProgress(int errcode){ return (errcode == EINPROGRESS); }
|
|
#endif
|
|
|
|
// psp strutcs and definitions
|
|
#define ADHOCCTL_MODE_ADHOC 0
|
|
#define ADHOCCTL_MODE_GAMEMODE 1
|
|
|
|
// Event Types for Event Handler
|
|
#define ADHOCCTL_EVENT_CONNECT 1
|
|
#define ADHOCCTL_EVENT_DISCONNECT 2
|
|
#define ADHOCCTL_EVENT_SCAN 3
|
|
|
|
// Internal Thread States
|
|
#define ADHOCCTL_STATE_DISCONNECTED 0
|
|
#define ADHOCCTL_STATE_CONNECTED 1
|
|
#define ADHOCCTL_STATE_SCANNING 2
|
|
#define ADHOCCTL_STATE_GAMEMODE 3
|
|
|
|
// Kernel Utility Netconf Adhoc Types
|
|
#define UTILITY_NETCONF_TYPE_CONNECT_ADHOC 2
|
|
#define UTILITY_NETCONF_TYPE_CREATE_ADHOC 4
|
|
#define UTILITY_NETCONF_TYPE_JOIN_ADHOC 5
|
|
|
|
// Kernel Utility States
|
|
#define UTILITY_NETCONF_STATUS_NONE 0
|
|
#define UTILITY_NETCONF_STATUS_INITIALIZE 1
|
|
#define UTILITY_NETCONF_STATUS_RUNNING 2
|
|
#define UTILITY_NETCONF_STATUS_FINISHED 3
|
|
#define UTILITY_NETCONF_STATUS_SHUTDOWN 4
|
|
|
|
// PTP Connection States
|
|
#define PTP_STATE_CLOSED 0
|
|
#define PTP_STATE_LISTEN 1
|
|
#define PTP_STATE_ESTABLISHED 4
|
|
|
|
#ifdef _MSC_VER
|
|
#pragma pack(push, 1)
|
|
#endif
|
|
// Ethernet Address
|
|
#define ETHER_ADDR_LEN 6
|
|
typedef struct SceNetEtherAddr {
|
|
uint8_t data[ETHER_ADDR_LEN];
|
|
} PACK SceNetEtherAddr;
|
|
|
|
|
|
// Adhoc Virtual Network Name
|
|
#define ADHOCCTL_GROUPNAME_LEN 8
|
|
typedef struct SceNetAdhocctlGroupName {
|
|
uint8_t data[ADHOCCTL_GROUPNAME_LEN];
|
|
} PACK SceNetAdhocctlGroupName;
|
|
|
|
// Virtual Network Host Information
|
|
typedef struct SceNetAdhocctlBSSId {
|
|
SceNetEtherAddr mac_addr;
|
|
uint8_t padding[2];
|
|
} PACK SceNetAdhocctlBSSId;
|
|
|
|
// Virtual Network Information
|
|
typedef struct SceNetAdhocctlScanInfo {
|
|
struct SceNetAdhocctlScanInfo * next;
|
|
s32_le channel;
|
|
SceNetAdhocctlGroupName group_name;
|
|
SceNetAdhocctlBSSId bssid;
|
|
s32_le mode;
|
|
} PACK SceNetAdhocctlScanInfo;
|
|
|
|
// Player Nickname
|
|
#define ADHOCCTL_NICKNAME_LEN 128
|
|
typedef struct SceNetAdhocctlNickname {
|
|
uint8_t data[ADHOCCTL_NICKNAME_LEN];
|
|
} PACK SceNetAdhocctlNickname;
|
|
|
|
// Active Virtual Network Information
|
|
typedef struct SceNetAdhocctlParameter {
|
|
s32_le channel;
|
|
SceNetAdhocctlGroupName group_name;
|
|
SceNetAdhocctlBSSId bssid;
|
|
SceNetAdhocctlNickname nickname;
|
|
} PACK SceNetAdhocctlParameter;
|
|
|
|
// Peer Information
|
|
typedef struct SceNetAdhocctlPeerInfo {
|
|
SceNetAdhocctlPeerInfo * next;
|
|
SceNetAdhocctlNickname nickname;
|
|
SceNetEtherAddr mac_addr;
|
|
u32_le ip_addr;
|
|
uint8_t padding[2];
|
|
u64_le last_recv;
|
|
} PACK SceNetAdhocctlPeerInfo;
|
|
|
|
// Peer Information with u32 pointers
|
|
typedef struct SceNetAdhocctlPeerInfoEmu {
|
|
u32_le next; // Changed the pointer to u32
|
|
SceNetAdhocctlNickname nickname;
|
|
SceNetEtherAddr mac_addr;
|
|
u32_le ip_addr;
|
|
u32 padding; // Changed the pointer to u32
|
|
u64_le last_recv;
|
|
} SceNetAdhocctlPeerInfoEmu;
|
|
|
|
// Game Mode Peer List
|
|
#define ADHOCCTL_GAMEMODE_MAX_MEMBERS 16
|
|
typedef struct SceNetAdhocctlGameModeInfo {
|
|
s32_le num;
|
|
SceNetEtherAddr member[ADHOCCTL_GAMEMODE_MAX_MEMBERS];
|
|
} PACK SceNetAdhocctlGameModeInfo;
|
|
#ifdef _MSC_VER
|
|
#pragma pack(pop)
|
|
#endif
|
|
|
|
// Adhoc ID (Game Product Key)
|
|
#define ADHOCCTL_ADHOCID_LEN 9
|
|
typedef struct SceNetAdhocctlAdhocId {
|
|
s32_le type;
|
|
uint8_t data[ADHOCCTL_ADHOCID_LEN];
|
|
uint8_t padding[3];
|
|
} SceNetAdhocctlAdhocId;
|
|
|
|
// Socket Polling Event Listener
|
|
struct SceNetAdhocPollSd {
|
|
s32_le id;
|
|
s32_le events;
|
|
s32_le revents;
|
|
};
|
|
|
|
// PDP Socket Status
|
|
struct SceNetAdhocPdpStat {
|
|
struct SceNetAdhocPdpStat * next;
|
|
s32_le id;
|
|
SceNetEtherAddr laddr;
|
|
u16_le lport;
|
|
u32_le rcv_sb_cc;
|
|
};
|
|
|
|
// PTP Socket Status
|
|
struct SceNetAdhocPtpStat {
|
|
u32_le next; // Changed the pointer to u32
|
|
s32_le id;
|
|
SceNetEtherAddr laddr;
|
|
SceNetEtherAddr paddr;
|
|
u16_le lport;
|
|
u16_le pport;
|
|
u32_le snd_sb_cc;
|
|
u32_le rcv_sb_cc;
|
|
s32_le state;
|
|
};
|
|
|
|
// Gamemode Optional Peer Buffer Data
|
|
struct SceNetAdhocGameModeOptData {
|
|
u32_le size;
|
|
u32_le flag;
|
|
u64_le last_recv;
|
|
};
|
|
|
|
// Gamemode Buffer Status
|
|
struct SceNetAdhocGameModeBufferStat {
|
|
struct SceNetAdhocGameModeBufferStat * next;
|
|
s32_le id;
|
|
void * ptr;
|
|
u32_le size;
|
|
u32_le master;
|
|
SceNetAdhocGameModeOptData opt;
|
|
};
|
|
|
|
|
|
// Internal Matching Peer Information
|
|
typedef struct SceNetAdhocMatchingMemberInternal {
|
|
// Next Peer
|
|
struct SceNetAdhocMatchingMemberInternal * next;
|
|
|
|
// MAC Address
|
|
SceNetEtherAddr mac;
|
|
|
|
// State Variable
|
|
s32_le state;
|
|
|
|
// Send in Progress
|
|
s32_le sending;
|
|
|
|
// Last Heartbeat
|
|
u64_le lastping;
|
|
} SceNetAdhocMatchingMemberInternal;
|
|
|
|
|
|
// Matching handler
|
|
struct SceNetAdhocMatchingHandlerArgs {
|
|
s32_le id;
|
|
s32_le event;
|
|
SceNetEtherAddr * peer;
|
|
s32_le optlen;
|
|
void * opt;
|
|
};
|
|
|
|
struct SceNetAdhocMatchingHandler {
|
|
u32_le entryPoint;
|
|
};
|
|
|
|
// Thread Message Stack Item
|
|
typedef struct ThreadMessage {
|
|
// Next Thread Message
|
|
struct ThreadMessage * next;
|
|
|
|
// Stack Event Opcode
|
|
u32_le opcode;
|
|
|
|
// Target MAC Address
|
|
SceNetEtherAddr mac;
|
|
|
|
// Optional Data Length
|
|
s32_le optlen;
|
|
} ThreadMessage;
|
|
|
|
// Established Peer
|
|
|
|
// Context Information
|
|
typedef struct SceNetAdhocMatchingContext {
|
|
// Next Context
|
|
struct SceNetAdhocMatchingContext * next;
|
|
|
|
// Externally Visible ID
|
|
s32_le id;
|
|
|
|
// Matching Mode (HOST, CLIENT, P2P)
|
|
s32_le mode;
|
|
|
|
// Running Flag (1 = running, 0 = created)
|
|
s32_le running;
|
|
|
|
// Maximum Number of Peers (for HOST, P2P)
|
|
s32_le maxpeers;
|
|
|
|
// Local MAC Address
|
|
SceNetEtherAddr mac;
|
|
|
|
// Peer List for Connectees
|
|
SceNetAdhocMatchingMemberInternal * peerlist;
|
|
|
|
// Local PDP Port
|
|
u16_le port;
|
|
|
|
// Local PDP Socket
|
|
s32_le socket;
|
|
|
|
// Receive Buffer Length
|
|
s32_le rxbuflen;
|
|
|
|
// Receive Buffer
|
|
uint8_t * rxbuf;
|
|
|
|
// Hello Broadcast Interval (Microseconds)
|
|
u32_le hello_int;
|
|
|
|
// Keep-Alive Broadcast Interval (Microseconds)
|
|
u32_le keepalive_int;
|
|
|
|
// Resend Interval (Microseconds)
|
|
u32_le resend_int;
|
|
|
|
// Resend-Counter
|
|
s32_le resendcounter;
|
|
|
|
// Keep-Alive Counter
|
|
s32_le keepalivecounter;
|
|
|
|
// Event Handler
|
|
SceNetAdhocMatchingHandler handler;
|
|
|
|
// Hello Data Length
|
|
u32_le hellolen;
|
|
|
|
// Hello Data
|
|
void * hello;
|
|
|
|
// Event Caller Thread
|
|
s32_le event_thid;
|
|
|
|
// IO Handler Thread
|
|
s32_le input_thid;
|
|
|
|
// Event Caller Thread Message Stack
|
|
s32_le event_stack_lock;
|
|
ThreadMessage * event_stack;
|
|
|
|
// IO Handler Thread Message Stack
|
|
s32_le input_stack_lock;
|
|
ThreadMessage * input_stack;
|
|
} SceNetAdhocMatchingContext;
|
|
|
|
// End of psp definitions
|
|
|
|
#define OPCODE_PING 0
|
|
#define OPCODE_LOGIN 1
|
|
#define OPCODE_CONNECT 2
|
|
#define OPCODE_DISCONNECT 3
|
|
#define OPCODE_SCAN 4
|
|
#define OPCODE_SCAN_COMPLETE 5
|
|
#define OPCODE_CONNECT_BSSID 6
|
|
#define OPCODE_CHAT 7
|
|
|
|
// PSP Product Code
|
|
#define PRODUCT_CODE_LENGTH 9
|
|
|
|
#ifdef _MSC_VER
|
|
#pragma pack(push,1)
|
|
#endif
|
|
|
|
typedef struct {
|
|
// Game Product Code (ex. ULUS12345)
|
|
char data[PRODUCT_CODE_LENGTH];
|
|
} PACK SceNetAdhocctlProductCode;
|
|
|
|
// Basic Packet
|
|
typedef struct {
|
|
uint8_t opcode;
|
|
} PACK SceNetAdhocctlPacketBase;
|
|
|
|
// C2S Login Packet
|
|
typedef struct {
|
|
SceNetAdhocctlPacketBase base;
|
|
SceNetEtherAddr mac;
|
|
SceNetAdhocctlNickname name;
|
|
SceNetAdhocctlProductCode game;
|
|
} PACK SceNetAdhocctlLoginPacketC2S;
|
|
|
|
// C2S Connect Packet
|
|
typedef struct {
|
|
SceNetAdhocctlPacketBase base;
|
|
SceNetAdhocctlGroupName group;
|
|
} PACK SceNetAdhocctlConnectPacketC2S;
|
|
|
|
// C2S Chat Packet
|
|
typedef struct {
|
|
SceNetAdhocctlPacketBase base;
|
|
char message[64];
|
|
} PACK SceNetAdhocctlChatPacketC2S;
|
|
|
|
// S2C Connect Packet
|
|
typedef struct {
|
|
SceNetAdhocctlPacketBase base;
|
|
SceNetAdhocctlNickname name;
|
|
SceNetEtherAddr mac;
|
|
uint32_t ip;
|
|
} PACK SceNetAdhocctlConnectPacketS2C;
|
|
|
|
// S2C Disconnect Packet
|
|
typedef struct {
|
|
SceNetAdhocctlPacketBase base;
|
|
uint32_t ip;
|
|
} PACK SceNetAdhocctlDisconnectPacketS2C;
|
|
|
|
// S2C Scan Packet
|
|
typedef struct {
|
|
SceNetAdhocctlPacketBase base;
|
|
SceNetAdhocctlGroupName group;
|
|
SceNetEtherAddr mac;
|
|
} PACK SceNetAdhocctlScanPacketS2C;
|
|
|
|
// S2C Connect BSSID Packet
|
|
typedef struct {
|
|
SceNetAdhocctlPacketBase base;
|
|
SceNetEtherAddr mac;
|
|
} PACK SceNetAdhocctlConnectBSSIDPacketS2C;
|
|
|
|
// S2C Chat Packet
|
|
typedef struct {
|
|
SceNetAdhocctlChatPacketC2S base;
|
|
SceNetAdhocctlNickname name;
|
|
} PACK SceNetAdhocctlChatPacketS2C;
|
|
#ifdef _MSC_VER
|
|
#pragma pack(pop)
|
|
#endif
|
|
|
|
// Aux vars
|
|
extern int metasocket;
|
|
extern SceNetAdhocctlParameter parameter;
|
|
extern std::thread friendFinderThread;
|
|
extern recursive_mutex peerlock;
|
|
extern SceNetAdhocPdpStat * pdp[255];
|
|
extern SceNetAdhocPtpStat * ptp[255];
|
|
|
|
extern uint32_t fakePoolSize;
|
|
extern SceNetAdhocMatchingContext * contexts;
|
|
extern int one;
|
|
extern bool friendFinderRunning;
|
|
extern SceNetAdhocctlPeerInfo * friends;
|
|
extern SceNetAdhocctlScanInfo * networks;
|
|
extern int eventHandlerUpdate;
|
|
extern int threadStatus;
|
|
// End of Aux vars
|
|
|
|
/**
|
|
* Local MAC Check
|
|
* @param saddr To-be-checked MAC Address
|
|
* @return 1 if valid or... 0
|
|
*/
|
|
int isLocalMAC(const SceNetEtherAddr * addr);
|
|
|
|
/**
|
|
* PDP Port Check
|
|
* @param port To-be-checked Port
|
|
* @return 1 if in use or... 0
|
|
*/
|
|
int isPDPPortInUse(uint16_t port);
|
|
|
|
/**
|
|
* Check whether PTP Port is in use or not
|
|
* @param port To-be-checked Port Number
|
|
* @return 1 if in use or... 0
|
|
*/
|
|
int isPTPPortInUse(uint16_t port);
|
|
|
|
/**
|
|
* Add Friend to Local List
|
|
* @param packet Friend Information
|
|
*/
|
|
void addFriend(SceNetAdhocctlConnectPacketS2C * packet);
|
|
|
|
/**
|
|
* Changes the Blocking Mode of the socket
|
|
* @param fd File Descriptor of the socket
|
|
* @param nonblocking 1 to set to nonblock and 0 to set blocking
|
|
*/
|
|
void changeBlockingMode(int fd, int nonblocking);
|
|
|
|
/**
|
|
* Count Virtual Networks by analyzing the Friend List
|
|
* @return Number of Virtual Networks
|
|
*/
|
|
int countAvailableNetworks();
|
|
|
|
/**
|
|
* Closes & Deletes all PDP Sockets
|
|
*/
|
|
void deleteAllPDP(void);
|
|
|
|
/**
|
|
* Closes & Deletes all PTP sockets
|
|
*/
|
|
void deleteAllPTP(void);
|
|
|
|
/**
|
|
* Delete Friend from Local List
|
|
* @param ip Friend IP
|
|
*/
|
|
void deleteFriendByIP(uint32_t ip);
|
|
|
|
/**
|
|
* Find Free Matching ID
|
|
* @return First unoccupied Matching ID
|
|
*/
|
|
int findFreeMatchingID(void);
|
|
|
|
/**
|
|
* Find Internal Matching Context for Matching ID
|
|
* @param id Matching ID
|
|
* @return Matching Context Pointer or... NULL
|
|
*/
|
|
SceNetAdhocMatchingContext * findMatchingContext(int id);
|
|
|
|
/**
|
|
* Recursive Memory Freeing-Helper for Friend-Structures
|
|
* @param node Current Node in List
|
|
*/
|
|
void freeFriendsRecursive(SceNetAdhocctlPeerInfo * node);
|
|
|
|
/**
|
|
* 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();
|
|
|
|
/**
|
|
* Return Number of active Peers in the same Network as the Local Player
|
|
* @return Number of active Peers
|
|
*/
|
|
int getActivePeerCount(void);
|
|
|
|
/**
|
|
* Returns the locall Ip of this machine, TODO: Implement the linux version
|
|
* @param SocketAddres OUT: local ip
|
|
*/
|
|
int getLocalIp(sockaddr_in * SocketAddress);
|
|
|
|
/**
|
|
* Joins two 32 bits number into a 64 bit one
|
|
* @param num1: first number
|
|
* @param num2: second number
|
|
* @return Single 64 bit number
|
|
*/
|
|
#define firstMask 0x00000000FFFFFFFF
|
|
#define secondMask 0xFFFFFFFF00000000
|
|
u64 join32(u32 num1, u32 num2);
|
|
|
|
/**
|
|
* Splits a 64 bit number into two 32 bit ones
|
|
* @param num: The number to be split
|
|
* @param buf OUT: Array containing the split numbers
|
|
*/
|
|
void split64(u64 num, int buff[]);
|
|
|
|
/**
|
|
* Returns the local mac, TODO: Read from Config file
|
|
* @param addr OUT: Local Mac
|
|
*/
|
|
void getLocalMac(SceNetEtherAddr * addr);
|
|
|
|
/**
|
|
* PTP Socket Counter
|
|
* @return Number of internal PTP Sockets
|
|
*/
|
|
int getPTPSocketCount(void);
|
|
|
|
/**
|
|
* 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(SceNetAdhocctlAdhocId *adhocid);
|
|
|
|
/**
|
|
* Broadcast MAC Check
|
|
* @param addr To-be-checked MAC Address
|
|
* @return 1 if Broadcast MAC or... 0
|
|
*/
|
|
int isBroadcastMAC(const SceNetEtherAddr * addr);
|
|
|
|
/**
|
|
* Resolve IP to MAC
|
|
* @param ip Peer IP Address
|
|
* @param mac OUT: Peer MAC
|
|
* @return 0 on success or... ADHOC_NO_ENTRY
|
|
*/
|
|
int resolveIP(uint32_t ip, SceNetEtherAddr * mac);
|
|
|
|
/**
|
|
* Resolve MAC to IP
|
|
* @param mac Peer MAC Address
|
|
* @param ip OUT: Peer IP
|
|
* @return 0 on success or... ADHOC_NO_ENTRY
|
|
*/
|
|
int resolveMAC(SceNetEtherAddr * mac, uint32_t * ip);
|
|
|
|
/**
|
|
* Check whether Network Name contains only valid symbols
|
|
* @param group_name To-be-checked Network Name
|
|
* @return 1 if valid or... 0
|
|
*/
|
|
int validNetworkName(const SceNetAdhocctlGroupName * groupname);
|