ASA AnyConnect Double Authentication with Certificate Validation Mapping and Pre-Fill Configuration Guide

Cisco AnyConnect Secure Mobility Client

Configuration Examples and TechNotes

ASA AnyConnect Double Authentication with Certificate Validation, Mapping, and Pre-Fill Configuration Guide

View with Adobe Reader on a variety of devices

ASA Configuration for Single Authentication and Certificate Validation

ASA Configuration for Double Authentication and Certificate Validation

ASA Configuration for Double Authentication and Pre-Fill

ASA Configuration for Double Authentication and Certificate Mapping

This document describes a configuration example for Adaptive Security Appliance (ASA) Cisco AnyConnect Secure Mobility Client access that uses double authentication with certificate validation. As an AnyConnect user, you must provide the correct certificate and credentials for the primary and secondary authentication in order to get VPN access. This document also provides an example of certificate mapping with the pre-fill feature.

Cisco recommends that you have knowledge of these topics:

Basic knowledge of ASA command-line interface (CLI) configuration and Secure Socket Layer (SSL) VPN configuration

Basic knowledge of X509 certificates

The information in this document is based on these software versions:

It is assumed that you used an external Certificate Authority (CA) in order to generate:

A public-key cryptography standard 12 (PKCS 12) base64-encoded certificate for ASA (anyconnect.pfx)

A PKCS 12 certificate for AnyConnect

Note: Use theCommand Lookup Toolregisteredcustomers only) in order to obtain more information on the commands used in this section.

In order to install an example certificate, double-click the anyconnect.pfx file, and install that certificate as a personal certificate.

Use the Certificate Manager (certmgr.msc) in order to verify the installation:

By default, AnyConnect tries to find a certificate in the Microsoft user store; there is no need to make any changes in the AnyConnect profile.

This example shows how ASA can import a base64 PKCS 12 certificate:

End with the word quit on a line by itself:

MIIJAQIBAzCCCMcGCSqGSIb3DQEHAaCCCLgEggi0MIIIsDCCBa8GCSqGSIb3DQEH

83EwMTAhMAkGBSsOAwIaBQAEFCS/WBSkrOIeT1HARHbLF1FFQvSvBAhu0j9bTtZo

INFO: Import PKCS12 operation completed successfully

Use theshow crypto ca certificatescommand in order to verify the import:

Certificate Serial Number: 00cf946de20d0ce6d9

Signature Algorithm: SHA1 with RSA Encryption

start date: 08:11:26 UTC Nov 16 2012

Certificate Serial Number: 00fe9c3d61e131cda9

Signature Algorithm: SHA1 with RSA Encryption

start date: 12:48:31 UTC Nov 29 2012

Note: TheOutput Interpreter Toolregisteredcustomers only) supports certainshowcommands. Use the Output Interpreter Tool in order to view an analysis ofshowcommand output.

ASA uses both authentication, authorization, and accounting (AAA) authentication and certificate authentication. Certificate validation is mandatory. AAA authentication uses a local database.

This example shows single authentication with certificate validation.

anyconnect image disk0:/anyconnect-win-3.1.01065-k9.pkg 1

vpn-tunnel-protocol ssl-client ssl-clientless

In addition to this configuration, it is possible to perform Lightweight Directory Access Protocol (LDAP) authorization with the username from a specific certificate field, such as the certificate name (CN). Additional attributes can then be retrieved and applied to the VPN session. For more information on authentication and certificate authorization, refer to ASA Anyconnect VPN and OpenLDAP Authorization with Custom Schema and Certificates Configuration Example.

Note: TheOutput Interpreter Toolregisteredcustomers only) supports certainshowcommands. Use the Output Interpreter Tool in order to view an analysis ofshowcommand output.

In order to test this configuration, provide the local credentials (username cisco with password cisco). The certificate must be present:

Enter theshow vpn-sessiondb detail anyconnectcommand on the ASA:

Assigned IP :10.1.1.10Public IP : 10.147.24.60

Protocol : AnyConnect-Parent SSL-Tunnel DTLS-Tunnel

Encryption : RC4 AES128 Hashing : none SHA1

Group Policy : Group1 Tunnel Group : RA

Login Time : 10:16:35 UTC Sat Apr 13 2013

Encryption : none TCP Src Port : 62531

TCP Dst Port : 443 Auth Mode :Certificate

Idle Time Out: 30 Minutes Idle TO Left : 28 Minutes

