/* ----------------------------- */ int PASCAL WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) { WSADATA WSAData; int Rc; // ------------------------------------------ // Start the App // ------------------------------------------ Rc = WSAStartup (MAKEWORD(2,0), & WSAData); if (Rc != 0) { CMsgBox (NULL, GetLastError()==WSAVERNOTSUPPORTED ? "Error: Tftpd32 now requires winsock version 2" : "Error: Can't init Winsocket", APPLICATION, MB_OK | MB_ICONERROR); return FALSE; } // opens Gui GuiMain (hInstance, hPrevInstance,lpszCmdLine, nCmdShow); WSACleanup (); return 0; } /* WinMain */
/* ----------------------------- */ int PASCAL WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) { WSADATA WSAData; int Rc; // ------------------------------------------ // Quick Uninstaller // ------------------------------------------ if (lstrcmpi ("-uninstall", lpszCmdLine) == 0) { // destroy the registry entries but not the ini file Tftpd32DestroySettings (); return 0; } // ------------------------------------------ // Start the App // ------------------------------------------ Rc = WSAStartup (MAKEWORD(2,0), & WSAData); if (Rc != 0) { CMsgBox (NULL, GetLastError()==WSAVERNOTSUPPORTED ? "Error: Tftpd32 now requires winsock version 2" : "Error: Can't init Winsocket", APPLICATION, MB_OK | MB_ICONERROR); return FALSE; } // start Services through a thread // the thread start the console, wait for 200ms // (time to start the GUI) then starts the services // this way, an early call to the SVC_ERROR procedure happens // when the console/GUI socket is connected. _beginthread ( StartTftpd32Services, 0, NULL ); // let the console opens its socket // Pause needs to be higher than the one in StartMultiWorkerThreads (start_threads.c) // otherwise DHCP settings will not be loaded in GUI //Sleep (500); // opens Gui GuiMain (hInstance, hPrevInstance,lpszCmdLine, nCmdShow); WSACleanup (); LogToMonitor ("That's all folks\n"); return 0; } /* WinMain */
/////////////////////////////////////////////////////// // 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
int TransferOK (time_t dNow) { char szBuf [256]; StopTransfer (); // free resources // close MD5 computation MD5Final (sTC.m.ident, & sTC.m.ctx); // Semaphore released ReleaseSemaphore (hTftpClientSemaphore, 1, NULL); if (! sTC.bMultiFile) {char szMD5 [33]; int Ark; for (Ark=0 ; Ark<16; Ark++) wsprintf (szMD5 + 2*Ark, "%02x", sTC.m.ident[Ark]); wsprintf (szBuf, "%d block%s transferred in %d second%s\n %d block%s retransmitted\nMD5: %s", sTC.nCount, // + (sTC.opcode==TFTP_RRQ ? 1 : 0), PLURAL (sTC.nCount), // + (sTC.opcode==TFTP_RRQ ? 1 : 0)), (int) (dNow-sTC.StartTime), PLURAL (dNow-sTC.StartTime), sTC.nTotRetrans, PLURAL (sTC.nTotRetrans), szMD5 ); CMsgBox (hTftpClientWnd, szBuf, APPLICATION, MB_OK | MB_ICONINFORMATION); } // one transfer --> display stats else { sTC.dwMultiFileBlk += sTC.nCount; sTC.dwMultiFile++; } return TRUE; } // TransferOK
int BadEndOfTransfer (const char *szFmt, ...) { char szBuf [512]; va_list marker; struct tftphdr *tp; // send NAK to server tp = (struct tftphdr *) sTC.BufSnd; tp->th_opcode = htons((u_short)TFTP_ERROR); tp->th_code = htons(EUNDEF); send (sTC.s, (char *) tp, TFTP_DATA_HEADERSIZE, 0); StopTransfer (); // display message va_start( marker, szFmt ); /* Initialize variable arguments. */ wvsprintf (szBuf, szFmt, marker); CMsgBox (hTftpClientWnd, szBuf, APPLICATION, MB_OK | MB_ICONERROR); // Semaphore released ReleaseSemaphore (hTftpClientSemaphore, 1, NULL); if (sTC.opcode==TFTP_RRQ && sTC.nRcvd!=0) DeleteFile (sTC.szFile); return FALSE; } // BadEndOfTransfer
void TftpdConsole (void *param) { SOCKET sDlg; int Rc; int nTriggeredEvent; static struct S_ConsoleMsg msg; enum e_Events { EV_TOGUI, EV_FROMGUI, EV_NUMBER }; HANDLE tEvents [EV_NUMBER]; // open logging facility StartAsyncMessagingFacility ( ); do { LogToMonitor ("opening comm socket\n"); SetGuiStatus (NOT_CONNECTED); sDlg = WaitForGuiConnection (); // fail only if thread ends if (sDlg==INVALID_SOCKET) continue; // Verify Versions LogToMonitor ("Verify Console/GUI parameters\n"); Rc = TcpExchangeChallenge (sDlg, 0x56AE, CURRENT_PROTOCOL_VERSION, NULL, sSettings.szConsolePwd); if ( Rc < 0 ) { Sleep (1000); continue; } LogToMonitor ( "Version check OK\n" ); SetGuiStatus (CONNECTED); // Startup blocking service by creating // one event and one semaphore to code the blocking sendmsgrequest hMsgRequestSemaf = CreateMutex(NULL, 0, NULL); hEvMsgSent = CreateEvent(NULL,FALSE,FALSE,NULL); if (hMsgRequestSemaf==NULL) CMsgBox (NULL, "Can not create resource", APPLICATION, MB_OK | MB_ICONERROR); tThreads[TH_CONSOLE].bInit = TRUE; // inits OK // Create Socket Event tEvents [EV_FROMGUI] = WSACreateEvent(); WSAEventSelect (sDlg, tEvents[EV_FROMGUI], FD_READ | FD_CLOSE); do { // waits either internal sollicitation or msg reception tEvents[EV_TOGUI] = tThreads[TH_CONSOLE].hEv; nTriggeredEvent = WaitForMultipleObjects (EV_NUMBER, tEvents, FALSE, INFINITE); switch (nTriggeredEvent) { case EV_FROMGUI : // WSA events should be manually reset WSAEventSelect (sDlg, 0, 0); ResetEvent (tEvents[EV_FROMGUI]); Rc = TcpPPRecv (sDlg, (void *) &msg, sizeof msg, 10, INVALID_HANDLE_VALUE); if (Rc>0) LOG (9, "received %d bytes from console", Rc); if (Rc>0) ProcessMsg (sDlg, &msg); else LogToMonitor ("rcvd error %d/%d in console\n", Rc, GetLastError ()); WSAEventSelect (sDlg, tEvents[EV_FROMGUI], FD_READ | FD_CLOSE); break; // message to be sent to Gui (except logs) case EV_TOGUI : ProcessAsyncMessages ( sDlg, hEvMsgSent ); break; } // switch signalled events } while (tThreads[TH_CONSOLE].gRunning && (Rc>0 || Rc==TCP4U_TIMEOUT) ); WSACloseEvent (tEvents [EV_FROMGUI]); tEvents [EV_FROMGUI] = INVALID_HANDLE_VALUE; closesocket (sDlg); // blocking service not available CloseHandle (hEvMsgSent); hEvMsgSent = INVALID_HANDLE_VALUE; CloseHandle (hMsgRequestSemaf); hMsgRequestSemaf = INVALID_HANDLE_VALUE; LogToMonitor ("end of GUI session\n"); } while ( tThreads[TH_CONSOLE].gRunning ); // terminate therad : don't listen anymore // closesocket (sListen); // unblock some threads SetEvent (hEvMsgSent); Sleep (10); SetEvent (hEvMsgSent); // stop logging service StopAsyncMessagingFacility (); LogToMonitor ("End of console thread\n"); _endthread (); } // TftpdConsole
// Hook designed to insert the name of the dragged file into the edit control LRESULT CALLBACK TftpClientFileNameProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { char szFileName [MAX_PATH]; static HANDLE hDrop; static int nAmount, Ark; switch (message) { case WM_TIMER : // is previous transfer terminated if (WaitForSingleObject (hTftpClientSemaphore, 0) == WAIT_OBJECT_0) { if (! sTC.bBreak && ++Ark<nAmount) { DragQueryFile (hDrop, Ark, szFileName, MAX_PATH-1); SetWindowText (hWnd, szFileName); // ignore directories (wait for next turn) if ( (GetFileAttributes (szFileName) & FILE_ATTRIBUTE_DIRECTORY) == 0) SendMessage (hTftpClientWnd, WM_COMMAND, IDC_CLIENT_SEND_BUTTON, 0); else ReleaseSemaphore (hTftpClientSemaphore, 1, NULL); } else // mutiple transfer either stopped or finished { DragFinish (hDrop); KillTimer (hWnd, wParam); CMsgBox (hWnd, "%d file%s fully transferred in %d block%s and %d retransmission%s", "Tftpd32", MB_OK, sTC.dwMultiFile, PLURAL(sTC.dwMultiFile), sTC.dwMultiFileBlk, PLURAL(sTC.dwMultiFileBlk), sTC.nTotRetrans, PLURAL(sTC.nTotRetrans)); sTC.bBreak = sTC.bMultiFile = FALSE; sTC.nTotRetrans = sTC.dwMultiFileBlk = sTC.dwMultiFile = 0 ; ReleaseSemaphore (hTftpClientSemaphore, 1, NULL); break; } } break; case WM_DROPFILES : hDrop = (HANDLE) wParam; nAmount = DragQueryFile (hDrop, -1, szFileName, MAX_PATH); // multi files mode : only if field Host has been filled if ( nAmount>=2 && GetDlgItemText (GetParent (hWnd), IDC_CLIENT_HOST, sTC.szHost, sizeof sTC.szHost) > 0) { if (CMsgBox (hWnd, "Upload (Put) %d files to host ?", "Tftpd32", MB_ICONQUESTION | MB_YESNOCANCEL, nAmount)==IDYES) { sTC.bMultiFile = TRUE; sTC.dwMultiFileBlk=sTC.dwMultiFile=0 ; Ark=-1 ; if (SetTimer (hWnd, ID_CLIENT_TRANSFER, 1000, NULL)==0) CMsgBox (hWnd, "Create timer failed", "Tftpd32", MB_OK); } // User do not cancel MessageBox warning } // multi files have been dropped else { // only one file selected : just put its name into control DragQueryFile (hDrop, 0, szFileName, MAX_PATH); SetWindowText (hWnd, szFileName); DragFinish (hDrop); } break; default : break; } return CallWindowProc (fEditBoxProc, hWnd, message, wParam, lParam); } // TftpClientFileNameProc
/////////////////////////////////////////////////////// // WM_Command /////////////////////////////////////////////////////// static int Handle_VM_Command (HWND hWnd, WPARAM wParam, LPARAM lParam) { int wItem = (int) LOWORD (wParam); HWND hParentWnd = GetParent (hWnd); char szCBTxt [128]; OPENFILENAME OpenFileName; char szCurDir[MAX_PATH]; switch ( wItem ) { case IDC_CLIENT_SEND_BUTTON : case IDC_CLIENT_GET_BUTTON : // fill sTC structure time (& sTC.StartTime); sTC.dwTimeout = TFTP_TIMEOUT * 1000; sTC.bBreak = FALSE; // clear file stats sTC.nToSend = sTC.nRcvd = sTC.nCount = sTC.nRetransmit = sTC.nPktSize = 0; sTC.s = INVALID_SOCKET; sTC.hFile = INVALID_HANDLE_VALUE; sTC.dwFileSize = 0; if (! sTC.bMultiFile) sTC.nTotRetrans = 0; // init MD5 computation MD5Init (& sTC.m.ctx); // récupérer les valeurs sTC.opcode = wItem==IDC_CLIENT_GET_BUTTON ? TFTP_RRQ : TFTP_WRQ; GetDlgItemText (hParentWnd, IDC_CLIENT_HOST, sTC.szHost, sizeof sTC.szHost); GetDlgItemText (hParentWnd, IDC_CLIENT_LOCALFILE, sTC.szFile, sizeof sTC.szFile); GetDlgItemText (hParentWnd, IDC_CLIENT_REMOTEFILE, sTC.szDestFile, sizeof sTC.szDestFile); if (strchr (sTC.szFile, '%') != NULL || strchr (sTC.szDestFile, '%') != NULL) { CMsgBox (hWnd, "Character %% not supported by Tftpd32", APPLICATION, MB_OK | MB_ICONHAND); break; } ComboBox_GetText (GetDlgItem (hParentWnd, IDC_CB_DATASEG), szCBTxt, sizeof szCBTxt); // STC.nPort set to 0 on error sTC.nPort = GetDlgItemInt (hParentWnd, IDC_CLIENT_PORT, NULL, FALSE); // datagram size. May be modified by an OACK message sTC.nPktSize = TFTP_SEGSIZE; if (sTC.szHost[0]==0 || sTC.szFile[0]==0) CMsgBox (hWnd, "Fields Host and File should be given.", APPLICATION, MB_OK | MB_ICONHAND); else if ( TftpCliOpenFile () && TftpSendConnect (szCBTxt, ISDLG_CHECKED(hParentWnd,IDC_CLIENT_FULL_PATH)) ) {int Rc; EnableWindow (GetDlgItem (hParentWnd, IDC_CLIENT_SEND_BUTTON), FALSE); EnableWindow (GetDlgItem (hParentWnd, IDC_CLIENT_GET_BUTTON), FALSE); EnableWindow (GetDlgItem (hParentWnd, IDC_CLIENT_BREAK_BUTTON), TRUE); SetTimer (hWnd, wItem==IDC_CLIENT_GET_BUTTON ? WM_CLIENT_DATA : WM_CLIENT_ACK, sTC.dwTimeout, NULL); Rc = WSAAsyncSelect (sTC.s, hWnd, wItem==IDC_CLIENT_GET_BUTTON ? WM_CLIENT_DATA : WM_CLIENT_ACK, FD_READ); Rc = GetLastError (); } else CloseHandle (sTC.hFile); break; case IDC_CLIENT_BREAK_BUTTON : sTC.bBreak = TRUE; WSAAsyncSelect (sTC.s, hWnd, 0, 0); BadEndOfTransfer ("Transfer cancelled by user"); break; // Code not implemented since OpenFileName dialog box change current directory case IDC_CLIENT_BROWSE : GetCurrentDirectory (sizeof szCurDir, szCurDir); memset (& OpenFileName, 0, sizeof OpenFileName); OpenFileName.lStructSize = sizeof (OPENFILENAME); OpenFileName.hwndOwner = hWnd; OpenFileName.hInstance = NULL; OpenFileName.lpstrFilter = NULL; OpenFileName.lpstrCustomFilter = NULL; OpenFileName.nMaxCustFilter = 0L; OpenFileName.nFilterIndex = 0L; OpenFileName.lpstrFile = sTC.szFile; OpenFileName.nMaxFile = sizeof sTC.szFile; OpenFileName.lpstrInitialDir = NULL; OpenFileName.lpstrTitle = "Select file"; OpenFileName.nFileOffset = 0; OpenFileName.nFileExtension = 0; OpenFileName.lpstrDefExt = "*.*"; OpenFileName.lCustData = 0; OpenFileName.Flags = 0; if (GetOpenFileName (&OpenFileName)) SetDlgItemText (hParentWnd, IDC_CLIENT_LOCALFILE, sTC.szFile); //else CMsgBox (hParentWnd, "GetOpenFailed raison %d", "bad", MB_OK, CommDlgExtendedError()); SetCurrentDirectory (szCurDir); break; } return FALSE; } // Handle_VM_Command