How Windows services are written (forwarded)

Source: Internet
Author: User
Tags call back win32 error

There is a class of applications that are capable of managing a user's authorization level for a variety of users, including local and remote users, and that is what is called a service, regardless of whether the user is physically connected to the computer that is running the application.

(i) basic knowledge of services

Question 1. What is a service? What is the characteristic of it?

In nt/2000, services are a class of programs that are favored by the operating system. A service is first a Win32 executable, and if you want to write a fully functional and powerful service, you need to be familiar with dynamic connection libraries (Dlls), fabric exception handling, memory mapped files, virtual memory, device I/O, threads and their synchronization, Unicode and other application interfaces provided by the WINAPI function. Of course, this article only discusses the establishment of a service that can be installed, run, started, and stopped without any other functions, so no need to continue to see the above knowledge, I will be in the process to understand the knowledge required by this article to explain one by one.

The second to know is that a service never needs a user interface. Most of the services will run on the powerful servers that are locked in some dark, winter-warm summer-cool little houses, even if there is no user interface that is generally visible to anyone. If the service provides any user interface such as a message box, then the likelihood of users missing these messages is very high, so the service is usually written in the form of a console program, the entry point function is main () instead of WinMain ().

Maybe someone has a question: how do I set up and manage a service without a user interface? How do I start and stop it? How does the service issue a warning or error message, and how do I report statistics about its performance? The answer to these questions is that services can be managed remotely, and Windows nt/2000 provides a number of administrative tools that allow the services on a machine to be managed through other computers on the network. For example, the "console" program (mmc.exe) in Windows 2000 allows you to use it to add "snap-in" to manage services on your computer or other machines.

Question 2. Security of the service ...

To write a service, you must be familiar with the security mechanism of win nt/2000, in the above operating system, all security is user-based. In other words--processes, threads, files, registry keys, signals, events, and so on are all part of a user. When a process is generated, it is executed in the context of a user, the user account may be in the local, or on other machines in the network, or in a special Account: System account---the context of the systems account

If a process is executing under a user account, the process has all the access that the user can have, whether on a native or a network. The system account is a special account, it is used to identify the system itself, and any process running under this account has all the access rights on the system, but the system account can not be used on the domain, access to network resources ...

The service is also a Win32 executable, it needs to be executed in a context, usually the service is running under the system account, but it can also be run under a user account according to the situation, it will get the corresponding access to the resources.

Question 3. Three components of a service

A service is made up of three parts, the first part is Service Control Manager (SCM). Each Windows nt/2000 system has a SCM,SCM that exists in Service.exe, which runs automatically when Windows starts and is generated and terminated with the startup and shutdown of the operating system. This process runs with system privileges and provides a unified, secure means to control the service. It's actually an RPC Server, so we can install and manage services remotely, but that's not within the scope of this article. The SCM contains a database that stores information about installed services and drivers, which can be managed uniformly and securely by SCM, so that the installation process for a service program is to write its own information to the database.

The second part is the service itself. A service has special code that is necessary to receive signals and commands from the SCM, and it can pass its state back to the SCM after processing.

The third part, the last part, is a service Control Dispatcher (SCP). It is a WIN32 application that has a user interface that allows users to start, stop, pause, resume, and control one or more of the services installed on the computer. The role of SCP is to communicate with SCM, and the "service" in Windows 2000 management tools is a typical SCP.

In these three components, the user is most likely to write the service itself, but also may have to write a client program with its accompanying as an SCP to communicate with the SCM, this article only discusses to design and implement a service, about how to implement an SCP is described in other future articles.

Question 4. How to start a design service

Remember the entry point function of the service program that I mentioned earlier is usually main ()? A service has a very important three functions, the first is the entry point function, in fact, with WinMain () as the entry point function is not not possible, although the service should not have a user interface, but there are few exceptions, this is the following diagram of the reasons for the existence of the options.

Because of the information interaction with the user's desktop, the service program sometimes takes WinMain () as the entry point function.

The Ingress function initializes the entire process, which is executed by the main thread in the process. This means that it applies to all the services in this executable file. You know, an executable file can contain multiple services to make execution more efficient. The master process notifies the SCM that there are several services in the executable file and gives the address of the ServiceMain callback (call back) function for each service. Once all the services within the executable have stopped running, the main thread clears the entire process before the process terminates.