Assigned IP : 10.1.1.10 Public IP : 10.147.24.60

Encapsulation: TLSv1.0 TCP Src Port : 62535

TCP Dst Port : 443 Auth Mode :Certificate

Idle Time Out: 30 Minutes Idle TO Left : 28 Minutes

Client Ver : Cisco AnyConnect VPN Agent for Windows 3.1.01065

Assigned IP : 10.1.1.10 Public IP : 10.147.24.60

Encapsulation: DTLSv1.0 UDP Src Port : 52818

UDP Dst Port : 443 Auth Mode :Certificate

Idle Time Out: 30 Minutes Idle TO Left : 29 Minutes

Reval Int (T): 0 Seconds Reval Left(T): 0 Seconds

SQ Int (T) : 0 Seconds EoU Age(T) : 92 Seconds

Hold Left (T): 0 Seconds Posture Token:

Note: Refer toImportant Information on Debug Commandsbefore you usedebugcommands.

In this example, the certificate was not cached in the database, a corresponding CA has been found, the correct Key usage was used (ClientAuthentication), and the certificate has been validated successfully:

Detailed debug commands, such as thedebug webvpn 255command, can generate many logs in a production environment and place a heavy load on an ASA. Some WebVPN debugs have been removed for clarity:

CERT_API: process msg cmd=0, session=0x0934d687

CERT_API: Async locked for session 0x0934d687

CRYPTO_PKI:Checking to see if an identical cert is

CRYPTO_PKI: looking for cert in handle=0x00007ffd8b80ee90, digest=

ad 3d a2 da 83 19 e0 ee d9 b5 2a 83 5c dd e0 70 .=……..*.\..p

CRYPTO_PKI: Cert record not found, returning E_NOT_FOUND

CRYPTO_PKI:Cert not found in database.

CRYPTO_PKI:Looking for suitable trustpoints…

CRYPTO_PKI: Storage context locked by thread CERT API

CRYPTO_PKI:Found a suitable authenticated trustpoint CA.

CRYPTO_PKI(make trustedCerts list)CRYPTO_PKI:check_key_usage: ExtendedKeyUsage

CRYPTO_PKI:check_key_usage:Key Usage check OK

CRYPTO_PKI:Certificate validation: Successful, status: 0. Attempting to

retrieve revocation status if necessary

CRYPTO_PKI:Certificate validated. serial number: 00FE9C3D61E131CDB1, subject name:

cn=test1,ou=Security,o=Cisco,l=Krakow,st=PL,c=PL.

CRYPTO_PKI: Storage context released by thread CERT API

CRYPTO_PKI: Certificate validated without revocation check

This is the attempt to find a matching tunnel-group. There are no specific certificate mapping rules, and the tunnel-group that you provide is used:

00FE9C3D61E131CDB1, subject name: cn=test1,ou=Security,o=Cisco,l=Krakow,st=PL,

c=PL, issuer_name: cn=TAC,ou=RAC,o=TAC,l=Warsaw,st=Maz,c=PL.

CRYPTO_PKI:No Tunnel Group Match for peer certificate.

CERT_API: Unable to find tunnel group for cert using rules (SSL)

These are the SSL and general session debugs:

%ASA-7-717025:Validating certificate chain containing 1 certificate(s).

%ASA-7-717029:Identified client certificatewithin certificate chain. serial

number: 00FE9C3D61E131CDB1, subject name:cn=test1,ou=Security,o=Cisco,l=Krakow,

%ASA-7-717030:Found a suitable trustpoint CA to validate certificate.

%ASA-6-717022:Certificate was successfully validated. serial number:

00FE9C3D61E131CDB1, subject name: cn=test1,ou=Security,o=Cisco,l=Krakow,st=PL,

%ASA-6-717028: Certificate chain was successfully validated with warning,

%ASA-6-725002: Device completed SSL handshake with client outside:

%ASA-7-717036:Looking for a tunnel group match based on certificate mapsfor

peer certificate with serial number: 00FE9C3D61E131CDB1, subject name: cn=test1,

o
u=Security,o=Cisco,l=Krakow,st=PL,c=PL, issuer_name: cn=TAC,ou=RAC,o=TAC,

%ASA-4-717037:Tunnel group search using certificate maps failed for peer

certificate: serial number: 00FE9C3D61E131CDB1, subject name: cn=test1,

ou=Security,o=Cisco,l=Krakow,st=PL,c=PL, issuer_name: cn=TAC,ou=RAC,o=TAC,

