#include /* You can experiment with some values for the buffer size in which you receive the data from the socket. I've experienced situations where a certain value like 10K has worked well while debugging step by step, however hasn't worked when the program runs without a breakpoint. A small value like the default OBEX packet size of 255 bytes is inefficient for large object transfers. */ #define MAX_BUFF_SIZE 0x0400 // 1K = 1024 Bytes #define MAX_FILE_NAME 0x0100 // 256 Bytes // OBEX Operation codes #define OBEX_PUT (BYTE)0x02 #define OBEX_PUT_FINAL (BYTE)0x82 #define OBEX_CONNECT (BYTE)0x80 #define OBEX_DISCONNECT (BYTE)0x81 // OBEX Header codes #define OBEX_NAME (BYTE)0x01 #define OBEX_LENGTH (BYTE)0xC3 #define OBEX_DESCRIPTION (BYTE)0x05 #define OBEX_PALM_CREATOR_ID (BYTE)0xCF #define OBEX_BODY (BYTE)0x48 #define OBEX_END_OF_BODY (BYTE)0x49 // OBEX Response codes #define OBEX_CONTINUE (BYTE)0x90 #define OBEX_SUCCESS (BYTE)0xA0 #define OBEX_VERSION (BYTE)0x10 #define OBEX_CONNECT_FLAGS (BYTE)0x00 #define FAILURE_MESG(x) \ {\ wsprintf (szError, x _T(" failed. Error: %d"), WSAGetLastError ());\ MessageBox (NULL, szError, _T("Error"), MB_OK);\ } static void CreateNewFile(BYTE* dataBuff, bool put_final); void ReceiveFile(void) { WSADATA wsaData; WORD wVersion = MAKEWORD(1,1); // Winsock Version 1.1 TCHAR szError[100]; if (WSAStartup(wVersion, &wsaData) != 0) { FAILURE_MESG(_T("WSAStartup")); WSACleanup(); return; } SOCKET ServSock; SOCKET ClientSock; if ((ServSock = socket(AF_IRDA, SOCK_STREAM, 0)) == INVALID_SOCKET) { FAILURE_MESG(_T("socket")); WSACleanup(); return; } // buffer for IAS set BYTE IASSetBuff[sizeof (IAS_SET) - 3 + IAS_MAX_ATTRIBNAME]; int IASSetLen = sizeof (IASSetBuff); PIAS_SET pIASSet = (PIAS_SET) &IASSetBuff; SOCKADDR_IRDA ServSockAddr = {AF_IRDA, 0, 0, 0, 0, "OBEX"}; memcpy(&pIASSet->irdaClassName[0], "OBEX", 5); // include length of the NULL character in the end memcpy(&pIASSet->irdaAttribName[0], "IrDA:TinyTP", 12); pIASSet->irdaAttribType = IAS_ATTRIB_STR; pIASSet->irdaAttribute.irdaAttribUsrStr.Len = 12; if (setsockopt(ServSock, SOL_IRLMP, IRLMP_IAS_SET, (const char *) pIASSet, IASSetLen) == SOCKET_ERROR) { FAILURE_MESG(_T("setsockopt")); closesocket (ServSock); WSACleanup(); return; } if (bind(ServSock, (const struct sockaddr *) &ServSockAddr, sizeof(SOCKADDR_IRDA)) == SOCKET_ERROR) { FAILURE_MESG(_T("bind")); closesocket (ServSock); WSACleanup(); return; } // Establish a socket to listen for incoming connections. // The backlog parameter is currently limited (silently) to 2. (API Reference) if (listen (ServSock, 2 /* backlog */) == SOCKET_ERROR) { FAILURE_MESG(_T("listen")); closesocket (ServSock); WSACleanup(); return; } // Accept a connection on the socket. if ((ClientSock = accept (ServSock, 0, 0)) == INVALID_SOCKET) { FAILURE_MESG(_T("accept")); closesocket (ServSock); WSACleanup(); return; } // Stop listening for connections from clients. closesocket (ServSock); bool bDisconnectClient = false; int iOffset = 0, totalBytesRead = 0, packetLen = 0; BYTE dataBuff[MAX_BUFF_SIZE]; // Receive data from the client. while (!bDisconnectClient) { if ((iOffset = recv (ClientSock, (char*)dataBuff + iOffset, sizeof (dataBuff) - iOffset, 0)) == SOCKET_ERROR) { FAILURE_MESG(_T("recv")); closesocket (ClientSock); WSACleanup(); return; } unsigned long arg; if (ioctlsocket( ClientSock, FIONREAD, &arg ) == SOCKET_ERROR) { FAILURE_MESG(_T("ioctlsocket")); closesocket (ClientSock); WSACleanup(); return; } if (arg > 0) // some data left to be collected { totalBytesRead += iOffset; iOffset = totalBytesRead; // adjust offset, so that next write happens at the correct place continue; } else totalBytesRead = iOffset = 0; // Interpret the packets received at the socket, parse for the appropriate operation // opcodes, and then to make the client believe it is talking to an OBEX compliant device, // construct headers for appropriate response... // Info. about what an OBEX packet contains for various operations, refer to the OBEX // specification at the IrDA site. if (dataBuff[0] == OBEX_CONNECT) { dataBuff[0] = OBEX_SUCCESS; *((unsigned short *)&dataBuff[1]) = htons((unsigned short)7); dataBuff[3] = OBEX_VERSION; dataBuff[4] = OBEX_CONNECT_FLAGS; *((unsigned short *)&dataBuff[5]) = htons((unsigned short)MAX_BUFF_SIZE); packetLen = 7; } else if (dataBuff[0] == OBEX_PUT) { CreateNewFile(dataBuff, false); dataBuff[0] = OBEX_CONTINUE; *((unsigned short *)&dataBuff[1]) = htons((unsigned short)3); packetLen = 3; } else if (dataBuff[0] == OBEX_PUT_FINAL) { CreateNewFile(dataBuff, true); dataBuff[0] = OBEX_SUCCESS; *((unsigned short *)&dataBuff[1]) = htons((unsigned short)3); packetLen = 3; } else if (dataBuff[0] == OBEX_DISCONNECT) { dataBuff[0] = OBEX_SUCCESS; *((unsigned short *)&dataBuff[1]) = htons((unsigned short)3); packetLen = 3; bDisconnectClient = true; } if (send (ClientSock, (char*)dataBuff, packetLen, 0) == SOCKET_ERROR) { FAILURE_MESG(_T("send")); closesocket (ClientSock); WSACleanup(); return; } } // Close the client socket, cleanup and exit closesocket (ClientSock); WSACleanup(); return; } static void CreateNewFile(BYTE* dataBuff, bool put_final) { // most of the header and value pairs are of the form... // Byte -> 0 1 2 3... // | Header ID | Length of Header | Value... // | | and Value | static FILE* fp = NULL; if (!put_final && (fp == NULL)) { wchar_t fileName[MAX_FILE_NAME]; // extract the name of the file // skip the first 3 bytes, i.e. PUT opcode + 2 bytes of Length of the packet if (dataBuff[3] == OBEX_NAME) { /* extract the length of the name */ int len_name = ntohs(*(unsigned short *)&dataBuff[4]) - 3; wchar_t* szFileName = (wchar_t *)malloc(len_name); /* Now convert the unicode text from network to host byte order */ for (int i=0; i < (len_name/2); i++) szFileName[i] = ntohs(*(unsigned short *)&dataBuff[6 + 2*i]); // we're using unicode functions instead of the generic functions // 'cos the filename in the OBEX headers is in unicode... // we'll save the file in the "My Documents" folder... wcscpy(fileName, _T("\\My Documents\\")); wcscat(fileName, szFileName); free(szFileName); } fp = _wfopen( fileName, _T("w")); _setmode(fp, _O_BINARY); } /* parse the OBEX header received till we reach the BODY header */ BYTE* buff = dataBuff; int total_bytes, skip = 0; while ((*buff != OBEX_BODY) && (*buff != OBEX_END_OF_BODY)) { if ((*buff == OBEX_PUT) || (*buff == OBEX_PUT_FINAL)) { total_bytes = ntohs(*(unsigned short *)(buff + 1)); skip += 3; } else if ((*buff == OBEX_NAME) || (*buff == OBEX_DESCRIPTION)) skip += ntohs(*(unsigned short *)(buff + 1)); else if ((*buff == OBEX_LENGTH) || (*buff == OBEX_PALM_CREATOR_ID)) skip += 5; // both occupy 4 bytes..., exceptions to the diagram above buff = dataBuff + skip; if (skip == total_bytes) break; } if ((*buff == OBEX_BODY) || (*buff == OBEX_END_OF_BODY)) { int size = ntohs(*(unsigned short *)(buff + 1)); if (fp) fwrite(buff + 3, size - 3, 1, fp); if (put_final || (*buff == OBEX_END_OF_BODY)) { /* close the file and set the pointer to NULL */ if (fp) fclose(fp); fp = NULL; } } }