// Module Name: Cbnbsvr.c // // Description: // This NetBIOS sample implements a server using the asynchronous // callback functions as opposed to asynch events. The server // will add its name to each LANA number on the machine and post // a listen (NCBLISTEN) on each LANA in order to service client // requests. // // Compile: // cl -o cbnbsvr.exe cbnbsvr.c ..\Common\nbcommon.obj netapi32.lib // // Command Line Options: // NONE - The server automatically uses the NetBIOS name as // defined by the constant SERVER_NAME // #include #include #include #include "..\Common\nbcommon.h" #define MAX_BUFFER 2048 #define SERVER_NAME "TEST-SERVER-1" DWORD WINAPI ClientThread(PVOID lpParam); // // Function: ListenCallback // // Description: // This function is called when an asynchronous listen completes. // If no error occured create a thread to handle the client. // Also post another listen for other client connections. // void CALLBACK ListenCallback(PNCB pncb) { HANDLE hThread; DWORD dwThreadId; if (pncb->ncb_retcode != NRC_GOODRET) { printf("ERROR: ListenCallback: %d\n", pncb->ncb_retcode); return; } Listen(pncb->ncb_lana_num, SERVER_NAME); hThread = CreateThread(NULL, 0, ClientThread, (PVOID)pncb, 0, &dwThreadId); if (hThread == NULL) { printf("ERROR: CreateThread: %d\n", GetLastError()); return; } CloseHandle(hThread); return; } // // Function: ClientThread // // Description: // The client thread blocks for data sent from clients and // simply sends it back to them. This is a continuous loop // until the sessions is closed or an error occurs. If // the read or write fails with NRC_SCLOSED then the session // has closed gracefully so exit the loop. // DWORD WINAPI ClientThread(PVOID lpParam) { PNCB pncb = (PNCB)lpParam; NCB ncb; char szRecvBuff[MAX_BUFFER]; DWORD dwBufferLen = MAX_BUFFER, dwRetVal = NRC_GOODRET; char szClientName[NCBNAMSZ+1]; FormatNetbiosName(pncb->ncb_callname, szClientName); while (1) { dwBufferLen = MAX_BUFFER; dwRetVal = Recv(pncb->ncb_lana_num, pncb->ncb_lsn, szRecvBuff, &dwBufferLen); if (dwRetVal != NRC_GOODRET) break; szRecvBuff[dwBufferLen] = 0; printf("READ [LANA=%d]: '%s'\n", pncb->ncb_lana_num, szRecvBuff); dwRetVal = Send(pncb->ncb_lana_num, pncb->ncb_lsn, szRecvBuff, dwBufferLen); if (dwRetVal != NRC_GOODRET) break; } printf("Client '%s' on LANA %d disconnected\n", szClientName, pncb->ncb_lana_num); if (dwRetVal != NRC_SCLOSED) { // Some other error occured, hang up the connection // ZeroMemory(&ncb, sizeof(NCB)); ncb.ncb_command = NCBHANGUP; ncb.ncb_lsn = pncb->ncb_lsn; ncb.ncb_lana_num = pncb->ncb_lana_num; if (Netbios(&ncb) != NRC_GOODRET) { printf("ERROR: Netbios: NCBHANGUP: %d\n", ncb.ncb_retcode); dwRetVal = ncb.ncb_retcode; } GlobalFree(pncb); return dwRetVal; } GlobalFree(pncb); return NRC_GOODRET; } // // Function: Listen // // Description: // Post an asynchronous listen with a callback function. Create // an NCB structure for use by the callback (since it needs a // global scope). // int Listen(int lana, char *name) { PNCB pncb = NULL; pncb = (PNCB)GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, sizeof(NCB)); pncb->ncb_command = NCBLISTEN | ASYNCH; pncb->ncb_lana_num = lana; pncb->ncb_post = ListenCallback; // // This is the name clients will connect to // memset(pncb->ncb_name, ' ', NCBNAMSZ); strncpy(pncb->ncb_name, name, strlen(name)); // // An '*' means we'll take a client connection from anyone. By // specifying an actual name here you restrict connections to // clients with that name only. // memset(pncb->ncb_callname, ' ', NCBNAMSZ); pncb->ncb_callname[0] = '*'; if (Netbios(pncb) != NRC_GOODRET) { printf("ERROR: Netbios: NCBLISTEN: %d\n", pncb->ncb_retcode); return pncb->ncb_retcode; } return NRC_GOODRET; } // // Function: main // // Description: // Initialize the NetBIOS interface, allocate some resources, add // the server name to each LANA, and post an asynch NCBLISTEN on // each LANA with the appropriate callback. Then wait for incoming // client connections, at which time, spawn a worker thread to // handle them. The main thread simply waits while the server // threads are handling client requests. You wouldn't do this in a // real application, but this sample is for illustrative purposes // only. // int main(int argc, char **argv) { LANA_ENUM lenum; int i, num; // Enumerate all LANAs and reset each one // if (LanaEnum(&lenum) != NRC_GOODRET) return 1; if (ResetAll(&lenum, 254, 254, FALSE) != NRC_GOODRET) return 1; // // Add the server name to each LANA and issue a listen on each // for(i = 0; i < lenum.length; i++) { AddName(lenum.lana[i], SERVER_NAME, &num); Listen(lenum.lana[i], SERVER_NAME); } while (1) { Sleep(5000); } }