%ASA-6-113012:AAA user authentication Successful : local database : user = cisco

%ASA-6-113009:AAA retrieved default group policy (Group1) for user = cisco

%ASA-6-113008: AAA transaction status ACCEPT : user = cisco

%ASA-7-734003: DAP: User cisco, Addr 10.147.24.60:

Session Attribute aaa.cisco.grouppolicy = Group1

%ASA-7-734003: DAP: User cisco, Addr 10.147.24.60:

%ASA-7-734003: DAP: User cisco, Addr 10.147.24.60:

Session Attribute aaa.cisco.username1 = cisco

%ASA-7-734003: DAP: User cisco, Addr 10.147.24.60:

Session Attribute aaa.cisco.username2 =

%ASA-7-734003: DAP: User cisco, Addr 10.147.24.60:

Session Attribute aaa.cisco.tunnelgroup = RA

%ASA-6-734001: DAP: User cisco, Addr 10.147.24.60, Connection AnyConnect: The

following DAP records were selected for this connection: DfltAccessPolicy

%ASA-6-113039: Group Group1 User cisco IP 10.147.24.60 AnyConnect parent

This is an example of double authentication, where the primary authentication server is LOCAL, and the secondary authentication server is LDAP. Certificate validation is still enabled.

This example shows the LDAP configuration:

aaa-server LDAP (outside) host 10.147.24.60

ldap-login-dn CN=Manager,DC=test-cisco,DC=com

Here is the addition of a secondary authentication server:

secondary-authentication-server-group LDAP

You do not see authentication-server-group LOCAL in the configuration because it is a default setting.

Any other AAA server can be used for authentication-server-group. For secondary-authentication-server-group, it is possible to use all AAA servers except for a Security Dynamics International (SDI) server; in that case, the SDI could still be the primary authentication server.

Note: TheOutput Interpreter Toolregisteredcustomers only) supports certainshowcommands. Use the Output Interpreter Tool in order to view an analysis ofshowcommand output.

In order to test this configuration, provide the local credentials (username cisco with password cisco) and LDAP credentials (username cisco with password from LDAP). The certificate must be present:

Enter theshow vpn-sessiondb detail anyconnectcommand on the ASA.

Results are similar to those for single authentication. Refer toASA Configuration for Single Authentication and Certificate Validation, Test.

Debugs for WebVPN session and authentication are similar. Refer to ASA Configuration for Single Authentication and Certificate Validation, Debug. One additional authentication process appears:

%ASA-6-302013: Built outbound TCP connection 1936 for outside:10.147.24.60/389

(10.147.24.60/389) to identity:10.48.67.153/54437 (10.48.67.153/54437)

%ASA-6-113004:AAA user authentication Successful : server = 10.147.24.60 :

%ASA-6-113009: AAA retrieved default group policy (Group1) for user = cisco

%ASA-6-113008: AAA transaction status ACCEPT : user = cisco

Debugs for LDAP show details that might vary with the LDAP configuration:

[34] New request Session, context 0x00007ffd8d7dd828, reqType = Authentication

[34] Creating LDAP context with uri=ldap://10.147.24.60:389

[34] Connect to LDAP server: ldap://10.147.24.60:389, status = Successful

[34] supportedLDAPVersion: value = 3

[34] Performing Simple authentication for Manager to 10.147.24.60

[34] User DN = [uid=cisco,ou=People,dc=test-cisco,dc=com]

[34] Server type for 10.147.24.60 unknown – no password policy

[34] Performing Simple authentication for cisco to 10.147.24.60

[34] Processing LDAP response for user cisco

[34] Authentication successful for cisco to 10.147.24.60

[34] homeDirectory: value = /home/cisco

[34] objectClass: value = posixAccount

[34] objectClass: value = shadowAccount

[34] objectClass: value = inetOrgPerson

[34] objectClass: value = organizationalPerson

[34] objectClass: value = CiscoPerson

[34] userPassword: value = SSHApndf5sfjscTPuyrhL+/QUqhK+i1UCUTy

[34] Fiber exit Tx=315 bytes Rx=911 bytes, status=1

It is possible to map certain certificate fields to the username that is used for primary and secondary authentication:

secondary-authentication-server-group LDAP

secondary-username-from-certificate OU

secondary-pre-fill-username ssl-client

In this example, the client is using the certificate: cn=test1,ou=Security,o=Cisco,l=Krakow,st=PL,c=PL.

For primary authentication, the username is taken from the CN, which is why local user test1 was created.

For secondary authentication, the username is taken from the organizational unit (OU, which is why user Security was created on the LDAP server.

It is also possible to force AnyConnect to use pre-fill commands in order to pre-fill the primary and secondary username.

In a real world scenario, the primary authentication server is usually an AD or LDAP server, while the secondary authentication server is the Rivest, Shamir, and Adelman (RSA) server that uses token passwords. In this scenario, the user must provide AD/LDAP credentials (which the user knows), an RSA token password (which the user has) and a certificate (on the machine that is used).

Observe that you cannot change the primary or secondary username because it is pre-filled from the certificate CN and OU fields:

This example shows the pre-fill request sent to AnyConnect:

%ASA-7-113028: Extraction of username from VPN client certificate has started.

%ASA-7-113028: Extraction of username from VPN client certificate has finished

%ASA-7-113028: Extraction of username from VPN client certificate has completed.

%ASA-7-113028: Extraction of username from VPN client certificate has been

%ASA-7-113028: Extraction of username from VPN client certificate has started.

%ASA-7-113028: Extraction of username from VPN client certificate has finished

%ASA-7-113028: Extraction of username from VPN client certificate has completed.

Here you see that authentication is using the correct usernames:

%ASA-6-302013: Built outbound TCP connection 2137 for outside:10.147.24.60/389

(10.147.24.60/389) to identity:10.48.67.153/46606 (10.48.67.153/46606)

%ASA-6-113004:AAA user authentication Successful : server = 10.147.24.60 :

It is also possible to map specific client certificates to specific tunnel-groups, as shown in this example:

certificate-group-map CERT-MAP 10 RA

This way, all user certificates signed by the Cisco Technical Assistance Center (TAC) CA are mapped to a tunnel-group named RA.

Note: Certificate mapping for SSL is configured differently than certificate mapping for IPsec. For IPsec, it is configured using tunnel-group-map rules in global config mode. For SSL, it is configured using certificate-group-map under webvpn config mode.

Observe that, once certificate mapping is enabled, you do not need to choose tunnel-group anymore:

In this example, the certificate mapping rule allows the tunnel-group to be found:

peer certificate with serial number: 00FE9C3D61E131CDB1, subject name: cn=test1,

ou=Security,o=Cisco,l=Krakow,st=PL,c=PL, issuer_name: cn=TAC,ou=RAC,o=TAC,

%ASA-7-717038:Tunnel group match found. Tunnel Group: RA, Peer certificate:

serial number: 00FE9C3D61E131CDB1, subject name: cn=test1,ou=Security,o=Cisco,

l=Krakow,st=PL,c=PL, issuer_name: cn=TAC,ou=RAC,o=TAC,l=Warsaw,st=Maz,c=PL.

This section provides information you can use in order to troubleshoot your configuration.

After you remove a valid certificate from Windows7, AnyConnect cannot find any valid certificates:

On the ASA, it looks like the session is terminated by the client (Reset-I):

(10.147.24.60/52838) to identity:10.48.67.153/443 (10.48.67.153/443)

%ASA-6-725001: Starting SSL handshake with client outside:10.147.24.60/52838 for

%ASA-7-725010: Device supports the following 4 cipher(s).

%ASA-7-725011: Cipher[2] : AES128-SHA

%ASA-7-725011: Cipher[3] : AES256-SHA

%ASA-7-725011: Cipher[4] : DES-CBC3-SHA

%ASA-7-725008: SSL client outside:10.147.24.60/52838 proposes the following 8

%ASA-7-725011: Cipher[1] : AES128-SHA

%ASA-7-725011: Cipher[2] : AES256-SHA

%ASA-7-725011: Cipher[4] : DES-CBC3-SHA

%ASA-7-725011: Cipher[5] : DHE-DSS-AES128-SHA

%ASA-7-725011: Cipher[6] : DHE-DSS-AES256-SHA

%ASA-7-725011: Cipher[7] : EDH-DSS-DES-CBC3-SHA

%ASA-7-725012: Device chooses cipher : RC4-SHA for the SSL session with client

%ASA-6-302014:Teardown TCP connection 2489 for outside:10.147.24.60/52838 to

identity:10.48.67.153/443 duration 0:00:00 bytes 1448 TCP Reset-I

Configuring Tunnel Grouips, Group Policies, and Users: Configuring Double Authentication

Configuring an External Server for Security Appliance User Authorization

Technical Support & Documentation – Cisco Systems

Related Support Community Discussions

This Document Applies to These Products

Adaptive Security Appliance (ASA) Software

Server and client example with C sockets on Linux

In a previous example we learnt about thebasics of socket programming in C. In this example we shall build a basic ECHO client and server. The server/client shown here use TCP sockets or SOCK_STREAM.

Tcp sockets are connection oriented, means that they have a concept of independant connection on a certain port which one application can use at a time. The concept of connection makes TCP a reliable stream such that if errors occur, they can be detected and compensated for by resending the failed packets.

Lets build a very simple web server. The steps to make a webserver are as follows :

4. Accept connections and process there after.

/* C socket server example */ includestdio.h includestring.h //strlen includesys/socket.h includearpa/inet.h //inet_addr includeunistd.h //write int main(int argc , char *argv[]) int socket_desc , client_sock , c , read_size; struct sockaddr_in server , client; char client_message[2000]; //Create socket socket_desc = socket(AF_INET , SOCK_STREAM , 0); if (socket_desc == -1) printf(Could not create socket); puts(Socket created); //Prepare the sockaddr_in structure server.sin_family = AF_INET; server.sin_addr.s_addr = INADDR_ANY; server.sin_port = htons( 8888 ); //Bind if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) 0) //print the error message perror(bind failed. Error); return 1; puts(bind done); //Listen listen(socket_desc , 3); //Accept and incoming connection puts(Waiting for incoming connections…); c = sizeof(struct sockaddr_in); //accept connection from an incoming client client_sock = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*) if (client_sock 0) perror(accept failed); return 1; puts(Connection accepted); //Receive a message from client while( (read_size = recv(client_sock , client_message , 2000 , 0)) 0 ) //Send the message back to client write(client_sock , client_message , strlen(client_message)); if(read_size == 0) puts(Client disconnected); fflush(stdout); else if(read_size == -1) perror(recv failed); return 0;

The above code example will start a server on localhost (127.0.0.1) port 8888

Once it receives a connection, it will read some input from the client and reply back with the same message.

To test the server run the server and then connect from another terminal using the telnet command like this

Now instead of using the telnet program as a client, why not write our own client program. Quite simple again

/* C ECHO client example using sockets */ includestdio.h //printf includestring.h //strlen includesys/socket.h //socket includearpa/inet.h //inet_addr int main(int argc , char *argv[]) int sock; struct sockaddr_in server; char message[1000] , server_reply[2000]; //Create socket sock = socket(AF_INET , SOCK_STREAM , 0); if (sock == -1) printf(Could not create socket); puts(Socket created); server.sin_addr.s_addr = inet_addr(127.0.0.1); server.sin_family = AF_INET; server.sin_port = htons( 8888 ); //Connect to remote server if (connect(sock , (struct sockaddr *)&server , sizeof(server)) 0) perror(connect failed. Error); return 1; puts(Connected\n); //keep communicating with server while(1) printf(Enter message : ); scanf(%s , message); //Send some data if( send(sock , message , strlen(message) , 0) 0) puts(Send failed); return 1; //Receive a reply from the server if( recv(sock , server_reply , 2000 , 0) 0) puts(recv failed); break; puts(Server reply :); puts(server_reply); close(sock); return 0;

The above program will connect to localhost port 8888 and then ask for commands to send. Here is an example, how the output would look

The server in the above example has a drawback. It can handle communication with only 1 client. Thats not very useful. One way to work around this is by using threads. A thread can be assigned for each connected client which will handle communication with the client.

/* C socket server example, handles multiple clients using threads */ includestdio.h includestring.h //strlen includestdlib.h //strlen includesys/socket.h includearpa/inet.h //inet_addr includeunistd.h //write includepthread.h //for threading , link with lpthread //the thread function void *connection_handler(void *); int main(int argc , char *argv[]) int socket_desc , client_sock , c , *new_sock; struct sockaddr_in server , client; //Create socket socket_desc = socket(AF_INET , SOCK_STREAM , 0); if (socket_desc == -1) printf(Could not create socket); puts(Socket created); //Prepare the sockaddr_in structure server.sin_family = AF_INET; server.sin_addr.s_addr = INADDR_ANY; server.sin_port = htons( 8888 ); //Bind if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) 0) //print the error message perror(bind failed. Error); return 1; puts(bind done); //Listen listen(socket_desc , 3); //Accept and incoming connection puts(Waiting for incoming connections…); c = sizeof(struct sockaddr_in); //Accept and incoming connection puts(Waiting for incoming connections…); c = sizeof(struct sockaddr_in); while( (client_sock = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c)) ) puts(Connection accepted); pthread_t sniffer_thread; new_sock = malloc(1); *new_sock = client_sock; if( pthread_create( &sniffer_thread , NULL , connection_handler , (void*) new_sock) 0) perror(could not create thread); return 1; //Now join the thread , so that we dont terminate before the thread //pthread_join( sniffer_thread , NULL); puts(Handler assigned); if (client_sock 0) perror(accept failed); return 1; return 0; /* * This will handle connection for each client * */ void *connection_handler(void *socket_desc) //Get the socket descriptor int sock = *(int*)socket_desc; int read_size; char *message , client_message[2000]; //Send some messages to the client message = Greetings! I am your connection handler\n; write(sock , message , strlen(message)); message = Now type something and i shall repeat what you type \n; write(sock , message , strlen(message)); //Receive a message from client while( (read_size = recv(sock , client_message , 2000 , 0)) 0 ) //Send the message back to client write(sock , client_message , strlen(client_message)); if(read_size == 0) puts(Client disconnected); fflush(stdout); else if(read_size == -1) perror(recv failed); //Free the socket pointer free(socket_desc); return 0;

Run the above server and connect from multiple clients and it will handle all of them. There are other ways to handle multiple clients, like select, poll etc. We shall talk about them in some other article. Till then practise the above code examples and enjoy.

Subscribe to get updates delivered to your inbox

Php developer, blogger and Linux enthusiast.

He can be reached at[emailprotected].

I found two problem with the threaded server code:

1. The file descriptor is never closed when the thread is freed. After a while this eats up all of the file descriptors in the operating system. To fix this, add close(sock); just before free(sock_desc), like so:

2. There is a memory leak that can be fixed by uncommenting //pthread_join( sniffer_thread , NULL);

When these two issues are corrected it works perfectly for me.

Hello. I cannot compile client example. Got that message: client.c:60:5: warning: implict declaration of function close (-Wimplict-function-declaration) close(sock);

what should i do to make the client ask for only one message and server prints it completely but just once. i am using single client code.

i want to make a process , such as a reverse the message. which has sent by clients and server goes to reverse it ,repost it back. How could i do this function ? please help me . thanks

Sometimes i get error:invalid operands to binary expression in this line

if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) 0)

Sometimes i do and sometimes not, very wierd

when i excute the socket ing switch case function. i am getting my input in server.. itself when i excuteplz help it

Can someone explain the pthread_join? Why is it commented out? I assume we need it, but where should it go i
n the code?

This code itself has some serious issues in it. Do NOT use it, on the long term if you try to build a server on this it will hang after a time.

Nice tutorial. I do have a question:

In this program were using INADDR_ANY as the server address, which means listen on all the available IP address.

How to re-write a this program if I want to achieve this:

1. Server should listen on two specific sockets lets say for example 192.168.1.1:8888 & 192.168.1.2:8888?

Can you please demonstrate the same, it would be really helpful for me?

Kindly any one tell me how we can make this code so that client can communicate with client in multi clients

Hey every one; i tried to compiler the multithraded server code but i got this message:

/tmp/ccTHnrln.o: In function `main:

thread.c:(.text+0x142): undefined reference to `pthread_create

how it can be implemented? please

Hey you got a solution? I am also stuck with this problem.

how exactly is it added cuz i hav same prob

Hey Cephas.while compiling type,

Compile it like gcc -lthread client.c . Do similarly for server program.

hii, did you get a solution to that error because Im having the same issue and i dont know how to go about

Excellent code. Just what I needed. Thank you.

Hi Silver, thanks for every tutorial you wrote here, they have been very useful :). I do have a question, though: I need to make a server write a clients message into every other client connected to simulate a chatroom. So if client 1 writes hello, client 2 and 3 see in their own screen Client 1 wrote: hello. Any ideas to do this? Thanks for everything!.

Thanks for writing tutorials, but as far as the multi client versions goes, both this version and the revised version posted below are prone to errors for different reasons. The original version containing a buffer overflow/possible access violation and the revised version containing a race condition.

great codei have use this code to receive data from gps thanksbut when i try receive data from vt310 gps meitrack, i just receive $$, can you help me?sorry for my bad english

how to kick client if send wrong message?

Very nice well explained piece of work. Got it to build and run on a PC with eclipse and Cygwin compiler in a few minutes 🙂 , think I needed to add one stupid include for the definition of close.

I got the multithreaded code to work, but when I send a message using the client, I get this:

Hi There! Im the connection handler.

Type the message and the server shall repeat it.

Hellohere! Im the connection handler.

Type the message and the server shall repeat it.

Hellohere! Im the connection handler.

Type the message and the server shall repeat it.

Helpohere! Im the connection handler.

Type the message and the server shall repeat it.

thisisere! Im the connection handler.

Type the message and the server shall repeat it.

