/*************************************************************************
> File Name: udp_client.c
> Author: chad
> Mail: linczone@163.com
************************************************************************/
#include <sys/types.h>
#include <sys/socket.h>
#include <pthread.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <strings.h>
#include <pthread.h>
#include <errno.h>
#include <signal.h>
#include "udp_msg.h"
#include "read_cmd.h"
#include "my_debug.h"
#define OFFSET_OF(obj_type,mb) ((int)&(((obj_type*)0)->mb))
#define MSG_SIZE(msg) OFFSET_OF(struct Msg,dat)+msg.len
#define MESSAGE_SIZE( message ) OFFSET_OF(struct message,text)+message.len
#define MAX(a, b) ((a) > (b)?(a):(b))
#define MIN(a, b) ((a) > (b)?(b):(a))
/*
模块内局部变量
*/
static int debugModule = MY_SECTION_MAIN;
char *command = NULL;
char **parameters = NULL;
extern int errno;
struct userinfo userlist[5];
int user_num = 0;
int P2P_No = 0;//P2P通信对方的序号
struct sockaddr_in host_addr;//服务器
char myname[20]={'c','o','m','m','a','n','d',0};
int sock;
void rec_cleanup(void *arg)
{
printf("cleaning up ressources allocated by rec thread \n");
}
void print_userlist(void)
{
int i = 0;
while( i < user_num )
{
printf("\n----------------------------\n");
printf("%d. username: %s\n", i+1, userlist[i].username );
printf(" ip: %s\n", userlist[i].ip );
printf(" port: %d\n", userlist[i].port );
printf("----------------------------\n");
i ++;
}
}
int get_user_no( const char* username )
{
int i = 0;
while( i < user_num )
{
i++;
if( !strcmp( userlist[i-1].username, username ))
return i;
}
return -1;
}
int SendMsg(int sock, struct sockaddr *addr, struct Msg msg )
{
int n = sendto(sock, &msg, MSG_SIZE(msg), 0, addr, sizeof(struct sockaddr));
if( n < 0 )
{
perror("sendto");
}
return n;
}
void *recthread( void *param )
{
char buff[512];
int sock = *(int*)param;
int len;
struct Msg msg;
struct sockaddr_in addr;
bzero( &msg, sizeof(msg) );
while(1)
{
int n = recvfrom(sock, &msg, sizeof(msg), 0, (struct sockaddr *)0, NULL);
if (n>0)
{
my_debug_print_buf(debugModule, DEBUG_LEVEL_INFO)("",(char*)&msg,n);
if( msg.id == USERLIST )//收到登录信息
{
struct userinfo uif;
bzero(&uif, sizeof(struct userinfo));
len = msg.len;
user_num = 0;
while( len != 0 )
{
struct userinfo uif;
memcpy( &uif, msg.dat+user_num*sizeof(uif), sizeof(uif));
len -= sizeof(uif);
printf("\n----------------------------\n");
printf("%d. username: %s\n", user_num+1, uif.username );
printf(" ip: %s\n", uif.ip );
printf(" port: %d\n", uif.port );
printf("----------------------------\n");
memcpy( &userlist[user_num], &uif, sizeof(uif) );
user_num ++;
}
}
else if( msg.id == CONNECTUSER )//链接请求
{
struct linkinfo connect;
memcpy( &connect, msg.dat, msg.len );
addr.sin_family = AF_INET;
addr.sin_port = htons(connect.srcinfo.port);
addr.sin_addr.s_addr = inet_addr(connect.srcinfo.ip);
if(addr.sin_addr.s_addr == INADDR_NONE)
{
my_debug( debugModule, DEBUG_LEVEL_ERROR)("Incorrect ip address!\n");
continue;
}
print_date( debugModule, DEBUG_LEVEL_INFO );
my_debug( debugModule, DEBUG_LEVEL_INFO)("receive connect from: %s:%d\n",connect.srcinfo.ip,connect.srcinfo.port);
my_debug( debugModule, DEBUG_LEVEL_INFO)("send connect to: %s:%d\n",connect.srcinfo.ip,connect.srcinfo.port);
my_debug( debugModule, DEBUG_LEVEL_INFO)("send connect to host: %s:%d\n",inet_ntoa(host_addr.sin_addr),ntohs(host_addr.sin_port));
msg.id = ACK;
msg.len = sizeof(connect);
struct userinfo uif;
memcpy( &uif, &connect.destinfo, sizeof(uif));
memcpy( &connect.destinfo, &connect.srcinfo, sizeof(uif));
memcpy( &connect.srcinfo, &uif, sizeof(uif));// 源与目标信息调换
memcpy( msg.dat, &connect, msg.len );
my_debug( debugModule, DEBUG_LEVEL_INFO)("send ack\n");
SendMsg( sock, (struct sockaddr *)&addr, msg);//向发起者回复确认,表示我已经开好洞
usleep(100*1000);//100ms
SendMsg( sock, (struct sockaddr *)&host_addr, msg);//发送链接请求到服务器
}
else if( msg.id == ACK )//链接请求被受理,只有发起者会收到该消息
{
struct linkinfo connect;
memcpy( &connect, msg.dat, msg.len );
struct message message;
bzero( &message, sizeof(message) );
memcpy(message.user.srcinfo.username, myname , strlen(myname));
int No = get_user_no(myname);
if( No > user_num || No < 0 )
{
print_userlist();
my_debug( debugModule, DEBUG_LEVEL_ERROR)("Incorrect username\n");
continue;
}
//源是自己
memcpy(message.user.srcinfo.ip, userlist[No-1].ip , strlen(userlist[No-1].ip));
message.user.srcinfo.port = userlist[No-1].port;
memcpy(&message.user.destinfo, &connect.srcinfo, sizeof(connect.srcinfo));
message.len = 3;
strcpy( message.text, "ok" );
msg.len = MESSAGE_SIZE( message );
msg.id = P2PLINK;
memcpy( msg.dat, &message, msg.len );
print_date( debugModule, DEBUG_LEVEL_INFO );
my_debug( debugModule, DEBUG_LEVEL_INFO)("receive ACK from: %s:%d\n",connect.srcinfo.ip,connect.srcinfo.port);
my_debug( debugModule, DEBUG_LEVEL_INFO)("send p2plink to: %s:%d\n",connect.srcinfo.ip,connect.srcinfo.port);
//不再经过服务器,直接发送到目标端点
addr.sin_family = AF_INET;
addr.sin_port = htons(connect.srcinfo.port);
addr.sin_addr.s_addr = inet_addr(connect.srcinfo.ip);
if(addr.sin_addr.s_addr == INADDR_NONE)
{
my_debug( debugModule, DEBUG_LEVEL_ERROR)("Incorrect ip address!");
continue;
}
SendMsg( sock, (struct sockaddr *)&addr, msg);//向目标机发送第一条消息
}
else if(msg.id == P2PLINK)
{
struct message message;
memcpy( &message, msg.dat , msg.len );
if( !strcmp(message.user.srcinfo.username, myname) )//如果源是自己,说明我发起的P2P链接建立成功
{
print_date( debugModule, DEBUG_LEVEL_INFO );
my_debug( debugModule, DEBUG_LEVEL_INFO)("Launched by I create P2P links to establish a success!\n");
message.len = 9;
strcpy( message.text, "link ok!" );
msg.len = MESSAGE_SIZE( message );
msg.id = MSG_TEXT;
memcpy( msg.dat, &message, msg.len );
//不再经过服务器,直接发送到目标端点
addr.sin_family = AF_INET;
addr.sin_port = htons(message.user.destinfo.port);
addr.sin_addr.s_addr = inet_addr(message.user.destinfo.ip);
if(addr.sin_addr.s_addr == INADDR_NONE)
{
my_debug( debugModule, DEBUG_LEVEL_ERROR)("Incorrect ip address!");
continue;
}
SendMsg( sock, (struct sockaddr *)&addr, msg);//发送第二条消息
P2P_No = get_user_no(message.user.destinfo.username);
} else {//收到发起者发过来的P2P数据,说明链接建立成功
//不再经过服务器,直接发送到目标端点
addr.sin_family = AF_INET;
addr.sin_port = htons(message.user.srcinfo.port);
addr.sin_addr.s_addr = inet_addr(message.user.srcinfo.ip);
if(addr.sin_addr.s_addr == INADDR_NONE)
{
my_debug( debugModule, DEBUG_LEVEL_ERROR)("Incorrect ip address!");
continue;
}
SendMsg( sock, (struct sockaddr *)&addr, msg);//发送第一条消息
print_date( debugModule, DEBUG_LEVEL_INFO );
my_debug( debugModule, DEBUG_LEVEL_INFO)("Already establish P2P links with the initiator\n");
P2P_No = get_user_no(message.u