LPFN_WSARECVMSG GetWSARecvMsgFunctionPointer() { LPFN_WSARECVMSG lpfnWSARecvMsg = NULL; GUID guidWSARecvMsg = WSAID_WSARECVMSG; SOCKET sock = INVALID_SOCKET; DWORD dwBytes = 0; sock = socket(AF_INET6,SOCK_DGRAM,0); if(SOCKET_ERROR == WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &guidWSARecvMsg, sizeof(guidWSARecvMsg), &lpfnWSARecvMsg, sizeof(lpfnWSARecvMsg), &dwBytes, NULL, NULL )) { ERR("WSAIoctl SIO_GET_EXTENSION_FUNCTION_POINTER"); return NULL; } CLOSESOCK(sock); return lpfnWSARecvMsg; }
int __cdecl main() { WSADATA wsd; INT i = 0, nErr = 0, nStartup = 0, rc = 0; SOCKET sock = INVALID_SOCKET; SOCKADDR_STORAGE addr = {0}, mcaddr = {0}, remoteaddr = {0}; WSAOVERLAPPED over = {0}; WSABUF wsabuf = {0}; DWORD dwBytes = 0, dwFlags = 0, dwRet = 0; IPV6_MREQ mreq = {0}; WSAMSG wsamsg = {0}; LPFN_WSARECVMSG WSARecvMsg = NULL; __try { //Initialize Winsock nErr = WSAStartup(WS_VER,&wsd); if (nErr) { WSASetLastError(nErr); ERR("WSAStartup"); __leave; } else nStartup++; // bind socket and register multicast mcaddr.ss_family = AF_INET6; InitMcastAddr((SOCKADDR*)&mcaddr,sizeof mcaddr); if (INVALID_SOCKET == (sock = socket(AF_INET6,SOCK_DGRAM,0))) { ERR("socket"); __leave; } if(!RouteLookup((SOCKADDR*)&mcaddr, sizeof mcaddr, (SOCKADDR*)&addr, sizeof addr )) { ERR("RouteLookup"); __leave; } SET_PORT((SOCKADDR*)&addr,DEFAULT_PORT); if (SOCKET_ERROR == bind(sock,(SOCKADDR*)&addr,sizeof addr)) { ERR("bind"); __leave; } mreq.ipv6mr_multiaddr = ((SOCKADDR_IN6*)&mcaddr)->sin6_addr; if (SOCKET_ERROR == setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char*)&mreq, sizeof mreq )) { ERR("setsockopt IPV6_ADD_MEMBRESHIP"); __leave; } // PktInfo if (!SetIpv6PktInfoOption(sock)) { ERR("SetIpv6PktInfoOption"); __leave; } if(!AllocAndInitIpv6PktInfo(&wsamsg)) { ERR("AllocAndInitIpv6PktInfo"); __leave; } // data buffer wsabuf.buf = (CHAR*)MALLOC(100); if(NULL == wsabuf.buf) { ERR("HeapAlloc"); __leave; } wsabuf.len = (ULONG)MSIZE(wsabuf.buf); wsamsg.lpBuffers = &wsabuf; wsamsg.dwBufferCount = 1; // packet source address wsamsg.name = (SOCKADDR*)&remoteaddr; wsamsg.namelen = sizeof remoteaddr; //Post overlapped WSARecvMsg InitOverlap(&over); if (NULL == (WSARecvMsg = GetWSARecvMsgFunctionPointer())) { ERR("GetWSARecvMsgFunctionPointer"); __leave; } if (SOCKET_ERROR == WSARecvMsg(sock, &wsamsg, &dwBytes, &over, NULL )) { if (WSA_IO_PENDING != WSAGetLastError()) { ERR("WSARecvMsg"); __leave; } } //set send interface if (SOCKET_ERROR == SetSendInterface(sock,(SOCKADDR*)&addr)) { ERR("SetSendInterface"); __leave; } //send msg to multicast SET_PORT((SOCKADDR*)&mcaddr,DEFAULT_PORT); //send a few packets for (i=0; i<5; i++) { if (SOCKET_ERROR == (rc = sendto(sock, TST_MSG, lstrlenA(TST_MSG), 0, (SOCKADDR*)&mcaddr, sizeof (mcaddr) ))) { ERR("sendto"); __leave; } printf("Sent %d bytes\n",rc); } dwRet = WaitForSingleObject(over.hEvent,DEFAULT_WAIT); if (dwRet) { printf("%s\n",gai_strerror(dwRet)); __leave; } if (!WSAGetOverlappedResult(sock, &over, &dwBytes, TRUE, &dwFlags )) { ERR("WSAGetOverlappedResult"); __leave; } printf("WSARecvMsg completed with %d bytes\n",dwBytes); // if multicast packet do further processing if (MSG_MCAST & wsamsg.dwFlags) { if (ProcessIpv6Msg(&wsamsg)) { //do something more interesting here printf("Recvd multicast msg.\n"); } } } __finally { CLOSESOCK(sock); FREE(wsabuf.buf); FREE(wsamsg.Control.buf); CLOSESOCKEVENT(over.hEvent); if(nStartup) WSACleanup(); } return 0; }
BOOL RouteLookup(SOCKADDR *destAddr, int destLen, SOCKADDR *localAddr, int localLen ) { DWORD dwBytes = 0; BOOL bRet = FALSE; CHAR szAddr[MAX_PATH] = {0}; SOCKET s = INVALID_SOCKET; __try { if (INVALID_SOCKET == (s = socket(destAddr->sa_family,SOCK_DGRAM,0))) { ERR("socket"); __leave; } if (SOCKET_ERROR == WSAIoctl(s, SIO_ROUTING_INTERFACE_QUERY, destAddr, destLen, localAddr, localLen, &dwBytes, NULL, NULL )) { ERR("WSAIoctl"); __leave; } dwBytes = sizeof(szAddr); ZeroMemory(szAddr,dwBytes); WSAAddressToStringA(destAddr, (DWORD)destLen, NULL, szAddr, &dwBytes ); dwBytes = sizeof(szAddr); ZeroMemory(szAddr,dwBytes); WSAAddressToStringA(localAddr, (DWORD)localLen, NULL, szAddr, &dwBytes ); bRet = TRUE; } __finally { CLOSESOCK(s); } return bRet; }
int __cdecl main(int argc, char **argv) { char *interface = NULL; char *Buffer = NULL; char *port = DEFAULT_PORT; char host[NI_MAXHOST]; char serv[NI_MAXSERV]; int hostlen = NI_MAXHOST; int servlen = NI_MAXSERV; int ai_family = AF_UNSPEC; int i = 0; int nStartup = 0; struct addrinfo hints = {0}; struct addrinfo *local = NULL; WSADATA wsaData; SOCKET listen_socket = INVALID_SOCKET; SOCKET accept_socket = INVALID_SOCKET; WSAOVERLAPPED *Overlap = NULL; DWORD bytes = 0; DWORD bytes_read = 0; DWORD lasterror = 0; // // Handles is the array that stores the Event Handles // WSAEVENT Handles[MAX_IO_PEND] ; // // socklist is a parallel array that keeps state information for // each Handle. // Socklist socklist[MAX_IO_PEND]; // // Pointers to Microsoft specific extensions // LPFN_ACCEPTEX pfnAcceptEx; GUID acceptex_guid = WSAID_ACCEPTEX; __try { if (NULL == (Buffer = (char*)XMALLOC(((2*sizeof(SOCKADDR_STORAGE))+32)*sizeof(char)))) { ERR("HeapAlloc()"); __leave; } // // Parse arguments // if ( argc > 1 ) { for ( i = 1;i < argc; i++ ) { if ( (argv[i][0] == '-') || (argv[i][0] == '/') ) { switch ( tolower(argv[i][1]) ) { case 'i': if ( i+1 < argc ) interface = argv[++i]; break; case 'e': if ( i+1 < argc ) port = argv[++i]; break; default: { Usage(argv[0]); __leave; } break; } } else { Usage(argv[0]); __leave; } } } // // Since port 0 would be any available port. // Resetting port back to DEFAULT_PORT to avoid confusion. // if ( 0 == strncmp(port, "0", 1) ) { port = DEFAULT_PORT; } if ( 0 != (nStartup = WSAStartup(WS_VER, &wsaData)) ) { WSASetLastError(nStartup); //WSAStartup does not set last error on failure ERR("WSAStartup()"); __leave; } else nStartup++; // // Resolve the interface // SecureZeroMemory(&hints,sizeof(hints)); hints.ai_flags = ((interface) ? 0 : AI_PASSIVE); hints.ai_family = ai_family; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; if ( 0 != getaddrinfo(interface, port, &hints, &local)) { ERR("getaddrinfo()"); __leave; } ai_family = local->ai_family; if (NULL == local) { fprintf(stderr, "getaddrinfo() failed to resolve/convert the interface\n"); __leave; } if (INVALID_SOCKET == (listen_socket = WSASocket(local->ai_family, local->ai_socktype, local->ai_protocol, NULL, 0, WSA_FLAG_OVERLAPPED ))) { ERR("WSASocket()"); __leave; } if ( SOCKET_ERROR == bind(listen_socket, local->ai_addr, (int)local->ai_addrlen )) { ERR("bind()"); __leave; } if ( SOCKET_ERROR == listen(listen_socket, DEFAULT_BACKLOG)) { ERR("listen()"); __leave; } // // Resolve numeric host name // if ( 0 != getnameinfo(local->ai_addr, (int)local->ai_addrlen, host, hostlen, serv, servlen, NI_NUMERICHOST | NI_NUMERICSERV )) { ERR("getnameinfo()"); __leave; } // Don't need the local interface anymore if (NULL != local) freeaddrinfo(local); printf("Listening on %s:%s\n", host, serv); // // Add the listening socket to our state information for the handle. // socklist[0].sock = listen_socket; curr_size =1; for ( i = 0;i < MAX_IO_PEND;i++ ) Handles[i] = WSA_INVALID_EVENT; // // Load the extension functions // if ( SOCKET_ERROR == WSAIoctl(listen_socket, SIO_GET_EXTENSION_FUNCTION_POINTER, &acceptex_guid, sizeof(acceptex_guid), &pfnAcceptEx, sizeof(pfnAcceptEx), &bytes, NULL, NULL )) { fprintf(stderr,"Failed to obtain AcceptEx() pointer: "); ERR("WSAIoctl()"); __leave; } // // The structure of the following loop is very similar to a situation // where select() might be used. // We use WSAGetOverlappedResult() to multiplex between incoming/outgoing // data on existing connections. // // We don't queue an AcceptEx() until someone actually connects to // the previous socket. This is to keep the code simple, not a limitation // of the API itself. // for ( ;; ) { // create a socket for AcceptEx() if (INVALID_SOCKET == (accept_socket = WSASocket(ai_family, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED ))) { ERR("WSASocket()"); __leave; } // // Allocate an overlapped structure. // We use the Offset field to keep track of the socket handle // we have accepted a connection on, since there is no other // way to pass information to GetOverlappedResult() // Overlap = (WSAOVERLAPPED*)XMALLOC(sizeof(WSAOVERLAPPED)); // // Did the HeapAllocation FAIL?? // if ( Overlap == NULL ) { ERR("HeapAlloc()"); __leave; } SecureZeroMemory(Overlap, sizeof(WSAOVERLAPPED)); if ( WSA_INVALID_EVENT == (Overlap->hEvent = WSACreateEvent() )) { ERR("WSACreateEvent()"); __leave; } // // Set the appropriate array members // Handles[0] = Overlap->hEvent; socklist[0].overlap = Overlap; socklist[0].SockAccepted = accept_socket; // // AcceptEx() // if ( !pfnAcceptEx(listen_socket, accept_socket, Buffer, 0, // read nothing from the socket sizeof(SOCKADDR_STORAGE)+16, sizeof(SOCKADDR_STORAGE)+16, &bytes_read, Overlap )) { lasterror = WSAGetLastError(); if ( WSA_IO_PENDING != lasterror) { ERR("AcceptEx()"); for ( i = 0; i < curr_size; i++ ) { shutdown(socklist[i].sock, SD_BOTH); CLOSESOCK(socklist[i].sock); XFREE(socklist[i].overlap); CLOSEEVENT(Handles[i]); } __leave; } } // // This loop simple checks the handles to see which one is // signalled. // If error, exit. // If there is a new incoming connection, we break to the outer loop // queue another AcceptEx() // for ( ;; ) { i = DoWait(Handles, socklist); if ( i < 0 ) break; HandleEvent(i, Handles, socklist); if ( i == 0 ) break; }; if ( i < 0 ) { for ( i = 0; i < curr_size; i++ ) { shutdown(socklist[i].sock, SD_BOTH); CLOSESOCK(socklist[i].sock); XFREE(socklist[i].overlap); CLOSEEVENT(Handles[i]); } __leave; } } } __finally { XFREE(Buffer); if (NULL != local) freeaddrinfo(local); CLOSESOCK(listen_socket); CLOSESOCK(accept_socket); CLOSEEVENT(Overlap->hEvent); XFREE(Overlap); } }
/* * This is the main function that handles all the events occuring on the * different handles we are watching. * * Parameters: * index: Index into the Handles[] array. Returned by DoWait() * Handles: Array of Event Handles we are watching * socklist: Helper parallel array of state information * */ void HandleEvent(int index, WSAEVENT *Handles, Socklist *socklist) { WSAOVERLAPPED *Overlap; SOCKET newsock = INVALID_SOCKET; DWORD bytes = 0; DWORD flags = 0; DWORD lasterr = 0; int i = 0; Overlap = socklist[index].overlap; if (!WSAResetEvent(Handles[index])) { ERR("WSAResetEvent()"); } // // Check the specified handle // // If a socket is closed by the other side, the error returned is // WSAECONNRESET // if ( !WSAGetOverlappedResult(socklist[index].sock, Overlap, &bytes, FALSE, &flags)) { ERR("WSAGetOverlappedResult()"); } newsock = socklist[index].SockAccepted; // // If the other side closed the connection, close our socket and // move the next element of the Handles[] array into our // index. // // The array compaction is done so that we only pass valid handles // in the first "curr_size" elements of the array to // WSAWaitForMultipleEvents(). The function will fail otherwise. // // // We should NEVER get this for our listening socket // if ( (index != 0) && (bytes == 0 ) ) { CLOSESOCK(newsock); XFREE(Overlap); CLOSEEVENT(Handles[index]); for ( i = index; i < curr_size; i++ ) { Handles[i] = Handles[i+1]; socklist[i] = socklist[i+1]; } curr_size--; return; } if ( (index == 0) ) { // listening socket if ( curr_size >= MAX_IO_PEND ) { shutdown(newsock, SD_BOTH); CLOSESOCK(newsock); fprintf(stderr,"Too many pending requests\n"); return; } // // Get the event handle used to queue the AcceptEx(), // and re-use it to queue a WSARecv() on the socket. // Handles[curr_size] = Overlap->hEvent; // // Fill in the details of our accepted socket // socklist[curr_size].sock = newsock; SecureZeroMemory(socklist[curr_size].Buffer, sizeof(socklist[curr_size].Buffer)/sizeof(socklist[curr_size].Buffer[0] )); socklist[curr_size].overlap = Overlap; socklist[curr_size].DataBuf.len = sizeof(socklist[curr_size].Buffer); socklist[curr_size].DataBuf.buf = socklist[curr_size].Buffer; // // The OffsetHigh field is used to keep track of what we are doing. // This enables us to alternate WSARecv() and WSASend() on a // connection // socklist[curr_size].Op = OP_READ; flags = 0; if ( SOCKET_ERROR == WSARecv(socklist[curr_size].sock, &(socklist[curr_size].DataBuf), 1, &bytes, &flags, socklist[curr_size].overlap, NULL )) { lasterr = WSAGetLastError(); if ( WSA_IO_PENDING != lasterr) { ERR("WSARecv()"); if ( WSAECONNRESET == lasterr) { // // Handle WSAECONNRESET specially // Other errors are not good // shutdown(newsock, SD_BOTH); CLOSESOCK(newsock); XFREE(Overlap); CLOSEEVENT(Handles[index]); for ( i = index; i < curr_size; i++ ) { Handles[i] = Handles[i+1]; socklist[i] = socklist[i+1]; } curr_size--; } return; } } // // Increment the last valid handle location in the Handles // array. // curr_size++; return; } // // If the previous operation was an OP_READ, queue WSASend() on the // socket // if ( socklist[index].Op == OP_READ ) { // WSARecv() was queued printf("Read buffer [%s]\n", socklist[index].Buffer); printf("Echoing back to client\n"); if ( SOCKET_ERROR == WSASend(socklist[index].sock, &(socklist[index].DataBuf), 1, &bytes, 0, socklist[index].overlap, NULL)) { lasterr = WSAGetLastError(); if(WSA_IO_PENDING != lasterr) { ERR("WSASend()"); if ( WSAECONNRESET == lasterr) { shutdown(newsock, SD_BOTH); CLOSESOCK(newsock); XFREE(Overlap); CLOSEEVENT(Handles[index]); for ( i = index; i < curr_size; i++ ) { Handles[i] = Handles[i+1]; socklist[i] = socklist[i+1]; } curr_size--; } return; } } socklist[index].Op = OP_WRITE; return; } // // If we had a WSASend() queued, now do a WSARecv() // else if ( socklist[index].Op == OP_WRITE ) { // WSASend() was queued printf("Wrote %d bytes\n",bytes); printf("Queueing read\n"); flags = 0; if ( SOCKET_ERROR == WSARecv(socklist[index].sock, &(socklist[index].DataBuf), 1, &bytes, &flags, socklist[index].overlap, NULL )) { lasterr = WSAGetLastError(); if(WSA_IO_PENDING != lasterr) { ERR("WSARecv()"); if ( WSAECONNRESET == lasterr) { shutdown(newsock, SD_BOTH); CLOSESOCK(newsock); XFREE(Overlap); CLOSEEVENT(Handles[index]); for ( i = index; i < curr_size; i++ ) { Handles[i] = Handles[i+1]; socklist[i] = socklist[i+1]; } curr_size--; } return; } } socklist[index].Op = OP_READ; return; } else { fprintf(stderr,"Unknown operation queued\n"); } }
int __cdecl main() { WSADATA wsd; INT nStartup = 0, nErr = 0, ret = 0; SOCKET lsock = INVALID_SOCKET, asock = INVALID_SOCKET; SOCKADDR_STORAGE addr = {0}; WSAPOLLFD fdarray = {0}; ULONG uNonBlockingMode = 1; CHAR buf[MAX_PATH] = {0}; HANDLE hThread = NULL; DWORD dwThreadId = 0; nErr = WSAStartup(WS_VER,&wsd); if (nErr) { WSASetLastError(nErr); ERR("WSAStartup"); exit(0); } else { nStartup++; } if (NULL == (hCloseSignal = CreateEvent(NULL, TRUE, FALSE, NULL))) { ERR("CreateEvent"); exit(0); } /* if (NULL == (hThread = CreateThread(NULL, 0, ConnectThread, NULL, 0, &dwThreadId))) { ERR("CreateThread"); //exit__leave; } */ addr.ss_family = AF_INET; INETADDR_SETANY((SOCKADDR*)&addr); SS_PORT((SOCKADDR*)&addr) = htons(DEFAULT_PORT); if (INVALID_SOCKET == (lsock = socket(AF_INET, SOCK_STREAM, 0))) { ERR("socket"); exit(0); } /* if (SOCKET_ERROR == ioctlsocket(lsock, FIONBIO, &uNonBlockingMode)) { ERR("FIONBIO"); exit(0); } */ if (SOCKET_ERROR == bind(lsock, (SOCKADDR*)&addr, sizeof (addr))) { ERR("bind"); exit(0); } if (SOCKET_ERROR == listen(lsock, 100)) { ERR("listen"); exit(0); } //Call WSAPoll for readability of listener (accepted) //fdarray.fd = lsock; //fdarray.events = POLLRDNORM | POLLWRNORM; /* if (SOCKET_ERROR == (ret = WSAPoll(&fdarray, 1, DEFAULT_WAIT))) { ERR("WSAPoll"); exit(0); } */ while (1) { //if (ret) { //if ((fdarray.revents & POLLRDNORM) || (fdarray.revents & POLLWRNORM)) { // printf("Main: Connection established.\n"); if (INVALID_SOCKET == (asock = accept(lsock, NULL, NULL))) { ERR("accept"); //__leave; } /* if (SOCKET_ERROR == (ret = recv(asock, buf, sizeof(buf), 0))) { ERR("recv"); } else { printf("Main: recvd %d bytes\n",ret); } */ //} //} //Call WSAPoll for writeability of accepted fdarray.fd = asock; fdarray.events = POLLWRNORM; if (SOCKET_ERROR == (ret = WSAPoll(&fdarray, 1, DEFAULT_WAIT))) { ERR("WSAPoll"); // exit } if (ret) { if (fdarray.revents & POLLWRNORM) { if (SOCKET_ERROR == (ret = send(asock, TST_MSG, sizeof(TST_MSG), 0))) { ERR("send"); // exit } else { printf("Main: sent %d bytes\n",ret); closesocket(asock); } } } } //SetEvent(hCloseSignal); //WaitForSingleObject(hThread,DEFAULT_WAIT); /* clean up before exit */ CloseHandle(hCloseSignal); CloseHandle(hThread); CLOSESOCK(asock); CLOSESOCK(lsock); if (nStartup) { WSACleanup(); } return 0; }