stupidere! Im the connection handler.

Type the message and the server shall repeat it.

Same thing happened to me. No idea why :/

The problem is in reusind client_message buffer. Replace in server code:

while( (read_size = recv(client_sock , client_message , 2000 , 0)) 0 )

write(client_sock , client_message , strlen(client_message));

while( (read_size = recv(client_sock , client_message , 2000 , 0)) 0 )

write(client_sock , client_message , read_size);

This will send exactly received number of bytes, not whole string.

sorry to say but this suggestion did not help in solving the problem

pranav i used the single client code but had the same problem. so what you can do in every code of server and client after printing initialize the char array to null. worked for me.

memset(client_message,,sizeof(client_message));

while( (read_size = recv(client_sock , client_message , 2000 , 0)) 0 )

I solved that issue adding a +1 after every use of the function strlen(), i.e.

write(client_sock , client_message , strlen(client_message) + 1);

strlen returns the length of the c string omitting the the terminating null character, so write sends the string without it. you receive it fine in the receive buffer, but when you try to read from it you read all the characters from the beginning of buffer until it finds a random occurring null character. You could null out your buffer before reading or writing like so:

memset(client_message,\n,sizeof(client_message));

I think sending the null character is simpler.

Hey, I tried running the multithreaded server code, but when I compiled it I received this error message:

echoserver.c:88:1: error: expected declaration or statement at end of input

Where line 88 is the closing curly bracket just after :

Im not sure what went wrong, any suggestions?

first of all thanks a lot for sharing this. I really appreciate it, so thanks again.

Here come my questions, just in order to clarify:

1. You declare new_sock as a pointer and dynamically allocate e new byte each time a new client connects. Why didnt you just declared it as a normal int, assigning the pointer to client_sock as you already did?

2. Sniffer_thread is only declared once and no dynamic allocation happens after a client connects, so I assume more than one thread (or thread_handler) can refer to the same pthread_t variable without any influence on the previously created/started threads. Am I right?

3. When passing arguments to the thread handler function (I see you pass the new socket variable as a pointer), these become thread variables, thus are not shared by the different threads, am I right?

4. This would also be valid if passing a client address to the thread handler, thus it would not affect the client address of any other connection handled by the other threads, right?

Again, thanks a lot for the code snippet.

well, the thread handling shown in the code, may not be fully correct, I just wrote it as an experiment and it worked.

1. I created new_sock as a pointer to allocate memory separately for each thread, otherwise it would get overwritten across threads.

2. The sniffer_thread (should have named it something better) variable is created everytime in the while loop, so a new one gets created for every client. Its address is the first parameter to pthread_create function.

3. Not exactly, the new_sock is created by doing a malloc(1); in the main thread, so a new one is created for every thread.

4. You can pass any custom structure variable to the thread function and store anything in it. Like create a struct, fill it in the main thread with socket pointer, address variables, and then pass to thread. Just make sure that in the main thread it does not get over-written (by using malloc for example)

thanks once again for the prompt answer. You are right for what concerns point 4: as long as the thread copies the passed struct in an own local struct, so it gets not over-written by the next thread operation, everything should be fine.

Still, for what concerns points 1 to 3, Im not quite sure the dynamic allocation was the best choice and also the constant declaration of a new pthread_t var in the while loop sounds a little weird to me. I compared a couple of other threaded server sources and many of them declare the new_sock variable as a global one, passing it as an argument and not caring anymore about it (as it gets copied in a local thread variable) and only declare the pthread_t var once (in the main function variables). It then gets handled by the OS (?) in order to create all the needed and independent threadsas far as I got. Am I missing something or did I get it right?

Thanks again for the clarifications.

I gave the code a little thought. Your arguments are probably right.

Since we are accept and create a thread for only 1 incoming connection at a time, it is okay to use the same new_sock and pthread_t variable. The thread would create its local copy of n
ew_sock and work fine.

