/////////////////////////////////////////////////////// // Build the send the first message (RRQ or WRQ) // All Data are in sTC struct /////////////////////////////////////////////////////// static BOOL TftpSendConnect (char *szBlkSize, BOOL bFullPath) { ADDRINFO Hints, *ai; int Rc; char szPort[NI_MAXSERV]; // preparte a data packet (either RRQ or WRQ) PopulateXRQPacket (szBlkSize, bFullPath); // resolve host name memset (& Hints, 0, sizeof Hints); Hints.ai_family = AF_UNSPEC; Hints.ai_socktype = SOCK_DGRAM; Hints.ai_protocol = IPPROTO_UDP; // first use port given as parameter, if (sTC.nPort==0) lstrcpy (szPort, "tftp"); else { wsprintf (szPort, "%d", sTC.nPort), Hints.ai_flags = AI_NUMERICSERV; } Rc = getaddrinfo (sTC.szHost, szPort, & Hints, &ai ); // last chance : use default tftp port 69 if (Rc==WSASERVICE_NOT_FOUND) { Hints.ai_flags = AI_NUMERICSERV; Rc = getaddrinfo (sTC.szHost, DEFAULT_TFTP_PORT, & Hints, &ai ); } if (Rc!=0) return BadEndOfTransfer ("Host is unknown or invalid. Error %d", GetLastError()); sTC.s = socket( ai->ai_family,ai->ai_socktype, ai->ai_protocol ) ; if (sTC.s == INVALID_SOCKET) { freeaddrinfo (ai); return BadEndOfTransfer ( "Can't create client socket.\nError code %d (%s)", WSAGetLastError (), LastErrorText()); } // since remote port will change do not use either bind or connect Rc = sendto (sTC.s, sTC.BufSnd, sTC.nToSend , 0, ai->ai_addr, ai->ai_addrlen ); if (Rc == SOCKET_ERROR) { freeaddrinfo (ai); return BadEndOfTransfer ("can not send data packet.\n%s\nError code %d (%s)", "Tftp server may have been stopped", WSAGetLastError (), LastErrorText()); } freeaddrinfo (ai); return TRUE; } // TftpSendConnect
//////////////////////////// // Attach and destroy icon to the TaskTray void TrayMessage(HWND hDlg, DWORD dwMessage, HICON hIcon, int TaskTrayId, int uCallBckMsg) { NOTIFYICONDATA IconData; LogToMonitor ("TrayMessage Call : msg %d <%s>, wnd %d, id %d\n", dwMessage, dwMessage==NIM_ADD ? "ADD" : dwMessage==NIM_DELETE ? "DELETE" : "OTHER", hDlg, TaskTrayId ); memset (& IconData, 0, sizeof IconData); // IconData.cbSize = NOTIFYICONDATA_V1_SIZE; IconData.cbSize = sizeof IconData; IconData.hWnd = hDlg; IconData.uID = TaskTrayId ; if (dwMessage != NIM_DELETE) { IconData.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP; IconData.uCallbackMessage = uCallBckMsg; IconData.hIcon = hIcon; GetWindowText (hDlg, IconData.szTip, sizeof IconData.szTip - 1); } if ( ! Shell_NotifyIcon (dwMessage, &IconData) ) LogToMonitor ("error %d in Shell_NotifyIcon <%s>\n", GetLastError (), LastErrorText () ); } // TrayMessage
void ListenDhcpMessage (void *lpVoid) { struct dhcp_packet sDhcpPkt; char szHostname [128], *p; int Rc, nSize; struct S_WorkerParam *pParam = lpVoid; struct sockaddr_in SockFrom; int nFromLen = sizeof SockFrom; BOOL bUniCast; int True = 1; DHCPReadConfig (); Sleep (1000); //NJW Prompt to see if we should discover via ping before we start doing DHCP if(scanforleases) // && IDYES == CMsgBox(pParam->hWnd, "Should I reset the lease file and rediscover devices?", "Discover Devices", MB_YESNO)) { struct in_addr addr; int count; SetHourglass(TRUE); ReadKey(TFTPD32_DHCP_KEY, KEY_DHCP_POOL, & addr.s_addr, sizeof(addr.s_addr), REG_DWORD, szTftpd32IniFile); ReadKey(TFTPD32_DHCP_KEY, KEY_DHCP_POOLSIZE, &count, sizeof(count), REG_DWORD, szTftpd32IniFile); SetNumAllocated(0); FreeLeases(FALSE); if (sSettings.bPersLeases) LoadLeases (); if (sSettings.bPing) PingRange (&addr, count); // DHCPSaveConfig (); SetHourglass(FALSE); SVC_WARNING ("Lease file updated.\nDiscover Devices"); } // add broadcast permission to socket if (setsockopt (tThreads[TH_DHCP].skt, SOL_SOCKET, SO_BROADCAST, (char *) & True, sizeof True) != 0) { LOG (1, "can't set broadcast option.\nPlease, suppress DHCP server in the settings window"); LogToMonitor ("can't set broadcast option.\n"); tThreads[TH_DHCP].gRunning = FALSE; } while ( tThreads[TH_DHCP].gRunning ) { // send leases to GUI Dhcp_Send_Leases (tFirstIP, nAllocatedIP); memset (& sDhcpPkt, 0, sizeof sDhcpPkt); Rc = recvfrom ( tThreads[TH_DHCP].skt, (char *) & sDhcpPkt, sizeof sDhcpPkt, 0, (struct sockaddr *) & SockFrom, & nFromLen); // recv error // since Tftpd32 sends broadcasts, it receives its own message, just ignore it if (Rc < 0) { if (GetLastError () != WSAECONNRESET) { LOG (1, "Recv error %d", GetLastError ()); Sleep (500); } continue; } // recv failed // if msg is too short // If all bootP fields have been read if (Rc < offsetof ( struct dhcp_packet, options )) { LOG (5, "Message truncated (length was %d)", Rc); if ( tThreads[TH_DHCP].gRunning ) Sleep (500); continue; } // if pool is empty and MAC address not statically assigned : ignore request if ( sParamDHCP.nPoolSize == 0 && DHCP_StaticAssignation (& sDhcpPkt)==INADDR_NONE ) { Sleep (100); continue; } // handle only nul-terminated strings sDhcpPkt.sname[sizeof sDhcpPkt.sname - 1] = 0; sDhcpPkt.file [sizeof sDhcpPkt.file - 1] = 0; // read host name, truncate it if (gethostname (szHostname , sizeof szHostname )==SOCKET_ERROR) lstrcpy (szHostname, "Tftpd32DchpServer"); if ((p=strchr (szHostname, '.'))!=NULL) *p=0; szHostname [sizeof sDhcpPkt.sname - 1] = 0; if (sDhcpPkt.sname[0]!=0 && lstrcmp (sDhcpPkt.sname, szHostname)!=0) { LOG (2, "Packet addressed to %s", sDhcpPkt.sname); continue; } // we have only to answer to BOOTREQUEST msg if (sDhcpPkt.op != BOOTREQUEST) { LOG (2, "%d Request %d not processed", GetCurrentThreadId (),sDhcpPkt.op); continue ; } // if request OK and answer ready bUniCast = ( SockFrom.sin_addr.s_addr!=htonl (INADDR_NONE) && SockFrom.sin_addr.s_addr!=htonl (INADDR_ANY) // fix 5/02/2006 : 127.0.0.2 should be handle as a broadcast && SockFrom.sin_addr.S_un.S_un_b.s_b1 != 127 ) ; // class A 127 if (ProcessDHCPMessage ( & sDhcpPkt, & nSize ) ) {struct servent *lpServEnt; // BinDump ((char *)&sDhcpPkt, sizeof sDhcpPkt, "DHCP"); SockFrom.sin_family = AF_INET; // if no source address was specified reply with a broadcast if (!bUniCast) SockFrom.sin_addr.s_addr = htonl (INADDR_NONE); // Added : DHCP relay detection --> send replies to port 67 and 68 // Colin and others point ourt that this is wrong. I guess they are right. // However it should not be an issue and i am sure that the host receive an address ! if (sDhcpPkt.giaddr.s_addr!=htonl(INADDR_ANY) || sDhcpPkt.giaddr.s_addr!=htonl(INADDR_NONE)) { // sends to port 67 lpServEnt = getservbyname ("bootps", "udp") ; SockFrom.sin_port = (lpServEnt != NULL) ? lpServEnt->s_port : htons (BOOTPS_PORT); Rc = sendto (tThreads[TH_DHCP].skt, (char *) & sDhcpPkt, nSize, 0, (struct sockaddr *) & SockFrom, sizeof SockFrom); // and prepare for port 68 lpServEnt = getservbyname ("bootpc", "udp") ; SockFrom.sin_port = (lpServEnt != NULL) ? lpServEnt->s_port : htons (BOOTPC_PORT); } LOG (15, "Thread 0x%X: send %d bytes", GetCurrentThreadId(), nSize ); Rc = sendto (tThreads[TH_DHCP].skt, (char *) & sDhcpPkt, nSize, 0, (struct sockaddr *) & SockFrom, sizeof SockFrom); if (Rc<nSize) LOG (1, "sendto error %d: %s", GetLastError(), LastErrorText ()); } // ProcessDHCPMessage } // do it eternally LogToMonitor ("DHCP thread ends here\n"); _endthread (); } // ListenDhcpMessage
///////////////////////////// // Fenetre Background gestion des appels TCP // LRESULT CALLBACK TftpClientProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { DWORD nbWrt; struct tftphdr *tpr, *tps; time_t dNow; int Ark; HWND hCBWnd, hParentWnd; time (&dNow); switch (message) { ///////////////////////// // Message Windows case WM_INITCLIENT : // only one client transfer available hTftpClientSemaphore = CreateSemaphore(NULL, 1, 1, TFTP_CLIENT_SEMAPHORE); hTftpClientWnd = hWnd; hParentWnd = GetParent (hWnd); EnableWindow (GetDlgItem (hParentWnd, IDC_CLIENT_BREAK_BUTTON), FALSE); SetDlgItemText (hParentWnd, IDC_CLIENT_BLOCK, ""); // populate combo with proposed block sizes hCBWnd = GetDlgItem (hParentWnd, IDC_CB_DATASEG); for (Ark=0 ; Ark<SizeOfTab (tBlkSize); Ark++) ComboBox_AddString (hCBWnd, tBlkSize[Ark].szBlkSize); ComboBox_SetCurSel (hCBWnd, 0); // uncheck "Send full path to server" SendDlgItemMessage (hParentWnd, IDC_CLIENT_FULL_PATH, BM_SETCHECK, BST_UNCHECKED, 0); // edittext IDC_CLIENT_FILE will accept dropped file (works only because it is on the top in Z-Order DragAcceptFiles (GetDlgItem (hParentWnd, IDC_CLIENT_LOCALFILE), TRUE); // fEditBoxProc = (WNDPROC) SetWindowLong (GetDlgItem (hParentWnd, IDC_CLIENT_LOCALFILE), GWL_WNDPROC, (LONG) TftpClientFileNameProc); fEditBoxProc = (WNDPROC) SetWindowLongPtr (GetDlgItem (hParentWnd, IDC_CLIENT_LOCALFILE), GWLP_WNDPROC, (LONG_PTR) TftpClientFileNameProc); // SetWindowLong (GetDlgItem (hParentWnd, IDC_CLIENT_FILE), GWL_USERDATA, (LONG) TftpClientFileNameProc); SetWindowLongPtr (GetDlgItem (hParentWnd, IDC_CLIENT_LOCALFILE), GWLP_USERDATA, (LONG_PTR) TftpClientFileNameProc); break; case WM_CLOSE : LogToMonitor ("GUI: Closing Tftp Client"); CloseHandle (hTftpClientSemaphore); CloseHandle (sTC.hFile); closesocket (sTC.s); break; case WM_COMMAND : Handle_VM_Command (hWnd, wParam, lParam); break; case WM_TIMER : KillTimer(hWnd, wParam); PostMessage (hWnd, wParam, 0, (LPARAM) -1); // pour pas confondre break; ////////////////////// // Download : fichier envoyé par le serveur case WM_CLIENT_DATA : // WSAAsyncSelect (sTC.s, hWnd, 0, 0); A SUPPRIMER KillTimer(hWnd, wParam); if (sTC.bBreak) return FALSE; sTC.nRcvd = 0; // On est reveillé par un message reçu tpr = (struct tftphdr *) sTC.BufRcv; if (WSAGETSELECTEVENT(lParam) == FD_READ) { if (! UdpRecv ()) return BadEndOfTransfer ("Error in Recv.\nError code is %d (%s)", WSAGetLastError (), LastErrorText() ); // parcours des codes retours switch (htons (tpr->th_opcode)) { case TFTP_ERROR : return BadEndOfTransfer ("Server stops the transfer.\nError #%d: %s", htons (tpr->th_code), tpr->th_msg); case TFTP_OACK : if (sTC.nCount==0) TftpProcessOACK (); break; case TFTP_DATA : // a data packet has been received. Check #block if ( htons (tpr->th_block) == (unsigned short) (sTC.nCount+1) ) { if ( !WriteFile (sTC.hFile, tpr->th_data, sTC.nRcvd - TFTP_DATA_HEADERSIZE, & nbWrt, NULL) || sTC.nRcvd-TFTP_DATA_HEADERSIZE!=nbWrt) return BadEndOfTransfer ("Error in writing file.\nError code is %d (%s)", GetLastError(), LastErrorText()); sTC.nCount++; sTC.nRetransmit = 0; // prepare Ack block tps = (struct tftphdr *) sTC.BufSnd; tps->th_opcode = htons (TFTP_ACK), tps->th_block = htons ((unsigned short) sTC.nCount); sTC.nToSend = TFTP_DATA_HEADERSIZE; // compute MD5 MD5Update (& sTC.m.ctx, tpr->th_data, nbWrt); } break; default : return BadEndOfTransfer ("Server sent illegal opcode %d", htons (tpr->th_opcode)); } // switch opcode } // il y a un message à recevoir // La comparaison marche si le paquet est le bon ou une répétition du précédent message if ( htons (tpr->th_block) == (unsigned short) sTC.nCount) { if (sTC.nRetransmit) sTC.nTotRetrans ++; if (sTC.nRetransmit++ > TFTP_RETRANSMIT) return BadEndOfTransfer ("Timeout waiting block #%d", sTC.nCount+1); send (sTC.s, sTC.BufSnd, sTC.nToSend, 0); SetTimer (hWnd, WM_CLIENT_DATA, sTC.dwTimeout, NULL); } // sTC.nRcvd ne peut être inférieur que si on a reçu un block if ( htons (tpr->th_opcode)==TFTP_DATA && sTC.nRcvd!=0 && sTC.nRcvd < sTC.nPktSize + TFTP_DATA_HEADERSIZE) return TransferOK (dNow); Statistics (dNow); break; //////////////////////// // Upload : server sends ACK case WM_CLIENT_ACK : KillTimer(hWnd, wParam); if (sTC.bBreak || sTC.s==INVALID_SOCKET) return FALSE; // socket not closed by StopTransfer tpr = (struct tftphdr *) sTC.BufRcv; if ( WSAGETSELECTEVENT(lParam) == FD_READ ) { if (! UdpRecv ()) return BadEndOfTransfer ("Error in Recv.\nError code is %d (%s)", WSAGetLastError (), LastErrorText() ); switch (htons (tpr->th_opcode)) { case TFTP_ERROR : return BadEndOfTransfer ("Server stops the transfer.\nError #%d: %s", htons (tpr->th_code), tpr->th_msg); case TFTP_OACK : if (sTC.nCount!=0) break; // ignore message TftpProcessOACK (); tpr->th_block = htons(0); // pour passer en dessous // Fall through case TFTP_ACK : if ( htons (tpr->th_block) == (unsigned short) sTC.nCount ) { // prepare Data block tps = (struct tftphdr *) sTC.BufSnd; if ( !ReadFile (sTC.hFile, tps->th_data, sTC.nPktSize, & sTC.nRcvd, NULL) ) { if (sTC.nToSend == TFTP_DATA_HEADERSIZE + sTC.nPktSize) // file was exactly N * PkSize return TransferOK (dNow); else return BadEndOfTransfer ("Error in reading file.\nError code is %d (%s)", GetLastError(), LastErrorText()); } if (sTC.nRcvd == 0) // EOF { if (sTC.nToSend < TFTP_DATA_HEADERSIZE + sTC.nPktSize) return TransferOK (dNow); } sTC.nCount++; sTC.nRetransmit = 0; tps->th_opcode = htons (TFTP_DATA), tps->th_block = htons ((unsigned short) sTC.nCount); sTC.nToSend = TFTP_DATA_HEADERSIZE + sTC.nRcvd; // compute MD5 MD5Update (& sTC.m.ctx, tps->th_data, sTC.nRcvd); } break; default : return BadEndOfTransfer ("Server sent illegal opcode %d", htons (tpr->th_opcode)); } // switch opcode } // il y a un message à recevoir // Timeout or ack of previous block else if ( htons (tpr->th_block) == (unsigned short) (sTC.nCount-1) ) { if (sTC.nRetransmit) sTC.nTotRetrans ++; if (sTC.nRetransmit++ > TFTP_RETRANSMIT) return BadEndOfTransfer ("Timeout while waiting ack block #%d", sTC.nCount); // une possibilité : on est au dernier message et le serveur TFTP n'a pas acquitté // --> on renvoie, mais sur Timeout, on signale un transfert OK if (sTC.nToSend < TFTP_DATA_HEADERSIZE + sTC.nPktSize && sTC.nRetransmit<TFTP_RETRANSMIT) return TransferOK (dNow); } send (sTC.s, sTC.BufSnd, sTC.nToSend, 0); SetTimer (hWnd, WM_CLIENT_ACK, sTC.dwTimeout, NULL); Statistics (dNow); break; } // switch message return DefWindowProc (hWnd, message, wParam, lParam); } // TftpProc
/////////////////////////////////////////////////////// // open the file /////////////////////////////////////////////////////// BOOL TftpCliOpenFile (void) { // creation fichier ou lecture switch (sTC.opcode) { case TFTP_WRQ : sTC.hFile = CreateFile ( sTC.szFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE | FILE_FLAG_SEQUENTIAL_SCAN , NULL ); if (sTC.hFile == INVALID_HANDLE_VALUE) return BadEndOfTransfer ("Error opening file %s for reading\nreturn code is %d (%s)", sTC.szFile, GetLastError (), LastErrorText() ); sTC.dwFileSize = GetFileSize (sTC.hFile, NULL); break; case TFTP_RRQ : sTC.hFile = CreateFile ( sTC.szFile, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_ARCHIVE | FILE_FLAG_SEQUENTIAL_SCAN , NULL ); if ( sTC.hFile==INVALID_HANDLE_VALUE && GetLastError()==ERROR_FILE_EXISTS && CMsgBox (hTftpClientWnd, "File exists, overwrite it ?", APPLICATION, MB_YESNOCANCEL) == IDYES ) { sTC.hFile = CreateFile ( sTC.szFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_ARCHIVE | FILE_FLAG_SEQUENTIAL_SCAN , NULL ); if (sTC.hFile == INVALID_HANDLE_VALUE) return BadEndOfTransfer ("Error opening file %s for writing\nreturn code is %d (%s)", sTC.szFile, GetLastError (), LastErrorText() ); } break; } //switch opcode return sTC.hFile!=INVALID_HANDLE_VALUE; } // TftpCliOpenFile
// bind the thread socket static SOCKET BindServiceSocket (const char *name, int type, const char *service, int def_port, int rfc_port, const char *sz_if) { struct sockaddr_in SockAddr; SOCKET sListenSocket = INVALID_SOCKET; int Rc; struct servent *lpServEnt; sListenSocket = socket (AF_INET, type, 0); if (sListenSocket == INVALID_SOCKET) { SVC_ERROR ("Error : Can't create socket\nError %d (%s)", GetLastError(), LastErrorText() ); return sListenSocket; } // REUSEADDR option in order to allow thread to open 69 port if (sSettings.bPortOption && lstrcmp (service, "tftp")==0) {int True=1; Rc = setsockopt (sListenSocket, SOL_SOCKET, SO_REUSEADDR, (char *) & True, sizeof True); LogToMonitor (Rc==0 ? "Port %d may be reused" : "setsockopt error", sSettings.Port); } memset (& SockAddr, 0, sizeof SockAddr); SockAddr.sin_family = AF_INET; // get the port number: read it from conf or from /etc/services files else take default port if (def_port != rfc_port) // config has modified port SockAddr.sin_port = htons ( (short) def_port ); else { // use /etc/services lpServEnt = getservbyname (service, type==SOCK_DGRAM ? "udp" : "tcp") ; SockAddr.sin_port = (lpServEnt != NULL) ? lpServEnt->s_port : htons ((short) rfc_port); } // bind the socket to the active interface // if no interface has been specified szLocalIP is empty // all interfaces are activated. SockAddr.sin_addr.s_addr = (sz_if==NULL || sz_if[0]==0) ? INADDR_ANY : inet_addr (sz_if); Rc = bind (sListenSocket, (struct sockaddr *) & SockAddr, sizeof SockAddr); if (Rc == INVALID_SOCKET) { // 3 causes : access violation, socket already bound, bind on an adress switch (GetLastError ()) { case WSAEADDRNOTAVAIL : // 10049 SVC_ERROR ("Error %d\n%s\n\n" "Tftpd32 tried to bind the %s port\n" "to the interface %s\nwhich is not available for this host\n" "Either remove the %s service or suppress %s interface assignation", GetLastError (), LastErrorText (), name, sz_if, name, sz_if); break; case WSAEINVAL : case WSAEADDRINUSE : SVC_ERROR ("Error %d\n%s\n\n" "Tftpd32 can not bind the %s port\n" "an application is already listening on this port", GetLastError (), LastErrorText (), name ); break; default : SVC_ERROR ("Bind error %d\n%s", GetLastError (), LastErrorText () ); break; } // switch error type closesocket (sListenSocket); LogToMonitor ("bind port to %s port %d failed\n", inet_ntoa (SockAddr.sin_addr), htons (SockAddr.sin_port) ); return INVALID_SOCKET; } return sListenSocket; } // BindServiceSocket