Are you doing an explicit bind before you call sendto? If you are, I would suggest removing the bind call and allowing sendto to do an implicit bind.
I came up with some code which lists the local addresses and scope ids. However, this does not tell you which one to use. I guess you could try each in turn. You can determine if an address is link-local by checking its prefix which is FE80::/64 for link-local addresses.
Code:
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#pragma comment(lib, "ws2_32.lib")
int main(void)
{
BYTE buf1[65535] = { 0 };
BYTE buf2[65535] = { 0 };
DWORD cbBuf1 = sizeof(buf1);
DWORD cbBuf2 = sizeof(buf2);
SOCKET_ADDRESS_LIST* pList = (SOCKET_ADDRESS_LIST*) buf2;
int i = 0;
WSADATA wd = { 0 };
SOCKET sock = 0;
BOOL fLinkLocal = FALSE;
BYTE prefix[8] = { 0xFE, 0x80 }; // Link-local prefix FE80::/64
WSAStartup(MAKEWORD(2,0), &wd);
sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
WSAIoctl(sock, SIO_ADDRESS_LIST_QUERY, NULL, 0, buf1, sizeof(buf1), &cbBuf1, NULL, NULL);
WSAIoctl(sock, SIO_ADDRESS_LIST_SORT, buf1, cbBuf1, buf2, sizeof(buf2), &cbBuf2, NULL, NULL);
for (i = 0; i < pList->iAddressCount;i++)
{
char ip[500];
SOCKADDR_IN6* pAddr = (SOCKADDR_IN6*) pList->Address[i].lpSockaddr;
getnameinfo((const struct sockaddr*) pAddr, sizeof(SOCKADDR_IN6), ip, sizeof(ip), NULL, 0, NI_NUMERICHOST);
fLinkLocal = (memcmp(pAddr->sin6_addr.u.Byte, prefix, sizeof(prefix)) == 0);
printf("Address: %s -- Scope ID: %lu -- Link Local: %d\n", ip, pAddr->sin6_scope_id, fLinkLocal);
}
getchar();
closesocket(sock);
WSACleanup();
return 0;
}