⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 serdev.sgml

📁 SIP Express Router, Linux下的SIP代理服务器,小巧实用,开发测试VoIP设备和应用的必备.
💻 SGML
📖 第 1 页 / 共 5 页
字号:
			<para>If <acronym>SNMP</acronym> support was enabled, another child will be created.</para>		    </listitem>		</itemizedlist>				<para>		    The following initialization will be performed in dont fork mode.		    (look into function <function moreinfo="none">main_loop</function> in file 		    <filename moreinfo="none">main.c</filename>.		</para>		<itemizedlist>		    <listitem>			<para>Another child will be forked for the timer subsystem.</para>		    </listitem>		    <listitem>			<para>			    Initialize the <acronym>FIFO</acronym> server if enabled, this will fork another child.			    For more info about the <acronym>FIFO</acronym> server, 			    see section The <acronym>FIFO</acronym> server.			</para>		    </listitem>		    <listitem>			<para>			    Call <function moreinfo="none">init_child(0).</function>			    The function performs per-child specific initialization of all loaded modules.			    A module can be initialized though <function moreinfo="none">mod_init</function> function.			    The function is called <emphasis>BEFORE</emphasis> the server forks and thus is common for all 			    children.			</para>			<para>			    If there is anything, that needs to be initialized in every child separately (for example			    if each child needs to open its own file descriptor), it cannot be done in 			    <function>mod_init</function>.			    To make such initialization possible, a module can export another initialization function			    called <function moreinfo="none">init_child</function>. The function will be called in			    all children <emphasis>AFTER</emphasis> fork of the server.			</para>			<para>			    And since we are in <quote>dont fork</quote> mode and there will no children processing 			    requests (remember the main process will be processing all requests), the 			    <function moreinfo="none">init_child</function> wouldn't be called.			</para>			<para>			    That would be bad, because <function moreinfo="none">child_init</function> might do some			    initialization that must be done otherwise modules might not work properly.			</para>			<para>			    To make sure that module initialization is complete we will call 			    <function moreinfo="none">init_child</function> here for the main process even if we			    are not going to fork.			</para>		    </listitem>		</itemizedlist>		<para>		    That's it. Everything has been initialized properly and as the last step we will call		    <function moreinfo="none">udp_rcv_loop</function> which is the main loop function. The function		    will be described later.		</para>	    </section> <!-- dont-fork-set -->	    <section id="dont-fork-not-set">		<title><varname>dont_fork</varname> is not set (zero)</title>		<para>		    <varname>dont_fork</varname> is not set. That means that the server will fork children and the children		    will be processing incoming requests. How many children will be created depends on		    the configuration (<varname>children</varname> variable). The main process will be sleeping and 		    handling signals only.		</para>		<para>		    The main process will then initialize the <acronym>FIFO</acronym> server. The <acronym>FIFO</acronym> server 		    needs another child to handle communication over <acronym>FIFO</acronym> and thus another child will be 		    created. The <acronym>FIFO</acronym> server will be described in more detail later.		</para>		<para>		    Then the main process will perform another fork for the timer attendant. The child will		    take care of timer lists and execute specified function when a timer hits.		</para>		<para>		    The main process is now completely initialized, it will sleep in <function moreinfo="none">pause</function>		    function until a signal comes and call <function moreinfo="none">handle_sigs</function> when such		    condition occurs.		</para>				<para>		    The following initialization will be performed by each child separately:		</para>		<para>		    Each child executes <function moreinfo="none">init_child</function> function. The function		    will sequentially call <function moreinfo="none">child_init</function> functions of all loaded modules.		</para>		<para>		    Because the function is called in each child separately, it can initialize per-child		    specific data. For example if a module needs to communicate with database, it must open		    a database connection. If the connection would be opened in <function moreinfo="none">mod_init</function>		    function, all the children would share the same connection and locking would be necessary		    to avoid conflicts. On the other hand if the connection was opened in		    <function moreinfo="none">child_init</function> function, each child will have its own		    connection and concurrency conflicts will be handled by the database server.		</para>		<para>		    And last, but not least, each child executes <function moreinfo="none">udp_rcv_loop</function> function		    which contains the main loop logic.		</para>			    </section> <!-- dont-fork-not-set -->	</section> <!-- forking -->    </chapter> <!-- server-startup -->        <chapter id="main-loop">	<title>Main Loop</title>	<para>	    Upon startup, all children execute <function moreinfo="none">recvfrom</function> function. The process will	    enter the kernel mode. When there is no data to be processed at the moment, the kernel will put the process on	    list of processes waiting for data and the process will be put asleep. 	</para>	<para>	    When data to be processed was received, the first process on the list will be removed from the list and woken	    up. After the process finished processing of the data, it will call <function moreinfo="none">recvfrom</function>	    again and will be put by the kernel at the end of the list.	</para>	<para>	    When next data arrives, the first process on the list will be removed, processes the data and will be put on the	    end of the list again. And so on...	</para>	<para>	    The main loop logic can be found in function <function moreinfo="none">udp_rcv_loop</function> in file	    <filename moreinfo="none">udp_server.c</filename>.	</para>	<para>	    The message is received using <function moreinfo="none">recvfrom</function> function. The received data is	    stored in buffer and zero terminated. 	</para>	<para>	    If configured so, basic sanity checks over the received message will be performed.	</para>	<para>	    The message is then processed by <function moreinfo="none">receive_msg</function> function and 	    <function moreinfo="none">recvfrom</function> is called again.	</para>		<section id="recv-message">	    <title><function moreinfo="none">receive_msg</function> Function</title>	    <para>		The function can be found in <filename moreinfo="none">receive.c</filename> file.	    </para>	    	    <itemizedlist>		<listitem>		    <para>			In the server, a request or response is represented by <structname>sip_msg</structname>			structure. The structure is allocated in this function. The original message is stored in 			<structfield>buf</structfield>			attribute of the structure and is zero terminated. Then, another copy of the received message will be			created and the copy will be stored in <structfield>orig</structfield> field. The original copy will be not			modified during the server operation. All changes will be made to the copy in <structfield>buf</structfield>			field. The second copy of the message will be removed in the future.		    </para>		</listitem>		<listitem>		    <para>			The message will be parsed (function <function moreinfo="none">parse_msg</function>). We don't			need the whole message header to be parsed at this stage. Only the first line and first Via			header need to be parsed. The server needs to know if the message is request or response - hence			the first line. The server also needs the first Via to be able to add its own Via - hence			the first Via. Nothing else will be parsed at the moment - this saves time. (Message parser			as well as <structname>sip_msg</structname> structure will be described later).		    </para>		</listitem>		<listitem>		    <para>			A module may register callbacks. Each callback have associated an event, that			will trigger the callback. One such callback is <emphasis>pre-script</emphasis> callback. Such			callback will be called immediately before the routing part of the config file will be executed. 			If there are such callbacks registered, they will be executed now.		    </para>		</listitem>		<listitem>		    <para>			As the next step we will determine type of the message. If the message being processed is a REQUEST			then basic sanity checks will be performed (make sure that there is the first Via and parsing was			successful) and the message will be passed to routing engine.			The routing engine is one of the most complicated parts of the server and will be in detail			described in chapter <link linkend="routing-engine">The Routing Engine</link>.		    </para>		</listitem>		<listitem>		    <para>			If the message is a RESPONSE, it will be simply forwarded to its destination.		    </para>		</listitem>		<listitem>		    <para>			After all, <emphasis>post-script</emphasis> callbacks will be executed if any and the 			structure representing the message will be released.		    </para>		</listitem>		<listitem>		    <para>			Processing of the message is done now and the process is ready for another 			<acronym>SIP</acronym> message.		    </para>		</listitem>	    </itemizedlist>	</section> <!-- recv-message -->    </chapter> <!-- main-loop -->    <chapter id="server-shutdown">	<title>The Server Shutdown</title>	<para>	    The server shutdown can be triggered by sending a signal to the server. The server will behave differently upon 	    receiving various types of signals, here is a brief summary:	</para>	<itemizedlist>	    <listitem>		<para>		    <emphasis>SIGINT, SIGPIPE, SIGTERM, SIGCHLD</emphasis> will terminate the server.		</para>	    </listitem>	    <listitem>		<para>		    <emphasis>SIGUSR1</emphasis> will print statistics and let the server continue.		</para>	    </listitem>	    <listitem>		<para>		    <emphasis>SIGHUP, SIGUSR2</emphasis> will be ignored.		</para>	    </listitem>	</itemizedlist>		<para>	    There is only one common signal handler for all signals - function <function moreinfo="none">sig_usr</function>	    in file <filename moreinfo="none">main.c</filename>.	</para>	<para>	    In normal mode of operation (<varname>dont_fork</varname> variable is not set), the main server is not processing any 	    requests, it calls <function moreinfo="none">pause</function> function and will be waiting for signals only. What	    happens when a signal arrives is shown in the previous paragraph.	</para>	<para>	    When in normal mode (<varname>dont_fork</varname> is not set), the signal handler of the main process will 	    only store number of the signal received.	    All the processing logic will be executed by the main process outside the signal handler (function	    <function moreinfo="none">handle_sigs</function>) The function will be called immediately after the signal	    handler finish. The main	    process usually does some cleanup and running such things outside the signal handler is much	    more safe than doing it from the handler itself. Children only print statistics and exit	    or ignore the signal completely, that is quite safe and can be done directly from the signal handler of	    children.	</para>	<para>	    When <varname>dont_fork</varname> is set, all the cleanup will be done directly from the signal handler, 	    because there is only one process - the main process. This is not so safe as the previous case, but this mode 	    should be  used for debugging only and such shortcoming doesn't harm in that case.	</para>	<para>	    Upon receipt of SIGINT, SIGPIPE or SIGTERM <function moreinfo="none">destroy_modules</function> will be called.	    Each module may register so-called <function moreinfo="none">destroy</function> function if it needs to do some 	    cleanup when the server is terminating (flush of cache to disk  for example). 	    <function moreinfo="none">destroy_modules</function> will call destroy function of all loaded modules.	</para>	<para>	    If you need to terminate the server and all of its children, the best way how to do it is to send SIGTERM	    to the main process, the main process will in turn send the same signal to its children.	</para>	<para>	    The main process and its children are in the same process group. Therefore the main process can kill all	    its children simply by sending a signal to pid 0, sending to pid 0 will send the signal to all processes	    in the same process group as the sending process. This is how the main process will terminate all children 	    when it is going to shut down.	</para>	<para>	    If one child exited during normal operation, the whole server will be shut down. This is better than let	    the server continue - a dead child might hold a lock and that could block the whole server, such situation	    cannot be avoided easily. Instead of that it is better to shutdown the whole server and let it restart.	</para>    </chapter> <!-- server-shutdown -->    <chapter id="internal-data-struct">	<title>Internal Data Structures</title>	<para>	    There are some data structures that are important and widely used in the server. We will describe them	    in detail in this section.	</para>		<note>	    <para>		There are many more structures and types defined across the server and modules. We will describe		only the most important and common data structure here. The rest will be described in other sections		if needed.	    </para>	</note>	<section id="str">	    <title>Type <type>str</type></title>	    <para>		One of our main goals was to make <acronym>SER</acronym> really fast. There are many functions across		the server that need to work with strings. Usually these functions need to know string length. We wanted		to avoid using of <function moreinfo="none">strlen</function> because the function is relatively slow. It		must scan the whole string and find the first occurrence of zero character. To avoid this, we created		<type>str</type> type. The type has 2 fields, field <structfield>s</structfield> is pointer		to the beginning of the string and field <structfield>len</structfield> is length of the string. We then		calculate length of the string only once and later reuse saved value.	    </para>	    <important>		<para>		    <type>str</type> structure is quite important because it is widely used in		    <acronym>SER</acronym> (most functions accept <type>str</type> instead of <type>char*</type>).		</para>	    </important>	    	    <para><emphasis><type>str</type> Type Declaration</emphasis></para>	    <programlisting format="linespecific">struct _str{    char* s;    int len;};typedef struct _str str;		    </programlisting>	    <para>		The declaration can be found in header file <filename moreinfo="none">str.h</filename>.	    </para>	    <warning>		<para>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -