DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
  1. DZone
  2. Data Engineering
  3. Databases
  4. Refactoring C Code: Starting With an API

Refactoring C Code: Starting With an API

Need to learn to refactor some code for that pesky legacy app? Read on to see how one dev refactored his C-based code.

Oren Eini user avatar by
Oren Eini
·
Jan. 10, 19 · Tutorial
Like (1)
Save
Tweet
Share
7.39K Views

Join the DZone community and get the full member experience.

Join For Free

In my last post, I introduced a basic error handling mechanism for C API. The code I showed had a small memory leak in it. I love that fact about it, because it is hidden away and probably won’t show up very easily for production code until very late in the game. Here is the fix:

image

The problem was that I was freeing the error struct, but wasn’t freeing the actual error message. That is something that is very easy to miss, unfortunately. Especially as we assume that errors are rare. With that minor issue out of the way, let’s look at how we actually write the code. Here is the updated version of creating a connection, with proper error handling:

image

The calling code will check if it got NULL and then can decide whatever it should add it’s own error (for context) and return a failure to its own caller or handle it. The cleanup stuff is still annoying with goto, but I don’t believe that there is much that can be done about it.

I’m going to refactored things a bit, so I have proper separation and an explicit API. Here is what the API looks like now:

image

This is basically a wrapper around all the things we need to around SSL. It handles one time initialization and any other necessary work that is required. Note that I don’t actually expose any state outside, instead just forward declaring the state struct and leaving it at that. In addition to the overall server state, there is also a single connection state, whose API looks like this:

image

Now, let’s bring it all together and see how it works.

int main(int argc, char **argv)
{
int rc;
int sock = -1;
struct server_state* srv_state;

const char* cert = "cert.pem";
const char* key =  "key.pem" ;

sock = create_server_socket(4433);
if (sock == -1) {
goto handle_error;
}

srv_state = server_state_create(cert, key);

if (srv_state == NULL) {
goto handle_error;
}

while (1) {
struct sockaddr_in addr;
struct connection* con;
unsigned int len = sizeof(addr);
char buffer[256];

int client = accept(sock, (struct sockaddr*)&addr, &len);
if (client == INVALID_SOCKET) {
push_error(ENETRESET, "Unable to accept connection, error: %i", GetLastError());
// failure to accept impacts everything, we'll abort
goto handle_error; 
}

con = connection_create(srv_state, client);

if (con == NULL)
{
closesocket(client);
print_all_errors();
continue; // accept the next connection...
}

if (connection_write_format(con, "Connected!\n") == 0) {
goto handle_connection_error;
}

while (1)
{
      // now, let's do echo server...
rc = connection_read(con, buffer, sizeof buffer);
if (rc == 0) {
goto handle_connection_error;
}

if (connection_write(con, buffer, rc) == 0) {
goto handle_connection_error;
}
}

handle_connection_error:
print_all_errors();
if (con != NULL) {
connection_drop(con);
}
// now go back and accept another connection
}

handle_error:

if(srv_state != NULL)
server_state_drop(srv_state);

if (sock != -1)
closesocket(sock);

print_all_errors();


return EINVAL;
}

This is a pretty trivial echo server, I’ll admit, but it actually handles things like SSL setup, good error handling and give us a good baseline to start from.

The code for this series can be found here and this post’s code is this commit. Next, I want to see what it would take to setup client authentication with OpenSSL.

API

Published at DZone with permission of Oren Eini, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • How and Why You Should Start Automating DevOps
  • Easy Smart Contract Debugging With Truffle’s Console.log
  • Streamlining Your Workflow With the Jenkins HTTP Request Plugin: A Guide to Replacing CURL in Scripts
  • Top Authentication Trends to Watch Out for in 2023

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: