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

📄 connection.c

📁 gphone is a net phone base on the rtp protocol. It is simple but pratical and can be a good sample f
💻 C
字号:
/*  Gnome-o-Phone - A program for internet telephony  Copyright (C) 1999  Roland Dreier    This program is free software; you can redistribute it and/or modify  it under the terms of the GNU General Public License as published by  the Free Software Foundation; either version 2 of the License, or  (at your option) any later version.    This program is distributed in the hope that it will be useful,  but WITHOUT ANY WARRANTY; without even the implied warranty of  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the  GNU General Public License for more details.    You should have received a copy of the GNU General Public License  along with this program; if not, write to the Free Software  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.    $Id: connection.c 1.13 Sat, 11 Dec 1999 23:53:26 -0600 dreier $*/#ifdef HAVE_CONFIG_H#include <config.h>#endif#include "connection.h"#include <unistd.h>#include <stdlib.h>#include <sys/time.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <glib.h>#include <math.h>#include <string.h>#include <netdb.h>#include <sys/utsname.h>#include "rtp.h"#include "rtp-packet.h"#include "rtcp-packet.h"#include "listen.h"#include "thread.h"#include "sound.h"#include "request.h"#include "gphone.h"#include "gphone-lib.h"extern int Remote_Port;static const gchar App_Name[] = { /* Name for APP packets */  'g', 'p', 'h', 'n'};static GHashTable *Source_Table;G_LOCK_DEFINE_STATIC(Source_Table);static int Data_Sock;static int Control_Sock;static int Send_Sock;static guint32 My_Ssrc;static guint16 My_Seq;static guint32 My_Timestamp;static struct sockaddr_in Send_Addr;static gchar *Dest_Hostname;static struct timeval Next_Report;static guint32 Rtp_Packets_Sent;static guint32 Rtp_Octets_Sent;static int Avg_Rtcp_Size;static int We_Called;static gintssrc_equal(gconstpointer a, gconstpointer b){  return *((const guint32 *) a) == *((const guint32 *) b);}static guintssrc_hash(gconstpointer key){  return (guint) *((const guint32 *) key);}static voidopen_sockets(int port){  struct sockaddr_in address;      if ((Data_Sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {    gphone_perror_exit("*** open_sockets : socket1", 1);  }  address.sin_family = AF_INET;  address.sin_port = g_htons(port);  address.sin_addr.s_addr = INADDR_ANY;  memset(&address.sin_zero, 0, sizeof address.sin_zero);  if (bind(Data_Sock, (struct sockaddr * ) &address,           sizeof (struct sockaddr_in)) < 0) {    gphone_perror_exit("bind", 1);  }      if ((Control_Sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {    gphone_perror_exit("*** open_sockets : socket2", 1);  }      address.sin_family = AF_INET;  address.sin_port = g_htons(port + 1);  address.sin_addr.s_addr = INADDR_ANY;  memset(&address.sin_zero, 0, sizeof address.sin_zero);  if (bind(Control_Sock, (struct sockaddr * ) &address,           sizeof (struct sockaddr_in)) < 0) {    gphone_perror_exit("bind", 1);  }  if ((Send_Sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {    gphone_perror_exit("*** open_sockets : socket3", 1);  }}static voidset_next_report_time(int packetsize, int init){  double interval;  struct timeval tv, now;  /* some bad hardwired constants to be fixed here */  interval = rtcp_interval(2, 2, 33 * 50 * .05, 1, packetsize,                           &Avg_Rtcp_Size, init);  tv.tv_sec = (time_t) floor(interval);  tv.tv_usec = (time_t) ((interval - floor(interval)) * 1.0e6);           if (gettimeofday(&now, 0) < 0) {    gphone_perror_exit("*** set_next_report_time : gettimeofday", 1);  }  timeradd(&now, &tv, &Next_Report);}static gchar *make_cname(void){  gchar *cname;  struct utsname un;  if ((cname = getenv("GPHONE_CNAME")) != NULL) {    return cname;  } else {    if (uname(&un) < 0) {      gphone_perror_exit("*** make_cname : uname", 1);    }    cname = g_strconcat(g_get_user_name(), "@", un.nodename, NULL);    return cname;  }}static intsend_rtcp_sr(void){  Rtcp_Compound compound;  int packetsize;  int nsdes;  Rtcp_Sdes_Type *type;  char **value;  gint8 *length;  compound = rtcp_compound_new_allocate(RTP_MTU);  rtcp_compound_add_sr(compound, My_Ssrc, My_Timestamp,                       Rtp_Packets_Sent, Rtp_Octets_Sent);  nsdes = 1;  type = g_new(Rtcp_Sdes_Type, nsdes);  value = g_new(char *, nsdes);  length = g_new(gint8, nsdes);  type[0] = RTCP_SDES_CNAME;  value[0] = make_cname();  length[0] = strlen(value[0]);  rtcp_compound_add_sdes(compound, My_Ssrc, nsdes,                         type, value, length);  Send_Addr.sin_port = g_htons(Remote_Port + 1);  rtcp_compound_send(compound, Send_Sock, &Send_Addr);  g_free(value[0]);  g_free(type);  g_free(value);  g_free(length);  packetsize = rtcp_compound_get_length(compound);  rtcp_compound_free(compound);  return packetsize;}voidsend_switch_packet(void){  Rtcp_Compound compound;  guint32 message;  compound = rtcp_compound_new_allocate(RTP_MTU);  rtcp_compound_add_sr(compound, My_Ssrc, My_Timestamp,                       Rtp_Packets_Sent, Rtp_Octets_Sent);  message = g_htonl(GPHONE_APP_SWITCH);  rtcp_compound_add_app(compound, My_Ssrc, App_Name,                        &message, sizeof message);  Send_Addr.sin_port = g_htons(Remote_Port + 1);  rtcp_compound_send(compound, Send_Sock, &Send_Addr);  rtcp_compound_free(compound);}voidmaybe_send_rtcp(void){  int packetsize;  struct timeval tv;  if (gettimeofday(&tv, 0) < 0) {    gphone_perror_exit("*** maybe_send_rtcp : gettimeofday", 1);  }  if (timercmp(&tv, &Next_Report, >)) {    packetsize = send_rtcp_sr();        /* 28 is UDP encapsulation */    set_next_report_time(packetsize + 28, 0);  }}voidconnection_init(int port){  Source_Table = g_hash_table_new(ssrc_hash, ssrc_equal);  Dest_Hostname = NULL;  Rtp_Packets_Sent = 0;  Rtp_Octets_Sent = 0;  We_Called = 0;  open_sockets(port);}voidconnection_call(gchar *hostname){  struct in_addr call_host;     /* host info of computer to call */  if (find_host(hostname, &call_host)) {    Send_Addr.sin_family = AF_INET;    Send_Addr.sin_port = g_htons(Remote_Port);    g_memmove(&Send_Addr.sin_addr.s_addr,              &call_host, sizeof (struct in_addr));        My_Seq = random32(1);    My_Ssrc = random32(2);    My_Timestamp = random32(3);    Dest_Hostname = g_strdup(hostname);        if (get_sound_duplex() == HALF_DUPLEX) {      set_status(STAT_TALK);    } else {      set_status(STAT_TALK_FD);    }    set_next_report_time(0, 1);        We_Called = 1;  } else {    /* FIX: Raise error somehow */  }}gbooleanconnection_connected(void){  gboolean connected;    connected = (Dest_Hostname != NULL) ? TRUE : FALSE;  return connected;}gchar *connection_hostname(void){  if (connection_connected()) {    return g_strdup(Dest_Hostname);  } else {    return NULL;  }}rtp_source *find_member(guint32 src) {  rtp_source *s;  G_LOCK(Source_Table);  s = (rtp_source *) g_hash_table_lookup(Source_Table, &src);  G_UNLOCK(Source_Table);  return s;}static rtp_source *add_member(guint32 src, guint16 seq, struct in_addr *addr){  const int MIN_SEQUENTIAL = 2;  int i;  guint32 *srcptr;  rtp_source *s;  struct hostent *h;  s = g_new(rtp_source, 1);  init_seq(s, seq);  s -> probation = MIN_SEQUENTIAL;  s -> ssrc = src;  for (i = 0; i < RTCP_SDES_MAX; i++) {    s -> sdes_len[i] = 0;  }  g_memmove(&s -> address, addr, sizeof (struct in_addr));  h = gethostbyaddr((char *) addr, sizeof (struct in_addr), AF_INET);    if (h != NULL) {    s -> hostname = g_strdup(h -> h_name);  } else {    s -> hostname = g_strdup(inet_ntoa(*addr));  }  g_log("GPHONE", G_LOG_LEVEL_INFO,        "New source: %4.4x  %s", src, s -> hostname);  G_LOCK(Source_Table);  srcptr = g_new(guint32, 1);  *srcptr = src;  g_hash_table_insert(Source_Table, srcptr, s);  if (g_hash_table_size(Source_Table) == 1) { /* added our first host */    if (We_Called) {      if (memcmp(addr, &Send_Addr.sin_addr.s_addr,                 sizeof (struct in_addr))) {        /* We got a packet from someone we didn't call */        g_warning("We didn't call THIS guy");      }    } else {      int seed = 3;      Send_Addr.sin_family = AF_INET;      g_memmove(&Send_Addr.sin_addr.s_addr, addr, sizeof(struct in_addr));            My_Seq = random32(1);      My_Timestamp = random32(2);      while ((My_Ssrc = random32(seed)) == src) {       /* try to avoid collision */        seed++;      }      Dest_Hostname = g_strdup(s -> hostname);            if (get_sound_duplex() == HALF_DUPLEX) {        set_status(STAT_LISTEN);      } else {        set_status(STAT_TALK_FD);      }      set_next_report_time(0, 1);    }   }  G_UNLOCK(Source_Table);  return s;}voidmember_sdes(rtp_source *s, guint8 type, char *data, guint8 length){  if (s == NULL) {    g_warning("SDES from unknown source.");    return;  }  g_assert(type < RTCP_SDES_MAX);  if (s -> sdes_len[type] != 0) {    g_free(s -> sdes_data[type]);  }  s -> sdes_len[type] = length;  s -> sdes_data[type] = g_malloc(length);  g_memmove(s -> sdes_data[type], data, length);  {    int i;    gchar *data;    data = g_malloc(length + 1);    for (i = 0; i < length; i++) {      data[i] = s -> sdes_data[type][i];    }    data[length] = '\0';    g_log("GPHONE", G_LOG_LEVEL_DEBUG,          "    type: %d length: %d   %s", type, length, data);    g_free(data);  }}static gbooleancheck_from(struct sockaddr_in *fromaddr, rtp_source *s){  return (memcmp(&s -> address, &fromaddr -> sin_addr,                 sizeof (struct in_addr)) == 0) ? TRUE : FALSE;}voidrtp_send(gchar *buf, int nbytes, rtp_payload_t pt, guint32 nsamp){  Rtp_Packet packet;  packet = rtp_packet_new_allocate(nbytes, 0, 0);  rtp_packet_set_csrc_count(packet, 0);  rtp_packet_set_extension(packet, 0);  rtp_packet_set_padding(packet, 0);  rtp_packet_set_version(packet, RTP_VERSION);  rtp_packet_set_payload_type(packet, pt);  rtp_packet_set_marker(packet, 0);  rtp_packet_set_ssrc(packet, My_Ssrc);   rtp_packet_set_seq(packet, My_Seq);  rtp_packet_set_timestamp(packet, My_Timestamp);  ++My_Seq;  My_Timestamp += nsamp;  g_memmove(rtp_packet_get_payload(packet), buf, nbytes);  Send_Addr.sin_port = g_htons(Remote_Port);  rtp_packet_send(packet, Send_Sock, &Send_Addr);  ++Rtp_Packets_Sent;  Rtp_Octets_Sent += rtp_packet_get_packet_len(packet);  rtp_packet_free(packet);}static voidparse_rtp_packet(Rtp_Packet packet, struct sockaddr_in *fromaddr){  rtp_source *source;  if (rtp_packet_get_version(packet) != RTP_VERSION) {    g_warning("RTP packet version != %d", RTP_VERSION);  }  source = find_member(rtp_packet_get_ssrc(packet));  if (source == NULL) {    source = add_member(rtp_packet_get_ssrc(packet),                        rtp_packet_get_seq(packet),                        &fromaddr -> sin_addr);  }  if (check_from(fromaddr, source)) {    if (update_seq(source, rtp_packet_get_seq(packet))) {      switch(rtp_packet_get_payload_type(packet)) {      case PAYLOAD_GSM:        /* really should do something with sequence/timestamp here */        play_gsm_data(rtp_packet_get_payload(packet),                      rtp_packet_get_payload_len(packet));        break;      default:        g_warning("Unsupported RTP payload type %d",                  rtp_packet_get_payload_type(packet));        break;      }    }  } else {                      /*  source doesn't match */    g_warning("Got RTP packet from new host %s, ssrc %x\n(old host %s, ssrc %x)",              inet_ntoa(fromaddr -> sin_addr),              rtp_packet_get_ssrc(packet),              inet_ntoa(source -> address),              source -> ssrc);  }}static voidparse_rtcp_app_packet(Rtcp_Packet packet,                      struct sockaddr_in *fromaddr){  int match;  gchar *name;  gpointer data;  Request req;  name = rtcp_app_packet_get_name(packet);  data = rtcp_app_packet_get_data(packet);  match = (memcmp(name, App_Name, sizeof App_Name) == 0);  if (match) {    guint32 type = g_ntohl(*((guint32 *) data));    switch (type) {    case GPHONE_APP_SWITCH:      req = g_malloc(sizeof *req);            req->type = REQUEST_SWITCH;      req->data_len = 0;      req->data = NULL;            listen_add_request(req);      g_log("GPHONE", G_LOG_LEVEL_DEBUG,            "    switch");      break;    default:      g_warning("Unrecognized gphn APP packet type %d\n",                type);      break;    }  } else {    int i;    gchar bad_name[4 + 1];    for (i = 0; i < 4; i++) {      bad_name[i] = name[i];    }    bad_name[4] = '\0';    g_warning("APP packet with unrecognized name '%s'",              bad_name);  }}static voidparse_rtcp_packet(Rtcp_Packet packet, struct sockaddr_in *fromaddr){  g_log("GPHONE", G_LOG_LEVEL_DEBUG,        "read RTCP packet of length %d", rtcp_packet_get_length(packet));  switch (rtcp_packet_get_packet_type(packet)) {  case RTCP_SR:    g_log("GPHONE", G_LOG_LEVEL_DEBUG,          "  SR");    break;  case RTCP_RR:    g_log("GPHONE", G_LOG_LEVEL_DEBUG,          "  RR");    break;  case RTCP_SDES:    g_log("GPHONE", G_LOG_LEVEL_DEBUG,          "  SDES, count = %d",          rtcp_packet_get_count(packet));    rtcp_read_sdes(packet, find_member, member_sdes);    break;  case RTCP_BYE:    g_log("GPHONE", G_LOG_LEVEL_DEBUG,          "  BYE");    break;  case RTCP_APP:    g_log("GPHONE", G_LOG_LEVEL_DEBUG,          "  APP");    parse_rtcp_app_packet(packet, fromaddr);    break;  default:    g_assert_not_reached();    break;  }}static voidparse_rtcp_compound(Rtcp_Compound compound, struct sockaddr_in *fromaddr){  rtcp_compound_foreach(compound,                        (Rtcp_Foreach_Func) parse_rtcp_packet,                        fromaddr);}intconnection_listen(float timeout){  int fdmax;  int rtp_read = 0;  fd_set fds;  struct timeval tv;  struct sockaddr_in fromaddr;  fdmax = MAX(Data_Sock, Control_Sock) + 1;  FD_ZERO(&fds);  FD_SET(Data_Sock, &fds);  FD_SET(Control_Sock, &fds);  tv.tv_sec = (time_t) floor(timeout);  tv.tv_usec = (time_t) ((timeout - floor(timeout)) * 1.0e6);  if (select(fdmax, &fds, NULL, NULL, &tv) < 0) {    gphone_perror_exit("*** connection_listen : select", 1);  }  if (FD_ISSET(Data_Sock, &fds)) {    /* read an RTP packet */    Rtp_Packet packet;    packet = rtp_packet_read(Data_Sock, &fromaddr);    parse_rtp_packet(packet, &fromaddr);    rtp_packet_free(packet);    rtp_read = 1;  }  if (FD_ISSET(Control_Sock, &fds)) {    /* read and handle an RTCP packet */    Rtcp_Compound compound;    compound = rtcp_compound_read(Control_Sock, &fromaddr);    parse_rtcp_compound(compound, &fromaddr);    rtcp_compound_free(compound);  }  return rtp_read;}/* * Local variables: *  compile-command: "make -k gphone" * End: */

⌨️ 快捷键说明

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