I am trying to write a small program demonstrating Remote DMA over iWarp. I have the softiwarp Linux kernel module loaded and the userspace library compiled.
I am looking for documentation or sample code that explains setting up a connection and, e.g., sending a simple data block to the remote end ("Hello World!") to get me started, yet all I can find is the OpenFabrics' training web site, which is not helpful at all.
#include <arpa/inet.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <getopt.h>
#include <stdlib.h>
#include <unistd.h>
#include <rdma/rdma_cma.h>
struct Args {
char *remote_addr;
int is_server;
int port;
};
struct Args args;
int main(int argc, char *argv[])
{
struct rdma_event_channel *evch;
struct rdma_cm_id *server_id;
struct rdma_cm_id *client_id;
struct rdma_cm_event *event;
struct rdma_conn_param conn_param;
struct ibv_pd *pd;
struct ibv_cq *cq;
struct ibv_mr *mr;
struct ibv_send_wr snd_wr;
struct ibv_recv_wr rcv_wr;
struct ibv_sge sge;
struct ibv_wc wc;
struct ibv_qp_init_attr attr = {
.cap = {
.max_send_wr = 32,
.max_recv_wr = 32,
.max_send_sge = 1,
.max_recv_sge = 1,
.max_inline_data = 64
},
.qp_type = IBV_QPT_RC
};
char msg[256] = "Hello World";
int msg_len = strlen(msg) + 1;
struct sockaddr_in sin;
args.remote_addr = "0.0.0.0";
args.is_server = 1;
args.port = 21234;
/* Parameter parsing. */
while (1) {
int c;
c = getopt(argc, argv, "c:p:");
if (c == -1)
break;
switch (c) {
case 'c':
args.is_server = 0;
args.remote_addr = optarg;
break;
case 'p':
args.port = strtol(optarg, NULL, 0);
break;
default:
perror("Invalid option");
exit(-1);
};
}
if (args.is_server) {
if (!(evch = rdma_create_event_channel())) {
perror("rdma_create_event_channel");
exit(-1);
}
if (rdma_create_id(evch, &server_id, NULL, RDMA_PS_TCP)) {
perror("rdma_create_id");
exit(-1);
}
sin.sin_family = AF_INET;
sin.sin_port = htons(args.port);
sin.sin_addr.s_addr = htonl(INADDR_ANY);
if (rdma_bind_addr(server_id, (struct sockaddr *)&sin)) {
perror("rdma_bind_addr");
exit(-1);
}
if (rdma_listen(server_id, 6)) {
perror("rdma_listen");
exit(-1);
}
if (rdma_get_cm_event(evch, &event)
|| event->event != RDMA_CM_EVENT_CONNECT_REQUEST) {
perror("rdma_get_cm_event");
exit(-1);
}
client_id = (struct rdma_cm_id *)event->id;
if (!(pd = ibv_alloc_pd(client_id->verbs))) {
perror("ibv_alloc_pd");
exit(-1);
}
if (!(mr = ibv_reg_mr(pd, msg, 256,
IBV_ACCESS_REMOTE_WRITE |
IBV_ACCESS_LOCAL_WRITE |
IBV_ACCESS_REMOTE_READ))) {
perror("ibv_reg_mr");
exit(-1);
}
if (!(cq = ibv_create_cq(client_id->verbs, 32, 0, 0, 0))) {
perror("ibv_create_cq");
exit(-1);
}
attr.send_cq = attr.recv_cq = cq;
if (rdma_create_qp(client_id, pd, &attr)) {
perror("rdma_create_qp");
exit(-1);
}
memset(&conn_param, 0, sizeof conn_param);
if (rdma_accept(client_id, &conn_param)) {
perror("rdma_accept");
exit(-1);
}
rdma_ack_cm_event(event);
if (rdma_get_cm_event(evch, &event)
|| event->event != RDMA_CM_EVENT_ESTABLISHED) {
perror("rdma_get_cm_event");
exit(-1);
}
rdma_ack_cm_event(event);
sge.addr = (uint64_t)msg;
sge.length = msg_len;
sge.lkey = mr->lkey;
snd_wr.sg_list = &sge;
snd_wr.num_sge = 1;
snd_wr.opcode = IBV_WR_SEND;
snd_wr.send_flags = IBV_SEND_SIGNALED;
snd_wr.next = NULL;
if (ibv_post_send(client_id->qp, &snd_wr, NULL)) {
perror("ibv_post_send");
exit(-1);
}
while (!ibv_poll_cq(cq, 1, &wc))
;
if (wc.status != IBV_WC_SUCCESS) {
perror("ibv_poll_cq");
exit(-1);
}
}
else {
if (!(evch = rdma_create_event_channel())) {
perror("rdma_create_event_channel");
exit(-1);
}
if (rdma_create_id(evch, &client_id, NULL, RDMA_PS_TCP)) {
perror("rdma_create_id");
exit(-1);
}
sin.sin_family = AF_INET;
sin.sin_port = htons(args.port);
sin.sin_addr.s_addr = inet_addr(args.remote_addr);
if (rdma_resolve_addr
(client_id, NULL, (struct sockaddr *)&sin, 2000)) {
perror("rdma_resolve_addr");
exit(-1);
}
if (rdma_get_cm_event(evch, &event)
|| event->event != RDMA_CM_EVENT_ADDR_RESOLVED) {
perror("rdma_get_cm_event");
exit(-1);
}
rdma_ack_cm_event(event);
if (rdma_resolve_route(client_id, 2000)) {
perror("rdma_resolve_route");
exit(-1);
}
if (rdma_get_cm_event(evch, &event)
|| event->event != RDMA_CM_EVENT_ROUTE_RESOLVED) {
perror("rdma_get_cm_event");
exit(-1);
}
rdma_ack_cm_event(event);
if (!(pd = ibv_alloc_pd(client_id->verbs))) {
perror("ibv_alloc_pd");
exit(-1);
}
if (!(mr = ibv_reg_mr(pd, msg, 256,
IBV_ACCESS_REMOTE_WRITE |
IBV_ACCESS_LOCAL_WRITE |
IBV_ACCESS_REMOTE_READ))) {
perror("ibv_reg_mr");
exit(-1);
}
if (!(cq = ibv_create_cq(client_id->verbs, 32, 0, 0, 0))) {
perror("ibv_create_cq");
exit(-1);
}
attr.send_cq = attr.recv_cq = cq;
if (rdma_create_qp(client_id, pd, &attr)) {
perror("rdma_create_qp");
exit(-1);
}
sge.addr = (uint64_t)msg;
sge.length = msg_len;
sge.lkey = mr->lkey;
rcv_wr.sg_list = &sge;
rcv_wr.num_sge = 1;
rcv_wr.next = NULL;
if (ibv_post_recv(client_id->qp, &rcv_wr, NULL)) {
perror("ibv_post_recv");
exit(-1);
}
memset(&conn_param, 0, sizeof conn_param);
if (rdma_connect(client_id, &conn_param)) {
perror("rdma_connect");
exit(-1);
}
if (rdma_get_cm_event(evch, &event)
|| event->event != RDMA_CM_EVENT_ESTABLISHED) {
perror("rdma_get_cm_event");
exit(-1);
}
rdma_ack_cm_event(event);
while (!ibv_poll_cq(cq, 1, &wc)) ;
if (wc.status != IBV_WC_SUCCESS) {
perror("ibv_poll_cq");
exit(-1);
}
fprintf(stdout, "Received %s \n", msg);
}
fprintf(stdout, "Done \n");
return 0;
}
Probably the best documentation and examples are in the librdmacm source. It includes full man pages around establishing connections (actually moving data is in the libibverbs man pages), as well as a number of example programs under the examples directory. The simplest example is rping.
As the comment says, trying to code something up and then asking specific questions is more productive.
Related
The TCP Echo Server sample from the Azure Sphere Samples at github works great and I am able to use my PC or a raspberryPi as a TCP client and communicate to the TCP echo server at the sphere device. However, I have a requirement where I need my Azure Sphere device as a TCP client. I modified the private network services sample application to work as a client (commented out Echo TCP Server) but the connection to the TCP server running at PC fails. The 'connect' returns -1 with errno set to 115 (ERROR: Operation in progress). I have configured the network services at azure sphere device with static ip. I have also verified that the same TCP client and server application works fine when a raspberrypi is used as a client and PC as the server. This is the modified main file of the application:
#include <errno.h>
#include <signal.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <arpa/inet.h>
#include "applibs_versions.h"
#include <applibs/log.h>
#include <applibs/networking.h>
#include <hw/sample_hardware.h>
typedef enum {
ExitCode_Success = 0,
ExitCode_TermHandler_SigTerm = 1,
ExitCode_StoppedHandler_Stopped = 2,
ExitCode_CheckStatus_SetInterfaceState = 3,
ExitCode_CheckStatus_GetInterfaceCount = 4,
ExitCode_CheckStatus_GetInterfaceConnectionStatus = 5,
ExitCode_ConfigureStaticIp_IpConfigApply = 6,
ExitCode_StartSntpServer_StartSntp = 7,
ExitCode_StartDhcpServer_StartDhcp = 8,
ExitCode_TimerHandler_Consume = 9,
ExitCode_InitLaunch_Epoll = 10,
ExitCode_InitLaunch_Timer = 11,
ExitCode_Main_WaitCallFailure = 12,
ExitCode_EchoStart_Listen = 13,
ExitCode_OpenIpV4_Socket = 14,
ExitCode_OpenIpV4_SetSockOpt = 15,
ExitCode_OpenIpV4_Bind = 16
} ExitCode;
int tcp_client(void);
static bool isNetworkStackReady = false;
static volatile sig_atomic_t exitCode = ExitCode_Success;
static struct in_addr localServerIpAddress;
static struct in_addr subnetMask;
static struct in_addr gatewayIpAddress;
static const uint16_t LocalTcpServerPort = 11000;
static int serverBacklogSize = 3;
static const char NetworkInterface[] = "eth0";
int tcp_client(void) {
int sock = 0, valread;
struct sockaddr_in serv_addr;
char* hello = "Hello from client";
char buffer[1024] = { 0 };
if ((sock = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0)) < 0)
{
Log_Debug("\n Socket creation error \n");
return -1;
}
Log_Debug("TCP_CLIENT: socket created\n");
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(8080);
if (inet_pton(AF_INET, "169.254.57.67", &serv_addr.sin_addr) <= 0)
{
Log_Debug("\nInvalid address/ Address not supported \n");
return -1;
}
Log_Debug("TCP_CLIENT: ip assigned\n");
int conn = connect(sock, (struct sockaddr*) & serv_addr, sizeof(serv_addr));
Log_Debug("TCP_CLIENT: conn = %d\n", conn);
Log_Debug("ERROR: %s\n", strerror(errno));
if (conn < 0)
{
Log_Debug("\nConnection Failed \n");
return -1;
}
send(sock, hello, strlen(hello), 0);
Log_Debug("Hello message sent\n");
valread = read(sock, buffer, 1024);
Log_Debug("%s\n", buffer);
return 0;
}
static ExitCode CheckNetworkStatus(void)
{
int result = Networking_SetInterfaceState(NetworkInterface, true);
if (result != 0) {
if (errno == EAGAIN) {
Log_Debug("INFO: The networking stack isn't ready yet, will try again later.\n");
return ExitCode_Success;
} else {
Log_Debug(
"ERROR: Networking_SetInterfaceState for interface '%s' failed: errno=%d (%s)\n",
NetworkInterface, errno, strerror(errno));
return ExitCode_CheckStatus_SetInterfaceState;
}
}
Log_Debug("INFO: CheckNetworkStatus: Network stack is ready\n");
isNetworkStackReady = true;
ssize_t count = Networking_GetInterfaceCount();
if (count == -1) {
Log_Debug("ERROR: Networking_GetInterfaceCount: errno=%d (%s)\n", errno, strerror(errno));
return ExitCode_CheckStatus_GetInterfaceCount;
}
Log_Debug("INFO:CheckNetworkStatus: Networking_GetInterfaceCount: count=%zd\n", count);
// Read current status of all interfaces.
size_t bytesRequired = ((size_t)count) * sizeof(Networking_NetworkInterface);
Networking_NetworkInterface *interfaces = malloc(bytesRequired);
if (!interfaces) {
abort();
}
ssize_t actualCount = Networking_GetInterfaces(interfaces, (size_t)count);
if (actualCount == -1) {
Log_Debug("ERROR: Networking_GetInterfaces: errno=%d (%s)\n", errno, strerror(errno));
}
Log_Debug("INFO: Networking_GetInterfaces: actualCount=%zd\n", actualCount);
for (ssize_t i = 0; i < actualCount; ++i) {
Log_Debug("INFO: interface #%zd\n", i);
Log_Debug("INFO: interfaceName=\"%s\"\n", interfaces[i].interfaceName);
Log_Debug("INFO: isEnabled=\"%d\"\n", interfaces[i].isEnabled);
Networking_IpType ipType = interfaces[i].ipConfigurationType;
const char *typeText;
switch (ipType) {
case Networking_IpType_DhcpNone:
typeText = "DhcpNone";
break;
case Networking_IpType_DhcpClient:
typeText = "DhcpClient";
break;
default:
typeText = "unknown-configuration-type";
break;
}
Log_Debug("INFO: ipConfigurationType=%d (%s)\n", ipType, typeText);
Networking_InterfaceMedium_Type mediumType = interfaces[i].interfaceMediumType;
const char *mediumText;
switch (mediumType) {
case Networking_InterfaceMedium_Unspecified:
mediumText = "unspecified";
break;
case Networking_InterfaceMedium_Wifi:
mediumText = "Wi-Fi";
break;
case Networking_InterfaceMedium_Ethernet:
mediumText = "Ethernet";
break;
default:
mediumText = "unknown-medium";
break;
}
Log_Debug("INFO: interfaceMediumType=%d (%s)\n", mediumType, mediumText);
Networking_InterfaceConnectionStatus status;
int result = Networking_GetInterfaceConnectionStatus(interfaces[i].interfaceName, &status);
if (result != 0) {
Log_Debug("ERROR: Networking_GetInterfaceConnectionStatus: errno=%d (%s)\n", errno,
strerror(errno));
return ExitCode_CheckStatus_GetInterfaceConnectionStatus;
}
Log_Debug("INFO: interfaceStatus=0x%02x\n", status);
}
free(interfaces);
return ExitCode_Success;
}
static ExitCode ConfigureNetworkInterfaceWithStaticIp(const char *interfaceName)
{
Networking_IpConfig ipConfig;
Log_Debug("INFO: ConfigureNetworkInterfaceWithStaticIp: %s.\n", interfaceName);
Networking_IpConfig_Init(&ipConfig);
inet_aton("169.254.57.70", &localServerIpAddress);
inet_aton("255.255.0.0", &subnetMask);
inet_aton("0.0.0.0", &gatewayIpAddress);
Networking_IpConfig_EnableStaticIp(&ipConfig, localServerIpAddress, subnetMask,
gatewayIpAddress);
int result = Networking_IpConfig_Apply(interfaceName, &ipConfig);
Networking_IpConfig_Destroy(&ipConfig);
if (result != 0) {
Log_Debug("ERROR: Networking_IpConfig_Apply: %d (%s)\n", errno, strerror(errno));
return ExitCode_ConfigureStaticIp_IpConfigApply;
}
Log_Debug("INFO: Set static IP address on network interface: %s.\n", interfaceName);
return ExitCode_Success;
}
static ExitCode init_nw_services(void)
{
// Check the network stack readiness and display available interfaces when it's ready.
Log_Debug("INFO: Inside init_nw_services\n");
ExitCode localExitCode = CheckNetworkStatus();
if (localExitCode != ExitCode_Success) {
return localExitCode;
}
if (isNetworkStackReady) {
Log_Debug("INFO: init_nw_services: The network stack is ready, so unregister the timer event handler and launch servers.\n");
localExitCode = ConfigureNetworkInterfaceWithStaticIp(NetworkInterface);
}
return ExitCode_Success;
}
static ExitCode initialize_nw(void)
{
while (!isNetworkStackReady) {
if (!isNetworkStackReady) {
Log_Debug("INFO: init_nw_services\n");
ExitCode localExitCode = init_nw_services();
if (localExitCode != ExitCode_Success) {
exitCode = localExitCode;
return;
}
}
else {
Log_Debug("INFO: Network stack is ready\n");
}
}
Log_Debug("INFO: Initialization and server launch complete\n");
return ExitCode_Success;
}
int main(int argc, char *argv[])
{
Log_Debug("INFO: Private Ethernet TCP server application starting.\n");
exitCode = initialize_nw();
if (isNetworkStackReady)
tcp_client();
Log_Debug("INFO: Application exiting.\n");
return exitCode;
}
Yes this is possible. Please ensure that the destination is in the app manifest under AllowedConnections
Hello I'm trying IPC practice. But I have problem... Here is the code
Send_process.c (path : /home/John/h1/send_process.c)
struct mymsgbuf {
long mtype;
char mtext[80];
};
int main(void) {
key_t key;
int msgid;
struct mymsgbuf mesg;
char inputmsg[80];
if(msgid = msgget((key_t)123, IPC_CREAT | 0666) == -1) {
perror("Failed to create new MessageQueue");
exit(1);
}
printf("%d\n", msgid);
mesg.mtype = 1;
while(1) {
printf("Enter Sending Message. (Input exit, programm terminate) : ");
scanf("%s", inputmsg);
strcpy(mesg.mtext, inputmsg);
if(msgsnd(msgid, (void *)&mesg, sizeof(mesg.mtext), IPC_NOWAIT) == -1) {
perror("msgsnd");
exit(1);
}
if(strcmp(inputmsg, "exit") == 0) {
printf("Sending Process Terminated\n");
break;
}
}
return 0;
}
Receive_process.c (path : /home/John/h1/send_process.c)
struct mymsgbuf {
long mtype;
char mtext[80];
};
int main(void) {
struct mymsgbuf inmsg;
key_t key;
int msgid;
key = ftok("/home/John/h1/receive_process.c", 123);
if((msgid = msgget(key,0666)) < 0 ) { //here is error
perror("msgget");
exit(1);
}
printf("%d\n", msgid);
while(1) {
if(msgrcv(msgid, &inmsg, sizeof(inmsg.mtext), 0,0) == -1) {
perror("Message Receive");
exit(1);
}
printf("Received Message. Message is [%s]\n", inmsg.mtext);
if(strcmp(inmsg.mtext, "exit") == 0 ) {
printf("Receive_process end\n");
exit(0);
}
}
return 0;
}
Send_process is works very well, but Receive_process not works well. What is the problem?
I am trying to do Socket programming. I've google and looked at problems like mine. However, I can't see to figure out my error.
Whenever I run my code, I get an error in connect() in main in client.c. The error is invalid argument.
Server.c
/* chatroom server */
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <pthread.h>
#include <signal.h>
#define MAX_ROOMS 36
#define MAX_NAME_SIZE 56
#define PORT_NUM 12333
#define MSG_SIZE 8
#define MAX_LOAD 246
#define MAX_CRC 64 //max clients
#define MAX_BUF 256
#define SERVER_IP 32
#define DEBUG 0
struct msg {
int type; //create, join, delete
int length; // length or port num
};
struct chat_room {
int socket_d; //socket descriptor
int port;
pthread_t id; //id of chatroom
char name[MAX_NAME_SIZE];
int clients[MAX_ROOMS]; // used to hold the client's master sockets
};
struct chat_room* findRoom(char* name, struct chat_room* chat){
int iterator;
for(iterator = 0; iterator < MAX_ROOMS; iterator++){
if(strcmp(name, chat[iterator].name) && (chat[iterator].port != 0)) {
return &chat[iterator];
}
}
//if room does not exist
return NULL;
}
struct chat_room* joinServer(int chat_socket, char* name, struct chat_room* chat){
struct chat_room* local_chat = findRoom(name, chat);
int i;
if(local_chat != NULL){ //if the chat exists
for(i= 0; i< MAX_CRC; i++){
if(local_chat->clients[i] == 0)
{
local_chat->clients[i] = chat_socket;
}
return local_chat;
}
}
//if server if full or else error
return NULL;
}
int createResponse(int chat_socket, int new_port_num, int type){
struct msg temp;
char temp_buff[MAX_LOAD];
memset(temp_buff, 0, MAX_LOAD);
temp.type = type;
temp.length = new_port_num;
memcpy(temp_buff, &temp, sizeof(temp));
write(chat_socket, temp_buff, MSG_SIZE);
return 0;
}
int joinResponse(int chat_socket, int new_port_num){
struct msg temp;
char temp_buff[MAX_LOAD];
memset(temp_buff, 0, MAX_LOAD);
temp.type = 11;
temp.length = new_port_num;
memcpy(temp_buff, &temp, sizeof(temp));
write(chat_socket, temp_buff, MSG_SIZE);
return 0;
}
int deleteResponse(int chat_socket, struct chat_room* chat){
struct msg temp;
char temp_buff[MAX_LOAD];
int i;
memset(temp_buff, 0, MAX_LOAD);
temp.type = 12;
memcpy(temp_buff, &temp, sizeof(temp));
for(i=0; i<MAX_CRC; i++){
if((chat->clients[i] != chat_socket) && (chat->clients[i] != 0))
write(chat->clients[i],temp_buff, MSG_SIZE);
}
return 0;
}
struct chat_room* addRoom(int chat_socket, char* name, struct chat_room* chat){
int socket_d;
int i;
struct sockaddr_in sock;
static int port = PORT_NUM;
memset(&sock, 0, sizeof(sock));
int temp = -1;
for(i = 0; i<MAX_ROOMS; i++){
if((strcmp(chat[i].name, name) == 0) && (chat[i].port != 0)){
createResponse(chat_socket, chat[i].port, 15);
return NULL;
}
else if((chat[i].port == 0) && (temp== -1)){
temp = i;
}
}
if(temp == -1){
return NULL;
}
socket_d = socket(AF_INET, SOCK_STREAM, 0);
if(socket_d == -1 && DEBUG){
perror("Error creating chatroom socket");
return NULL;
}
sock.sin_family = AF_INET;
port++;
sock.sin_port = htons(port);
if(bind(socket_d, (struct sockaddr*)&sock, sizeof(struct sockaddr_in)) == -1){
perror("error in binding ");
return NULL;
}
chat[temp].socket_d = socket_d;
chat[temp].port = port;
strcpy(chat[temp].name, name);
return &chat[temp];
}
void* chat_room_main(void* chat_room_cluster){
char buf[MAX_LOAD];
int socket_d, chat_socket;
int temp; //temp_fd
int read_val;
int num_clients = 0;
int i;
int clients[MAX_CRC];
fd_set allfd, modfd;
struct chat_room chat_room_para;
memcpy(&chat_room_para, (struct chat_room*)chat_room_cluster, sizeof(struct chat_room));
free(chat_room_cluster);
memset(clients, 0, sizeof(int)*MAX_CRC);
socket_d = chat_room_para.socket_d;
listen(socket_d, 1);
FD_ZERO(&allfd);
FD_SET(socket_d, &allfd);
printf("New Chatroom Started\n");
while(1){
modfd = allfd;
select(FD_SETSIZE, &modfd, NULL, NULL, NULL);
for(temp = 0; temp < FD_SETSIZE; temp++){
if(FD_ISSET(temp, &modfd)){
memset(buf, 0, sizeof(buf));
if(temp == socket_d) {
chat_socket = accept(socket_d, NULL, NULL);
FD_SET(chat_socket, &allfd);
// find an empty spot to add the chat room
for(i = 0; i<MAX_CRC; i++) {
if(clients[i] == 0){
clients[i] = chat_socket;
break;
}
}
sprintf(buf, "Number of people in chatroom: %d", num_clients);
write(chat_socket, buf, strlen(buf));
num_clients++;
}
else{
if(read_val = read(temp, buf, MAX_LOAD) > 0){
for(i = 0; i< MAX_CRC; i++){
if((clients[i] != temp) && (clients[i] != 0)){
write(clients[i], buf, read_val);
}
}
}
else if(read_val <= 0) {
FD_CLR(temp, &allfd);
for(i = 0; i<MAX_CRC; i++){
if(clients[i] == temp)
clients[i] = 0;
}
num_clients--;
close(chat_socket);
}
}
}
}
}
}
int main(int argc, char* argv[]){
int server_socket, chat_socket; //file descriptors for server and chat
int temp; //tempfd
int i, j;
char server_ip[SERVER_IP];
char buf[MAX_BUF];
char msg_buf[MSG_SIZE];
fd_set allfd, modfd;
struct sockaddr_in sock;
struct hostent* host_name;
struct chat_room chatrooms[MAX_ROOMS];
memset(chatrooms, '\0', sizeof(struct chat_room)* MAX_ROOMS);
memset(&sock, '\0', sizeof(sock));
server_socket = socket(AF_INET, SOCK_STREAM, 0);
if(server_socket == -1){
perror("Error creating socket");
return -1;
}
sock.sin_family = AF_INET;
sock.sin_port = htons(PORT_NUM);
sock.sin_addr.s_addr = INADDR_ANY;
if((bind(server_socket, (struct sockaddr*)&sock, sizeof(struct sockaddr_in))) == -1){
perror("Error in bind()");
return -1;
}
listen(server_socket, 1);
FD_ZERO(&allfd);
FD_SET(server_socket, &allfd);
FD_SET(0, &allfd);
printf("\n*******Chatroom Server*******");
while(1){
modfd = allfd;
select(FD_SETSIZE, &modfd, NULL, NULL, NULL);
for(temp = 0; temp < FD_SETSIZE; temp++) {
if(FD_ISSET(temp, &modfd)) {
switch(temp){
case 0:
break;
default:
if(temp == server_socket){
chat_socket = accept(server_socket, NULL, NULL);
}
else{
char msg_buf[MSG_SIZE];
char buf[MAX_LOAD];
char name[MAX_LOAD];
struct msg temp_message;
struct chat_room* local_chat = NULL;
void* (*init_chatroom)() = &chat_room_main;
void* thread_args;
pthread_attr_t attr;
pthread_t tid;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
memset(buf, 0, sizeof(buf));
memset(msg_buf, 0, sizeof(msg_buf));
msg_buf[19]= 0;
int read_val = read(temp, msg_buf, MSG_SIZE);
if(read_val > 0){
memcpy(&temp_message, msg_buf, sizeof(temp_message));
read(temp, buf, temp_message.length - sizeof(temp_message));
memcpy(name, buf, temp_message.length - sizeof(temp_message));
if(temp_message.type == 0) {//if create
local_chat = addRoom(temp, name, chatrooms);
if(local_chat != NULL){
thread_args = (void*)malloc(sizeof(struct chat_room));
memcpy((struct chat_room*) thread_args, local_chat, sizeof(struct chat_room));
pthread_create(&tid, &attr, init_chatroom, thread_args);
local_chat->id = tid;
createResponse(temp, local_chat->port, 10);
}
}
else if(temp_message.type == 1){ //join
local_chat = joinServer(temp, name, chatrooms);
if(local_chat != NULL){
joinResponse(temp, local_chat->port);
}
}
else if(temp_message.type == 2){ //delete
local_chat = findRoom(name, chatrooms);
printf("Deleting Room\n");
if(local_chat != NULL) {
local_chat->port = 0;
close(local_chat->socket_d);
deleteResponse(temp, local_chat);
for(j = 0; j<MAX_CRC; j++){
if(local_chat->clients[j]!=0) {
FD_CLR(local_chat->clients[j], &modfd);
local_chat->clients[j] = 0;
}
}
pthread_cancel(local_chat->id);
}
}
}
else if(read_val <= 0){
FD_CLR(temp, &allfd);
close(temp);
}
}
}
}
}
}
return 0;
}
Client.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <pthread.h>
#define PORT_NUM 12333
#define MSG_SIZE 8
#define MAX_LOAD 246
#define MAX_BUF 256
#define SERVER_IP 32
struct msg {
int type;
int length;
};
struct thread_para {
int port;
struct hostent* host_name;
};
int sendCmd(int chat_socket, char* buf, int type){ //function for sending the command
struct msg temp;
char temp_buf[MAX_LOAD];
char name[MAX_LOAD];
int iterator;
if(type == 0){
iterator = 6;
}
else if(type == 1){
iterator = 4;
}
else if(type == 2){
iterator = 6;
}
for(; iterator < strlen(buf); iterator++){
if(buf[iterator] == ' ') {
continue;
}
else{
break;
}
}
strcpy(name, buf+iterator);
memset(temp_buf, 0, MAX_LOAD);
temp.type = type;
temp.length = sizeof(temp)+strlen(name)+1; //for \0
memcpy(temp_buf, &temp, sizeof(temp));
memcpy(temp_buf+sizeof(temp), name, strlen(name)+1);
write(chat_socket, temp_buf, temp.length);
return 0;
}
void* connectChat(int port_num, struct hostent* host_name, int master){
char buf[MAX_BUF];
char temp_buf[MAX_BUF];
int chat_socket;
int i;
int input;
int temp; //temp fd
fd_set allfd, modfd;
struct sockaddr_in sock;
printf("Successfully Joined Room\n");
memset(buf, 0, sizeof(buf));
memset(&sock, 0, sizeof(sock));
sock.sin_family = AF_INET;
sock.sin_port = htons(port_num);
memcpy((char*)&sock.sin_addr.s_addr, host_name->h_addr, host_name->h_length);
chat_socket = socket(AF_INET, SOCK_STREAM, 0);
if(chat_socket == -1){
perror("Error in creation");
return NULL;
}
if(connect(chat_socket, (struct sockaddr*)&sock, sizeof(struct sockaddr)) < 0 ){
perror("Error in connection");
return NULL;
}
FD_ZERO(&allfd);
FD_SET(chat_socket, &allfd);
FD_SET(0, &allfd);
FD_SET(master, &allfd);
while(1) {
modfd = allfd;
select(FD_SETSIZE, &modfd, NULL, NULL, NULL);
for(temp = 0; temp< FD_SETSIZE; temp++){
memset(buf, 0, sizeof(buf));
memset(temp, 0, sizeof(buf));
if(temp == 0) { //reading from standard in
input = read(0, buf, MAX_BUF);
buf[input-1] = '\0'; //add termination to end
write(chat_socket, buf, strlen(buf));
}
else if(temp == chat_socket){
input = read(0, buf, MAX_BUF);
buf[input] = '\0';
memcpy(temp, buf, input);
//display message
printf("%s \n", temp_buf);
}
else if(temp == master){
struct msg temp_message;
input = read(temp, buf, MSG_SIZE);
memcpy(&temp_message, buf, MSG_SIZE);
if(temp_message.type == 12){
printf("Chatroom has been deleted, Shutting down chatroom\n");
return NULL;
}
}
}
}
return 0;
}
int main(int argc, char* argv[]){
char buf[MAX_BUF];
int chat_socket;
int i;
int input;
int temp; //temp fd
int accept_input = 1; // take input for stdin to create a chat thread
fd_set allfd, modfd;
char server_ip[SERVER_IP];
struct hostent* host_name;
struct sockaddr_in sock;
struct msg temp_message;
pthread_attr_t tattr;
pthread_t tid;
if(argc < 2) {
printf("Please try ./crc <server IP> \n");
return -1;
}
pthread_attr_init(&tattr);
pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
memset(&sock, '\0', sizeof(sock));
sock.sin_family = AF_INET;
sock.sin_port = htons(PORT_NUM);
strcpy(server_ip ,argv[1]);
if((host_name = (struct hostent*)gethostbyname(server_ip)) == NULL){
perror("failed to get host name");
return -1;
}
memcpy((char*)&sock.sin_addr.s_addr, host_name->h_addr, host_name->h_length);
chat_socket = socket(AF_INET, SOCK_STREAM, 0);
if(chat_socket == -1){
perror("Error creating socket");
return -1;
}
if((connect(chat_socket, (struct sockaddr*)&sock, sizeof(sock))) < 0) {
perror("Error connecting");
return -1;
}
FD_ZERO(&allfd); /* first, clear the allfd set */
FD_SET(chat_socket, &allfd); /* adding client to the set */
FD_SET(0, &allfd);
printf("*****Welcome to the Chatroom*****\n");
while(1){
modfd = allfd;
select(FD_SETSIZE, &modfd, NULL, NULL, NULL);
for(temp = 0; temp < FD_SETSIZE; temp++){
if(FD_ISSET(temp, &modfd)){
if(temp == 0){
input = read(0, buf, MAX_BUF);
buf[input-1] = '\0'; //remove \n inserts termination
if((strncasecmp(buf, "create ", 7) == 0)) {
sendCmd(chat_socket, buf, 0);
}
else if((strncasecmp(buf, "join ", 5) == 0)) {
sendCmd(chat_socket, buf, 1);
}
else if((strncasecmp(buf, "delete ", 7)==0)){
sendCmd(chat_socket, buf, 2);
}
else
{
printf("Enter a valid command: create <Room_name>, join <Room_name>, delete <Room_name>\n");
}
}
else if(temp == chat_socket){
input = read(temp, buf, MSG_SIZE);
memcpy(&temp_message, buf, sizeof(temp_message));
if(temp_message.type == 10) {
printf("Created Chatroom\n");
}
else if(temp_message.type == 11){
connectChat(temp_message.length, host_name, chat_socket);
fflush(stdin);
}
else if(temp_message.type == 15) {
printf("Chatroom exits. Type join <Room_name> to join\n");
}
}
}
}
}
close(chat_socket);
return 0;
}
I gave both sets of code just in case it was need. The program is designed to create multiple chat rooms.
invalid argument is the EINVAL error code, which in the context of connect() means:
An invalid argument was detected (e.g., address_len is not valid for the address family, the specified address family is invalid).
You have multiple calls to connect() in your client code (why?), but you did not indicate which call is the one that is failing. In connectChat() at least, sizeof(struct sockaddr) should be sizeof(struct sockaddr_in) instead, or better sizeof(sock), like you do in main().
Also, if either connect() fails, you are leaking the socket returned by socket(). You need to close() it.
Also, gethostbyname() is deprecated, you should be using getaddrinfo() instead. You are creating IPv4 sockets, which only work with IPv4 addresses. You are not checking if gethostbyname() actually returns an IPv4 address (host_name->h_addr_type == AF_INET) before copying the address bytes into your sock variable. At least with getaddrinfo(), you can restrict the output to IPv4 addresses only. You don't have that option with gethostbyname().
Since you're looking for a way to figure out your error, I'll suggest you to use the following Makefile:
CFLAGS=-Wall -g -O2
CC=gcc
LDFLAGS=-lpthread
all: Server Client
Server: Server.c
Client: Client.c
After running make command you'll see a lot of warnings. Some of them:
Server.c: In function ‘createResponse’:
Server.c:81:5: warning: ignoring return value of ‘write’, declared with attribute warn_unused_result [-Wunused-result]
write(chat_socket, temp_buff, MSG_SIZE);
^
Server.c: In function ‘chat_room_main’:
Server.c:237:25: warning: ‘chat_socket’ may be used uninitialized in this function [-Wmaybe-uninitialized]
close(chat_socket);
^
Server.c: In function ‘main’:
Server.c:319:36: warning: array subscript is above array bounds [-Warray-bounds]
msg_buf[19]= 0;
Client.c: In function ‘connectChat’:
Client.c:113:20: warning: passing argument 1 of ‘memset’ makes pointer from integer without a cast
memset(temp, 0, sizeof(buf));
^
So just try to fix these warnings. I mean all of them.
As a school project , i was asked to build a simple HTTP server which can handle and process multiple and simultaneous requests , and to proof that this server will deliver my home page to the internet browser. (Using RFC 1945/HTTP 1.0)
I took a part of my project so you know how it goes
- the server listens to a fixed port. When it receives a TCP connection request, it sets up a TCP connection through another port and services the request in a separate thread. To simplify this programming task, we will develop the code in two stages. In the first stage, you will write a multi-threaded server that simply displays the contents of the HTTP request message that it receives. After this program is running properly, you will add the code required to generate an appropriate response.
Any ideas or samples?
This is a sample of http server with thread pool which I wrote a year ago:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
#include <pthread.h>
#include <malloc.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/wait.h>
#include <ctype.h>
#include <sys/mman.h>
#include <string.h>
#include <errno.h>
#include <dirent.h>
#include <signal.h>
#define KB 1024
/*function declerations*/
void send_content(int fd, int connfd,int isDir,char* path);
void enqueue(int data);
void* dequeue(void* ptr);
void send_to_client(int connfd, char* line);
/*global vars*/
pthread_mutex_t lock;
pthread_cond_t emp;
int sock =0;
int max_threads =0;
int global_count=0;
int finished =1;
int length=0;
/*Queue*/
struct node{
int info;
struct node *ptr;
}*head,*tail;
struct sigaction ready, last;
int main(int argc, char** argv){
int threads;
int requests;
int port;
int i;
int s;
int len_of_packet=1;
int fd;
int port1;
int file;
char content[16000];
char *fileContent ;
int thrd ;
int rc;
char method[KB];
char path[KB];
int s_len=0;
int r_len=0;
int fileLen;
int parsing;
unsigned int addr_size;
struct sockaddr_in serv_addr, client_addr;
struct stat st;
struct dirent *entry;
DIR *dir;
static fd_set readsocks, socks;
char buf[KB] ;
char Uniform_Resource_Identifier[KB];
int servfd;
int socket_of_accept;
off_t chunk=0;
size_t readData;
int sent;
assert (argc ==3 || argc ==4);
threads = strtol(argv[1], NULL, 10);
if ((errno == ERANGE && (threads == LONG_MAX || threads == LONG_MIN))
|| (errno != 0 && threads == 0)) {
perror("Error: strtol has been failed\n");
exit(0);
}
max_threads = threads;
requests = strtol(argv[2], NULL, 10);
if ((errno == ERANGE && (requests == LONG_MAX || requests == LONG_MIN))
|| (errno != 0 && requests == 0)) {
perror("Error: strtol has been failed\n");
exit(0);
}
port = 80;
if (argc == 4){
port = strtol(argv[3], NULL, 10);
if ((errno == ERANGE && (port == LONG_MAX || port == LONG_MIN))
|| (errno != 0 && port == 0)) {
perror("Error: strtol has been failed\n");
exit(0);
}
}
pthread_t threadsArr[threads];
if(pthread_mutex_init(&lock,NULL)!=0){
printf("Error: failed to init mutex\n");
return 1;
}
pthread_cond_init( &emp, NULL);
head=NULL;
tail=NULL;
/*create threads*/
for (thrd=0; thrd<threads;thrd++){
rc = pthread_create(&threadsArr[thrd], NULL, dequeue, (void*) &thrd);
if (rc){
printf("Error: failed to create thread\n");
return 1;
}
}
/* create socket */
servfd = socket(AF_INET, SOCK_STREAM, 0);
sock = servfd;
if (servfd == -1) {
printf("Error creating socket\n");
exit(1);
}
/* init prepernces */
memset(&serv_addr, '0', sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(port);
/* bind */
setsockopt(servfd, SOL_SOCKET, SO_REUSEADDR, (const char *) &len_of_packet,sizeof(int));
if (bind(servfd, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) == -1) {
printf("Error: Bind has been failed\n");
perror ("Bind: ");
exit(1);
}
/*listen */
if (listen(servfd, requests) == -1) {
printf("Error: Listen has been failed\n");
perror ("Listen: ");
exit(1);
}
FD_ZERO(&socks);
FD_SET(servfd, &socks);
int startLen = strlen("HTTP/1.0 200 OK\r\n"
"Content-Type: text/html; charset=UTF-8\r\n\r\n"
"<doctype !html><html><head><title></title>"
"<style>body"
"h1 { font-size:4cm; text-align: center; color: black;"
"}</style></head>"
"<body><h1>Service Unavailable (HTTP 503)</h1></body></html>\r\n");
int endLen = strlen("</h1></body></html>\r\n");
while(1){
sigfillset(&ready.sa_mask);
ready.sa_handler = SIG_IGN;
ready.sa_flags = 0;
if (sigaction(SIGINT, &ready,&last) || sigaction(SIGINT,&last,NULL)){
finished=0;
for(i=0; i<threads; i++){
rc = pthread_join(threadsArr[i], NULL);
if(rc != 0){
printf("Error: join has been failed\n");
perror("Join: ");
return 1;
}
}
pthread_mutex_destroy(&lock);
close(sock);
}
addr_size = sizeof(client_addr);
socket_of_accept = accept(servfd, (struct sockaddr *) &client_addr, &addr_size);
if (socket_of_accept == -1) {
printf("Error: Accept has been failed\n");
perror ("Accept: ");
exit(1);
}
enqueue(socket_of_accept);
if (length <= requests){
/*recieve message*/
r_len = recv(socket_of_accept, buf, KB,0);
if (r_len == -1){
printf("Error: recieve has been %d\n", socket_of_accept);
close(socket_of_accept);
exit(1);
}
sscanf(buf,"%s %s", method, Uniform_Resource_Identifier);
sscanf(Uniform_Resource_Identifier,"%s", path);
printf("method = %s, path = %s\n", method, path);
/*GET OR POST*/
if(strcmp(method, "GET")!= 0 && strcmp(method, "POST") != 0){
char response[] = "HTTP/1.0 200 OK\r\n"
"Content-Type: text/html; charset=UTF-8\r\n\r\n"
"<doctype !html><html><head><title></title>"
"<style>body"
"h1 { font-size:4cm; text-align: center; color: black;"
"}</style></head>"
"<body><h1>Service Unavailable (HTTP 503)</h1></body></html>\r\n";
s_len = send(socket_of_accept, response, strlen(response), 0);
if (s_len == -1){
printf("Error: failed to send message %s to client %d\n", response, socket_of_accept);
close(socket_of_accept);
exit(1);
}
}
if (stat(path, &st) == -1){ /*file not found*/
char response[] = "HTTP/1.0 200 OK\r\n"
"Content-Type: text/html; charset=UTF-8\r\n\r\n"
"<doctype !html><html><head><title></title>"
"<style>body"
"h1 { font-size:4cm; text-align: center; color: black;"
"}</style></head>"
"<body><h1>Not Found (HTTP 404)</h1></body></html>\r\n";
s_len = send(socket_of_accept, response, strlen(response), 0);
if (s_len == -1){
printf("Error: failed to send message %s to client %d\n", response, socket_of_accept);
close(socket_of_accept);
exit(1);
}
close(socket_of_accept);
}else {
if(S_ISDIR(st.st_mode)){/*directory*/
if((dir = opendir (path)) != NULL){
send_content(fd, socket_of_accept,1,path);
close(socket_of_accept);
}else{
printf("Error: failed to open directory: %s\n", path);
}
}else if(S_ISREG(st.st_mode) && st.st_size != 0){/*regular file*/
fd=open(path,O_RDONLY);
send_content(fd, socket_of_accept,0,path);
close(file);
close(socket_of_accept);
}
else{/*empty file*/
char response[] = "HTTP/1.0 200 OK\r\n"
"Content-Type: text/html; charset=UTF-8\r\n\r\n"
"<doctype !html><html><head><title></title>"
"<style>body"
"h1 { font-size:4cm; text-align: center; color: black;"
"}</style></head>"
"<body><h1> </h1></body></html>\r\n";
s_len = send(socket_of_accept, response, strlen(response), 0);
if (s_len == -1){
printf("Error: failed to send message %s to client %d\n", response, socket_of_accept);
close(socket_of_accept);
exit(1);
}
}
}
}else{/*full queue*/
/*send (HTTP 503)*/
char response[3000] = "HTTP/1.0 200 OK\r\n"
"Content-Type: text/html; charset=UTF-8\r\n\r\n"
"<doctype !html><html><head><title></title>"
"<style>body"
"h1 { font-size:4cm; text-align: center; color: black;"
"}</style></head>"
"<body><h1>Service Unavailable (HTTP 503)</h1></body></html>\r\n";
s_len = send(socket_of_accept, response, strlen(response), 0);
if (s_len == -1){
printf("Error: unable to send a message %s to: %d\n", response, socket_of_accept);
close(socket_of_accept);
exit(1);
}
close(socket_of_accept);
}
}
return 0;
}
void send_content(int fd, int connfd,int isDir,char* path){
char line[KB];
memset(line, 0, sizeof(line));
send_to_client(connfd, "HTTP/1.0 200 OK\r\n\r\n");
int return_value;
if(!isDir){
while ((return_value=read(fd, line, KB)) > 0) {
send_to_client(connfd, line);
memset(line, 0, sizeof(line));
}
if (return_value < 0){
perror("Error read");
send_to_client(connfd, "Error Resorces\n");
return;
}
}
else {
DIR *d;
struct dirent *dir;
d = opendir(path);
if (d)
{
while ((dir = readdir(d)) != NULL)
{
strcpy(line,dir->d_name);
strcat(line,"\n");
send_to_client(connfd,line);
memset(line, 0, sizeof(line));
}
closedir(d);
}
}
}
/*enqueue*/
void enqueue(int data)
{
int rc;
struct node* temp;
temp = (struct node *)malloc(1*sizeof(struct node));
if(temp == NULL){
printf("Error: couldn't allocate memory\n");
exit(1);
}
temp->ptr = NULL;
temp->info = data;
if (pthread_mutex_lock(&lock) !=0){
printf("Error: failed to lock\n");
exit(1);
}
if (length == 0) /*empty queue*/
{
head = temp;
}else
{
tail->ptr = temp;
}
tail = temp;
length++;
rc = pthread_cond_broadcast(&emp);
assert(rc==0);
if (pthread_mutex_unlock(&lock)!=0){
printf("Error: failed to unlock\n");
pthread_exit(0);
}
return;
}
void send_to_client(int connfd, char* line){
int nsent, totalsent;
int notwritten = strlen(line);
/* keep looping until nothing left to write*/
totalsent = 0;
while (notwritten > 0){
/* notwritten = how much we have left to write
totalsent = how much we've written so far
nsent = how much we've written in last write() call */
nsent = write(connfd, line + totalsent, notwritten);
assert(nsent>=0); // check if error occured (client closed connection?)
totalsent += nsent;
notwritten -= nsent;
}
}
/*dequeue*/
void* dequeue(void* ptr)
{
int rc;
int i=0;
int thread = *((int*)ptr);
struct node* temp;
while(finished){
if (pthread_mutex_lock(&lock) !=0){
printf("Error: lock has been failed\n");
pthread_exit(0);
}
while (length == 0)
{
rc = pthread_cond_wait(&emp, &lock);
assert(rc == 0);
}
int info = head->info;
temp = head;
head = head->ptr;
free(temp);
length--;
rc = pthread_cond_broadcast(&emp);
assert(rc==0);
if (pthread_mutex_unlock(&lock)!=0){
printf("Error: unlock has been failed\n");
pthread_exit(0);
}
}
pthread_exit(0);
}
I have similar problem as here:
Netlink sockets and libnl - nl_recvmsgs_default returning -16 (EBUSY)
But nl_recvmsgs_defaul() return this error value -22 (NLE_MSGTYPE_NOSUPPORT).
Does anyone have an idea why I get this error?
Here is example program:
Kernel:
enum {
DOC_EXMPL_A_UNSPEC,
DOC_EXMPL_A_MSG,
__DOC_EXMPL_A_MAX,
};
#define DOC_EXMPL_A_MAX (__DOC_EXMPL_A_MAX - 1)
#define VERSION_NR 1
static struct genl_family doc_exmpl_gnl_family = {
.id = GENL_ID_GENERATE,
.hdrsize = 0,
.name = "CONTROL_EXMPL",
.version = VERSION_NR,
};
enum {
DOC_EXMPL_C_UNSPEC,
DOC_EXMPL_C_ECHO,
__DOC_EXMPL_C_MAX,
};
#define DOC_EXMPL_C_MAX (__DOC_EXMPL_C_MAX - 1)
int doc_exmpl_echo(struct sk_buff *skb_2, struct genl_info *info)
{
struct sk_buff *skb;
struct nlattr *na, *pos;
int len, rem, type, rc;
char * mydata;
void *msg_head;
if (info == NULL)
goto out;
len = nlmsg_attrlen(info->nlhdr, GENL_HDRLEN);
na = nlmsg_attrdata(info->nlhdr, GENL_HDRLEN);
printk(KERN_DEBUG "len1: %d, sizeof: %d ,len: %d", nlmsg_len(info->nlhdr),
GENL_HDRLEN, len);
nla_for_each_attr(pos, na, len, rem) {
type = nla_type(pos);
mydata = (char *) nla_data(pos);
printk(KERN_DEBUG "Type: %d", type);
if (mydata != NULL)
printk(KERN_DEBUG "Data: %s", mydata);
}
skb = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
if (skb == NULL)
goto out;
msg_head = genlmsg_put(skb, 0, info->snd_seq+1, &doc_exmpl_gnl_family, 0, DOC_EXMPL_C_ECHO);
if (msg_head == NULL) {
rc = -ENOMEM;
goto out;
}
rc = nla_put_u8(skb, DOC_EXMPL_A_MSG, 8);
if (rc != 0)
goto out;
/* finalize the message */
genlmsg_end(skb, msg_head);
//rc = genlmsg_unicast(skb,info->snd_pid );
rc = genlmsg_unicast(genl_info_net(info), skb,info->snd_pid);
if (rc != 0)
goto out;
printk(KERN_DEBUG "End");
return 0;
out:
printk("an error occured in doc_exmpl_echo:\n");
return 0;
}
struct genl_ops doc_exmpl_gnl_ops_echo = {
.cmd = DOC_EXMPL_C_ECHO,
.flags = 0,
.policy = NULL,
.doit = doc_exmpl_echo,
.dumpit = NULL,
};
Userspace code
#include <stdio.h>
#include <stdlib.h>
#include <netlink/netlink.h>
#include <netlink/genl/genl.h>
#include <netlink/genl/ctrl.h>
#include <netlink/socket.h>
#include <netlink/msg.h>
#include <net/if.h>
static int expectedId;
static int nlCallback(struct nl_msg* msg, void* arg)
{
struct nlmsghdr* ret_hdr = nlmsg_hdr(msg);
struct nlattr *tb_msg[2 + 1];
char *str;
if (ret_hdr->nlmsg_type != expectedId)
{
// what is this??
return NL_STOP;
}
struct genlmsghdr *gnlh = (struct genlmsghdr*) nlmsg_data(ret_hdr);
nla_parse(tb_msg, 2, genlmsg_attrdata(gnlh, 0),
genlmsg_attrlen(gnlh, 0), NULL);
if (tb_msg[1]) {
str = nla_get_string(tb_msg[1]);
printf("str: %s", str);
}
return 0;
}
int main(int argc, char **argv) {
int cmd, rc;
struct nl_handle *sk;
struct nl_msg *msg;
//allocate socket
sk = nl_handle_alloc();
//connect to generic netlink
genl_connect(sk);
//find the nl80211 driver ID
expectedId = genl_ctrl_resolve(sk, "CONTROL_EXMPL");
//allocate a message
msg = nlmsg_alloc();
cmd = 1;
int flags = 0;
// setup the message
genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, expectedId, 0, NLM_F_REQUEST, cmd, 1);
NLA_PUT_STRING(msg, 3, "Hello test");
nl_send_auto_complete(sk, msg);
nl_socket_modify_cb(sk, NL_CB_VALID, NL_CB_CUSTOM,
nlCallback, NULL);
rc = nl_recvmsgs_default(sk);
printf("rc = %d \n", rc);
nlmsg_free(msg);
return 0;
nla_put_failure:
nlmsg_free(msg);
return 1;
}
OK I found the problem.
I have bad sequencer number in kernel code, it should be:
genlmsg_put(skb, 0, info->snd_seq, &doc_exmpl_gnl_family, 0, DOC_EXMPL_C_ECHO);
It's the same problem as here: Netlink sockets and libnl - nl_recvmsgs_default returning -16 (EBUSY) but I got other error.