I have the following source compiled by g++ 4.8.2 :
g++ --std=c++11 testx.cpp -pthread -lrt -O2 -o testx.exe
g++ --std=c++11 testx.cpp -pthread -lrt -o testy.exe
layout.h :
#pragma once
typedef struct DBInfo_
{
volatile int seqno ;
char groupname[32] ;
char action[32] ;
int booklayer ;
} DBInfo ;
#define DBARRAYSIZE 100
static DBInfo *conf;
#define STATE_FILE "/strategy2/test.shared"
testx.cpp :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/file.h>
#include <ctype.h>
#include <pthread.h>
#include <sys/stat.h>
#include <assert.h>
#include "layout.h"
int g_DBSharedMemIdx = 0 ;
volatile int iGlbErrorSeqLock = 0 ;
void create_shmem(void)
{
int shm_fd;
if((shm_fd = shm_open(STATE_FILE, (O_CREAT | O_EXCL | O_RDWR),
(S_IREAD | S_IWRITE))) > 0 ) {
printf("O_CREAT | O_EXCL | O_RDWR \n"); /* We are the first instance */
}
else if((shm_fd = shm_open(STATE_FILE, (O_CREAT | O_RDWR),
(S_IREAD | S_IWRITE))) < 0)
{
printf("Could not create shm object. \n");
exit( 0 ) ;
}
int iTotalByte = sizeof(DBInfo)*DBARRAYSIZE ;
ftruncate(shm_fd, iTotalByte );
conf = (DBInfo*) mmap(0, iTotalByte , (PROT_READ | PROT_WRITE), MAP_SHARED, shm_fd, 0) ;
if(conf == MAP_FAILED)
{
printf(" mmap error ....\n") ;
exit( 0 ) ;
}
g_DBSharedMemIdx = 0 ;
(conf+g_DBSharedMemIdx)->seqno = 0 ;
strcpy( (conf+g_DBSharedMemIdx)->groupname,"" ) ;
strcpy( (conf+g_DBSharedMemIdx)->action,"" ) ;
(conf+g_DBSharedMemIdx)->booklayer = 0 ;
}//create_shmem
int getDBInfo(DBInfo& pDBInfo)
{
if( pDBInfo.seqno == (conf+g_DBSharedMemIdx)->seqno)
return 0 ;
volatile int ilocalseqno1 = 0 , ilocalseqno2 = 0 ;
volatile int icnt=0;
while( 1 ){
icnt++ ;
if( icnt >= 10000 ){
iGlbErrorSeqLock = 1 ;
break ;
}
ilocalseqno1 = (conf+g_DBSharedMemIdx)->seqno ;
if( ilocalseqno1 % 2 ){
printf("***************************************************************************** \n");
continue;
}
strcpy( pDBInfo.action,(conf+g_DBSharedMemIdx)->action ) ;
pDBInfo.booklayer = (conf+g_DBSharedMemIdx)->booklayer ;
ilocalseqno2 = (conf+g_DBSharedMemIdx)->seqno ;
if( ilocalseqno1 != ilocalseqno2 ){
printf("***************************************************************************** \n");
continue;
}
pDBInfo.seqno = ilocalseqno2 ;
break ;
} //while
if( iGlbErrorSeqLock == 1 )
return -1 ;
return 1 ;
}//getDBInfo
void *ThreadONE(void *param)
{
printf("TestThread...(%p)\n",param) ;
pthread_detach(pthread_self());
while( 1 ){
(conf+g_DBSharedMemIdx)->seqno++ ;
strcpy( (conf+g_DBSharedMemIdx)->groupname,"group1" ) ;
strcpy( (conf+g_DBSharedMemIdx)->action,"RUN" ) ;
(conf+g_DBSharedMemIdx)->booklayer = 3 ;
if( (conf+g_DBSharedMemIdx)->seqno % 2 == 1 )
(conf+g_DBSharedMemIdx)->seqno++ ;
usleep( 1 ) ;
}//while
}//ThreadONE
void *ThreadTWO(void *param)
{
DBInfo pDBInfo ;
printf("TestThread...(%p)\n",param) ;
pthread_detach(pthread_self());
int icnt = 0 ;
while( 1 ){
int iret = getDBInfo(pDBInfo);
if( iret < 0 ){
printf("iGlbErrorSeqLock happened \n") ;
assert( iGlbErrorSeqLock == 100 );
}else if(iret == 1){
icnt++ ;
//printf("icnt=(%d)\n",icnt);
}
usleep( 1 ) ;
}//while
}//ThreadTWO
int main(int argc, char** argv)
{
create_shmem();
sleep( 1 ) ;
pthread_t tid ;
pthread_create(&tid , NULL, ThreadONE, (void*)(long)3);
pthread_create(&tid , NULL, ThreadTWO, (void*)(long)3);
while( 1 )
sleep( 5 ) ;
} //main
testy.exe(compiled without -O2) run will see "**************" 2 times per second ,
testx.exe(compiled with -O2) run will see "***********" not quite easy .
I have this test because in my original source , sometimes call function
like getDBInfo will be trapped in endless loop if compiled with -O2,
and it will be fine without -O2 , so I am curious what compiler do in
getDBInfo function and what should I do according to it .
Related
I try to test one application which will run several threads with different priority , so the following is my test ap , run in linux x86_64 :
pthread_spinlock_t orderspinlock ;
int iGlbCnt=0 ;
void * donothing(void *arg)
{
pthread_attr_t attr;
pthread_attr_init (&attr);
//int s = pthread_attr_setinheritsched (&attr, PTHREAD_INHERIT_SCHED );
int s = pthread_attr_setinheritsched (&attr, PTHREAD_EXPLICIT_SCHED );
if( s != 0 ){
printf("pthread_attr_setinheritsched error \n");
exit(0) ;
}
int ipriority = (int)(long) arg ;
const char *sched_policy[] = {
"SCHED_OTHER",
"SCHED_FIFO",
"SCHED_RR",
"SCHED_BATCH"
};
struct sched_param sp = {
.sched_priority = ipriority
};
pid_t pid = getpid();
printf("pid=(%d)\n",pid);
sched_setscheduler(pid, SCHED_RR, &sp);
printf("Scheduler Policy is %s.\n", sched_policy[sched_getscheduler(pid)]);
pthread_detach(pthread_self());
int icnt=0;
while(1){
usleep( 1 ) ;
pthread_spin_lock(&orderspinlock) ;
iGlbCnt++ ;
pthread_spin_unlock(&orderspinlock) ;
if( ++icnt > 10000000 )
break;
}
printf("thread done...(%d)\n",iGlbCnt);
}
int main(int argc, char **argv)
{
pthread_spin_init(&orderspinlock, 0);
pthread_attr_t attr;
pthread_attr_init (&attr);
//int s = pthread_attr_setinheritsched (&attr, PTHREAD_INHERIT_SCHED );
int s = pthread_attr_setinheritsched (&attr, PTHREAD_EXPLICIT_SCHED );
if( s != 0 ){
printf("pthread_attr_setinheritsched error \n");
exit(0) ;
}
pthread_t tid;
pthread_create(&tid, NULL, &donothing, (void *)(long) 80);
pthread_create(&tid, NULL, &donothing, (void *)(long) 10);
while( 1 )
sleep( 5 ) ;
}
and g++ --std=c++11 y.cpp -pthread -o y.exe
run :
sudo chrt -r -v 66 ./y.exe
another terminal watch the threads by
top -H -p `pidof y.exe`
I see the threads PR are -67 , -67 , -11 , after both donothing threads die ,
the main thread PR = -11 , What should I do so that all three threads
priority are -81 , -11 , -67 and the main thread keep in -67 to the end ?!
Edit :
int policy = 2 ;
s = pthread_setschedparam(pthread_self(),policy,&sp) ;
instead of :
pid_t pid = getpid();
sched_setscheduler(pid, SCHED_RR, &sp);
look work fine to me .
I have recently testing queue with hazard pointer application as below :
https://github.com/chergert/dukes_of_hazard
I have noticed that RES raise quite fast in my own test ap ,
MEMORY-ERROR: [30770]: GSlice: failed to allocate 120 bytes (alignment: 128): Cannot allocate memory
happened in the end , the ap has 5 threads to enqueue , 5 threads to dequeue and then
send to 5 socket server each thread , like following :
#include "lf-queue.h"
typedef struct People_
{
int age ;
char name[16] ;
double income ;
} People ;
#define NUM 20000000
LfQueue *q ;
int GlbCnt,GlbRow ;
int iConn[5] ;
int main()
{
q = lf_queue_new();
g_thread_init(NULL);
if(DoConnect() != 1)
{
printf("Error in connect server .exe , port=5566,5567,5568,5569,5570 ! \n") ;
exit(0) ;
}
pthread_t tid1[5],tid2[5];
int icnt1[5] = {0,1,2,3,4} ;
int icnt2[5] = {0,1,2,3,4} ;
void *func1(void *);
void *func2(void *);
for(int idx=0;idx<5;idx++)
{
pthread_create(&tid1[idx], NULL, &func1 , (void *) icnt1[idx] );
pthread_create(&tid2[idx], NULL, &func2 , (void *) icnt2[idx] );
}
while(1){
printf("Done(%d)\n",GlbCnt) ;
sleep(1) ;
}
} //main
void *func1(void * inum)
{
int ithread = (long)(int) inum ;
pthread_detach(pthread_self());
People* p ;
while(1){
for(int idx=0;idx<NUM;idx++){
usleep(1) ;
p = (People *) malloc( sizeof(People) ) ;
p->age = __sync_add_and_fetch(&GlbRow,1) ;
sprintf(p->name,"%s%08d","NAME",p->age ) ;
p->income = p->age * 1.0 ;
lf_queue_enqueue(q,p) ;
}
break ;
} //while
}
void *func2(void * inum)
{
int ithread = (long)(int) inum ;
pthread_detach(pthread_self());
People* p ;
while(1){
usleep(1) ;
p = (People *) lf_queue_dequeue(q) ;;
if(p){
char line[128]={0} ;
sprintf(line,"%010d|%s|%010.0f|",p->age,p->name,p->income) ;
if (send(iConn[ithread],line,35,MSG_NOSIGNAL)<0){
printf("send error \n");
exit( 0 ) ;
}
__sync_add_and_fetch(&GlbCnt,1) ;
free(p) ;
}
} //while
}
Is there an easy way to check if a key is being pressed so I can loop through that in a thread? Preferred not to use a library and definitely not ncurses. There isn't a single thing working that I have found over the internet.
Try this:-
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
int main()
{
struct termios oldSettings, newSettings;
tcgetattr( fileno( stdin ), &oldSettings );
newSettings = oldSettings;
newSettings.c_lflag &= (~ICANON & ~ECHO);
tcsetattr( fileno( stdin ), TCSANOW, &newSettings );
while ( 1 )
{
fd_set set;
struct timeval tv;
tv.tv_sec = 10;
tv.tv_usec = 0;
FD_ZERO( &set );
FD_SET( fileno( stdin ), &set );
int res = select( fileno( stdin )+1, &set, NULL, NULL, &tv );
if( res > 0 )
{
char c;
printf( "Input available\n" );
read( fileno( stdin ), &c, 1 );
}
else if( res < 0 )
{
perror( "select error" );
break;
}
else
{
printf( "Select timeout\n" );
}
}
tcsetattr( fileno( stdin ), TCSANOW, &oldSettings );
return 0;
}
From here
I find a simpler way:
#include <X11/Xlib.h>
#include <iostream>
#include "X11/keysym.h"
/**
*
* #param ks like XK_Shift_L, see /usr/include/X11/keysymdef.h
* #return
*/
bool key_is_pressed(KeySym ks) {
Display *dpy = XOpenDisplay(":0");
char keys_return[32];
XQueryKeymap(dpy, keys_return);
KeyCode kc2 = XKeysymToKeycode(dpy, ks);
bool isPressed = !!(keys_return[kc2 >> 3] & (1 << (kc2 & 7)));
XCloseDisplay(dpy);
return isPressed;
}
bool ctrl_is_pressed() {
return key_is_pressed(XK_Control_L) || key_is_pressed(XK_Control_R);
}
int main(int argc, char **argv) {
std::cout << ctrl_is_pressed() << std::endl;
return (0);
};
I'm looking for a way to get a number which will almost surely change when running the code on different machines and almost surely stay the same between two runs on the same machine.
If I were doing this as a shell script in Linux, I would use something like this:
{ uname -n ; cat /proc/meminfo | head -n1 ; cat /proc/cpuinfo ; } | md5sum
But I need this in C++ (with boost) and at least on Windows, Linux and Mac.
To generate a mostly unique machine id, you can get a few serial numbers from various pieces of hardware on the system. Most processors will have a CPU serial number, the hard disks each have a number, and each network card will have a unique MAC address.
You can get these and build a fingerprint for the machine. You might want to allow some of these numbers to change before declaring it a new machine. ( e.g. if the 2 out of three are the same, then the machine is the same ). So you can deal somewhat gracefully from having a component upgraded.
I've clipped some code from one of my projects that gets these numbers.
Windows:
#include "machine_id.h"
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <intrin.h>
#include <iphlpapi.h>
#ifndef _MSC_VER
#include <cpuid.h>
#else
#include <intrin.h>
#endif
// we just need this for purposes of unique machine id. So any one or two mac's is
// fine.
u16 hashMacAddress( PIP_ADAPTER_INFO info )
{
u16 hash = 0;
for ( u32 i = 0; i < info->AddressLength; i++ )
{
hash += ( info->Address[i] << (( i & 1 ) * 8 ));
}
return hash;
}
void getMacHash( u16& mac1, u16& mac2 )
{
IP_ADAPTER_INFO AdapterInfo[32];
DWORD dwBufLen = sizeof( AdapterInfo );
DWORD dwStatus = GetAdaptersInfo( AdapterInfo, &dwBufLen );
if ( dwStatus != ERROR_SUCCESS )
return; // no adapters.
PIP_ADAPTER_INFO pAdapterInfo = AdapterInfo;
mac1 = hashMacAddress( pAdapterInfo );
if ( pAdapterInfo->Next )
mac2 = hashMacAddress( pAdapterInfo->Next );
// sort the mac addresses. We don't want to invalidate
// both macs if they just change order.
if ( mac1 > mac2 )
{
u16 tmp = mac2;
mac2 = mac1;
mac1 = tmp;
}
}
u16 getVolumeHash()
{
DWORD serialNum = 0;
// Determine if this volume uses an NTFS file system.
GetVolumeInformation( "c:\\", NULL, 0, &serialNum, NULL, NULL, NULL, 0 );
u16 hash = (u16)(( serialNum + ( serialNum >> 16 )) & 0xFFFF );
return hash;
}
u16 getCpuHash()
{
int cpuinfo[4] = { 0, 0, 0, 0 };
__cpuid( cpuinfo, 0 );
u16 hash = 0;
u16* ptr = (u16*)(&cpuinfo[0]);
for ( u32 i = 0; i < 8; i++ )
hash += ptr[i];
return hash;
}
const char* getMachineName()
{
static char computerName[1024];
DWORD size = 1024;
GetComputerName( computerName, &size );
return &(computerName[0]);
}
Linux and OsX:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/resource.h>
#include <sys/utsname.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <assert.h>
#ifdef DARWIN
#include <net/if_dl.h>
#include <ifaddrs.h>
#include <net/if_types.h>
#else //!DARWIN
// #include <linux/if.h>
// #include <linux/sockios.h>
#endif //!DARWIN
const char* getMachineName()
{
static struct utsname u;
if ( uname( &u ) < 0 )
{
assert(0);
return "unknown";
}
return u.nodename;
}
//---------------------------------get MAC addresses ------------------------------------unsigned short-unsigned short----------
// we just need this for purposes of unique machine id. So any one or two mac's is fine.
unsigned short hashMacAddress( unsigned char* mac )
{
unsigned short hash = 0;
for ( unsigned int i = 0; i < 6; i++ )
{
hash += ( mac[i] << (( i & 1 ) * 8 ));
}
return hash;
}
void getMacHash( unsigned short& mac1, unsigned short& mac2 )
{
mac1 = 0;
mac2 = 0;
#ifdef DARWIN
struct ifaddrs* ifaphead;
if ( getifaddrs( &ifaphead ) != 0 )
return;
// iterate over the net interfaces
bool foundMac1 = false;
struct ifaddrs* ifap;
for ( ifap = ifaphead; ifap; ifap = ifap->ifa_next )
{
struct sockaddr_dl* sdl = (struct sockaddr_dl*)ifap->ifa_addr;
if ( sdl && ( sdl->sdl_family == AF_LINK ) && ( sdl->sdl_type == IFT_ETHER ))
{
if ( !foundMac1 )
{
foundMac1 = true;
mac1 = hashMacAddress( (unsigned char*)(LLADDR(sdl))); //sdl->sdl_data) + sdl->sdl_nlen) );
} else {
mac2 = hashMacAddress( (unsigned char*)(LLADDR(sdl))); //sdl->sdl_data) + sdl->sdl_nlen) );
break;
}
}
}
freeifaddrs( ifaphead );
#else // !DARWIN
int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP );
if ( sock < 0 ) return;
// enumerate all IP addresses of the system
struct ifconf conf;
char ifconfbuf[ 128 * sizeof(struct ifreq) ];
memset( ifconfbuf, 0, sizeof( ifconfbuf ));
conf.ifc_buf = ifconfbuf;
conf.ifc_len = sizeof( ifconfbuf );
if ( ioctl( sock, SIOCGIFCONF, &conf ))
{
assert(0);
return;
}
// get MAC address
bool foundMac1 = false;
struct ifreq* ifr;
for ( ifr = conf.ifc_req; (char*)ifr < (char*)conf.ifc_req + conf.ifc_len; ifr++ )
{
if ( ifr->ifr_addr.sa_data == (ifr+1)->ifr_addr.sa_data )
continue; // duplicate, skip it
if ( ioctl( sock, SIOCGIFFLAGS, ifr ))
continue; // failed to get flags, skip it
if ( ioctl( sock, SIOCGIFHWADDR, ifr ) == 0 )
{
if ( !foundMac1 )
{
foundMac1 = true;
mac1 = hashMacAddress( (unsigned char*)&(ifr->ifr_addr.sa_data));
} else {
mac2 = hashMacAddress( (unsigned char*)&(ifr->ifr_addr.sa_data));
break;
}
}
}
close( sock );
#endif // !DARWIN
// sort the mac addresses. We don't want to invalidate
// both macs if they just change order.
if ( mac1 > mac2 )
{
unsigned short tmp = mac2;
mac2 = mac1;
mac1 = tmp;
}
}
unsigned short getVolumeHash()
{
// we don't have a 'volume serial number' like on windows. Lets hash the system name instead.
unsigned char* sysname = (unsigned char*)getMachineName();
unsigned short hash = 0;
for ( unsigned int i = 0; sysname[i]; i++ )
hash += ( sysname[i] << (( i & 1 ) * 8 ));
return hash;
}
#ifdef DARWIN
#include <mach-o/arch.h>
unsigned short getCpuHash()
{
const NXArchInfo* info = NXGetLocalArchInfo();
unsigned short val = 0;
val += (unsigned short)info->cputype;
val += (unsigned short)info->cpusubtype;
return val;
}
#else // !DARWIN
static void getCpuid( unsigned int* p, unsigned int ax )
{
__asm __volatile
( "movl %%ebx, %%esi\n\t"
"cpuid\n\t"
"xchgl %%ebx, %%esi"
: "=a" (p[0]), "=S" (p[1]),
"=c" (p[2]), "=d" (p[3])
: "0" (ax)
);
}
unsigned short getCpuHash()
{
unsigned int cpuinfo[4] = { 0, 0, 0, 0 };
getCpuid( cpuinfo, 0 );
unsigned short hash = 0;
unsigned int* ptr = (&cpuinfo[0]);
for ( unsigned int i = 0; i < 4; i++ )
hash += (ptr[i] & 0xFFFF) + ( ptr[i] >> 16 );
return hash;
}
#endif // !DARWIN
int main()
{
printf("Machine: %s\n", getMachineName());
printf("CPU: %d\n", getCpuHash());
printf("Volume: %d\n", getVolumeHash());
return 0;
}
I know, the question is bit too old to be answered. But I have on many occasions faced this issue. I like the accept solution, but if you have tried the code then you will know that it has issues.
firstly the CPU id is the product ID- it is not the serial. So if you have same CPU in another Server then it is just not going to work. also the MAC Address can be changed with ease.
If you are only trying to get this done on Linux- you could try like hal services. ie.
hal-get-property --udi /org/freedesktop/Hal/devices/computer --key system.hardware.uuid
But best thing probably to do is if you can enforce root access and if you want to get your hands dirty- is to look at the code for dmidecode. It will allow you to extract UUID of Chasis, Bios, Video and System. You cannot beat that :) and with a few tweaking you can convert it to a class.
Maybe you can generate almost unique id from unique hardware ids -
MAC is universally unique, you can also use cpu model
In my opinion you should pick only those things which may not be changed frequently like cpu or LAN/WLAN cards.
One quite portable solution would be to use modification time of a current executable. stat function is available on unix and windows, although API is different so you would need to use some IFDEFs.
A binary is unlikely to be deployed at the exactly same time to different machines, so the ids should be unique. The drawback is that the binary update will change the ids.
EDIT
I've made changes to what I saw below and this is what I have
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/un.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <string>
#include <vector>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <errno.h>
using namespace std;
string buffer;
vector<string> ex;
int s;
void recvline ( int s, string* buf ) {
char in, t;
while ( 1 ) {
recv ( s, &in, 1, 0 );
*buf += in;
if ( in == 10 ) {
t = 1; }
if ( t && in == 13 ) {
break; }
}
}
void push ( int s, string msg ) {
string o = msg + "\r\n";
cout << "SENT:", o;
send ( s, o.c_str(), o.size(), 0 );
}
int main ( int argc, char *argv[] ) {
if ( argc < 3 ) {
cout << "Insufficient Arguments" << endl;
exit ( 7 ); }
s = socket ( AF_INET, SOCK_STREAM, IPPROTO_TCP );
if ( s < 0 )
exit ( 1 );
struct hostent h = *gethostbyname ( argv[1] );
struct sockaddr_in c;
c.sin_family = AF_INET;
c.sin_port = htons(atoi(argv[2]));
c.sin_addr.s_addr = inet_addr ( h.h_addr_list[0] );
if ( connect ( s, (struct sockaddr*)&c, sizeof c ) != 0 ) {
cout << "Unable to connect to network" << endl;
cout << strerror(errno) << endl;
exit ( 2 );
}
push ( s, "USER LOLwat Lw lol.wat :LOLwat" );
push ( s, "NICK LOLwat" );
while ( true ) {
recvline ( s, &buffer );
cout << buffer;
if ( buffer.substr(0,4).c_str() == "PING" )
push ( s, "PONG " + buffer.substr(6,-2) );
}
}
And this is the result:
[dbdii407#xpcd Desktop]$ g++ ?.cpp -o 4096 -
[dbdii407#xpcd Desktop]$ ./4096 irc.scrapirc.com 6667 - Unable to connect to network - Network is unreachable
I think the problem is that this line:
c.sin_port = htons(*argv[2]);
Is not doing what you think it's doing. argv[2] is a string, *argv[2] is the first character of the string. So if you passed "4567" as the second command-line argument, then *argv[2] will be '4' which has ASCII value 52. That means you'll be attempting to connect to port 52, not "4567" as you would expect.
Change the line to:
c.sin_port = htons(atoi(argv[2]));
The atoi function takes a string and converts it to an integer. So "4567" would become 4567.
Also, in general, you should check the value of errno when a function call like that fails (it'll usually tell you in the documentation whether errno is set and the possible values it can be set to). That should help to give you some clue in the future.
Edit
As others have noted, make sure you pay attention to your braces. It's usually easier if you just always use braces around if, while, and so on. That is, this:
if ( connect ( s, (struct sockaddr*)&c, sizeof c ) != 0 )
cout << "Unable to connect to network" << endl;
exit ( 2 );
Is completely different to this:
if ( connect ( s, (struct sockaddr*)&c, sizeof c ) != 0 ) {
cout << "Unable to connect to network" << endl;
exit ( 2 );
}
I decided to completely redo my answer, in part due to the following comment in the gethostbyname manpage:
The gethostbyname*() and
gethostbyaddr*() functions are
obsolete. Applications should use
getaddrinfo(3) and getnameinfo(3)
instead.
Here is the reworked program ( cleaned up a bit with bcpp ) based on using getaddrinfo. I would strongly suggest always compiling with the following options:
g++ -Wall -Wextra irc.cpp -o irc
This showed up the following bugs in your code:
irc.cpp: In function ‘void push(int, std::string)’:
irc.cpp:40: warning: right-hand operand of comma has no effect
irc.cpp: In function ‘int main(int, char**)’:
irc.cpp:87: warning: comparison with string literal results in unspecified behaviour
I went ahead and fixed the errors. Also, try and eliminate global variables as much as possible.
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/un.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <string>
#include <vector>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <errno.h>
using namespace std;
string buffer;
vector<string> ex;
void recvline ( int s, string* buf )
{
char in, t;
while ( 1 )
{
recv ( s, &in, 1, 0 );
*buf += in;
if ( in == 10 )
{
t = 1;
}
if ( t && in == 13 )
{
break;
}
}
}
void push ( int s, string msg )
{
string o = msg + "\r\n";
cout << "SENT:" << o;
send ( s, o.c_str(), o.size(), 0 );
}
int main ( int argc, char *argv[] )
{
if ( argc < 3 )
{
cout << "Insufficient Arguments" << endl;
exit ( 7 );
}
int s, sfd;
struct addrinfo *result, *rp;
s = getaddrinfo(argv[1], argv[2], NULL, &result);
if (s != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
exit(EXIT_FAILURE);
}
for (rp = result; rp != NULL; rp = rp->ai_next) {
sfd = socket(rp->ai_family, rp->ai_socktype,
rp->ai_protocol);
if (sfd == -1)
continue;
if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1)
break; /* Success */
close(sfd);
}
if (rp == NULL) { /* No address succeeded */
fprintf(stderr, "Could not connect\n");
exit(EXIT_FAILURE);
}
freeaddrinfo(result); /* No longer needed */
push ( sfd, "USER LOLwat Lw lol.wat :LOLwat" );
push ( sfd, "NICK LOLwat" );
while ( true )
{
recvline ( sfd, &buffer );
cout << buffer;
if ( buffer.substr(0,4) == "PING" )
push ( sfd, "PONG " + buffer.substr(6,-2) );
}
}