I guess its all right to declare pthread_t variable only once and reuse it.

Before returning, a successful call to pthread_create() stores the ID

of the new thread in the buffer pointed to by thread; this identifier

is used to refer to the thread in subsequent calls to other pthreads

Therefore you can use the same variable again and again.

I wrote another version of the server following your ideas and it works fine.

I have met such issue that the client_sock is modified before the connection_handler handle the connection. That means one clients request will be ignored forever!

Thanks for the example!!!!! Just what I am looking for.

Could you post the code again? the link is down.

Will be checking out the select version as well. 🙂

Thanks for the example! Just what I am looking for.

I am wondering whether a similar threaded C-server will be sufficient when the client is a Python Web-handler issuing large number of simultaneous requests to the C-program.

the server and client can be in different languages, it does not matter.

However, how many requests the server can handle will depend on how it is coded. Instead of threads, select function can be used to handle multiple connections.

Check the following article for details on how to use the select function.

very well laid out and crisp ! Thankyou!

iam getting connection refused error

I want to include one functionality which is not working here.

If we disconnect the server, all the client processes connecte dto it, will automatically be disconnected.

How to add that functionality in the above code?

thank you very much for your explanation!, it help me a lot!!

Mail (will not be published) (required)

linux c socket tcp

if ((sockfd = socket(AF_INET, type, 0)) == -1) printf(create socker error\n); return -1; struct sockaddr_in addrv4; bzero(&addrv4, sizeof(addrv4)); addrv4.sin_family = AF_INET; addrv4.sin_port = htons(PORT); addrv4.sin_addr.s_addr = INADDR_ANY; if (bind(sockfd, (struct sockaddr *)&addrv4, sizeof(addrv4)) 0) printf (bind sockfd error\n); return -1; if (listen(sockfd, BACKLOG) 0) printf (listen sockfd error\n); return -1; return sockfd;

if ((sockfd = init_server(SOCK_STREAM)) == -1) printf (server init failed\n); exit(1); while (1) struct sockaddr client_addr; bzero(&client_addr, sizeof(client_addr)); socklen_t len = sizeof(client_addr); char recvbuf[RECVBUF_SIZE]; if ((newfd = accept(sockfd, &client_addr, &len)) 0) printf(%s\n, strerror(errno)); printf (accept request error\n); exit(1); printf( the client fd is :%d\n, newfd); printf (client ip is %s, inet_ntoa(((struct sockaddr_in *)&client_addr)-sin_addr)); ssize_t ret; if ((ret = recv(newfd, recvbuf, RECVBUF_SIZE, 0)) 0) printf(%s\n, strerror(errno)); printf(recv data error \n); exit(1); if (ret == 0) printf(always read to EOF\n); printf(the client request data is :\n\t\t%s, recvbuf); char *resp_data = the server was recvived success!; if (send(newfd, resp_data, strlen(resp_data), 0) == -1) printf(response data error\n); exit(1); //shutdown(newfd, SHUT_RDWR); //close(newfd); if (strcmp(recvbuf, exit) == 0) shutdown(sockfd, SHUT_RDWR); close(sockfd);

the error info is : %s\n, str, strerror(errno));

if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) error(socket error); return -1; struct sockaddr_in addrv4; bzero(&addrv4, sizeof(addrv4)); addrv4.sin_family = AF_INET; addrv4.sin_port = htons(PORT); addrv4.sin_addr.s_addr = inet_addr(127.0.0.1); if (connect(sockfd, (struct sockaddr *)&addrv4, (socklen_t) sizeof(addrv4)) == -1) error(connect error); return -1; return sockfd;

if ((sockfd = init_client()) == -1)

while (1) printf(input ); if ((len = read(STDIN_FILENO, &consolebuf, BUFSIZE)) == -1) error(read data error); exit(1); if (strcmp(consolebuf, exit-client) == 0) break; if (send(sockfd, consolebuf, len, 0) == -1) error(send data error); exit(1); if ((recvlen = recv(sockfd, recvbuf, BUFSIZE, 0)) == -1) error(receive the server response error\n); exit(1); write(STDOUT_FILENO, recvbuf, recvlen); shutdown(sockfd, SHUT_RDWR); close(sockfd); exit(0);

socket,

recv

C

linuxsocketTCP

Linux SocketTCP/IP

C Socket TCP ,,,

C Socket2CMD

SelectTCP,Socket

linux c—-TCP/(socket,bind)

cordova jspapkhtml