#include <stddef.h>
#include <process.h>
+#include <iphlpapi.h>
#include "options.h"
#include "memory.h"
#define FIOSETOWN _IOW('f', 124, long) /* set owner (struct Task *) */
#define FIOGETOWN _IOR('f', 123, long) /* get owner (struct Task *) */
+#define _IOWR(x,y,t) (IOC_OUT|IOC_IN|(((long)(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y))
+
+#define SIOCGIFADDR _IOWR('i', 33, 16) /* get ifnet address */
+#define SIOCGIFFLAGS _IOWR('i', 17, 32) /* get ifnet flags */
+#define SIOCGIFBRDADDR _IOWR('i', 35, 16) /* get broadcast addr */
+#define SIOCGIFCONF _IOWR('i', 36, 8) /* get ifnet list */
+#define SIOCGIFNETMASK _IOWR('i', 37, 16) /* get net addr mask */
+#define SIOCGIFMETRIC _IOWR('i', 23, 32) /* get IF metric */
+#define SIOCGIFMTU _IOWR('i', 51, 32) /* get IF mtu */
+#define SIOCGIFPHYS _IOWR('i', 53, 32) /* get IF wire */
+
#define BEGINBLOCKING if (sb->ftable[sd - 1] & SF_BLOCKING) sb->ftable[sd - 1] |= SF_BLOCKINGINPROGRESS
#define ENDBLOCKING sb->ftable[sd - 1] &= ~SF_BLOCKINGINPROGRESS
#define SF_RAW_RICMP 0x02000000
#define SF_RAW_HDR 0x01000000
+#if 0
typedef struct ip_option_information {
u_char Ttl; /* Time To Live (used for traceroute) */
u_char Tos; /* Type Of Service (usually 0) */
u_char OptionsSize; /* Size of options data (usually 0, max 40) */
u_char FAR *OptionsData; /* Options data buffer */
} IPINFO, *PIPINFO, FAR *LPIPINFO;
+#endif
static void bsdsetpriority (HANDLE thread)
{
if (!bsd) {
bsd = xcalloc (struct bsdsockdata, 1);
+ if (!bsd) {
+ return 0;
+ }
for (i = 0; i < MAX_GET_THREADS; i++)
threadindextable[i] = i;
}
deinit_socket_layer ();
if (currprefs.socket_emu) {
if((result = mySockStartup())) {
+ if (!bsd)
+ return 0;
if(bsd->hSockThread == NULL) {
WNDCLASS wc; // Set up an invisible window and dummy wndproc
DeleteCriticalSection(&bsd->SockThreadCS);
bsd->hSockThread = NULL;
SetEvent (bsd->hSockReq);
- WaitForSingleObject(bsd->hSockThread, INFINITE);
+ WaitForSingleObject(t, INFINITE);
CloseHandle(t);
CloseHandle(bsd->hSockReq);
CloseHandle(bsd->hSockReqHandled);
return -1;
}
+#define MAX_NET_INTERFACES 30
+struct bsdsock_interface_info {
+ bool inuse;
+ int mtu;
+ int metric;
+ uae_u8 mac[6];
+ bool hasmac;
+};
+static INTERFACE_INFO *net_interfaces;
+static bsdsock_interface_info *net_interfaces2;
+static int net_interfaces_num;
+
+static void get_net_if_extra(void)
+{
+ xfree(net_interfaces2);
+ net_interfaces2 = NULL;
+ DWORD ret = 16 * 1024;
+ DWORD gaaFlags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_FRIENDLY_NAME | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_INCLUDE_GATEWAYS;
+ IP_ADAPTER_ADDRESSES *ipaa = (IP_ADAPTER_ADDRESSES*)malloc(ret);
+ if (GetAdaptersAddresses(AF_INET, gaaFlags, NULL, ipaa, &ret) == ERROR_BUFFER_OVERFLOW) {
+ xfree(ipaa);
+ ipaa = (IP_ADAPTER_ADDRESSES*)malloc(ret);
+ if (GetAdaptersAddresses(AF_INET, gaaFlags, NULL, ipaa, &ret) != ERROR_SUCCESS) {
+ xfree(ipaa);
+ ipaa = NULL;
+ }
+ }
+ if (ipaa) {
+ net_interfaces2 = xcalloc(struct bsdsock_interface_info, MAX_NET_INTERFACES);
+ if (net_interfaces2) {
+ for (int i = 0; i < net_interfaces_num; i++) {
+ INTERFACE_INFO* ii = &net_interfaces[i];
+ struct bsdsock_interface_info *ii2 = &net_interfaces2[i];
+ IP_ADAPTER_ADDRESSES *ipa = ipaa;
+ while (ipa && ii2->inuse == false) {
+ if (ipa->Ipv4Enabled && (ipa->IfType == IF_TYPE_ETHERNET_CSMACD || ipa->IfType == IF_TYPE_IEEE80211)) {
+ PIP_ADAPTER_UNICAST_ADDRESS pua = ipa->FirstUnicastAddress;
+ while (pua) {
+ if (pua->Address.iSockaddrLength == 16 && !memcmp(pua->Address.lpSockaddr, &ii->iiAddress.Address, 16)) {
+ ii2->mtu = ipa->Mtu;
+ if (ipa->PhysicalAddressLength == 6) {
+ memcpy(ii2->mac, ipa->PhysicalAddress, 6);
+ ii2->hasmac = true;
+ }
+ ii2->metric = ipa->Ipv4Metric;
+ ii2->inuse = true;
+ }
+ pua = pua->Next;
+ }
+ }
+ ipa = ipa->Next;
+ }
+ }
+ }
+ xfree(ipaa);
+ }
+}
+
+static int get_net_if(TrapContext *ctx, uaecptr addr, bool extra)
+{
+ char name[17];
+ trap_get_bytes(ctx, name, addr, 16);
+ name[16] = 0;
+ if (name[0] == 'l' && name[1] == 'o' && name[2] == 0) {
+ for (int i = 0; i < net_interfaces_num; i++) {
+ if (net_interfaces[i].iiFlags & IFF_LOOPBACK) {
+ return i;
+ }
+ }
+ }
+ if (name[0] == 'e' && name[1] == 't' && name[2] == 'h') {
+ int num = atoi(name + 3);
+ if (num == 0 && name[3] != '0') {
+ return -1;
+ }
+ if (num >= net_interfaces_num) {
+ return -1;
+ }
+ // query extra information only if needed (MTU, Metric, MAC)
+ if (extra && !net_interfaces2) {
+ get_net_if_extra();
+ }
+ return num;
+ }
+ return -1;
+}
+
uae_u32 host_IoctlSocket(TrapContext *ctx, SB, uae_u32 sd, uae_u32 request, uae_u32 arg)
{
SOCKET s;
case FIONREAD:
ioctlsocket(s,request,(u_long *)&data);
BSDTRACE((_T("[FIONREAD] -> %d\n"),data));
- trap_put_long(ctx, arg,data);
+ trap_put_long(ctx, arg, data);
success = 0;
break;
case FIOASYNC:
success = -1;
break;
+
+ case SIOCGIFFLAGS:
+ {
+ int idx = get_net_if(ctx, arg, false);
+ if (idx >= 0) {
+ INTERFACE_INFO *ii = &net_interfaces[idx];
+ uae_u16 flags = 0;
+ if (ii->iiFlags & IFF_UP) {
+ flags |= 1;
+ flags |= 0x40; // IFF_RUNNING
+ }
+ if (ii->iiFlags & IFF_BROADCAST) {
+ flags |= 2;
+ }
+ if (ii->iiFlags & IFF_LOOPBACK) {
+ flags |= 8;
+ }
+ if (ii->iiFlags & IFF_POINTTOPOINT) {
+ flags |= 0x10;
+ }
+ if (ii->iiFlags & IFF_MULTICAST) {
+ flags |= 0x8000;
+ }
+ trap_put_word(ctx, arg + 16, flags);
+ success = 0;
+ }
+ }
+ break;
+ case SIOCGIFMTU:
+ case SIOCGIFMETRIC:
+ case SIOCGIFPHYS:
+ {
+ int idx = get_net_if(ctx, arg, true);
+ if (idx >= 0) {
+ struct bsdsock_interface_info *ii2 = &net_interfaces2[idx];
+ if (ii2->inuse) {
+ if (request == SIOCGIFMETRIC) {
+ trap_put_long(ctx, arg + 16, ii2->metric);
+ success = 0;
+ } else if (request == SIOCGIFMTU) {
+ trap_put_long(ctx, arg + 16, ii2->mtu);
+ success = 0;
+ } else if (request == SIOCGIFPHYS) {
+ if (ii2->hasmac) {
+ trap_put_bytes(ctx, ii2->mac, arg + 16, 6);
+ success = 0;
+ }
+ }
+ }
+ }
+ }
+ break;
+ case SIOCGIFADDR:
+ case SIOCGIFNETMASK:
+ case SIOCGIFBRDADDR:
+ {
+ int idx = get_net_if(ctx, arg, false);
+ if (idx >= 0) {
+ INTERFACE_INFO *ii = &net_interfaces[idx];
+ sockaddr_gen *sa = &ii->iiAddress;
+ if (request == SIOCGIFNETMASK) {
+ sa = &ii->iiNetmask;
+ } else if (request == SIOCGIFBRDADDR) {
+ sa = &ii->iiBroadcastAddress;
+ }
+ trap_put_byte(ctx, arg + 16, 16);
+ trap_put_byte(ctx, arg + 17, (uae_u8)sa->Address.sa_family);
+ trap_put_bytes(ctx, sa->Address.sa_data, arg + 16 + 2, 14);
+ success = 0;
+ }
+ }
+ break;
+ case SIOCGIFCONF:
+ {
+ xfree(net_interfaces);
+ xfree(net_interfaces2);
+ net_interfaces2 = NULL;
+ net_interfaces_num = 0;
+ net_interfaces = xcalloc(INTERFACE_INFO, MAX_NET_INTERFACES);
+ if (net_interfaces) {
+ DWORD ret;
+ if (WSAIoctl(s, SIO_GET_INTERFACE_LIST, NULL, 0, (LPVOID*)net_interfaces, MAX_NET_INTERFACES * sizeof(INTERFACE_INFO), &ret, NULL, NULL) != SOCKET_ERROR) {
+ net_interfaces_num = ret / sizeof(INTERFACE_INFO);
+ int cnt = 0;
+ int bytes = trap_get_long(ctx, arg);
+ uaecptr ptr = trap_get_long(ctx, arg + 4);
+ int ethcnt = 0;
+ int bytecnt = 0;
+ for (int i = 0; i < net_interfaces_num; i++) {
+ INTERFACE_INFO *ii = &net_interfaces[i];
+ if (bytes < 32) {
+ break;
+ }
+ // fake names
+ if (ii->iiFlags & IFF_LOOPBACK) {
+ trap_put_string(ctx, "lo", ptr, 16);
+ } else {
+ char tmp[10];
+ sprintf(tmp, "eth%d", ethcnt++);
+ trap_put_string(ctx, tmp, ptr, 16);
+ }
+ trap_put_byte(ctx, ptr + 16, 16);
+ trap_put_byte(ctx, ptr + 17, (uae_u8)ii->iiAddress.Address.sa_family);
+ trap_put_bytes(ctx, ii->iiAddress.Address.sa_data, ptr + 16 + 2, 14);
+ ptr += 32;
+ bytes -= 32;
+ bytecnt += 32;
+ }
+ trap_put_long(ctx, arg, bytecnt);
+ success = 0;
+ }
+ }
+ }
+ break;
+
default:
write_log (_T("BSDSOCK: WARNING - Unknown IoctlSocket request: 0x%08lx\n"), request);
bsdsocklib_seterrno(ctx, sb, 22); // EINVAL