//////////////////////////// // 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
// send data using Udp int UdpSend (int nFromPort, struct sockaddr_in *sa_to, const char *data, int len) { SOCKET s; struct sockaddr_in sa_from; int Rc; int True=1; s = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (s == INVALID_SOCKET) return TCP4U_ERROR; // REUSEADDR option in order to allow thread to open 69 port Rc = setsockopt (s, SOL_SOCKET, SO_REUSEADDR, (char *) & True, sizeof True); LogToMonitor (Rc==0 ? "UdpSend: Port %d may be reused" : "setsockopt error", nFromPort); // populate sa_from sa_from.sin_family = AF_INET; sa_from.sin_addr.s_addr = htonl (INADDR_ANY); // will be changed by sendto sa_from.sin_port = htons (nFromPort); Rc = bind (s, & sa_from, sizeof sa_from); LogToMonitor ("UdpSend bind returns %d (error %d)", Rc, GetLastError ()); if (Rc<0) { closesocket (s); return TCP4U_BINDERROR; } Rc = sendto (s, data, len, 0, sa_to, sizeof *sa_to); LogToMonitor ("sendto returns %d", Rc); closesocket (s); return Rc; } // UdpSend
int TcpRecv (SOCKET s, LPSTR szBuf, unsigned uBufSize, unsigned uTimeOut, HANDLE hLogFile) { int Rc, nUpRc; /* Return Code of select and recv */ struct timeval TO; /* Time Out structure */ struct timeval *pTO; /* Time Out structure */ fd_set ReadMask; /* select mask */ DWORD dummy; if (s==INVALID_SOCKET) return TCP4U_ERROR; FD_ZERO (& ReadMask); /* mise a zero du masque */ FD_SET (s, & ReadMask); /* Attente d'evenement en lecture */ /* detail des modes */ switch (uTimeOut) { case TCP4U_WAITFOREVER : pTO = NULL; break; case TCP4U_DONTWAIT : TO.tv_sec = TO.tv_usec=0 ; pTO = & TO; break; /* Otherwise uTimeout is really the Timeout */ default : TO.tv_sec = (long) uTimeOut; TO.tv_usec=0; pTO = & TO; break; } /* s+1 normally unused but better for a lot of bugged TCP Stacks */ Rc = select (s+1, & ReadMask, NULL, NULL, pTO); if (Rc<0) { LogToMonitor ("select returns error %d\n", WSAGetLastError()); return TCP4U_ERROR; } if (Rc==0) return TCP4U_TIMEOUT; /* timeout en reception */ if (szBuf==NULL || uBufSize==0) return TCP4U_SUCCESS; Rc = recv (s, szBuf, uBufSize, 0); /* chgt 11/01/95 */ switch (Rc) { case SOCKET_ERROR : LogToMonitor ("recv returns error %d\n", WSAGetLastError()); nUpRc = TCP4U_ERROR ; break; case 0 : nUpRc = TCP4U_SOCKETCLOSED ; break; default : if (hLogFile!=INVALID_HANDLE_VALUE) WriteFile (hLogFile, szBuf, Rc, &dummy, NULL); nUpRc = Rc; break; } /* translation des codes d'erreurs */ return nUpRc; } /* TcpRecv */
// --------------------------------------------------------------- //a therad which asynchronously save th registry entries // --------------------------------------------------------------- void AsyncSaveKeyBckgProc (void *param) { struct S_ini *pmsg; LL_Create (LL_ID_SETTINGS, 500); tThreads[TH_ASYNCSAVEKEY].bInit = TRUE; // inits OK do { WaitForSingleObject (tThreads[TH_ASYNCSAVEKEY].hEv, INFINITE); Sleep (10); for ( pmsg = LL_PopMsg (LL_ID_SETTINGS); pmsg != NULL ; pmsg = LL_PopMsg (LL_ID_SETTINGS) ) { SaveKey (pmsg->path, pmsg->key, pmsg->buf, pmsg->bufsize, pmsg->type, pmsg->inifile); DeleteMsg(pmsg); } ResetEvent ( tThreads[TH_ASYNCSAVEKEY].hEv ); } while ( tThreads[TH_ASYNCSAVEKEY].gRunning ); LL_Destroy (LL_ID_SETTINGS); LogToMonitor ("end of registry thread\n"); _endthread (); } // AsyncSaveKeyProc
// // FUNCTION: ReportStatusToSCMgr() // // PURPOSE: Sets the current status of the service and // reports it to the Service Control Manager // // PARAMETERS: // dwCurrentState - the state of the service // dwWin32ExitCode - error code to report // dwWaitHint - worst case estimate to next checkpoint // // RETURN VALUE: // TRUE - success // FALSE - failure // // COMMENTS: // BOOL ReportStatusToSCMgr(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint) { static DWORD dwCheckPoint = 1; BOOL fResult = TRUE; if ( !bDebug ) // when debugging we don't report to the SCM { if (dwCurrentState == SERVICE_START_PENDING) ssStatus.dwControlsAccepted = 0; else ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP; ssStatus.dwCurrentState = dwCurrentState; ssStatus.dwWin32ExitCode = dwWin32ExitCode; ssStatus.dwWaitHint = dwWaitHint; if ( ( dwCurrentState == SERVICE_RUNNING ) || ( dwCurrentState == SERVICE_STOPPED ) ) ssStatus.dwCheckPoint = 0; else ssStatus.dwCheckPoint = dwCheckPoint++; // Report the status of the service to the service control manager. // LogToMonitor ("reporting service status %d\n", ssStatus.dwCurrentState); if (!(fResult = SetServiceStatus( sshStatusHandle, &ssStatus))) { AddToMessageLog ("SetServiceStatus"); } } return fResult; } // ReportStatusToSCMgr
void TerminateWorkerThreads (BOOL bSoft) { int Ark; HANDLE tHdle[TH_NUMBER]; int nCount; for ( Ark=0, nCount=0 ; Ark<TH_NUMBER ; Ark++ ) { // if bSoft do not kill management threads if ( bSoft && TFTPD32_MNGT_THREADS & tThreadsConfig[Ark].serv_mask) continue; if (tThreads [Ark].gRunning) { tThreads [Ark].gRunning = FALSE; WakeUpThread (nCount); tHdle[nCount++] = tThreads [Ark].tTh; } // if service is running } // wait for end of threads WaitForMultipleObjects (nCount, tHdle, TRUE, 5000); for ( Ark=0 ; Ark<TH_NUMBER ; Ark++ ) { if ( ! (bSoft && TFTPD32_MNGT_THREADS & tThreadsConfig[Ark].serv_mask) ) FreeThreadResources (Ark); } LogToMonitor ("all level 1 threads have returned\n"); } // TerminateWorkerThreads
///////////////////////////// // Background window // void SyslogProc (void * param) { SOCKET sSyslogListenSocket=INVALID_SOCKET; char szSyslogBuf[SYSLOG_MAXMSG+1]; // Buffer int Rc; struct sockaddr_in sSock; int nDummy; HANDLE m_hPipe=INVALID_HANDLE_VALUE; struct S_SyslogMsg msg; if (sSettings.bSyslogPipe) { m_hPipe = CreateFile (sPipeName, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); //if (m_hPipe == INVALID_HANDLE_VALUE) // MY_WARNING("Named pipe Tftpd32Syslog has not been created\r\nTftpd32 will not forward Syslog messages"); } sSyslogListenSocket = tThreads[TH_SYSLOG].skt; SyslogCreateLogFile (sSettings.szSyslogFile); while ( tThreads[TH_SYSLOG].gRunning ) { nDummy = sizeof sSock; // get the message, checks its format and display it Rc = recvfrom (sSyslogListenSocket, szSyslogBuf, SYSLOG_MAXMSG, 0, (struct sockaddr *) & sSock, & nDummy); // something received and format OK if (Rc>0 && CheckSyslogMsg (szSyslogBuf, Rc) ) { if (hSysLogFile != INVALID_HANDLE_VALUE) {struct tm *newtime; time_t tm; int Dummy; char szTxt [SYSLOG_MAXMSG +1 + 30]; time (&tm); newtime = localtime (& tm); // copy in file the string without the new-line wsprintf (szTxt, "%24.24s: %s\r\n", asctime (newtime), szSyslogBuf); WriteFile (hSysLogFile, szTxt, lstrlen (szTxt), &Dummy, NULL); } // log in file if (m_hPipe!=INVALID_HANDLE_VALUE) WriteFile (m_hPipe, szSyslogBuf, Rc, &nDummy, NULL); lstrcpy (msg.from, inet_ntoa (sSock.sin_addr)); lstrcpy (msg.txt, szSyslogBuf); SendMsgRequest ( C_SYSLOG, & msg, 1 + Rc + sizeof msg.from, FALSE, // don't block thread until msg sent FALSE ); // if no GUI return } } // loop if (m_hPipe != INVALID_HANDLE_VALUE) CloseHandle (m_hPipe); if (hSysLogFile != INVALID_HANDLE_VALUE) CloseHandle (hSysLogFile); LogToMonitor ("End of Syslog thread\n"); _endthread (); } // SyslogDProc
/* ----------------------------- */ 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 */
int TcpPPSend (SOCKET s, LPCSTR szBuf, unsigned uBufSize, HANDLE hLogFile) { int Rc; unsigned Total; DWORD dummy; unsigned short usSize = htons (uBufSize); if (s==INVALID_SOCKET) return TCP4U_ERROR; if (uBufSize > 0x7FFF) return TCP4U_OVERFLOW; if (hLogFile!=INVALID_HANDLE_VALUE) WriteFile (hLogFile, szBuf, uBufSize, &dummy, NULL); // send msg length Rc = send (s, (char *) & usSize, sizeof usSize, 0); for ( Total = 0 ; Total < uBufSize && Rc > 0 ; Total += Rc) { Rc = send (s, & szBuf[Total], uBufSize-Total, 0); } if (Rc<0) LogToMonitor ("send returns error %d\n", WSAGetLastError()); return Total>=uBufSize ? TCP4U_SUCCESS : TCP4U_ERROR; } /* TcpPPSend */
int TcpExchangeChallenge (SOCKET s, int seed, int nVersion, const char *key) { FILETIME ft; struct S_Challenge Out1, In1, Out2, In2; int Rc; int Ark; GetSystemTimeAsFileTime (&ft); srand (ft.dwLowDateTime + seed + (unsigned) s); for (Ark=0 ; Ark< sizeof Out1.challenge ; Ark++) Out1.challenge[Ark] = (unsigned char) (rand () & 0xFF); Out1.pad = 0; Out1.version = nVersion; Rc = TcpPPSend ( s, (char *) & Out1, sizeof Out1, INVALID_FILE_HANDLE ); if (Rc<0) return Rc; Rc = TcpPPRecv ( s, (char *) & In1, sizeof In1, 10, INVALID_FILE_HANDLE ); if (Rc<0) {int Ark = WSAGetLastError (); LogToMonitor ("Error %d receiving on socket %d\n", Ark, s); return Rc; } /* verify version */ if (In1.version != nVersion) return TCP4U_VERSION_ERROR; /* 'crypt' challenge */ Out2 = In1; sym_crypt ( Out2.challenge, sizeof Out2.challenge, key ); /* resend frame */ Rc = TcpPPSend ( s, (char *)& Out2, sizeof Out2, INVALID_FILE_HANDLE ); if (Rc<0) return Rc; /* wait for our Challenge (*/ Rc = TcpPPRecv ( s, (char *)& In2, sizeof In2, 10, INVALID_FILE_HANDLE ); if (Rc<0) return Rc; /* un crypt In2 and compare with Out1 */ sym_crypt ( In2.challenge, sizeof In2.challenge, key ); return memcmp (In2.challenge, Out1.challenge, sizeof Out1.challenge)==0 ? TCP4U_SUCCESS : TCP4U_BAD_AUTHENT ; } // TcpExchangeChallenge
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
static void SetGuiStatus (int status) { LogToMonitor ("Console %sconnected", status==CONNECTED ? "" : "dis"); gGuiStatus = status; }
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
// wait until GUI is connected SOCKET WaitForGuiConnection (void) { static SOCKET sListen = INVALID_SOCKET; SOCKET sDlg = INVALID_SOCKET; SOCKADDR_STORAGE saSockAddr; /* specifications pour le Accept */ int nAddrLen = sizeof saSockAddr; int Rc; do { sSettings.uConsolePort = TFTPD32_TCP_PORT; // sListen is static --> don't reopen if (sListen == INVALID_SOCKET) sListen = TcpGetListenSocket (AF_INET, "tftpd32", & sSettings.uConsolePort); #ifdef STANDALONE_EDITION // second chance (standalone edition):let the system choose its socket // pass the port nb through the sGuiSettings structure Rc = GetLastError(); if (sListen==INVALID_SOCKET && GetLastError()==WSAEADDRINUSE) { sGuiSettings.uConsolePort = 0; sListen = TcpGetListenSocket (AF_INET, NULL, & sGuiSettings.uConsolePort); } #endif if (sListen==INVALID_SOCKET) { SVC_ERROR ("can not create listening socket\nError %d", GetLastError ()); } else {HANDLE tEvents[2]; int nTriggeredEvent; // Create Socket Event to process either wake up or accept tEvents [0] = WSACreateEvent(); WSAEventSelect (sListen, tEvents[0], FD_ACCEPT); // waits either internal sollicitation or msg recpetion tEvents[1] = tThreads[TH_CONSOLE].hEv; nTriggeredEvent = WaitForMultipleObjects (2, tEvents, FALSE, INFINITE); if (nTriggeredEvent==1) { WSACloseEvent (tEvents [0]); closesocket (sListen); continue; } // an accept is ready --> Establish session sDlg = accept (sListen, (struct sockaddr *) &saSockAddr, &nAddrLen); if (sDlg == INVALID_SOCKET) { SVC_ERROR ("accept error %d", GetLastError()); } // free listening socket WSACloseEvent (tEvents [0]); // sListen socket no more necessary closesocket (sListen); sListen = INVALID_SOCKET; } // sListen OK if (sDlg==INVALID_SOCKET && tThreads[TH_CONSOLE].gRunning) Sleep (1000); } while (sDlg==INVALID_SOCKET && tThreads[TH_CONSOLE].gRunning); // detect if the client hangs and does not quit properly if (sDlg != INVALID_SOCKET) {int True=TRUE; Rc = setsockopt (sDlg, SOL_SOCKET, SO_KEEPALIVE, (char *) & True, sizeof True); if (Rc) LogToMonitor ("Error %d during setsockopt\n", GetLastError ()); } // sDlg OK return sDlg; } // WaitForGuiConnection
static int ProcessMsg (SOCKET s, const struct S_ConsoleMsg *pmsg) { struct LL_TftpInfo *pTftp; int uServices; LogToMonitor ("TFTPd console receive msg %d\n", pmsg->type); switch (pmsg->type) { case C_CONS_KILL_TRF : LOG (1, "transfer %d must be killed", pmsg->u.kill.dwTransferId); for ( pTftp=pTftpFirst ; pTftp!=NULL && pTftp->tm.dwTransferId != pmsg->u.kill.dwTransferId ; pTftp = pTftp->next ); if (pTftp != NULL) { nak (pTftp, ECANCELLED); pTftp->st.ret_code=TFTP_TRF_STOPPED; } break; case C_TFTP_TERMINATE : LogToMonitor ("terminating TFTP service\n"); tThreads[TH_TFTP].gRunning = FALSE; WakeUpThread (TH_TFTP); break; case C_DHCP_TERMINATE : LogToMonitor ("terminating DHCP service\n"); tThreads[TH_DHCP].gRunning = FALSE; // wake up DHCP thread WakeUpThread (TH_DHCP); break; case C_TERMINATE : LogToMonitor ("stopping services\n"); TerminateWorkerThreads (FALSE); // keep management threads break; case C_SUSPEND : LogToMonitor ("suspending services\n"); TerminateWorkerThreads (TRUE); // keep management threads break; case C_START : LogToMonitor ("starting services\n"); StartMultiWorkerThreads (TRUE); break; case C_DHCP_RRQ_SETTINGS : LogToMonitor ("sending DHCP settings\n"); SendMsg (s, C_DHCP_RPLY_SETTINGS, & sParamDHCP, sizeof sParamDHCP); break; case C_TFTP_RRQ_SETTINGS : LogToMonitor ("sending TFTP settings\n"); SendMsg (s, C_TFTP_RPLY_SETTINGS, & sSettings, sizeof sSettings); break; case C_DHCP_WRQ_SETTINGS : LogToMonitor ("storing new DHCP settings\n"); DHCPSaveConfig ( & pmsg->u.dhcp_settings ); break; case C_TFTP_WRQ_SETTINGS : LogToMonitor ("storing new TFTP settings\n"); {static struct S_RestartTable sRestart; sRestart.newservices = pmsg->u.tftp_settings.uServices; sRestart.oldservices = sSettings.uServices; sRestart.flapservices = 0; if ( sSettings.Port != pmsg->u.tftp_settings.Port || lstrcmp (sSettings.szTftpLocalIP, pmsg->u.tftp_settings.szTftpLocalIP )!=0 ) sRestart.flapservices |= TFTPD32_TFTP_SERVER; // restart syslog if its settings log has changed if ( sSettings.uServices & TFTPD32_SYSLOG_SERVER && ( sSettings.bSyslogPipe != pmsg->u.tftp_settings.bSyslogPipe || strcmp(sSettings.szSyslogFile,pmsg->u.tftp_settings.szSyslogFile)!= 0 ) ) sRestart.flapservices |= TFTPD32_SYSLOG_SERVER; sSettings = pmsg->u.tftp_settings; if ( IsValidDirectory ( pmsg->u.tftp_settings.szBaseDirectory ) ) lstrcpyn ( sSettings.szWorkingDirectory, pmsg->u.tftp_settings.szBaseDirectory, sizeof sSettings.szWorkingDirectory ); _beginthread ( Tftpd32UpdateServices, 0, (void *) & sRestart ); Tftpd32SaveSettings (); } break; case C_TFTP_RESTORE_DEFAULT_SETTINGS : LogToMonitor ("restore default settings\n"); Tftpd32DestroySettings (); break; case C_TFTP_CHG_WORKING_DIR : LogToMonitor ("changing working directory to <%s>\n", pmsg->u.working_dir); if ( IsValidDirectory ( pmsg->u.working_dir ) ) lstrcpyn ( sSettings.szWorkingDirectory, pmsg->u.working_dir, sizeof sSettings.szWorkingDirectory ); break; case C_RRQ_WORKING_DIR : LogToMonitor ("sending working directory <%s>\n", sSettings.szWorkingDirectory); SendMsg (s, C_REPLY_WORKING_DIR, sSettings.szWorkingDirectory, 1 + lstrlen (sSettings.szWorkingDirectory) ); break; case C_DELETE_ASSIGNATION : LogToMonitor ("deleting DHCP entry %X\n", pmsg->u.del_lease.ip); { struct in_addr addr; BOOL dummy; addr.s_addr = pmsg->u.del_lease.ip; DHCPDestroyItem ( DHCPSearchByIP ( & addr, &dummy ) ); } break; case C_RRQ_GET_SERVICES : LogToMonitor ("sending running services\n"); uServices = GetRunningThreads (); SendMsg (s, C_REPLY_GET_SERVICES, & uServices, sizeof uServices ); break; case C_RRQ_GET_INTERFACES : LogToMonitor ("sending IP interfaces"); AnswerIPList (); break; case C_RRQ_DIRECTORY_CONTENT : LogToMonitor ("sending Directory content"); SendDirectoryContent (); break; case C_TFTP_GET_FULL_STAT : LogToMonitor ("sending Directory content"); ConsoleTftpGetStatistics (); break; default : LogToMonitor ("Service received unknown message %d\n", pmsg->type); break; } return 1; } // ReadMsg
///////////////////////////// // 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
static SOCKET TftpProcessOACK (void) { struct tftphdr *tpr, *tps; char *pOpt, *pValue; // couples Option/Valeur int Rc; tpr = (struct tftphdr *) sTC.BufRcv; tps = (struct tftphdr *) sTC.BufSnd; // parse options pOpt = tpr->th_stuff ; while (pOpt - tpr->th_stuff < TFTP_SEGSIZE && *pOpt!=0 ) { // find value string (next word) do not use strlen since string is possibly not 0 terminated for (pValue = pOpt ; pValue - tpr->th_stuff < TFTP_SEGSIZE && *pValue != 0 ; pValue++); pValue++; if (pValue - tpr->th_stuff == TFTP_SEGSIZE) return FALSE; if (sTC.opcode==TFTP_RRQ && IS_OPT (pOpt, TFTP_OPT_TSIZE)) { // prendre la valeur et envoyer un ACK du block #0 sTC.dwFileSize = atoi (pValue); tps->th_opcode = htons (TFTP_ACK); tps->th_block = htons (0); SetTimer (hTftpClientWnd, WM_CLIENT_DATA, sTC.dwTimeout, NULL); send (sTC.s, (char *) tps, TFTP_DATA_HEADERSIZE, 0); } // option Tsize if (IS_OPT (pOpt, TFTP_OPT_BLKSIZE)) { // prendre la valeur sTC.nPktSize = atoi (pValue); #ifdef JKKLLKJLKJLKLKJKLLKJ // If read -> send a ack of block #0 if (sTC.opcode==TFTP_RRQ) { tps->th_opcode = htons (TFTP_ACK); tps->th_block = htons (0); SetTimer (hTftpClientWnd, WM_CLIENT_DATA, sTC.dwTimeout, NULL); send (sTC.s, (char *) tps, TFTP_DATA_HEADERSIZE, 0); } #endif } // option BlkSize if (IS_OPT (pOpt, TFTP_OPT_PORT)) {char szServ[NI_MAXSERV]; getnameinfo ( (LPSOCKADDR) & sTC.saFrom, sizeof sTC.saFrom, NULL, 0, szServ, sizeof szServ, NI_NUMERICSERV); LogToMonitor ("Port value is %s should be changed to %s", szServ, pValue); switch (sTC.saFrom.ss_family) { case AF_INET : ( (struct sockaddr_in *) (&sTC.saFrom) )->sin_port = htons (atoi (pValue)); break; case AF_INET6 : ( (struct sockaddr_in6 *) (&sTC.saFrom) )->sin6_port = htons (atoi (pValue)); break; } Rc = connect (sTC.s, (struct sockaddr *) & sTC.saFrom, sizeof sTC.saFrom); LogToMonitor ("re-connect returns %d (%d)", Rc, GetLastError ()); } pOpt = pValue + lstrlen (pValue) + 1; } // next option return TRUE; } // TftpProcessOACK
// 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