Choco OS  V.0.16.9.0
Join to the chocolate world
oc_telnet.c
Go to the documentation of this file.
1 
27 #include <oc_telnet.h>
28 #include <oc_tcp.h>
29 #include <oc_thread.h>
30 #include <oc_list.h>
31 #include <oc_service.h>
32 #include <oc_dynamic_config.h>
33 #include <oc_process.h>
34 #include <oc_program.h>
35 #include <oc_programman.h>
36 #include <oc_intman.h>
37 #include <oc_mutex.h>
38 #include <oc_semaphore.h>
39 
45 #define _________________________________________DEFINITIONS_SECTION________________________________________________________________________
46 
47 #define MODULE_NAME "Telnet"
48 
49 #undef _________________________________________DEFINITIONS_SECTION________________________________________________________________________
50 
51 
52 
58 #define _________________________________________TYPES_SECTION______________________________________________________________________________
59 
60 //==========================================================================================================================================
66 //==========================================================================================================================================
67 typedef struct Context_t
68 {
70  oC_Tcp_Server_t Server;
72 
73 //==========================================================================================================================================
79 //==========================================================================================================================================
80 typedef struct ConnectionContext_t
81 {
83  const char * Name;
84  oC_Tcp_Connection_t Connection;
85  oC_Process_t Process;
86  oC_Stream_t Stream;
87 
88  struct
89  {
90  oC_Timestamp_t InactiveTimestamp;
91  uint8_t * Buffer;
92  oC_MemorySize_t Size;
93  oC_MemorySize_t FilledSize;
94  oC_Thread_t Thread;
95  oC_Mutex_t BusyMutex;
96  oC_Semaphore_t CountingSemaphore;
97  } NagleAlgorithm;
99 
100 //==========================================================================================================================================
104 //==========================================================================================================================================
105 typedef struct
106 {
107  oC_Tcp_Connection_t Connection;
108  oC_Process_t Process;
109  oC_Tcp_Server_t Server;
111 
112 //==========================================================================================================================================
113 //==========================================================================================================================================
114 typedef struct
115 {
116  uint16_t Width;
117  uint16_t Height;
118 } WindowSize_t;
119 
120 //==========================================================================================================================================
124 //==========================================================================================================================================
125 typedef enum
126 {
127  Command_IAC = 255 ,
128 } Command_t;
129 
130 //==========================================================================================================================================
134 //==========================================================================================================================================
135 typedef enum
136 {
137  Option_Echo = 1 ,
138  Option_GoAhead = 3 ,
139  Option_Status = 5,
140  Option_TimingMark = 6 ,
141  Option_TerminalType = 24 ,
142  Option_WindowSize = 31 ,
143  Option_TerminalSpeed = 32 ,
144  Option_RemoteFlowControl = 33 ,
145  Option_LineMode = 34 ,
146  Option_EnvironmentVariables = 36 ,
147 } Option_t;
148 
149 //==========================================================================================================================================
153 //==========================================================================================================================================
154 typedef enum
155 {
156  Operation_Will = 251 ,
157  Operation_Wont = 252 ,
158  Operation_Do = 253 ,
159  Operation_Dont = 254 ,
160 } Operation_t;
161 
162 //==========================================================================================================================================
166 //==========================================================================================================================================
167 typedef struct
168 {
169  uint8_t Command;
170  uint8_t Operation;
171  uint8_t Option;
173 
174 #undef _________________________________________TYPES_SECTION______________________________________________________________________________
175 
181 #define _________________________________________PROTOTYPES_SECTION_________________________________________________________________________
182 
183 static bool IsConnectionContextCorrect ( ConnectionContext_t Context );
185 static bool ConnectionContext_Delete ( ConnectionContext_t Context );
186 static bool ServiceContext_IsCorrect ( ServiceContext_t Context );
187 static ServiceContext_t ServiceContext_New ( void );
188 static bool ServiceContext_Delete ( ServiceContext_t Context );
189 static oC_ErrorCode_t StartService ( ServiceContext_t * outContext );
190 static oC_ErrorCode_t StopService ( ServiceContext_t * Context );
191 static oC_ErrorCode_t RunProgramForConnection ( oC_Tcp_Connection_t Connection, oC_Tcp_Server_t Server );
192 static oC_ErrorCode_t ServiceThread ( ServiceContext_t Context );
193 static oC_ErrorCode_t Configure ( VirtualDriverConfig_t * Config , ConnectionContext_t * outContext );
194 static oC_ErrorCode_t Unconfigure ( void * Dummy , ConnectionContext_t * Context );
195 static oC_ErrorCode_t Write ( ConnectionContext_t Context , const char * Buffer , uint32_t * Size , oC_Time_t Timeout );
196 static oC_ErrorCode_t Read ( ConnectionContext_t Context , char * outBuffer , uint32_t * Size , oC_Time_t Timeout );
197 static void ConnectionFinished ( oC_Tcp_Connection_t Connection , void * Context );
198 static void MainThreadFinished ( oC_Thread_t Thread , void * Connection );
199 static oC_ErrorCode_t SaveDataInNagleBuffer ( ConnectionContext_t Context , const char * Data, uint32_t * Size , oC_Time_t Timeout );
200 static oC_ErrorCode_t Fflush ( ConnectionContext_t Context , oC_Time_t Timeout );
201 static void NagleThread ( void * Context );
202 
203 #undef _________________________________________PROTOTYPES_SECTION_________________________________________________________________________
204 
205 
211 #define _________________________________________GLOBALS_SECTION____________________________________________________________________________
212 
213 //==========================================================================================================================================
217 //==========================================================================================================================================
219  .Name = MODULE_NAME ,
220  .StartFunction = StartService ,
221  .StopFunction = StopService ,
222  .MainFunction = ServiceThread ,
223  .MainThreadStackSize = B(4096),
224  .HeapMapSize = 0 ,
225  .AllocationLimit = 0 ,
226  .RequiredModules = { oC_Module_Tcp , oC_Module_ProcessMan , oC_Module_ThreadMan , oC_Module_NetifMan } ,
227  .Priority = oC_Process_Priority_NetworkHandlerProcess ,
228 };
229 //==========================================================================================================================================
233 //==========================================================================================================================================
234 static const oC_Driver_Registration_t DriverRegistration = {
235  .FileName = MODULE_NAME,
236  .ConfigurationSize = sizeof(oC_Tcp_Connection_t),
237  .Configure = (oC_Driver_ConfigureFunction_t) Configure ,
238  .Unconfigure = (oC_Driver_UnconfigureFunction_t)Unconfigure ,
239  .Write = (oC_Driver_WriteFunction_t) Write ,
240  .Read = (oC_Driver_ReadFunction_t) Read ,
241 };
242 
243 #undef _________________________________________GLOBALS_SECTION____________________________________________________________________________
244 
245 
246 
252 #define _________________________________________FUNCTIONS_SECTION__________________________________________________________________________
253 
254 
255 #undef _________________________________________FUNCTIONS_SECTION__________________________________________________________________________
256 
262 #define _________________________________________LOCAL_FUNCTIONS_SECTION____________________________________________________________________
263 
264 //==========================================================================================================================================
268 //==========================================================================================================================================
270 {
271  return isram(Context) && oC_CheckObjectControl(Context,oC_ObjectId_TelnetConnectionContext,Context->ObjectControl);
272 }
273 
274 //==========================================================================================================================================
278 //==========================================================================================================================================
280 {
281  ConnectionContext_t context = kmalloc( sizeof(struct ConnectionContext_t), oC_Process_GetAllocator(Process), AllocationFlags_ZeroFill );
282  Allocator_t allocator = oC_Process_GetAllocator(Process);
283 
284  if(oC_SaveIfFalse("context", context != NULL, oC_ErrorCode_AllocationError ))
285  {
286  context->Connection = Connection;
287  context->ObjectControl = oC_CountObjectControl(context,oC_ObjectId_TelnetConnectionContext);
288  context->Stream = NULL;
289  context->Process = Process;
290  context->Name = oC_Tcp_Connection_GetName(Connection);
291 
292  /* Nagle's Algorithm */
293  context->NagleAlgorithm.Size = oC_DynamicConfig_GetValue(Telnet, NagleBufferSize);
294  context->NagleAlgorithm.Buffer = kmalloc( context->NagleAlgorithm.Size, allocator, AllocationFlags_ZeroFill );
295  context->NagleAlgorithm.FilledSize = 0;
296  context->NagleAlgorithm.Thread = oC_Thread_New(0, oC_DynamicConfig_GetValue(Telnet, NagleThreadStackSize), Process, context->Name, NagleThread, context);
297  context->NagleAlgorithm.InactiveTimestamp = oC_DynamicConfig_GetValue(Telnet, NagleMaximumInactiveTime) + gettimestamp();
298  context->NagleAlgorithm.BusyMutex = oC_Mutex_New( oC_Mutex_Type_Normal, allocator, 0 );
299  context->NagleAlgorithm.CountingSemaphore = oC_Semaphore_New(context->NagleAlgorithm.Size,context->NagleAlgorithm.Size, allocator, 0 );
300 
301  if(
302  oC_SaveIfFalse("Thread", context->NagleAlgorithm.Thread != NULL , oC_ErrorCode_AllocationError )
303  && oC_SaveIfFalse("Size" , context->NagleAlgorithm.Size > 0 , oC_ErrorCode_SizeNotCorrect )
304  && oC_SaveIfFalse("Buffer", context->NagleAlgorithm.Buffer != NULL , oC_ErrorCode_AllocationError )
305  && oC_SaveIfFalse("Mutex" , context->NagleAlgorithm.BusyMutex != NULL , oC_ErrorCode_AllocationError )
306  && oC_SaveIfFalse("Semaph", context->NagleAlgorithm.CountingSemaphore != NULL , oC_ErrorCode_AllocationError )
307  && oC_SaveIfFalse("Thread", oC_Thread_Run(context->NagleAlgorithm.Thread) , oC_ErrorCode_CannotRunThread )
308  )
309  {
310  telnetlog( oC_LogType_Track, "Connection context for '%s' has been allocated", context->Name );
311  }
312  else
313  {
314  telnetlog( oC_LogType_Error, "Cannot allocate context for '%s'", context->Name );
315 
316  oC_SaveIfFalse( "thread" , oC_Thread_Delete(&context->NagleAlgorithm.Thread) , oC_ErrorCode_ReleaseError );
317  oC_SaveIfFalse( "mutex" , oC_Mutex_Delete (&context->NagleAlgorithm.BusyMutex,0) , oC_ErrorCode_ReleaseError );
318  oC_SaveIfFalse( "semaph" , oC_Semaphore_Delete(&context->NagleAlgorithm.CountingSemaphore,0), oC_ErrorCode_ReleaseError );
319  oC_SaveIfFalse( "buffer" , kfree(context->NagleAlgorithm.Buffer,0) , oC_ErrorCode_ReleaseError );
320  oC_SaveIfFalse( "context", kfree(context,0) , oC_ErrorCode_ReleaseError );
321 
322  context = NULL;
323  }
324  }
325  else
326  {
327  telnetlog( oC_LogType_Error, "Cannot allocate memory for context");
328  }
329 
330  return context;
331 }
332 
333 //==========================================================================================================================================
337 //==========================================================================================================================================
339 {
340  bool deleted = false;
341 
342  oC_IntMan_EnterCriticalSection();
343 
344  if( oC_SaveIfFalse("Context" , IsConnectionContextCorrect( Context ) , oC_ErrorCode_ObjectNotCorrect ) )
345  {
346  Context->ObjectControl = 0;
347 
348  bool thread = oC_SaveIfFalse( "thread" , oC_Thread_Delete(&Context->NagleAlgorithm.Thread) , oC_ErrorCode_ReleaseError );
349  bool mutex = oC_SaveIfFalse( "mutex" , oC_Mutex_Delete (&Context->NagleAlgorithm.BusyMutex,0) , oC_ErrorCode_ReleaseError );
350  bool semaph = oC_SaveIfFalse( "semaph" , oC_Semaphore_Delete(&Context->NagleAlgorithm.CountingSemaphore,0), oC_ErrorCode_ReleaseError );
351  bool buffer = oC_SaveIfFalse( "buffer" , kfree(Context->NagleAlgorithm.Buffer,0) , oC_ErrorCode_ReleaseError );
352  bool context = oC_SaveIfFalse( "context", kfree(Context,0) , oC_ErrorCode_ReleaseError );
353 
354  deleted = thread && mutex && semaph && buffer && context;
355  }
356 
357  oC_IntMan_ExitCriticalSection();
358 
359  return deleted;
360 }
361 //==========================================================================================================================================
365 //==========================================================================================================================================
367 {
368  return isram(Context) && oC_CheckObjectControl(Context,oC_ObjectId_TelnetServiceContext,Context->ObjectControl);
369 }
370 
371 //==========================================================================================================================================
375 //==========================================================================================================================================
377 {
378  ServiceContext_t context = malloc( sizeof(struct Context_t), AllocationFlags_ZeroFill );
379 
380  if(oC_SaveIfFalse("Telnet::ServiceContext_New: ", context != NULL, oC_ErrorCode_AllocationError ))
381  {
382  context->ObjectControl = oC_CountObjectControl(context,oC_ObjectId_TelnetServiceContext);
383  context->Server = NULL;
384  }
385 
386  return context;
387 }
388 
389 //==========================================================================================================================================
393 //==========================================================================================================================================
395 {
396  bool deleted = false;
397 
398  if(ServiceContext_IsCorrect(Context))
399  {
400  bool serverDeleted = Context->Server == NULL || oC_Tcp_Server_Delete(&Context->Server, oC_DynamicConfig_GetValue(Telnet,StopServerTimeout));
401 
402  Context->ObjectControl = 0;
403 
404  deleted = free( Context, AllocationFlags_Default ) && serverDeleted;
405  }
406 
407  return deleted;
408 }
409 
410 //==========================================================================================================================================
414 //==========================================================================================================================================
415 static oC_ErrorCode_t StartService( ServiceContext_t * outContext )
416 {
417  oC_ErrorCode_t errorCode = oC_ErrorCode_ImplementError;
418 
419  if(ErrorCondition( isram(outContext), oC_ErrorCode_OutputAddressNotInRAM ))
420  {
421  *outContext = ServiceContext_New();
422 
423  if(ErrorCondition( (*outContext) != NULL, oC_ErrorCode_AllocationError ))
424  {
425  errorCode = oC_ErrorCode_None;
426  }
427  }
428 
429  return errorCode;
430 }
431 
432 //==========================================================================================================================================
436 //==========================================================================================================================================
437 static oC_ErrorCode_t StopService( ServiceContext_t * Context )
438 {
439  oC_ErrorCode_t errorCode = oC_ErrorCode_ImplementError;
440 
441  if(
442  ErrorCondition( isram(Context) , oC_ErrorCode_AddressNotInRam )
443  && ErrorCondition( ServiceContext_IsCorrect(*Context) , oC_ErrorCode_ObjectNotCorrect )
444  )
445  {
446  if(ErrorCondition( ServiceContext_Delete(*Context), oC_ErrorCode_ReleaseError ))
447  {
448  *Context = NULL;
449  errorCode = oC_ErrorCode_None;
450  }
451  }
452 
453  return errorCode;
454 }
455 
456 //==========================================================================================================================================
460 //==========================================================================================================================================
461 static oC_ErrorCode_t RunProgramForConnection( oC_Tcp_Connection_t Connection , oC_Tcp_Server_t Server )
462 {
463  oC_ErrorCode_t errorCode = oC_ErrorCode_ImplementError;
464  oC_Stream_t stream = NULL;
465  VirtualDriverConfig_t config = {
466  .Connection = Connection,
467  .Server = Server,
468  };
469 
470  if(ErrorCondition( oC_Tcp_Connection_IsCorrect(Connection), oC_ErrorCode_ObjectNotCorrect ))
471  {
472  oC_Program_t program = oC_ProgramMan_GetDefaultProgram();
473  oC_Process_t process = oC_Program_NewProcess( program, getrootuser() );
474  oC_Thread_t thread = NULL;
475  const char * programName = oC_Program_GetName(program);
476  if(
477  ErrorCondition( program != NULL && programName != NULL , oC_ErrorCode_ProgramNotCorrect )
478  && ErrorCondition( process != NULL , oC_ErrorCode_AllocationError )
479  )
480  {
481  config.Process = process;
482 
483  stream = oC_Stream_New( oC_Process_GetAllocator(process),
484  AllocationFlags_Default,
485  oC_Stream_Type_Input | oC_Stream_Type_Output,
486  MODULE_NAME,
488  &config
489  );
490 
491  if( ErrorCondition( stream != NULL, oC_ErrorCode_AllocationError ) )
492  {
493  if(
494  ErrorCode( oC_Process_SetOutputStream(process,stream) )
495  && ErrorCode( oC_Process_SetInputStream(process,stream) )
496  && ErrorCode( oC_Program_Exec(program,process,1,&programName,&thread) )
497  )
498  {
499  oC_SaveIfFalse("Cannot set Thread Finished Function",
500  oC_Thread_SetFinishedFunction(thread,MainThreadFinished, Connection),
501  oC_ErrorCode_ThreadNotCorrect );
502  errorCode = oC_ErrorCode_None;
503  }
504  if(oC_ErrorOccur(errorCode))
505  {
506  oC_SaveIfFalse("Telnet - cannot delete stream ", oC_Stream_Delete(&stream), oC_ErrorCode_ReleaseError );
507  }
508  }
509  if(oC_ErrorOccur(errorCode))
510  {
511  oC_SaveIfFalse("Telnet - cannot delete process ", oC_Process_Delete(&process), oC_ErrorCode_ReleaseError );
512  }
513  }
514  }
515 
516  return errorCode;
517 }
518 
519 //==========================================================================================================================================
523 //==========================================================================================================================================
524 static oC_ErrorCode_t ServiceThread( ServiceContext_t Context )
525 {
526  oC_ErrorCode_t errorCode = oC_ErrorCode_ImplementError;
527  bool serviceActive = true;
528  oC_Tcp_Connection_t connection = NULL;
529  uint32_t maxConnections = oC_DynamicConfig_GetValue( Telnet, MaxConnections );
530  oC_Time_t startTimeout = oC_DynamicConfig_GetValue( Telnet, StartServerTimeout );
531  oC_Net_Address_t source = {
533  .Type = oC_Net_AddressType_IPv4 ,
534  .Protocol = oC_Net_Protocol_TCP ,
535  .IPv4 = 0 ,
536  };
537 
538  if(
539  ErrorCondition( ServiceContext_IsCorrect(Context), oC_ErrorCode_ContextNotCorrect )
540  && ErrorCode ( oC_Tcp_Listen( &source, &Context->Server, maxConnections, startTimeout ) )
541  )
542  {
543  kdebuglog( oC_LogType_Track, "Telnet server has been started" );
544 
545  while(serviceActive)
546  {
547  if(ErrorCode( oC_Tcp_Accept(Context->Server,&connection, day(365)) ))
548  {
549  if(ErrorCode( RunProgramForConnection(connection,Context->Server) ))
550  {
551  connection = NULL;
552  kdebuglog( oC_LogType_Track, "Telnet connection has been accepted" );
553  }
554  else
555  {
556  oC_SaveIfErrorOccur("Disconnecting after failure", oC_Tcp_Connection_Disconnect(connection, oC_DynamicConfig_GetValue(Telnet,DisconnectTimeout)));
557  }
558  }
559  else
560  {
561  serviceActive = errorCode == oC_ErrorCode_Timeout;
562  }
563  }
564 
565  oC_SaveError("Telnet::ServiceThread: ", errorCode);
566  }
567 
568  return errorCode;
569 }
570 
571 //==========================================================================================================================================
575 //==========================================================================================================================================
576 static oC_ErrorCode_t EstablishTelnetConnection( oC_Tcp_Connection_t Connection)
577 {
578  oC_ErrorCode_t errorCode = oC_ErrorCode_ImplementError;
579  TelnetOptionParser_t options[50] = {{0}};
580 
581  if(ErrorCode( oC_Tcp_Receive(Connection,options,sizeof(options),ms(100)) ))
582  {
583  oC_ARRAY_FOREACH_IN_ARRAY(options,option)
584  {
585  if(option->Command == Command_IAC)
586  {
587  if(option->Operation == Operation_Do)
588  {
589  if(option->Option == Option_Echo)
590  {
591  option->Operation = Operation_Will;
592  }
593  else
594  {
595  option->Operation = Operation_Wont;
596  }
597  }
598  else if(option->Operation == Operation_Will)
599  {
600  if(option->Option == Option_Echo)
601  {
602  option->Operation = Operation_Dont;
603  }
604  if(option->Option == Option_WindowSize)
605  {
606  option->Operation = Operation_Dont;
607  }
608  else
609  {
610  option->Operation = Operation_Do;
611  }
612  }
613  }
614  }
615  errorCode = oC_Tcp_Send(Connection,options,sizeof(options),s(1));
616  }
617  else if(errorCode == oC_ErrorCode_Timeout)
618  {
619  errorCode = oC_ErrorCode_None;
620  }
621 
622  return errorCode;
623 }
624 
625 //==========================================================================================================================================
629 //==========================================================================================================================================
630 static oC_ErrorCode_t Configure( VirtualDriverConfig_t * Config , ConnectionContext_t * outContext )
631 {
632  oC_ErrorCode_t errorCode = oC_ErrorCode_ImplementError;
633 
634  if(
635  ErrorCondition( isaddresscorrect(Config) , oC_ErrorCode_WrongConfigAddress )
636  && ErrorCondition( isram(outContext) , oC_ErrorCode_OutputAddressNotInRAM )
637  && ErrorCondition( isram(outContext) , oC_ErrorCode_AddressNotInRam )
638  )
639  {
640  *outContext = ConnectionContext_New( Config->Connection, Config->Process );
641 
642  if(
643  ErrorCondition( (*outContext) != NULL , oC_ErrorCode_AllocationError )
644  && ErrorCode ( oC_Tcp_Server_SetConnectionFinished(Config->Server,ConnectionFinished, *outContext) )
645  )
646  {
647  errorCode = EstablishTelnetConnection(Config->Connection);
648  }
649  else
650  {
651  oC_SaveIfFalse("Context", ConnectionContext_Delete(*outContext), oC_ErrorCode_ReleaseError);
652  }
653  }
654 
655  return errorCode;
656 }
657 
658 //==========================================================================================================================================
670 //==========================================================================================================================================
671 static oC_ErrorCode_t Unconfigure( void * Dummy, ConnectionContext_t * Context )
672 {
673  oC_ErrorCode_t errorCode = oC_ErrorCode_ImplementError;
674  oC_Time_t closingConnectionTimeout = oC_DynamicConfig_GetValue( Telnet, DisconnectTimeout );
675 
676  if(
677  ErrorCondition( IsConnectionContextCorrect(*Context) , oC_ErrorCode_ContextNotCorrect )
678  && ErrorCode( oC_Tcp_Disconnect( &((*Context)->Connection), closingConnectionTimeout ) )
679  && ErrorCondition( oC_Stream_Delete( &((*Context)->Stream)) ,oC_ErrorCode_ReleaseError )
680  && ErrorCondition( ConnectionContext_Delete(*Context) , oC_ErrorCode_ReleaseError )
681  )
682  {
683  errorCode = oC_ErrorCode_None;
684  }
685 
686  return errorCode;
687 }
688 
689 //==========================================================================================================================================
693 //==========================================================================================================================================
694 static oC_ErrorCode_t Write( ConnectionContext_t Context , const char * Buffer , uint32_t * Size , oC_Time_t Timeout )
695 {
696  oC_ErrorCode_t errorCode = oC_ErrorCode_ImplementError;
697  oC_Timestamp_t endTimestamp = gettimestamp() + Timeout;
698 
699  if(
700  ErrorCondition( IsConnectionContextCorrect(Context) , oC_ErrorCode_ContextNotCorrect )
701  && ErrorCondition( isaddresscorrect(Buffer) , oC_ErrorCode_WrongAddress )
702  && ErrorCondition( isram(Size) , oC_ErrorCode_AddressNotInRam )
703  && ErrorCondition( (*Size) > 0 , oC_ErrorCode_SizeNotCorrect )
704  && ErrorCondition( Timeout >= 0 , oC_ErrorCode_TimeNotCorrect )
705  )
706  {
707  if(gettimestamp() >= Context->NagleAlgorithm.InactiveTimestamp)
708  {
709  telnetlog(oC_LogType_Warning, "%s: Nagle's thread seems to be inactive. Fflushing and sending data by our own", Context->Name);
710 
711  if(
712  ErrorCode( Fflush(Context,gettimeout(endTimestamp)) )
713  && ErrorCode( oC_Tcp_Send(Context->Connection, Buffer, *Size, gettimeout(endTimestamp)) )
714  )
715  {
716  errorCode = oC_ErrorCode_None;
717  }
718  }
719  else
720  {
721  if( ErrorCode( SaveDataInNagleBuffer(Context,Buffer,Size,gettimeout(endTimestamp)) ) )
722  {
723  errorCode = oC_ErrorCode_None;
724  }
725  else
726  {
727  oC_SaveError("Cannot save data in Nagle's Buffer", errorCode);
728  telnetlog( oC_LogType_Error, "%s: Cannot save data in Nagle's buffer - %s, sending data without buffering", Context->Name, oC_GetErrorString(errorCode) );
729 
730  if(
731  ErrorCode( Fflush(Context,gettimeout(endTimestamp)) )
732  && ErrorCode( oC_Tcp_Send(Context->Connection, Buffer, *Size, gettimeout(endTimestamp)) )
733  )
734  {
735  errorCode = oC_ErrorCode_None;
736  }
737  }
738  }
739  }
740 
741  return errorCode;
742 }
743 
744 //==========================================================================================================================================
748 //==========================================================================================================================================
749 static oC_ErrorCode_t Read( ConnectionContext_t Context , char * outBuffer , uint32_t * Size , oC_Time_t Timeout )
750 {
751  oC_ErrorCode_t errorCode = oC_ErrorCode_ImplementError;
752  if(
753  ErrorCondition( IsConnectionContextCorrect(Context) , oC_ErrorCode_ContextNotCorrect )
754  && ErrorCondition( isram(outBuffer) , oC_ErrorCode_OutputAddressNotInRAM )
755  && ErrorCondition( (*Size) > 0 , oC_ErrorCode_SizeNotCorrect )
756  && ErrorCondition( Timeout >= 0 , oC_ErrorCode_TimeNotCorrect )
757  )
758  {
759  errorCode = oC_Tcp_Receive(Context->Connection, outBuffer, *Size, Timeout);
760  }
761 
762  return errorCode;
763 }
764 
765 //==========================================================================================================================================
769 //==========================================================================================================================================
770 static void ConnectionFinished( oC_Tcp_Connection_t Connection , void * Context )
771 {
772  ConnectionContext_t context = Context;
773 
774  telnetlog(oC_LogType_Track, "TCP Connection has finished, killing process and unconfigure the stream");
775 
776  if(
777  oC_SaveIfFalse("Connection", oC_Tcp_Connection_IsCorrect(Connection), oC_ErrorCode_ObjectNotCorrect )
778  && oC_SaveIfFalse("Context" , IsConnectionContextCorrect(Context) , oC_ErrorCode_ObjectNotCorrect )
779  )
780  {
781  oC_SaveIfFalse("Process", oC_Process_Kill(context->Process), oC_ErrorCode_CannotKillProcess);
782 
783  oC_SaveIfErrorOccur("Unconfigure", Unconfigure(NULL,&context));
784  }
785 }
786 
787 //==========================================================================================================================================
791 //==========================================================================================================================================
792 static void MainThreadFinished( oC_Thread_t Thread , void * Connection )
793 {
794  oC_Tcp_Connection_t connection = Connection;
795 
796  telnetlog(oC_LogType_Track, "Main thread (%s) has finished", oC_Thread_GetName(Thread));
797 
798  if(
799  oC_SaveIfFalse( "Thread" , oC_Thread_IsCorrect(Thread) , oC_ErrorCode_ObjectNotCorrect )
800  && oC_SaveIfFalse( "Connection", oC_Tcp_Connection_IsCorrect(connection), oC_ErrorCode_ObjectNotCorrect )
801  )
802  {
803  if(oC_SaveIfFalse("Interrupts", oC_IntMan_AreInterruptsTurnedOn() , oC_ErrorCode_InterruptsNotEnabled))
804  {
805  static const char * string = "Closing connection with ChocoOS - the main thread has finished";
806  oC_Tcp_Connection_Send(Connection,string,strlen(string) + 1, oC_DynamicConfig_GetValue(Telnet,DisconnectTimeout));
807  }
808  oC_SaveIfErrorOccur("TCP disconnect", oC_Tcp_Connection_Disconnect(connection,oC_DynamicConfig_GetValue(Telnet,DisconnectTimeout)));
809  }
810 }
811 
812 //==========================================================================================================================================
816 //==========================================================================================================================================
817 static oC_ErrorCode_t SaveDataInNagleBuffer( ConnectionContext_t Context , const char * Data, uint32_t * Size , oC_Time_t Timeout )
818 {
819  oC_ErrorCode_t errorCode = oC_ErrorCode_ImplementError;
820  oC_Timestamp_t endTimestamp = gettimestamp() + Timeout;
821 
822  if(
823  ErrorCondition( oC_Semaphore_TakeCounting(Context->NagleAlgorithm.CountingSemaphore, *Size, gettimeout(endTimestamp)), oC_ErrorCode_Timeout )
824  && ErrorCondition( oC_Mutex_Take(Context->NagleAlgorithm.BusyMutex, gettimeout(endTimestamp)) , oC_ErrorCode_Timeout )
825  )
826  {
827  uint8_t * buffer = &Context->NagleAlgorithm.Buffer[ Context->NagleAlgorithm.FilledSize ];
828  oC_MemorySize_t leftSize = Context->NagleAlgorithm.Size - Context->NagleAlgorithm.FilledSize;
829  oC_MemorySize_t sizeToCopy = oC_MIN(leftSize,*Size);
830 
831  memcpy( buffer, Data, sizeToCopy );
832 
833  Context->NagleAlgorithm.FilledSize += sizeToCopy;
834  *Size = sizeToCopy;
835  errorCode = oC_ErrorCode_None;
836 
837  oC_Mutex_Give(Context->NagleAlgorithm.BusyMutex);
838  }
839 
840  return errorCode;
841 }
842 
843 //==========================================================================================================================================
847 //==========================================================================================================================================
848 static oC_ErrorCode_t Fflush( ConnectionContext_t Context , oC_Time_t Timeout )
849 {
850  oC_ErrorCode_t errorCode = oC_ErrorCode_ImplementError;
851  oC_Timestamp_t endTimestamp = gettimestamp() + Timeout;
852 
853  if( ErrorCondition( oC_Mutex_Take(Context->NagleAlgorithm.BusyMutex, gettimeout(endTimestamp)) , oC_ErrorCode_Timeout ) )
854  {
855  if(Context->NagleAlgorithm.FilledSize > 0)
856  {
857  if( ErrorCode( oC_Tcp_Send(Context->Connection, Context->NagleAlgorithm.Buffer, Context->NagleAlgorithm.FilledSize, gettimeout(endTimestamp)) ) )
858  {
859  errorCode = oC_ErrorCode_None;
860  }
861  }
862  else
863  {
864  errorCode = oC_ErrorCode_None;
865  }
866 
867  memset(Context->NagleAlgorithm.Buffer, 0, Context->NagleAlgorithm.Size);
868  Context->NagleAlgorithm.FilledSize = 0;
869  oC_Mutex_Give(Context->NagleAlgorithm.BusyMutex);
870  oC_Semaphore_GiveCounting(Context->NagleAlgorithm.CountingSemaphore, Context->NagleAlgorithm.Size);
871  }
872  return errorCode;
873 }
874 
875 //==========================================================================================================================================
879 //==========================================================================================================================================
880 static void NagleThread( void * Context )
881 {
882  ConnectionContext_t context = Context;
883  oC_ErrorCode_t errorCode = oC_ErrorCode_ImplementError;
884 
885  telnetlog( oC_LogType_Track, "Telnet Nagle's thread has been started" );
886 
887  if(
888  oC_SaveIfFalse("ConnectionContext", IsConnectionContextCorrect(context), oC_ErrorCode_ObjectNotCorrect )
889  )
890  {
891  while(oC_Tcp_Connection_IsConnected(context->Connection))
892  {
893  context->NagleAlgorithm.InactiveTimestamp = oC_DynamicConfig_GetValue(Telnet, NagleMaximumInactiveTime) + gettimestamp();
894 
895  errorCode = Fflush(context,oC_DynamicConfig_GetValue(Telnet,NagleSendingTimeout));
896 
897  if(errorCode == oC_ErrorCode_Timeout)
898  {
899  telnetlog( oC_LogType_Warning, "%s: Cannot fflush data, mutex busy", context->Name);
900  }
901  else if(!oC_SaveIfErrorOccur( "Fflush", errorCode ))
902  {
903  telnetlog( oC_LogType_Error, "%s: Cannot fflush data. Error - %s", context->Name, oC_GetErrorString(errorCode));
904  break;
905  }
906  sleep(oC_DynamicConfig_GetValue(Telnet,NaglePeriod));
907  }
908  }
909 
910  telnetlog( oC_LogType_Track, "Telnet Nagle's thread has been finished" );
911 }
912 
913 #undef _________________________________________LOCAL_FUNCTIONS_SECTION____________________________________________________________________
914 
static oC_ErrorCode_t StartService(ServiceContext_t *outContext)
prepares Telnet service to work
Definition: oc_telnet.c:415
static bool ServiceContext_Delete(ServiceContext_t Context)
releases memory of a service context
Definition: oc_telnet.c:394
#define s(time)
Number of s.
Definition: oc_cfg.h:133
The file with interface for programs.
static bool IsConnectionContextCorrect(ConnectionContext_t Context)
checks if the telnet connection context is correct
Definition: oc_telnet.c:269
File with interface for TELNET protocol.
static void MainThreadFinished(oC_Thread_t Thread, void *Connection)
function called when the main thread is finished
Definition: oc_telnet.c:792
static oC_ErrorCode_t Configure(VirtualDriverConfig_t *Config, ConnectionContext_t *outContext)
configures TELNET connection to work
Definition: oc_telnet.c:630
stores TCP connection data
Operation_t
stores operation codes
Definition: oc_telnet.c:154
The file with interface for thread managing.
static oC_ErrorCode_t RunProgramForConnection(oC_Tcp_Connection_t Connection, oC_Tcp_Server_t Server)
runs default program for specific TCP connection
Definition: oc_telnet.c:461
identifier for allocations
Definition: oc_stdlib.h:159
static void NagleThread(void *Context)
thread for handling Nagle&#39;s buffering
Definition: oc_telnet.c:880
oC_ErrorCode_t oC_Tcp_Disconnect(oC_Tcp_Connection_t *Connection, oC_Time_t Timeout)
disconnects TCP connection
Definition: oc_tcp.c:532
static const oC_Driver_Registration_t DriverRegistration
registration of the Telnet dummy driver
Definition: oc_telnet.c:234
stores network address
Definition: oc_net.h:441
static ConnectionContext_t ConnectionContext_New(oC_Tcp_Connection_t Connection, oC_Process_t Process)
allocates memory for the telnet connection context
Definition: oc_telnet.c:279
#define B(Bytes)
Number of bytes.
Definition: oc_cfg.h:73
#define ms(time)
Number of ms.
Definition: oc_cfg.h:128
static oC_ErrorCode_t EstablishTelnetConnection(oC_Tcp_Connection_t Connection)
function for establishing telnet connection
Definition: oc_telnet.c:576
Transmission Control Protocol.
Definition: oc_net.h:159
struct Tcp_Connection_t * oC_Tcp_Connection_t
stores TCP connection data
Definition: oc_tcp.h:339
static oC_ErrorCode_t SaveDataInNagleBuffer(ConnectionContext_t Context, const char *Data, uint32_t *Size, oC_Time_t Timeout)
saves data in Nagle&#39;s Buffer
Definition: oc_telnet.c:817
static void ConnectionFinished(oC_Tcp_Connection_t Connection, void *Context)
function called when the connection has been finished
Definition: oc_telnet.c:770
oC_ErrorCode_t oC_Tcp_Accept(oC_Tcp_Server_t Server, oC_Tcp_Connection_t *outConnection, oC_Time_t Timeout)
waits for new connection and accepts it
Definition: oc_tcp.c:759
Telnet protocol—unencrypted text communications.
Definition: oc_tcp.h:95
static oC_ErrorCode_t Fflush(ConnectionContext_t Context, oC_Time_t Timeout)
flushes data from Nagle&#39;s buffer
Definition: oc_telnet.c:848
uint32_t oC_ObjectControl_t
stores object control value
Definition: oc_object.h:141
static bool ServiceContext_IsCorrect(ServiceContext_t Context)
checks if the telnet context is correct
Definition: oc_telnet.c:366
The file with list library.
static oC_ErrorCode_t Write(ConnectionContext_t Context, const char *Buffer, uint32_t *Size, oC_Time_t Timeout)
function called when process want to write data on STDOUT stream
Definition: oc_telnet.c:694
The file with interface for interrupt manager.
Option_t
stores options of the telnet
Definition: oc_telnet.c:135
Handles configuration of the Dynamic.
const oC_Service_Registration_t Telnet
registration of the Telnet service
Definition: oc_telnet.c:218
configuration for a virtual driver
Definition: oc_telnet.c:105
static oC_ObjectControl_t oC_CountObjectControl(void *ObjectPointer, oC_ObjectId_t ObjectId)
counts object control for object
Definition: oc_object.h:168
static bool oC_CheckObjectControl(void *ObjectPointer, oC_ObjectId_t ObjectId, oC_ObjectControl_t ObjectControl)
checks if object control is correct
Definition: oc_object.h:203
static ServiceContext_t ServiceContext_New(void)
allocates memory for a service context
Definition: oc_telnet.c:376
The file with interface for mutex managing.
static bool ConnectionContext_Delete(ConnectionContext_t Context)
releases memory of the telnet connection context
Definition: oc_telnet.c:338
IP address in version 4.
Definition: oc_net.h:429
static oC_ErrorCode_t Read(ConnectionContext_t Context, char *outBuffer, uint32_t *Size, oC_Time_t Timeout)
function called when process want to read data from STDIN stream
Definition: oc_telnet.c:749
oC_ObjectControl_t ObjectControl
Definition: oc_eth.c:100
stores ETH context
Definition: oc_eth.c:97
The file with interface for program manager.
oC_ErrorCode_t oC_Tcp_Send(oC_Tcp_Connection_t Connection, const void *Buffer, oC_MemorySize_t Size, oC_Time_t Timeout)
sends data by using TCP connection
Definition: oc_tcp.c:819
static oC_ErrorCode_t Unconfigure(void *Dummy, ConnectionContext_t *Context)
unconfigures virtual telnet driver
Definition: oc_telnet.c:671
The file with interface for process mechanism.
Command_t
stores commands for Telnet
Definition: oc_telnet.c:125
interface for handling services
stores TCP server data
Definition: oc_tcp_server.c:67
oC_ErrorCode_t oC_Tcp_Listen(const oC_Net_Address_t *Source, oC_Tcp_Server_t *outServer, uint32_t MaxConnections, oC_Time_t Timeout)
starts a server that listen at the given address
Definition: oc_tcp.c:615
const char * oC_GetErrorString(oC_ErrorCode_t ErrorCode)
Definition: oc_errors.c:115
stores Telnet option data
Definition: oc_telnet.c:167
The file with interface for semaphores.
static oC_ErrorCode_t ServiceThread(ServiceContext_t Context)
main Telnet service thread
Definition: oc_telnet.c:524
oC_ErrorCode_t oC_Tcp_Server_SetConnectionFinished(oC_Tcp_Server_t Server, oC_Tcp_ConnectionFinishedFunction_t Function, void *Parameter)
sets a pointer for &#39;connection finished function&#39;
oC_ErrorCode_t oC_Tcp_Receive(oC_Tcp_Connection_t Connection, void *outBuffer, oC_MemorySize_t Size, oC_Time_t Timeout)
receives data by using TCP connection
Definition: oc_tcp.c:858
#define day(time)
Number of day.
Definition: oc_cfg.h:148
context of the Telnet connection
Definition: oc_telnet.c:80
static oC_ErrorCode_t StopService(ServiceContext_t *Context)
releases Telnet service resources
Definition: oc_telnet.c:437
struct ConnectionContext_t * ConnectionContext_t
context of the Telnet connection
struct Context_t * ServiceContext_t
context of the Telnet Service
oC_Net_Port_t Port
Port of the address.
Definition: oc_net.h:450
bool oC_Tcp_Server_Delete(oC_Tcp_Server_t *Server, oC_Time_t Timeout)
deletes TCP server
#define NULL
pointer to a zero
Definition: oc_null.h:37