The second very important function is ServiceMain, I have seen some examples of the program inside the entry point function of their services are fixed named ServiceMain, in fact, there is no requirement to be named, any function as long as the following form can be used as a service entry point function.

VOID WINAPI ServiceMain (

DWORD DWARGC,//number of parameters

LPTSTR *lpszargv//parameter string

);

This function is called by the operating system and executes the code that can complete the service. A dedicated thread executes each service's ServiceMain function, noting that it is a service rather than a service program, because each service also has its own unique servicemain function, which can be used in the "Management tools" service To see Win2000 inside the service, you will find that in fact, many services are provided by Service.exe alone. When the main thread calls the Win32 function StartServiceCtrlDispatcher, the SCM generates a thread for each service in the process. Each of these threads executes with the ServiceMain function of its corresponding service, which is why the service is always multithreaded--a single executable with only one service will have a main thread, and the other threads execute the service itself.

The third and last important function is Ctrlhandler, which must have the following prototype:

VOID WINAPI Ctrlhandler (

DWORD Fdwcontrol//control command

Like ServiceMain, Ctrlhandler is also a callback function, and the user must write a separate Ctrlhandler function for each service in its service, so if a program contains two services, Then it must have at least 5 different functions: main () or WinMain () as the entry point, for the ServiceMain function and Ctrlhandler function of the first service, and the ServiceMain function and Ctrlhandler function for the second service.

The SCM invokes a service's Ctrlhandler function to change the state of the service. For example, when an administrator tries to stop your service using the service in the management tool, the Ctrlhandler function of your service will receive a SERVICE_CONTROL_STOP notification. The Ctrlhandler function is responsible for executing all the code required to stop the service. Since it is the main thread of the process that executes all the Ctrlhandler functions, you must optimize the code of your Ctrlhandler function so that it runs fast enough so that the Ctrlhandler functions of other services in the same process can receive their notifications within the appropriate time. And for these reasons, your Ctrlhandler function must be able to send the state you want to communicate to the service thread, which has no fixed method and depends entirely on the purpose of your service.

(ii) in-depth discussions on services

The last chapter is actually just a general introduction, the following is the real details of the beginning. In the entry point function to complete the initialization of the ServiceMain, the exact point is to initialize a service_table_entry structure array, this structure records all the services contained in the Service name and service entry point function, below is a service_ Examples of table_entry:

Service_table_entry service_table_entry[] =

{

{"Myftpd", Ftpdmain},

{"Myhttpd", Httpserv},

{null, NULL},

};

The first member represents the name of the service, the second member is the address of the ServiceMain callback function, the above service program has three service_table_entry elements, the first two for the service, and the last null to indicate the end of the array because it has two services.

The address of this array is then passed to the StartServiceCtrlDispatcher function:

BOOL StartServiceCtrlDispatcher (

Lpservice_table_entry lpservicestarttable

This Win32 function indicates how the executable process informs the SCM that the service is included in the process. As described in the previous chapter, StartServiceCtrlDispatcher produces a new thread for each non-empty element in the array passed to it. Each process starts executing the ServiceMain function indicated by lpservicestarttable in the array element.

After the SCM starts a service program, it waits for the program's main thread to tune StartServiceCtrlDispatcher. If that function is not called within two minutes, SCM will consider the service to be problematic and call terminateprocess to kill the process. This requires your main thread to call StartServiceCtrlDispatcher as quickly as possible.

The StartServiceCtrlDispatcher function does not return immediately, instead it resides within a loop. When inside the loop, the StartServiceCtrlDispatcher hangs itself, waiting for one of the following two events to occur. First, if the SCM is going to send a control notification to a service running in the process, the thread will be activated. When the control notification arrives, the thread activates and invokes the corresponding service's Ctrlhandler function. The Ctrlhandler function handles this service control notification and returns to StartServiceCtrlDispatcher. StartServiceCtrlDispatcher Loop back and hang yourself again.

Second, if a service in the service thread aborts, the thread will also be activated. In this case, the process will run the number of services inside it minus one. If the number of services is zero, StartServiceCtrlDispatcher returns to the entry point function so that it can perform any process-related cleanup work and end the process. If there is a service running, even if it is just a service, StartServiceCtrlDispatcher will continue to loop and wait for other control notifications or the rest of the service thread to abort.

The above is about the entry point function, and the following is about the ServiceMain function. Remember the prototype of the ServiceMain function you talked about before? But actually a servicemain function usually ignores the two arguments passed to it, because the service does not generally pass parameters. The best way to set up a service is to set up the registry, and the General Service

Hkey_local_machinesystemcurrentcontrolsetserviceservicenameparameters

Sub-keys to store their own settings, here the servicename is the name of the service. In fact, it is possible to write a client application to perform the background setting of the service, which the client application will present in the registry for the service to read. When an external application has changed the settings data for a running service, the service can use the RegNotifyChangeKeyValue function to accept a notification, allowing the service to quickly reset itself.

As mentioned earlier, StartServiceCtrlDispatcher produces a new thread for each non-empty element in the array that is passed into it. Next, what does a servicemain want to do? The original text in MSDN says this: The ServiceMain function should immediately call the RegisterServiceCtrlHandler function to specify a Handl Er function to handle control requests. Next, it should call the SetServiceStatus function to send status information to the Service Control Manager. Why is it? Since the start service request is issued, if the initialization of the service cannot be completed within a certain time, SCM will assume that the service startup has failed, the length of the time in Win NT 4.0 is 80 seconds, Win2000 unknown ...

Based on the above reasons, ServiceMain to quickly complete its own work, first of all the two necessary tasks, the first is to call the RegisterServiceCtrlHandler function to notify the SCM its Ctrlhandler callback function address:

Service_status_handle RegisterServiceCtrlHandler (

LPCTSTR Lpservicename,//service name

Lphandler_function Lphandlerproc//ctrlhandler function address

The first parameter indicates which service is used for the ctrlhandler you are building, and the second parameter is the address of the Ctrlhandler function. The Lpservicename must match the name of the service being initialized inside the service_table_entry. RegisterServiceCtrlHandler returns a Service_status_handle, which is a 32-bit handle. SCM uses it to uniquely determine this service. When the service needs to report its current state to the SCM, it must pass the handle to the WIN32 function that needs it. Note: This handle differs from most other handles, and you do not have to close it.

The SCM requires that the thread of the ServiceMain function call the RegisterServiceCtrlHandler function within one second, or the SCM will assume that the service has failed. In this case, however, the SCM does not terminate the service, but the service will not start in NT 4, and an incorrect error message will be returned, which has been fixed in Windows 2000.

After the RegisterServiceCtrlHandler function returns, the ServiceMain thread immediately tells the SCM service that it is continuing to initialize. The specific method is to pass the SERVICE_STATUS data structure by calling the SetServiceStatus function.

BOOL SetServiceStatus (

Service_status_handle Hservice,//Handle of the service

Address of the Service_status lpservicestatus//service_status structure

This function requires that the address of the service be passed to it indicating the handle (just obtained by calling RegisterServiceCtrlHandler), and an initialized Service_status structure:

typedef struct _SERVICE_STATUS

{

DWORD Dwservicetype;

DWORD dwcurrentstate;

DWORD dwcontrolsaccepted;

DWORD Dwwin32exitcode;

DWORD Dwservicespecificexitcode;

DWORD Dwcheckpoint;

DWORD Dwwaithint;

} service_status, *lpservice_status;

The SERVICE_STATUS structure contains seven members that reflect the current state of the service. All of these members must be correctly set before this structure is passed to SetServiceStatus.

The member Dwservicetype indicates the type of the service executable file. If you have a single service in your executable file, set this member to Service_win32_own_process, and if you have more than one service, set it to service_win32_share_process. In addition to these two flags, if your service needs to interact with the desktop (which is certainly not recommended), attach the service_interactive_process with the "OR" operator. The value of this member should never be changed during the lifetime of your service.

Member Dwcurrentstate is the most important member of this structure and will tell the SCM about the current state of your service. In order to report that the service is still initializing, this member should be set to service_start_pending. Explain the other possible values in detail later when describing the Ctrlhandler function.

Member dwcontrolsaccepted indicates what control notifications the service is willing to accept. If you allow an SCP to pause/resume the service, set it to service_accept_pause_continue. Many services do not support pausing or continuing, they must decide for themselves whether it is available in the service. If you allow an SCP to stop the service, you should set it to service_accept_stop. If the service is to be notified when the operating system shuts down, set it to Service_accept_shutdown to receive the expected results. These flags can be combined with the "OR" operator.

Members Dwwin32exitcode and Dwservicespecificexitcode are the key to allowing services to report errors, If you want the service to report a WIN32 error code (pre-defined in WinError.h), it sets Dwwin32exitcode as the code that is needed. A service can also report an error that is unique to itself and does not map to a predefined Win32 error code. To do this, set the Dwwin32exitcode to Error_service_specific_error, and then set the member Dwservicespecificexitcode as the service-specific error code. When the service is working properly and there are no errors to report, set the member Dwwin32exitcode to No_error.

The last two members Dwcheckpoint and Dwwaithint are a service used to report on the progress of its current events. When the member Dwcurrentstate is set to Service_start_pending, the dwcheckpoint should be set to 0,dwwaithint set to a number after several attempts to determine the more appropriate, so that the service can run efficiently. Once the service is fully initialized, the members of the SERVICE_STATUS structure should be reinitialized, changes dwcurrentstate to Service_running, and Dwcheckpoint and Dwwaithint changed to 0 The presence of a Dwcheckpoint member is beneficial to the user, which allows a service to report which step of the process it is in. Each time you call SetServiceStatus, you can increase it to a number that indicates what step the service has taken, which can help the user decide how long to report the progress of the service. If you decide to report each step of the initialization process for a service, you should set Dwwaithint to the number of milliseconds you think you will need to reach the next step, rather than the number of milliseconds the service needs to complete its process.

After all initialization of the service is complete, the service invocation setservicestatus indicates service_running, at which point the service has started to run. Usually a service is to put itself in a loop to run. Inside the loop this service process hangs itself, waiting to indicate that it next is a network request or notification that should pause, resume, or stop. When a request arrives, the service thread activates and processes the request, and then loops back to wait for the next request/notification.

If a service is activated due to a notification, it will process the notification first unless the service receives a notification that it is stopped or closed. If the notification is really stopped or closed, the service thread exits the loop, performs the necessary cleanup, and then returns from the thread. When the ServiceMain thread returns and aborts, the thread that causes sleep within StartServiceCtrlDispatcher is activated and, as explained earlier, reduces the count of the services it runs.

(iii) Under-depth discussion of services

Now we have one more function to discuss in detail, which is the Ctrlhandler function of the service.

When the RegisterServiceCtrlHandler function is called, the SCM obtains and saves the address of the callback function. An SCP tune a Win32 function that tells the SCM how to control the service, there are now 10 predefined control requests:

Control code Meaning

Service_control_stop requests the service to STOP. The Hservice handle must has service_stop access.

Service_control_pause requests the service to PAUSE. The Hservice handle must has service_pause_continue access.

Service_control_continue requests the paused service to resume. The Hservice handle must has service_pause_continue access.

Service_control_interrogate requests the service to update immediately it current status information to the service CONTR OL Manager. The Hservice handle must has service_interrogate access.

Service_control_shutdown requests the service to perform cleanup tasks, because the system was shutting down. For more information, see Remarks.

Service_control_paramchange Windows 2000:requests The service to reread its startup parameters. The Hservice handle must has service_pause_continue access.

Service_control_netbindchange Windows 2000:requests The service to update its network binding. The Hservice handle must has service_pause_continue access.

Service_control_netbindremove Windows 2000:notifies A network service, a component for binding have been removed. The service should reread its binding information and unbind from the removed component.

Service_control_netbindenable Windows 2000:notifies A network service, a disabled binding has been enabled. The service should reread its binding information and add the new binding.

Service_control_netbinddisable Windows 2000:notifies A network service that one of its bindings have been disabled. The service should reread its binding information and remove the binding.

In the table above, the word "Windows 2000" is the newly added control code in 2000. In addition to these codes, the service can also accept user-defined code that ranges between 128-255.

When the Ctrlhandler function receives a service_control_stop, Service_control_pause, and service_control_continue control code, SetServiceStatus must be called to confirm the code and specify the time that you think the service will take to handle the change in the state.

For example, if your service receives a stop request, first set the Dwcurrentstate member of the SERVICE_STATUS structure to service_stop_pending, which allows the SCM to determine that you have received the control code. When a service's pause or stop operation is executing, you must specify the time that you think the operation will take: this is because a service may not immediately change its state, it may have to wait for a network request to be completed or the data to be flushed to a drive. The method of specifying the time, as I said in the previous chapter, uses the member Dwcheckpoint and Dwwaithint to indicate the time it takes to complete the state change. If necessary, you can report progress periodically by increasing the value of the Dwcheckpoint member and setting the value of the Dwwaithint member to indicate how you expect the service to arrive at the next time.

Once the entire startup process is complete, call SetServiceStatus again. At this point the dwcurrentstate member of the SERVICE_STATUS structure is set to service_stopped, when the status code is reported, the member Dwcheckpoint and Dwwaithint must be set to 0, Because the service has completed its state change. The same method is used when pausing or continuing a service.

When the Ctrlhandler function receives a Service_control_interrogate control code, the service will simply set the Dwcurrentstate member to the current state of the service, and Set the members Dwcheckpoint and Dwwaithint to 0, and then call SetServiceStatus again.

When the operating system shuts down, the Ctrlhandler function receives a Service_control_shutdown control code. The service does not need to respond to this code at all, because the system is shutting down. It will execute the minimum set of actions needed to save the data in order to make sure that the machine shuts down in a timely manner. By default, the system only gives very little time to shut down all the services, MSDN said about 20 seconds, but that may be the Windows NT 4 settings, in my Windows server this time is 10 seconds, you can manually modify this value, it is recorded in the HKEY _local_machinesystemcurrentcontrolsetcontrol the WaitToKillServiceTimeout in the sub-key, the unit is milliseconds.

When the Ctrlhandler function receives any user-defined code, it should perform the desired user custom action. The SetServiceStatus function is not adjusted unless the user-defined action is to force the service to pause, resume, or stop. If a user-defined action forces the state of the service to change, SetServiceStatus will be called to set Dwcurrentstate, Dwcheckpoint, and Dwwaithint, with the exact control code as previously stated.

If your Ctrlhandler function takes a long time to perform, it is important to note that if the Ctrlhandler function does not return within 30 seconds, the SCM will return an error, which is not what we expected. So if this is the case, the best way to do this is to set up another thread to continue the operation so that the Ctrlhandler function can return quickly. For example, when a service_control_stop request is received, as stated above, the service may be waiting for a network request to be completed or the data is flushed to a drive, and the time required for these operations is not estimated by you. Then it is necessary to establish a new thread to wait for the operation to execute the Stop command, the Ctrlhandler function will still report the Service_stop_pending state before returning, and when the new thread finishes executing, it sets the state of the service to Service_ STOPPED. If the time of the current operation can be estimated, do not do so, still use the method previously confessed to deal with.

Ctrlhandler function I'll talk about this first, and here's how the service is installed. A service program can use the CreateService function to add service information to the SCM database.

Sc_handle CreateService (Sc_handle hscmanager,//HANDLE to SCM database LPCTSTR Lpservicename,//name of the service to star T LPCTSTR lpdisplayname,//Display name DWORD dwdesiredaccess,//type of access to service DWORD Dwservicetype,//Type Of service DWORD Dwstarttype,//When to start service DWORD Dwerrorcontrol,//severity of service failure LPCTSTR Lpbina Rypathname,//Name of binary file LPCTSTR Lploadordergroup,//Name of load ordering group Lpdword Lpdwtagid,//Tag Iden Tifier LPCTSTR lpdependencies,//array of dependency names LPCTSTR Lpservicestartname,//account name LPCTSTR Lppassword account password);

Hscmanager is a handle to the SCM database, which can be obtained simply by calling OpenSCManager.

Sc_handle OpenSCManager (LPCTSTR lpmachinename,//Computer name LPCTSTR lpdatabasename,//SCM database name DWORD Dwdesi Redaccess//access type);

Lpmachinename is the name of the target machine, remember I said in the first chapter can I install the service on the other machine? This is the method of implementation. The name of the other machine must begin with "\". If you pass null or an empty string, the default is native.

Lpdatabasename is the name of the SCM database above the target machine, but MSDN says this parameter is set to Services_active_database by default, and if NULL is passed, the default is open Services_active_ DATABASE. So I haven't really figured out the meaning of this parameter, but it's OK to pass NULL when using it.

dwDesiredAccess is the access permission for the SCM database, as shown in the following table:

Object Access Description

Sc_manager_all_access includes standard_rights_required, in addition to all of the ACCESS types listed in this table.

Sc_manager_connect enables connecting to the service control MANAGER.

Sc_manager_create_service enables calling of the CreateService function to CREATE a SERVICE object and add it to the Datab Ase.

Sc_manager_enumerate_service enables calling of the EnumServicesStatus function to list the services that is in the Datab Ase.

Sc_manager_lock enables calling of the Lockservicedatabase function to acquire a LOCK on the database.

Sc_manager_query_lock_status enables calling of the Queryservicelockstatus function to retrieve the LOCK STATUS informatio N for the database.

If you want to get access, it doesn't seem so complicated. MSDN says that all processes are allowed to obtain sc_manager_connect, Sc_manager_enumerate_service, and Sc_manager_query_lock_status permissions on all SCM databases, These permissions allow you to connect to the SCM database, enumerate the services installed on the target machine, and query whether the target database is locked. However, if you want to create a service, first you need to have the target machine administrator permissions, the general delivery sc_manager_all_access on it. The handle returned by this function can be closed by the Closeservicehandle function.

Lpservicename is the name of the service, and Lpdisplayname is the name that the service displays in the Service Management tool.

dwDesiredAccess is also a permission to access, there is a longer than the above a more than a table, you check MSDN yourself. We are going to install the service and still simply pass the sc_manager_all_access.

Dwservicetype refers to whether your service is associated with other processes, typically service_win32_own_process, that is not associated with any process. If you confirm that your service needs to be associated with certain processes, it is set to service_win32_share_process. When your service is associated with the desktop, it needs to be set to service_interactive_process.

Dwstarttype is how the service is started. There are three ways to start a service, namely "Automatic (Service_Auto_Start)" "Manual (Service_demand_start)" and "Disabled (service_disabled)". There are two other ways to do this on MSDN, but only for drivers.

Dwerrorcontrol decide what to do if the startup fails when the system starts.

Value meaning

The Service_error_ignore startup program logs an error but continues to start.

Service_error_normal Startup program logs an error and pops up a message box, but still continues to start

Service_error_severe Startup program Logging error occurs, if it is started with Last-known-good configuration, boot will continue. Otherwise, the computer will be restarted with the Last-known-good configuration.

Service_error_critical the startup program logs an error, if possible. If it is started with Last-known-good configuration, startup will fail. Otherwise, the computer will be restarted with the Last-known-good configuration. What a bad mistake.

Lpbinarypathname is the path to the service program. MSDN specifically mentions that if there are spaces in the service path, you must enclose the path in quotation marks. For example, "D:\My Share\myservice.exe" must be specified as "D:\My Share\myservice.exe".

The point of Lploadordergroup is that if there is a set of services to be started in a certain order, this parameter is used to specify a group name to flag this startup sequence group, but I have not used this parameter yet. Your service if it does not belong to any boot order group, just pass null or an empty string.

Lpdwtagid is the value to be specified after applying the above parameters, specifically for the driver, regardless of the contents of this article. Pass NULL.

Lpdependencies A string array that indicates the name of a string of services or a startup sequence group. When associated with a startup sequence group, the meaning of this parameter is that at least one of the startup sequence groups you specify has been started by at least one of the members of the entire group after all the attempts have been initiated by the member, and your service will be started successfully. If you do not need to establish a dependency relationship, you are still passing null or an empty string. But if you want to specify a startup order group, you must prefix the group name with the Sc_group_identifier, because the group name and service name are shared by a namespace.

Lpservicestartname is the start account of the service, if you set the association type of your service is service_win32_own_process, you need to specify the user name in domainnameusername format, If this account is on your local computer, use. Username can be specified. If NULL is passed, the local system account will be logged in. If it is a win NT 4.0 or earlier version, if you specify the service_win32_share_process, it must be passed. system specifies that the service uses the local systems account. Finally, if you specify Service_interactive_process, you must make the service run on the native system account.

See the name to know, Lppassword is the password of the account. If the system account is specified, NULL is passed. Pass an empty string if the account does not have a password

How Windows services are written (forwarded)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.