int disconnectSocket() { int i; for ( i = 0; i < 4; i ++ ) { if ( ctrl_opts.sock[i].thid >= 0 ) { ctrl_opts.sock[i].operation = S_TERM; sceKernelWakeupThread( ctrl_opts.sock[i].thid ); } sceNetInetClose( ctrl_opts.sock[i].server ); ctrl_opts.sock[i].server = -1; } return 0; }
/** * Adhoc Emulator PDP Socket Delete * @param id Socket File Descriptor * @param flag Bitflags (Unused) * @return 0 on success or... ADHOC_INVALID_ARG, ADHOC_NOT_INITIALIZED, ADHOC_INVALID_SOCKET_ID */ int proNetAdhocPdpDelete(int id, int flag) { // Library is initialized if(_init) { // Valid Arguments if(id > 0 && id <= 255) { // Log Delete Attempt #ifdef DEBUG printk("Attempting to Delete Socket %d\n", id); #endif // Cast Socket SceNetAdhocPdpStat * socket = _pdp[id - 1]; // Valid Socket if(socket != NULL) { // Close Connection sceNetInetClose(socket->id); // Remove Port Forward from Router sceNetPortClose("UDP", socket->lport); // Free Memory free(socket); // Free Translation Slot _pdp[id - 1] = NULL; // Success return 0; } // Invalid Socket ID return ADHOC_INVALID_SOCKET_ID; } // Invalid Argument return ADHOC_INVALID_ARG; } // Library is uninitialized return ADHOC_NOT_INITIALIZED; }
/** * 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; }
/** * Adhoc Emulator PDP Socket Creator * @param saddr Local MAC (Unused) * @param sport Local Binding Port * @param bufsize Socket Buffer Size * @param flag Bitflags (Unused) * @return Socket ID > 0 on success or... ADHOC_NOT_INITIALIZED, ADHOC_INVALID_ARG, ADHOC_SOCKET_ID_NOT_AVAIL, ADHOC_INVALID_ADDR, ADHOC_PORT_NOT_AVAIL, ADHOC_INVALID_PORT, ADHOC_PORT_IN_USE, NET_NO_SPACE */ int proNetAdhocPdpCreate(const SceNetEtherAddr * saddr, uint16_t sport, int bufsize, int flag) { // Library is initialized if(_init) { // Valid Arguments are supplied if(saddr != NULL && bufsize > 0) { // Valid MAC supplied if(_IsLocalMAC(saddr)) { // Random Port required if(sport == 0) { // Find unused Port while(sport == 0 || _IsPDPPortInUse(sport)) { // Generate Port Number sport = (uint16_t)_getRandomNumber(65535); } } // Unused Port supplied if(!_IsPDPPortInUse(sport)) { // Create Internet UDP Socket int socket = sceNetInetSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); // Valid Socket produced 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)); // Binding Information for local Port SceNetInetSockaddrIn addr; addr.sin_len = sizeof(addr); addr.sin_family = AF_INET; addr.sin_addr = INADDR_ANY; addr.sin_port = sceNetHtons(sport); // Bound Socket to local Port if(sceNetInetBind(socket, (SceNetInetSockaddr *)&addr, sizeof(addr)) == 0) { // Allocate Memory for Internal Data SceNetAdhocPdpStat * internal = (SceNetAdhocPdpStat *)malloc(sizeof(SceNetAdhocPdpStat)); // Allocated Memory if(internal != NULL) { // Clear Memory memset(internal, 0, sizeof(SceNetAdhocPdpStat)); // Find Free Translator Index int i = 0; for(; i < 255; i++) if(_pdp[i] == NULL) break; // Found Free Translator Index if(i < 255) { // Fill in Data internal->id = socket; internal->laddr = *saddr; internal->lport = sport; internal->rcv_sb_cc = bufsize; // Link Socket to Translator ID _pdp[i] = internal; // Forward Port on Router sceNetPortOpen("UDP", sport); // Success return i + 1; } // Free Memory for Internal Data free(internal); } } // Close Socket sceNetInetClose(socket); } // Default to No-Space Error return NET_NO_SPACE; } // Port is in use by another PDP Socket return ADHOC_PORT_IN_USE; } // Invalid MAC supplied return ADHOC_INVALID_ADDR; } // Invalid Arguments were supplied return ADHOC_INVALID_ARG; } // Library is uninitialized return ADHOC_NOT_INITIALIZED; }
/* simpleUPnPcommand2 : * not so simple ! * return values : * pointer - OK * NULL - error */ char * simpleUPnPcommand2(int s, const char * url, const char * service, const char * action, struct UPNParg * args, int * bufsize, const char * httpversion) { char hostname[MAXHOSTNAMELEN+1]; unsigned short port = 0; char * path; char soapact[128]; char soapbody[2048]; char * buf; int n; *bufsize = 0; snprintf(soapact, sizeof(soapact), "%s#%s", service, action); if(args==NULL) { /*soapbodylen = */snprintf(soapbody, sizeof(soapbody), "<?xml version=\"1.0\"?>\r\n" "<" SOAPPREFIX ":Envelope " "xmlns:" SOAPPREFIX "=\"http://schemas.xmlsoap.org/soap/envelope/\" " SOAPPREFIX ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" "<" SOAPPREFIX ":Body>" "<" SERVICEPREFIX ":%s xmlns:" SERVICEPREFIX "=\"%s\">" "</" SERVICEPREFIX ":%s>" "</" SOAPPREFIX ":Body></" SOAPPREFIX ":Envelope>" "\r\n", action, service, action); } else { char * p; const char * pe, * pv; int soapbodylen; soapbodylen = snprintf(soapbody, sizeof(soapbody), "<?xml version=\"1.0\"?>\r\n" "<" SOAPPREFIX ":Envelope " "xmlns:" SOAPPREFIX "=\"http://schemas.xmlsoap.org/soap/envelope/\" " SOAPPREFIX ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" "<" SOAPPREFIX ":Body>" "<" SERVICEPREFIX ":%s xmlns:" SERVICEPREFIX "=\"%s\">", action, service); p = soapbody + soapbodylen; while(args->elt) { /* check that we are never overflowing the string... */ if(soapbody + sizeof(soapbody) <= p + 100) { /* we keep a margin of at least 100 bytes */ return NULL; } *(p++) = '<'; pe = args->elt; while(*pe) *(p++) = *(pe++); *(p++) = '>'; if((pv = args->val)) { while(*pv) *(p++) = *(pv++); } *(p++) = '<'; *(p++) = '/'; pe = args->elt; while(*pe) *(p++) = *(pe++); *(p++) = '>'; args++; } *(p++) = '<'; *(p++) = '/'; *(p++) = SERVICEPREFIX2; *(p++) = ':'; pe = action; while(*pe) *(p++) = *(pe++); strncpy(p, "></" SOAPPREFIX ":Body></" SOAPPREFIX ":Envelope>\r\n", soapbody + sizeof(soapbody) - p); } if(!parseURL(url, hostname, &port, &path)) return NULL; if(s<0) { s = connecthostport(hostname, port); if(s < 0) { return NULL; } } n = soapPostSubmit(s, path, hostname, port, soapact, soapbody, httpversion); if(n<=0) { sceNetInetClose(s); return NULL; } buf = getHTTPResponse(s, bufsize); sceNetInetClose(s); return buf; }
/* upnpDiscover() : * return a chained list of all devices found or NULL if * no devices was found. * It is up to the caller to free the chained list * delay is in millisecond (poll) */ struct UPNPDev * upnpDiscover(int delay, const char * multicastif, const char * minissdpdsock, int sameport, int ipv6, //unused in psp port int * error) { struct UPNPDev * tmp; struct UPNPDev * devlist = 0; int opt = 1; static const char MSearchMsgFmt[] = "M-SEARCH * HTTP/1.1\r\n" "HOST: %s:" XSTR(PORT) "\r\n" "ST: %s\r\n" "MAN: \"ssdp:discover\"\r\n" "MX: %u\r\n" "\r\n"; static const char * const deviceList[] = { #if 0 "urn:schemas-upnp-org:device:InternetGatewayDevice:2", "urn:schemas-upnp-org:service:WANIPConnection:2", #endif "urn:schemas-upnp-org:device:InternetGatewayDevice:1", "urn:schemas-upnp-org:service:WANIPConnection:1", "urn:schemas-upnp-org:service:WANPPPConnection:1", "upnp:rootdevice", 0 }; int deviceIndex = 0; char bufr[1536]; /* reception and emission buffer */ int sudp; int n; SceNetInetSockaddrIn sockudp_r; unsigned int mx; SceNetInetSockaddrIn sockudp_w; int linklocal = 1; if(error) *error = UPNPDISCOVER_UNKNOWN_ERROR; /* fallback to direct discovery */ //sudp = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, 0); sudp = sceNetInetSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if(sudp < 0) { if(error) *error = UPNPDISCOVER_SOCKET_ERROR; return NULL; } /* reception */ memset(&sockudp_r, 0, sizeof(SceNetInetSockaddrIn)); SceNetInetSockaddrIn * p = (SceNetInetSockaddrIn *)&sockudp_r; p->sin_family = AF_INET; if(sameport) p->sin_port = sceNetHtons(PORT); p->sin_addr = INADDR_ANY; // Enable Port Re-use sceNetInetSetsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); sceNetInetSetsockopt(sudp, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt)); /* Avant d'envoyer le paquet on bind pour recevoir la reponse */ if (sceNetInetBind(sudp, (const struct SceNetInetSockaddr *)&sockudp_r, sizeof(SceNetInetSockaddrIn)) != 0) { if(error) *error = UPNPDISCOVER_SOCKET_ERROR; sceNetInetClose(sudp); return NULL; } if(error) *error = UPNPDISCOVER_SUCCESS; /* Calculating maximum response time in seconds */ mx = ((unsigned int)delay) / 1000u; /* receiving SSDP response packet */ for(n = 0; deviceList[deviceIndex]; deviceIndex++) { if(n == 0) { /* sending the SSDP M-SEARCH packet */ n = snprintf(bufr, sizeof(bufr), MSearchMsgFmt, UPNP_MCAST_ADDR, deviceList[deviceIndex], mx); /* the following code is not using getaddrinfo */ /* emission */ memset(&sockudp_w, 0, sizeof(SceNetInetSockaddrIn)); SceNetInetSockaddrIn * p = (SceNetInetSockaddrIn *)&sockudp_w; p->sin_family = AF_INET; p->sin_port = sceNetHtons(PORT); sceNetInetInetAton(UPNP_MCAST_ADDR, &p->sin_addr); n = sceNetInetSendto(sudp, bufr, n, 0, (SceNetInetSockaddr *)&sockudp_w, sizeof(SceNetInetSockaddrIn)); if (n < 0) { if(error) *error = UPNPDISCOVER_SOCKET_ERROR; break; } } /* Waiting for SSDP REPLY packet to M-SEARCH */ n = receivedata(sudp, bufr, sizeof(bufr), delay); if (n < 0) { /* error */ if(error) *error = UPNPDISCOVER_SOCKET_ERROR; break; } else if (n == 0) { /* no data or Time Out */ if (devlist) { /* no more device type to look for... */ if(error) *error = UPNPDISCOVER_SUCCESS; break; } if(ipv6) { if(linklocal) { linklocal = 0; --deviceIndex; } else { linklocal = 1; } } } else { const char * descURL=NULL; int urlsize=0; const char * st=NULL; int stsize=0; /*printf("%d byte(s) :\n%s\n", n, bufr);*/ /* affichage du message */ parseMSEARCHReply(bufr, n, &descURL, &urlsize, &st, &stsize); if(st&&descURL) { for(tmp=devlist; tmp; tmp = tmp->pNext) { if(memcmp(tmp->descURL, descURL, urlsize) == 0 && tmp->descURL[urlsize] == '\0' && memcmp(tmp->st, st, stsize) == 0 && tmp->st[stsize] == '\0') break; } /* at the exit of the loop above, tmp is null if * no duplicate device was found */ if(tmp) continue; tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize); if(!tmp) { /* memory allocation error */ if(error) *error = UPNPDISCOVER_MEMORY_ERROR; break; } tmp->pNext = devlist; tmp->descURL = tmp->buffer; tmp->st = tmp->buffer + 1 + urlsize; memcpy(tmp->buffer, descURL, urlsize); tmp->buffer[urlsize] = '\0'; memcpy(tmp->buffer + urlsize + 1, st, stsize); tmp->buffer[urlsize+1+stsize] = '\0'; devlist = tmp; } } } sceNetInetClose(sudp); return devlist; }
/** * Adhoc Emulator PTP Active Socket Creator * @param saddr Local MAC (Unused) * @param sport Local Binding Port * @param daddr Target MAC * @param dport Target Port * @param bufsize Socket Buffer Size * @param rexmt_int Retransmit Interval (in Microseconds) * @param rexmt_cnt Retransmit Count * @param flag Bitflags (Unused) * @return Socket ID > 0 on success or... ADHOC_NOT_INITIALIZED, ADHOC_INVALID_ARG, ADHOC_INVALID_ADDR, ADHOC_INVALID_PORT */ int proNetAdhocPtpOpen(const SceNetEtherAddr * saddr, uint16_t sport, const SceNetEtherAddr * daddr, uint16_t dport, uint32_t bufsize, uint32_t rexmt_int, int rexmt_cnt, int flag) { // Library is initialized if(_init) { // Valid Addresses if(saddr != NULL && _IsLocalMAC(saddr) && daddr != NULL && !_isBroadcastMAC(daddr)) { // Random Port required if(sport == 0) { // Find unused Port while(sport == 0 || _IsPTPPortInUse(sport)) { // Generate Port Number sport = (uint16_t)_getRandomNumber(65535); } } // Valid Ports if(!_IsPTPPortInUse(sport) && dport != 0) { // Valid Arguments if(bufsize > 0 && rexmt_int > 0 && rexmt_cnt > 0) { // Create Infrastructure Socket int socket = sceNetInetSocket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // Valid Socket produced 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)); // Binding Information for local Port SceNetInetSockaddrIn addr; addr.sin_len = sizeof(addr); addr.sin_family = AF_INET; addr.sin_addr = INADDR_ANY; addr.sin_port = sceNetHtons(sport); // Bound Socket to local Port if(sceNetInetBind(socket, (SceNetInetSockaddr *)&addr, sizeof(addr)) == 0) { // Allocate Memory SceNetAdhocPtpStat * internal = (SceNetAdhocPtpStat *)malloc(sizeof(SceNetAdhocPtpStat)); // Allocated Memory if(internal != NULL) { // Find Free Translator ID int i = 0; for(; i < 255; i++) if(_ptp[i] == NULL) break; // Found Free Translator ID if(i < 255) { // Clear Memory memset(internal, 0, sizeof(SceNetAdhocPtpStat)); // Copy Infrastructure Socket ID internal->id = socket; // Copy Address Information internal->laddr = *saddr; internal->paddr = *daddr; internal->lport = sport; internal->pport = dport; // Set Buffer Size internal->rcv_sb_cc = bufsize; // Link PTP Socket _ptp[i] = internal; // Add Port Forward to Router sceNetPortOpen("TCP", sport); // Return PTP Socket Pointer return i + 1; } // Free Memory free(internal); } } // Close Socket sceNetInetClose(socket); } } // Invalid Arguments return ADHOC_INVALID_ARG; } // Invalid Ports return ADHOC_INVALID_PORT; } // Invalid Addresses return ADHOC_INVALID_ADDR; } // Library is uninitialized return ADHOC_NOT_INITIALIZED; }
/* connecthostport() * return a socket connected (TCP) to the host and port * or -1 in case of error */ int connecthostport(const char * host, unsigned short port) { printk("Connect Attempt: %s:%u\n", host, port); // Target Address SceNetInetSockaddrIn in; // Clear Memory memset(&in, 0, sizeof(in)); // Set Address Family in.sin_family = AF_INET; // Set Structure Length in.sin_len = sizeof(in); // Translate Port in.sin_port = sceNetHtons(port); // Resolve Domain if(sceNetResolverStartNtoA(_rid, host, &in.sin_addr, 500000, 2) != 0) { // Attempt IP Conversion sceNetInetInetAton(host, &in.sin_addr); } // Create Socket int s = sceNetInetSocket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // Valid Socket if(s > 0) { // Enabler int one = 1; // Enable Port Re-use sceNetInetSetsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); sceNetInetSetsockopt(s, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)); // Set 3-Second Timeout uint32_t timeout = 3000000; sceNetInetSetsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); sceNetInetSetsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)); // Connect to Destination if(sceNetInetConnect(s, (SceNetInetSockaddr *)&in, sizeof(in)) == 0/* || sceNetInetGetErrno() == 106*/) { printk("Connection Success\n"); // Return Socket return s; } printk("Errno: %d\n", sceNetInetGetErrno()); // Close Socket sceNetInetClose(s); logSockets(); } // Error State return -1; }